比较排序之堆排序和快速排序

堆排序

    堆是一个数组,它可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除了最底层外,改树是完全充满的,而且是从左往右填充的。
    堆可以分成两种形式:最大堆和最小堆。
    在堆排序算法中,我们使用的是最大堆。最小堆一般用于构建优先队列。
    我们知道,在最大堆中,最大堆性质是指除了根以外的所有结点i都要满足:
    A[parent(i)]>=A[i]
    也就是说,某个结点的值至多与其父节点一样大,因此,堆中最大的元素存放在根结点中。
    所有我们需要一个用于维护最大堆性质的函数。它的输入是一个数组A和一个下标i,我们维护最大堆性质函数的作用就是让以下标i为根结点的堆遵循最大堆性质。
void max_heap(int *a,int i,int n)      //n=a.length
{
    int j=i*2+1;          //i's child node
    int temp=a[i];
    while(j<n)
    {
        if(a[j]<a[j+1]&&j+1<n)
            j++;
        if(a[i]>=a[j])
            break;
        a[i]=a[j];
        i=j;
        j=i*2+1;
    }
    a[i]=temp;
}
    现在我们就可以将我们要排序的数据建成一个最大堆数组。
void build_max_heap(int *a,int n)
{
    for(int i=n/2-1;i>=0;i--)
        max_heap(a,i,n);
}
    现在我们拥有了建立最大堆的能力,那么我们就可以用它来排序,因为最大的元素就在根结点处,所以我们将根结点放入数组的最后,然后将剩下的元素再建成一个最大堆,再将根结点放入数组的最后,依次循环,我们就排好序了。
void heap_sort(int *a,int n)
{
    for(int i=n-1;i>=0;i--)
    {
        build_max_heap(a,i+1);
        swap(a[0],a[i]);
    }
}
    我们可以看出堆排序的时间复杂度跟归并排序相同是O(nlgn),但是它的空间复杂度与插入排序相同都是常数。

快速排序

    快速排序也使用了分治思想,它的原理是找一个主元,然后将数组里的每一个元素与主元相比较,比主元小的放在主元左边,比主元大的放在主元右边,然后以主元为界,对左右两个子数组进行相同的操作,依次下去,就可以排好序了。
    下面我们以数组最后一个元素为主元:
int partition(int *a,int i,int n)
{
    int key=a[n];
    int m=i-1;
    for(int j=i;j<n;j++)
    {
        if(a[j]<=key)
        {
            m+=1;
            swap(a[m],a[j]);
        }
    }
    swap(a[m+1],a[n]);
    return m+1;
}

void quick_sort(int *a,int i,int n)
{
    int q;
    if(i<n)
    {
        q=partition(a,i,n);
        quick_sort(a,i,q-1);
        quick_sort(a,q+1,n);
    }
}
    我们可以看到快排的最坏情况时间复杂度是O(n^2),而在元素互异的情况下,期望时间复杂度是O(nlgn)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值