0
点赞
收藏
分享

微信扫一扫

归并排序递归和非递归写法+归并排序的精髓

一:归并排序算法实现

直接看图:
在这里插入图片描述
简单说:
一个数组分成两个数组,让两个子数组有序,将有序的两个子数组合并,怎么让子数组有序?依靠归并算法

归并算法

注意:传入的子数组是有序的.怎么得到有序的数组,子数组一直划分下去,子数组迟早是一个元素,一个元素的数组当然有序,然后合并,合并过程让两个有序的子数组变成一个有序的子数组,然后一直返回,直到让这个数组有序

 public static void merge(int[] arr,int L,int mid,int R){
        //用help数组去复制
        int[] help=new int[R-L+1];
        int leftPtr=L;
        int rightPtr=mid+1;
        int i=0;
        //这里必须等于也复制左数组的元素,保持元素稳定性
        while(leftPtr<=mid&&rightPtr<=R) help[i++]=arr[leftPtr]<=arr[rightPtr]?arr[leftPtr++]:arr[rightPtr++];
        while(leftPtr<=mid) help[i++]=arr[leftPtr++];
        while(rightPtr<=R) help[i++]=arr[rightPtr++];
        //把合并的数组复制会原数组对应的下标中;
        for (int j = 0; j < help.length; j++) {
            //注意:arr对应的下标是L+j;
            arr[L+j]=help[j];
        }
    }
递归实现
 public static void sort(int[] arr,int L,int R){//传递数组,分割成子数组,然后合并(合并过程就是排序的过程)
        if(L==R) return;//思考边界的情况,不可能出现L>R;
        //分割:
        int mid=L+(R-L)/2;
        sort(arr,L,mid);
        sort(arr,mid+1,R);
        //排序好子数组后,来合并两个子数组
        merge(arr,L,mid,R);
    }
非递归实现

它是从递归的最底层到上层通过一次一次循环模拟的

 public static void sort2(int[] arr){
        if(arr==null||arr.length<2) return;
        int len=arr.length;
        int mergeSize=1;//递归就是从子数组为1开始merge的....
        while(mergeSize<len){//每次更换一次mergeSize去迭代一遍数组
            int L=0;
            while(L<len){//以本mergeSize去迭代一遍
                if(mergeSize>=len-L) break;//剩下的长度不能分配一个子数组了
                int mid=L+mergeSize-1;//左数组的最后一个元素
                int R=mid+Math.min(len-mid-1,mergeSize);//R正常情况是mergeSize大小,不够就是剩下的大小len-mid-1
                merge(arr,L,mid,R);
                L=R+1;
            }
            //更新mergeSize
            if(mergeSize>len/2) break;//因为*2后会大于len的,此时mergeSize可能越界
            mergeSize=mergeSize<<1;
        }
    }

二:归并算法深度实践

思想:每次归并的时候,其实左右数组之间的数是会比较大小的
算法题
在一个数组中,一个数左边比它小的数的总和,叫该数的小和
所有数的小和累加起来,叫数组小和
给定一个数组arr,求数组小和

方法:利用归并时候比较过程,在比较左右子数组时机顺便我们最小和求出

代码:

public class SmallSum {
    public static void main(String[] args) {
        int[] arr={1,8,2,6,1,2,3,4,5,6,7};
        System.out.println(sort(arr, 0, arr.length - 1));
    }


    public static int sort(int[] arr, int L , int R){
        if(L==R){
            return 0;
        }
        int mid=L+(R-L)/2;
        //(合并过程,只有右数组的元素为基准,去观察左数组有没有小于它的元素,它不会找和自己一个数组中找,我们的规则是合并了一个数组,最小和就产生了)
        return  sort(arr,L,mid)+
                sort(arr,mid+1,R)+
                merge(arr,L,mid,R);
    }
    //每merge一次,就会产生一次最小和
    public  static int  merge(int[] arr,int L,int mid,int R){
       int result=0;
       int[] help=new int[R-L+1];
       int i=0;
       int lPtr=L;
       int rPtr=mid+1;
       while(lPtr<=mid&&rPtr<=R){
        result+=arr[lPtr]>arr[rPtr]?(mid-lPtr+1):0;//将序对的个数
        help[i++]=arr[lPtr]<=arr[rPtr]?arr[lPtr++]:arr[rPtr++];
       }
       while(lPtr<=mid) help[i++]=arr[lPtr++];
       while(rPtr<=R) help[i++]=arr[rPtr++];

        for (int j = 0; j < help.length; j++) {
            arr[L+j]=help[j];
        }
       return result;
    }
}
举报

相关推荐

0 条评论