排序2-时间复杂度为O(nlogn)的算法 归并排序 快排

上一篇博文排序1主要讲的是关于评定算法性能的一些指标,以及时间复杂为O(n2)的排序算法。这一篇博文我重点讲述世家复杂度为O(nlogn)的两个经典算法—归并排序 和快排
关于这两个算法 网上的资料很多 在面试中也会经常会被问到(特别是快排),这里我结合自己的理解和总结,写的不好的地方 请多指教。

归并排序(MergeSort)

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
归并排序的核心思想:如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。
在这里插入图片描述
我们可以看到归并排序的数据用书的结构来表示后,分和治都是一颗满二叉树,高度为O(log2n)。

分:采用递归的方法进行分解。

将待排序数组中的n个数据分解为n个有序的子数组,采用递归的方法。
首先,我们写出其递推公式及其终止条件:

递推公式:merge_sort(p…r) = merge(merge_sort(p...q),merger_sort(q+1,...r))
终止条件:p>=r

由递推公式写出"分"的代码:

public static void merge_sort(int[] a,int p,int r){
        //递归终止条件
        if(p>=r) return;
        //取p到r之间的中间位置q
        int q=(p+r)/2;
        //分治递归
        merge_sort(a,p,q);
        merge_sort(a,q+1,r);

        //将a[p,...,q]和a[q+1,..,r]合并为a[p,..,r]
        merge(a,p,q,r);
    }
治:合并相邻有序子序列

再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。
  在这里插入图片描述
在归并排序中最耗时的就是治(将两个小数组合并为大数组的过程)
治的java代码:

private static void merge(int[] arr,int left,int mid,int right){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        int[] temp=new int[right-left+1];    //申请一个大小和a[left,..,right]一样大的数组
        while (i<=mid && j<=right){
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }
归并排序的完整代码
package SortAlgorithm;

/**
 * 归并排序(体现分治的思想 利用到递归)
 * 归并排序是一个稳定的算法(值相同的元素,再合并前后的先后顺序不变)
 归并排序的时间复杂度是O(nlogn),这里值得注意的是,归并排序的执行效率和要排序的原始数组的有序程度无关,所以其时间复杂度是非常稳定的,不顾那是最好情况,最坏情况,还是平均情况,时间复杂度都是O(nlogn)
 归并排序的空间复杂度是O(n),归并排序是非原地排序算法
 * @author xjh 2018.10.22
 */
public class Sort02ToMergeSort {
    public static void main(String[] args) {
        int[] a={12,2,3,10,4,8,13,3};
        int n=a.length;
        mergeSort(a,n);
        for(int i=0;i<n;i++){
            System.out.print(a[i]+" ");
        }
        System.out.println();
    }

    /**
     * 归并排序
     * @param a
     * @param n
     */
    public static void mergeSort(int[] a,int n){
        merge_sort(a,0,n-1);
    }
    public static void merge_sort(int[] a,int p,int r){
        //递归终止条件
        if(p>=r) return;
        //取p到r之间的中间位置q
        int q=(p+r)/2;
        //分治递归
        merge_sort(a,p,q);
        merge_sort(a,q+1,r);

        //将a
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值