zno2

排序算法(sorting algorithm) 之 归并排序(merge sort)

初版(探索):运行很慢,写法有问题

import java.util.Arrays;

import cn.hutool.core.util.RandomUtil;

public class MergeSortTest {

    public static void main(String[] args) {
//        int[] arr = new int[] {0,4,1,9,3,6,2,7,5,8};
        int[] arr = RandomUtil.randomInts(101);
        Arena arena = new Arena(arr, false);
        arena.scanAndMerge();
        int[] merged = arena.getMerged();
        for (int i : merged) {
            System.out.println(i);
        }
    }

    public static class Arena {

        private int[] arr, merged;
        private boolean asc;
        private int l, r;

        public Arena(int[] arr, boolean asc) {
            this.arr = arr;
            this.merged = new int[0];
            this.asc = asc;
            this.l = 0;
            this.r = 1;
        }

        // 需要申请额外两块数组,最后一次合并,重写原始数组即可
        // 合并是只一个子序列和sorted合并,需要记录sorted当前指针,即head
        // 子序列是原始数组通过相对位置进行的记录,需要l,r
        // 扫描过程是r++
        // 合并后l和r 移动到下一个子序列开始位置
        public void scanAndMerge() {

            while (r < arr.length) {
                if (asc && arr[r - 1] <= arr[r] || !asc && arr[r - 1] >= arr[r]) {
                    r++;
                    if (r == arr.length) {
                        int[] subSeq = Arrays.copyOfRange(arr, l, r);
                        merged = merge(merged, subSeq, asc);
                    }
                } else {
                    int[] subSeq = Arrays.copyOfRange(arr, l, r);
                    merged = merge(merged, subSeq, asc);
                    l = r++;
                }
            }
        }

        public static int[] merge(int[] subSeq1, int[] subSeq2, boolean asc) {
            int len1 = subSeq1.length;
            int len2 = subSeq2.length;
            int head = 0;

            int[] merged = new int[len1 + len2];
            int i1 = 0;
            int i2 = 0;
            while (true) {
                if (i1 == len1 || i2 == len2) {
                    break;
                }
                int a = subSeq1[i1];
                int b = subSeq2[i2];
                if (asc) {
                    if (a <= b) {
                        merged[head++] = a;
                        i1++;
                    } else {
                        merged[head++] = b;
                        i2++;
                    }
                } else {
                    if (a >= b) {
                        merged[head++] = a;
                        i1++;
                    } else {
                        merged[head++] = b;
                        i2++;
                    }
                }

            }
            if (i1 == len1) {
                System.arraycopy(subSeq2, i2, merged, head, len2 - i2);
            } else {
                System.arraycopy(subSeq1, i1, merged, head, len1 - i1);
            }
            return merged;
        }

        public int[] getMerged() {
            return merged;
        }
    }

}

 

探索(依旧很慢,单向扫描不可行,还得看二分)

public class MergeSortTestXXXXX {

    public static void main(String[] args) {
        int[] arr = new int[] { 1, 4, 2, 3, 6, 5 };
//        int[] arr = new int[] { 1,2,3,4,5,6 };
//        int[] arr = RandomUtil.randomInts(10011111);
//        int[] arr = ArrayUtil.range(10011111);
        mergeSort(arr, true);

//        int[] arr = new int[] {4,1,3};
//        merge(arr, 0, 1, 2, false);
//        System.out.println(scan(arr,1, true));

        for (int i : arr) {
            System.out.println(i);
        }
    }

    public static void mergeSort(int[] arr, boolean asc) {

        int r0 = -1;

        for (;;) {
            int r1 = scan(arr, r0 + 1, asc);
            if (r1 < arr.length) {
                merge(arr, 0, r0, r1, asc);
                r0 = r1;
            } else {
                break;
            }
        }

    }

    public static int scan(int[] arr, int start, boolean asc) {
        int len = arr.length;
        if (start >= arr.length - 1) {
            return start;
        }
        while (start < len - 1) {
            if (asc && arr[start] <= arr[start + 1] || !asc && arr[start] >= arr[start + 1]) {
                start++;
            } else {
                break;
            }
        }

        return start;
    }

    // 初始 []1,4,2,3,6,5

    // 扫描[][1,4]2,3,6,5
    // 合并[1,4]2,3,6,5

    // 扫描[1,4][2,3,6]5
    // 合并[1,2,3,4,6]5

    // 扫描[1,2,3,4,6][5]
    // 合并[1,2,3,4,5,6]

    // 扫描[1,2,3,4,5,6][]
    // 结束

    /**
     * 合并相邻的、分别有序、总体无序的数组 ,比如[1,4][2,3] -> [1,2,3,4]
     * 
     * @param arr
     * @param l
     * @param f
     * @param r
     * @param asc
     */
    public static void merge(int[] arr, int l, int f, int r, boolean asc) {

        if (l == r) {
//            System.out.println(String.format("[%s,%s][%s,%s]失败", l, f,f+1,r));
            return;
        }

        int l0 = l;
        int l1 = f;
        int r0 = f + 1;
        int r1 = r;

        int t = 0;
        int[] tmp = new int[r1 - l0 + 1];
        while (l0 <= l1 && r0 <= r1) {
            int lv = arr[l0];
            int rv = arr[r0];
            tmp[t++] = (asc && lv <= rv || !asc && lv >= rv) ? arr[l0++] : arr[r0++];
        }
        while (l0 <= l1) {
            tmp[t++] = arr[l0++];
        }
        while (r0 <= r1) {
            tmp[t++] = arr[r0++];
        }

        System.arraycopy(tmp, 0, arr, l, tmp.length);
//        System.out.println(String.format("[%s,%s][%s,%s]成功", l, f,f+1,r));
    }
}

 

这个2000使用了类,便于理解

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.RandomUtil;

public class MergeSortTest2000 {

    public static void main(String[] args) {
        int[] arr = RandomUtil.randomInts(10011111);
        
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        mergeSort(new Arena(arr, 0, arr.length - 1, false));
        
        stopWatch.stop();
        
        System.out.println(stopWatch.getTotalTimeMillis());
    }

    //警告: 递归要用二分场景,不然会有栈内存溢出 
    public static void mergeSort(Arena arena) {
        if (arena == null) {
            return;
        }

        mergeSort(arena.left());
        mergeSort(arena.right());
        arena.merge();
    }

    public static class Arena {
        private int[] arr;
        private int l0, r0, l1, r1;
        private boolean asc;

//        2, 1, 3, 6, 4, 5
        public Arena(int[] arr, int l, int r, boolean asc) {
            this.arr = arr;
            this.asc = asc;
            this.l0 = l;
            this.r0 = r;
            this.l1 = (l + r) / 2;
            this.r1 = l1 + 1;
//            System.out.println(String.format("[%s,%s],[%s,%s]", l0,l1,r1,r0));
            
        }

        public Arena left() {
            return l0 >= l1 ? null : new Arena(arr, l0, l1, asc);
        }

        public Arena right() {
            return r1 >= r0 ? null : new Arena(arr, r1, r0, asc);
        }

        public void merge() {
            if (l0 >= r0) {
                return;
            }
            int a = l0;
            int t = 0;
            int[] tmp = new int[r0 - l0 + 1];
            while (l0 <= l1 && r1 <= r0) {
                int lv = arr[l0];
                int rv = arr[r1];
                tmp[t++] = (asc && lv <= rv || !asc && lv >= rv) ? arr[l0++] : arr[r1++];
            }
            while (l0 <= l1) {
                tmp[t++] = arr[l0++];
            }
            while (r1 <= r0) {
                tmp[t++] = arr[r1++];
            }

            System.arraycopy(tmp, 0, arr, a, tmp.length);
        }
    }
}
MergeSortTest2000

 

 

 

 

不使用类,单纯函数 

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.RandomUtil;

public class MergeSortTest1800 {

    public static void main(String[] args) {
        int[] arr = RandomUtil.randomInts(10011111);
        
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        mergeSort(arr, 0, arr.length - 1, true);
        
        stopWatch.stop();
        
        System.out.println(stopWatch.getTotalTimeMillis());
    }

    //警告: 递归要用二分场景,不然会有栈内存溢出 
    public static void mergeSort(int[] arr, int l, int r, boolean asc) {
        int l0 = l;
        int r0 = r;
        int l1 = (l + r) / 2;
        int r1 = l1 + 1;

        if(l >= r) {
            return;
        }
        
        mergeSort(arr, l0, l1, asc);
        mergeSort(arr, r1, r0, asc);
        
        int a = l0;
        int t = 0;
        int[] tmp = new int[r0 - l0 + 1];
        while (l0 <= l1 && r1 <= r0) {
            int lv = arr[l0];
            int rv = arr[r1];
            tmp[t++] = (asc && lv <= rv || !asc && lv >= rv) ? arr[l0++] : arr[r1++];
        }
        while (l0 <= l1) {
            tmp[t++] = arr[l0++];
        }
        while (r1 <= r0) {
            tmp[t++] = arr[r1++];
        }

        System.arraycopy(tmp, 0, arr, a, tmp.length);
    }
}
MergeSortTest1800

 

 

 

 

优化了三目运算

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.RandomUtil;

public class MergeSortTest1700 {

    public static void main(String[] args) {
        int[] arr = RandomUtil.randomInts(10011111);
        
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        mergeSort(arr, 0, arr.length - 1, true);
        
        stopWatch.stop();
        
        System.out.println(stopWatch.getTotalTimeMillis());
    }

    //警告: 递归要用二分场景,不然会有栈内存溢出 
    public static void mergeSort(int[] arr, int l, int r, boolean asc) {
        int l0 = l;
        int r0 = r;
        int l1 = (l + r) / 2;
        int r1 = l1 + 1;

        if(l >= r) {
            return;
        }
        
        mergeSort(arr, l0, l1, asc);
        mergeSort(arr, r1, r0, asc);
        
        int a = l0;
        int t = 0;
        int[] tmp = new int[r0 - l0 + 1];
        while (l0 <= l1 && r1 <= r0) {
            int lv = arr[l0];
            int rv = arr[r1];
            if((asc && lv <= rv || !asc && lv >= rv)) {
                tmp[t++] = arr[l0++];
            }else {
                tmp[t++] = arr[r1++];
            }
        }
        while (l0 <= l1) {
            tmp[t++] = arr[l0++];
        }
        while (r1 <= r0) {
            tmp[t++] = arr[r1++];
        }

        System.arraycopy(tmp, 0, arr, a, tmp.length);
    }
}
MergeSortTest1700

 

 

 

 

 

优化了赋值

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.RandomUtil;

public class MergeSortTest1650 {

    public static void main(String[] args) {
        int[] arr = RandomUtil.randomInts(10011111);
        
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        mergeSort(arr, 0, arr.length - 1, true);
        
        stopWatch.stop();
        
        System.out.println(stopWatch.getTotalTimeMillis());
    }

    //警告: 递归要用二分场景,不然会有栈内存溢出 
    public static void mergeSort(int[] arr, int l, int r, boolean asc) {
        int l0 = l;
        int r0 = r;
        int l1 = (l + r) / 2;
        int r1 = l1 + 1;

        if(l >= r) {
            return;
        }
        
        mergeSort(arr, l0, l1, asc);
        mergeSort(arr, r1, r0, asc);
        
        int a = l0;
        int t = 0;
        int[] tmp = new int[r0 - l0 + 1];
        while (l0 <= l1 && r1 <= r0) {
            int lv = arr[l0];
            int rv = arr[r1];
            if((asc && lv <= rv || !asc && lv >= rv)) {
                tmp[t++] = lv;
                l0++;
            }else {
                tmp[t++] = rv;
                r1++;
            }
        }
        while (l0 <= l1) {
            tmp[t++] = arr[l0++];
        }
        while (r1 <= r0) {
            tmp[t++] = arr[r1++];
        }

        System.arraycopy(tmp, 0, arr, a, tmp.length);
    }
}
MergeSortTest1650

 

 

 

 

 

优化了临时数组

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.RandomUtil;

public class MergeSortTest1500 {

    public static void main(String[] args) {
        int[] arr = RandomUtil.randomInts(10011111);
        
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        int[] tmp = new int[arr.length];
        mergeSort(arr, 0, arr.length - 1, true, tmp);
        
        stopWatch.stop();
        
        System.out.println(stopWatch.getTotalTimeMillis());
    }

    //警告: 递归要用二分场景,不然会有栈内存溢出 
    public static void mergeSort(int[] arr, int l, int r, boolean asc, int[] tmp) {
        int l0 = l;
        int r0 = r;
        int l1 = (l + r) / 2;
        int r1 = l1 + 1;

        if(l >= r) {
            return;
        }
        
        mergeSort(arr, l0, l1, asc, tmp);
        mergeSort(arr, r1, r0, asc, tmp);
        
        int a = l0;
        int t = 0;
        int len = r0 - l0 + 1;
        while (l0 <= l1 && r1 <= r0) {
            int lv = arr[l0];
            int rv = arr[r1];
            if((asc && lv <= rv || !asc && lv >= rv)) {
                tmp[t++] = lv;
                l0++;
            }else {
                tmp[t++] = rv;
                r1++;
            }
        }
        while (l0 <= l1) {
            tmp[t++] = arr[l0++];
        }
        while (r1 <= r0) {
            tmp[t++] = arr[r1++];
        }

        System.arraycopy(tmp, 0, arr, a, len);
    }
}
MergeSortTest1500

 

posted on 2023-06-02 08:14  zno2  阅读(6)  评论(0编辑  收藏  举报

导航