算法导论2.3MERGE-SORT(分治或者合并排序算法)

时间:2022-06-15 11:06:43
  public static void main(String[] args) {
        int[] s = {3, 2, 4, 5, 7, 6, 1};
        //注意下标的选取,用伪代码都需要+1
        sort(s,0,6);
        print(s);
    }

    private static void  print(int[] s){
        for (int i = 0; i < s.length; i++) {
            if(i == 0){
                System.out.print("{");
            }
            System.out.print(s[i]);
            if(i < s.length -1){
                System.out.print(",");
            }
            if(i ==  s.length -1){
                System.out.print("}\n");
            }
        }
    }
    private static void sort(int[] s , int p ,int r){
        //只要p<r说明还可以继续分解
        if(p < r ){
            //取不大于(p+r)/2的最大整数
            int q = (p+r)/2 ;
            //排序下标为p到q的元素
            sort(s,p,q);
            //排序下标为q+1到r的元素
            sort(s,q+1,r);
            //合并
            sortMegre(s,p,q,r);

        }
    }
    //哨兵牌处理子数组的结束
    private static void sortMegre(int[] s , int p , int q , int r){
            int n1 = q-p+1;
            int n2 = r-q;
            int[] L = new int[n1+1];
            int[] R = new int[n2+1];
        for (int i = 0; i < L.length-1; i++) {
            L[i] = s[p+i];
        }
        for (int i = 0; i < R.length-1; i++) {
            R[i] =s[q+i+1];
        }
        //哨兵牌
        L[n1] =Integer.MAX_VALUE;
        R[n2] =Integer.MAX_VALUE;
        int j =0;
        int k = 0;
        for (int i = p; i <= r; i++) {
            if(L[j] <=R[k]){
                s[i] = L[j];
                j++;
            }else{
                s[i] = R[k];
                k++;
            }
        }
        //没有哨兵牌的排序方法
    private static void sortMegreNosentinal(int[] s , int p , int q , int r){
            int n1 = q-p+1;
            int n2 = r-q;
            int[] L = new int[n1];
            int[] R = new int[n2];
        for (int i = 0; i < L.length; i++) {
            L[i] = s[p+i];
        }
        for (int i = 0; i < R.length; i++) {
            R[i] =s[q+i+1];
        }
        int j =0;
        int k = 0;
        int i ;
        for ( i = p; i <= r; i++) {
        //如果大于子数组的最大下标则说明子数组已经空了
            if(j > n1-1  || k > n2-1){
                break;
            }
            if(L[j] <=R[k]){
                s[i] = L[j];
                j++;
            }else{
                s[i] = R[k];
                k++;
            }

        }
        //左侧为空
        if(j  > n1-1){
         //将右侧剩余的列表赋值给s
            for ( int m = 0; m < r-i+1; m++) {
                s[i+m] = R[k+m];
            }
        }
        //右侧为空
        if(k > n2-1 ){
        //将左侧剩余的列表赋值给s
            for ( int m = 0; m < r-i+1; m++) {
                s[i+m] = L[j+m];
            }
        }
    }

注意事项详见注释吧
这个排序方法原理不是特别的麻烦
但写起来很麻烦
问题主要是在下标的处理
伪代码是从1开始
而java都是从0开始计算的
但是我觉得掌握到原理还是比较简单的
另外需要注意这里的下标p,q,r都是包含的关系,可能和我们平时写代码的习惯不一样,这是个不小的坑
哨兵牌我没有找到无穷大怎么表示,只能暂时用int的最大值来表示,这点可能会有隐患,不过还好有不需要哨兵牌的表达方式,虽然写起来稍微有点麻烦
没想到写算法也会让人沉迷.

睡了