排序之插入、归并、快速排序

一、插入排序

最简单的排序方法,类似玩扑克,开始时我们的左手为空,之后我们每次从桌子上拿走一张牌并插入左手中的正确位置。
我们可以将牌分为三部分,左手中的已排序好的牌,右手中的一张牌,桌子上的一堆牌。而为了找到一张牌的正确位置,我们从右到左将它与已在手中的每张牌进行比较,保证左手中的牌总是排序好的。

public void insertionSort(int a[]){
    for(int i=1;i<a.length;i++){
        int key=a[i];
        int j=i-1;
        while(j>=0&&a[j]>key){
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=key;
    }
}

算法很简单,但是算法时间复杂度为O(n²),除非数组已经完全排序好,这时的时间复杂度为O(n)。

二、归并排序

同样假定有两堆牌面朝上的牌,每堆都已排序,最小的牌在顶上,我们希望把这两堆牌合并成一堆排序好的牌。我们只要不断的从两堆牌的顶上选取较小的那一张,直到一堆为空就好。
就如a[p..q]和a[q+1…r]各自都按照升序排列,我们需要重新安排数组a中的位置使a[p,r]按照升序排列,可以采用同样的办法。

public void merge(int a[],int p,int q,int r){
    int[] temp=new int[r-p+1];
    int i=p;
    int j=q+1;
    int k=0;
    while(i<=q&&j<=r){
        if(a[i]<a[j]){
            temp[k]=a[i];
            i++;
        }else{
            temp[k]=a[j];
            j++;
        }
        k++;
    }
    if(i>q){
        while(j<=r){
            temp[k++]=a[j++];
        }
    }else{
        while(i<=q){
            temp[k++]=a[i++];
        }
    }
    int x=p;
    for(int l=0;l<r-p+1;l++){
        a[x++]=temp[l];
    }
}

接下来我们采用自顶向下的方法就好:

public void mergeSort(int a[],int p,int r){
    if(p<r){
        int mid=(p+r)/2;
        mergeSort(a, p, mid);
        mergeSort(a, mid+1, r);
        merge(a, p, mid, r);
    }
}

归并排序的时间复杂度为O(nlgn),明显优于插入排序。

三、快速排序

将数组a[p..r]分为两部分,左半部分a[p..q-1]都小于等于a[q],右半部分a[q+1…r]都大于a[q]。
方法就是通过将数组a[p..r-1]的所有元素都与a[r]进行比较,只要比a[r]小的都扔到左边,找到一个扔一个。

public int partition(int a[],int p,int r){
    int i=p-1;
    int j=p;
    while(j<r){
        if(a[j]<a[r]){
            i++;
            int temp=a[j];
            a[j]=a[i];
            a[i]=temp;
        }
        j++;
    }
    int temp=a[i+1];
    a[i+1]=a[r];
    a[r]=temp;
    return i+1; 
}

然后我们通过递归调用快速排序,对a[p,q-1],a[q+1,r]进行排序:

public void quickSort(int a[],int p,int r){
    if(p<r){
        int q=partition(a,p,r);
        quickSort(a,p,q-1);
        quickSort(a,q+1,r);
    }
}

快速排序的时间复杂度同样为O(nlgn),但是存在最坏情况,就是在已排序好的数组时,划分时左右两部分会分别包括0个元素和n-1个元素,这种情况下,时间复杂度为O(n²)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值