运用ForkJoin多线程框架实现归并排序

一、普通归并排序
1
public class MergeSort {
2
3
    /**
4
     * 原地归并排序(每次只将数组分为大和小两部分,并不是完全排序完成。需要递归)
5
     *
6
     * @param arr
7
     * @param lo
8
     * @param mid
9
     * @param hi
10
     */
11
    public void merge(int[] arr, int lo, int mid, int hi) {
12
        //1.复制数组
13
        int i = lo;
14
        int j = mid + 1;
15
        int[] temp = new int[arr.length];
16
        for (int k = lo; k <= hi; k++) {
17
            temp[k] = arr[k];
18
        }
19
        //2.移动指针进行排序(4种情况)
20
        for (int k = lo; k <= hi; k++) {
21
            if (i > mid) {//2.1 左边用尽
22
                arr[k] = temp[j++];
23
            } else if (j > hi) {//2.2 右边用尽
24
                arr[k] = temp[i++];
25
            } else if (temp[j] < temp[i]) {//2.3 左边大于右边
26
                arr[k] = temp[j++];
27
            } else {//2.4 右边大于左边
28
                arr[k] = temp[i++];
29
            }
30
31
        }
32
    }
33
34
    /**
35
     * 递归进行归并排序
36
     *
37
     * @param arr
38
     */
39
    public void sort(int[] arr) {
40
        sort(arr, 0, arr.length - 1);
41
    }
42
43
    public void sort(int[] arr, int lo, int hi) {
44
        if (hi <= lo) return;
45
        int mid = lo + (hi - lo) / 2;
46
        sort(arr,lo,mid);//左半边排序
47
        sort(arr,mid+1,hi);//右半边排序
48
        merge(arr,lo,mid,hi);//归并
49
    }
50
51
52
    // 生成一个数量为MAX的随机整数集合,准备计算数据
53
    private static int MAX = 100000;//100000个数进行排序
54
    private static int[] inits = new int[MAX];
55
    static {
56
        Random r = new Random();
57
        for(int index = 1 ; index <= MAX ; index++) {
58
            inits[index - 1] = r.nextInt(10000000);
59
        }
60
    }
61
    @Test
62
    public void testMerge() {
63
        long start = System.currentTimeMillis();
64
        sort(inits);
65
        long end = System.currentTimeMillis();
66
        //打印排序用时
67
        System.out.println(end - start);
68
    }
69
}
运行结果:

排序100000个随机数用了差不多5秒
 
二、ForkJoinPool实现归并排序
1
public class ConcurrentForkJoinMergeSort {
2
   private static int MAX = 100000;
3
4
    private static int inits[] = new int[MAX];
5
6
    // 同样进行随机队列初始化,这里就不再赘述了
7
    static {
8
        Random r = new Random();
9
        for(int index = 1 ; index <= MAX ; index++) {
10
            inits[index - 1] = r.nextInt(10000000);
11
        }
12
    }
13
14
    public static void main(String[] args) throws Exception {
15
        // 正式开始
16
        long beginTime = System.currentTimeMillis();
17
        ForkJoinPool pool = new ForkJoinPool();
18
        MyTask task = new MyTask(inits);
19
        ForkJoinTask<int[]> taskResult = pool.submit(task);
20
        try {
21
            taskResult.get();
22
        } catch (InterruptedException | ExecutionException e) {
23
            e.printStackTrace(System.out);
24
        }
25
        long endTime = System.currentTimeMillis();
26
        System.out.println("耗时=" + (endTime - beginTime));
27
    }
28
29
    /**
30
     * 单个排序的子任务
31
     */
32
    static class MyTask extends RecursiveTask<int[]> {
33
34
        private int source[];
35
36
        public MyTask(int source[]) {
37
            this.source = source;
38
        }
39
40
        /* (non-Javadoc)
41
         * @see java.util.concurrent.RecursiveTask#compute()
42
         */
43
        @Override
44
        protected int[] compute() {
45
            int sourceLen = source.length;
46
            // 如果条件成立,说明任务中要进行排序的集合还不够小
47
            if(sourceLen > 2) {
48
                int midIndex = sourceLen / 2;
49
                // 拆分成两个子任务
50
                MyTask task1 = new MyTask(Arrays.copyOf(source, midIndex));
51
                task1.fork();
52
                MyTask task2 = new MyTask(Arrays.copyOfRange(source, midIndex , sourceLen));
53
                task2.fork();
54
                // 将两个有序的数组,合并成一个有序的数组
55
                int result1[] = task1.join();
56
                int result2[] = task2.join();
57
                int mer[] = joinInts(result1 , result2);
58
                return mer;
59
            }
60
            // 否则说明集合中只有一个或者两个元素,可以进行这两个元素的比较排序了
61
            else {
62
                // 如果条件成立,说明数组中只有一个元素,或者是数组中的元素都已经排列好位置了
63
                if(sourceLen == 1
64
                        || source[0] <= source[1]) {
65
                    return source;
66
                } else {
67
                    int targetp[] = new int[sourceLen];
68
                    targetp[0] = source[1];
69
                    targetp[1] = source[0];
70
                    return targetp;
71
                }
72
            }
73
        }
74
75
        private int[] joinInts(int[] arr1, int[] arr2) {
76
77
            int left = 0;
78
            int right = 0;
79
            int[] mergeArr = new int[arr1.length + arr2.length];
80
            if(mergeArr.length == 0) return null;
81
            for (int i = 0; i < arr1.length + arr2.length; i++) {
82
                if(arr1.length == left) {
83
                    mergeArr[i] = arr2[right];
84
                    right++;
85
                    continue;
86
                }else if(arr2.length == right) {
87
                    mergeArr[i] = arr1[left];
88
                    left++;
89
                    continue;
90
                }
91
                if(arr1[left] <= arr2[right]){
92
                    mergeArr[i] = arr1[left];
93
                    left++;
94
                }else{
95
                    mergeArr[i] = arr2[right];
96
                    right++;
97
                }
98
            }
99
            return mergeArr;
100
        }
101
    }
102
}
运行结果:

 排序100000个随机数只用了28毫秒

你可能感兴趣的:(Java多线程,算法和数据结构)