排序-------归并排序(java)

概念 :归并算法是将两个或者两个以上的 有序列表 合并成一个新的有序列表,即把待排序列分为若干个子序列,每个子序列都是有序的,然后把子序列合并成整体有序列表。若将两个有序表合并成一个有序表,称为二路归并

算法思想:归并排序(mergeSort)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)

步骤:

  • 分解:将序列每次折半拆分

分组次数:log2^n

  • 合并:将划分后的序列段两两排序合并

合并次数:o(n)

算法描述:

  • 将序列每相邻的两个数字进行归并操作,形成n/2个子序列,排序后每个子序列包含两个元素。
  • 再讲子序列的相邻两个序列进行归并,形成n/4个子序列。
  • 直到所有元素排序完毕,排序结束。

 

方法:递归方法

public class MergeSort {
    //测试
    public static void main(String[] args) {
        int[] arr=new int[] {5,4,3,6,2,8,7,1};
        mergeSort(arr,0,arr.length-1);
        for(int a:arr){
            System.out.print(a+" ");
        }
    }
    //并归排序
    public static int[] mergeSort(int[] arr, int start,int end) {
        if(start<end){
            int mid=(start+end)/2;//划分排序的子序列个数
            mergeSort(arr,start,mid);//对左侧子序列进行排序
            mergeSort(arr,mid+1,end);//对右侧子序列进行排
            merge(arr,start,mid,end);//合并
        }
        return arr;
    }

     /*
       left左边有序列的作用值
       right右边有序列的索引值
       mid:中间索引(分割数组的元素)
      */
    public static void merge(int[] arr, int left, int mid, int right) {
        int[] tmp=new int[arr.length];//中转数组
        int p1=left;//左边的有序序列的初始索引
        int p2=mid+1;//右边有序序列的初始索引
        int k=left;//k是存放指针
        while(p1<=mid&&p2<=right){//把两个合并的子序列里面较小的数放前边,大的数放后边
            if(arr[p1]<=arr[p2]){
                tmp[k++]=arr[p1++];
            }else{
                tmp[k++]=arr[p2++];
            }
        }
        while(p1<=mid)//左边的有序序列还有剩余的元素,把没有排完的数直接追加到tmp后边
            tmp[k++]=arr[p1++];
        while(p2<=right)//右边的有序序列还有剩余的元素,把没有排完的数直接追加到tmp后边
            tmp[k++]=arr[p2++];
        for(int i=left;i<=right;i++){//把临时数组tmp里的内容赋给arr
            arr[i]=tmp[i];
        }
    }
}

优化:

1.当元素个数比较小时,调用直接插入排序

2.当左边数组最大元素都小于右边数组的最小元素,说明整个数组有序,排序结束

 public static void mergeSort2(int[] array,int low,int high) {
        // 优化一:数据比较少时,采用直接 插入排序
        if (high - low <= 15) {
            InsertSort.insertSort1(array,array.length);
            return;
        }
        int mid = (low + high) / 2;
        // 左边小数组
        mergeSort2(array,low,mid);
        // 右边小数组
        mergeSort2(array,mid+1,high);
        // 合并    ---->优化二:当左边元素的最大值比右边元素的最小值都da大时,说明整个数组有序,直接借宿排序
        if (array[mid] > array[mid+1]) {
            merge(array,low,mid,high);
        }
    }
    /*
      p: 开始位置:左边数组的开始位置
      q:中间位置:右边数组的开始位置
      r:结束位置
     */
    private static void merge2(int[] array,int p,int mid,int r) {
        int i = p;//左边的开始索引
        int j = mid+ 1;//右边的开始索引
        int[] temp = new int[r-p+1];//k开辟一个临时数组
        int k = 0;//新数组的下标
        // 此时两个数组中均有元素
        while (i <= mid && j <= r) {
            if (array[i] <= array[j]) {
                // 第一个数组中的相同位置元素最小
                temp[k++] = array[i++];
            }else {
                temp[k++] = array[j++];
            }
        }
        // 判断当前还有哪个数组元素没有走完
        int start = i;
        int end = mid;
         //剩下第二个数组
        if (j <= r) {
            start = j;
            end = r;
        }
        // 把剩余元素直接放置在temp数组后即可
        while (start <= end) {
            temp[k++] = array[start++];
        }
        // 将临时空间中已经合并好的元素拷贝回原数组
        for (i = 0;i < r-p+1;i++) {
            array[p+i] = temp[i];
        }
    }

直接插入排序的 代码在这里:https://blog.csdn.net/qq_40955824/article/details/89556522

时间复杂度:

空间复杂度:临时数组在合并后空间会释放

稳定性:取决于合并函数的写法,arr[p1]<=arr[jp2

归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值