常见算法温习之快速排序

博客内容中的排序以升序排列为例


1. 算法理解

快排的基本思想是:

  • 从原始序列Array(集合S)中选取一个元素(称之为枢纽元pivot)
  • 将剩余的元素分为两个集合S1和S2,其中S1中元素全都小于或等于pivot,S2中的元素全都大于或等于pivot
  • 递归分别对S1和S2执行上述两步

1.1 选取pivot
通常不加考虑地可以直接选取序列的第一个元素作为pivot,但是极端情况下,当原始序列恰好以降序排列时,快排时间复杂度将达到O(N^2)。比较好的方法是“三数中值分割法”,即选取序列的第0个、最后一个和最中间一个这三个元素,按照升序排列(left, center, right),选取中值(center)作为pivot,这样可以一定程序上缓解上述“坏情况”。

1.2 分割策略
快排可以通俗理解为“挖坑”和“填坑”的过程。

  • 因为选取了Array[center]作为pivot,所以相当于空出来了一个坑,首先将Array[left]的值填到center位置,则left位置就空出来了(“挖坑”)
  • 从最后一个元素开始往前(左)遍历,找到第一个小于或等于pivot的元素位置(标为位置 j),将该位置的元素填到left位置
  • 从left开始往后(右)遍历,找到第一个大于或等于pivot元素的位置(标为位置 i),将该位置的元素之值填到位置 j
  • 循环执行2、3步,直至i=j,将pivot的值填入位置i中,则pivot左边的元素均小于等于pivot(集合S1),pivot右边的元素均大于等于pivot(集合S2)
  • 对集合S1和S2分别递归执行上述四步

2. C++实现
#include <iostream>

using namespace std;

void swap(int *pa, int *pb)
{
    int temp = *pa;
    *pa = *pb;
    *pb = temp;
}


int median3(int a[], int left, int center, int right)
{
    if (a[left] > a[center]) swap(&a[left], &a[center]);
    if (a[left] > a[right]) swap(&a[left], &a[right]);
    if (a[center] > a[right]) swap(&a[center], &a[right]);

    return a[center];
}

void quicksort(int a[], int left, int right)
{
    if (left >= right) return;

    int center = (left + right) / 2;
    int pivot = median3(a, left, center, right);
    a[center] = a[left]; //将第0个元素空出来
    int i = left;
    int j = right;

    while (i < j)
    {
        while (a[j] >= pivot && i < j) j--;
        a[i] = a[j];
        while (a[i] <= pivot && i < j) i++;
        a[j] = a[i];
    }

    a[i] = pivot;
    quicksort(a, left, i-1);
    quicksort(a, i+1, right);
}

int main()
{
    int n, i;
    cout << "请输入序列元素个数" << endl;
    cin >> n;
    int *a = new int(n);

    cout << "请输入序列元素" << endl;
    for (i = 0; i < n; i++)
        cin >> a[i];

    quicksort(a, 0, n - 1);

    for (i = 0; i < n; i++)
        cout << a[i] << ' ';
    cout << endl;

    return 0;
}

3. 算法复杂度分析

最优情况下,集合S1和S2的元素数目每次都比较均匀,则时间复杂度为O(NlogN),最坏情况上面已经分析过,平均情况下是O(NlogN),分析过程可参照二叉树。
就空间复杂度来说,主要是递归造成的栈空间的调用,最好情况下递归树的深度为log2n,其空间复杂度也就为O(logn),最坏情况,需要进行n‐1递归调用,其空间复杂度为O(n),平均情况,空间复杂度也为O(logn)。


参考:
1. 《数据结构与算法分析——C语言描述》
2. http://blog.csdn.net/weshjiness/article/details/8660583

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值