总结一下常见的几种排序

1、插入排序

public void insertsort(int[] a)
{
    for(int i=1;i<a.length;i++)
    {
        for(int j=i;j>0;j--)
        {
            if(a[j]<a[j-1])
                swap(a,j,j-1);
        }
    }
}
时间复杂度O(n^2),没有多余的空间开销,虽然复杂度为平方级别,但在数组为近似有序的情况下效率非常高,有时在归并和快排的的子序列中可以使用插入排序,一般能提升20%-30%的效率。

2、希尔排序

希尔排序可以理解为插入排序的改进,大概思想是不断循环把数组根据间隔进行部分排序,直至间隔为1,这样做充分利用了插入排序对近似有序数组排序的高效特点,效率比插入排序提高70%-80%。

public void hillsort(int[] a)
{
    int length=a.length;
    int h=1;
    while(h<length/3)
    {
        h=h*3+1;
    }
    while(h>=1)
    {
        for(int i=h;i<length;i++)
        {
            for(int j=i;j>=h;j-=h)
            {
                if(a[j]<a[j-h])
                {
                    swap(a,j,j-h);
                }
            }
        }
        h/=3;
    }
}
这里的间隔取值是按《Algorithms》书中取得,一般来说这样的间隔取值能达到最优速度。

3、快速排序

快排的理论最差时间复杂度为O(n^2),但实际运行速度还是很快的,平均效率为O(nlgn),通过随机化key值基本可以规避掉最坏情况。笔者认为快排是一种很优秀的排序,内循环极为精简,比较次数很少,通过随机化快排切分数组的效果也很好。

public void quicksort(int[] a,int begin,int end)
{
    if(begin>=end) return;
    int temp=a[begin];
    int key=begin;
    for(int j=begin+1;j<=end;j++)
    {
        if(a[j]<temp) {
            swap(a, key + 1, j);
            key++;
        }
    }
    swap(a,begin,key);
    quicksort(a,begin,key-1);
    quicksort(a,key+1,end);
}
4、归并排序

归并排序的理论时间复杂度应该是排序中最优秀的了,但实际运行中其实速度却不是最快的,因为归并排序的代码操作非常多,因此性能并不像理论上表现的那么优秀,还有一个问题是归并排序需要额外的空间复杂度,与数组长度成正比,因此也要根据实际情况选择。

public void mergesort(int[] a,int begin,int end)
{
    if(begin>=end) return;
    int mid=(begin+end)/2;
    mergesort(a,begin,mid);
    mergesort(a,mid+1,end);
    merge(a,begin,mid,end);
}
public void merge(int[] a,int begin,int mid,int end){
    int[] temp=new int[end-begin+1];
    int i=begin,j=mid+1,k=0;
    while(i<=mid&&j<=end)
    {
        if(a[i]<a[j])
        {
            temp[k++]=a[i++];
        }
        else{
            temp[k++]=a[j++];
        }
    }
    while(i<=mid){
        temp[k++]=a[i++];
    }
    while(j<=end){
        temp[k++]=a[j++];
    }
    for(int m=0;m<temp.length;m++){
        a[m+begin]=temp[m];
    }
}
5、堆排序

二叉堆的维护分为插入和删除两种情况,即上浮和下沉两种操作,如果只是用堆排序的话只用到下沉就可以了,堆排序是目前所知能够同时最优的利用空间和时间的方法,它的缺点也很明显,无法利用缓存,因为很少与相邻的其他元素进行比较,因此缓存未命中的概率远高于快速排序、归并排序等排序。

public void heapsort(int[] a)
{
    int length=a.length;
    for(int i=(length-1)/2;i>=0;i--)
    {
        sink(a,i,length-1);
    }
    int n=length-1;
    while(n>0){
        swap(a,n--,0);
        sink(a,0,n);
    }
}
public void sink(int[] a,int k,int n)
{

    while(2*k+1<=n)
    {
        int j=2*k+1;
        if(j<n&&a[j]<a[j+1])
            j++;
        if(a[k]>a[j]) break;
        swap(a,j,k);
        k=j;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值