快速排序

快速排序


先看个例子:
对于数组 a = [427 353 112 914 141 555 96 696 294 883],我们选择tmp = a[0]作为我们的枢纽元,在实现第一轮排序后,我们要实现的效果是数组a分成两部分,前面的部分元素全部小于等于**tmp,后面部分全部大于等于**tmp。取i = 0; j = a.length-1; tmp = a[0]

第一轮排序过程如下
1. 从j开始,我们找到第一个小于 tmp=427 的元素,为 a[8]=294,将 a[j] 值存储到 i 位置,此时数组为
a = [294 353 112 914 141 555 96 696 294 883]。同时,i++ (因为当前元素已经确保小于等于 tmp)
2. 从 i 开始,我们找到第一个大于 tmp=427 的元素,为 a[3] = 914,将 a[i] 值存储到 j 位置,此时数组为 a = [294 353 112 914 141 555 96 696 914 883] ,同时 j–
3. 循环步骤1和步骤2,直到 i >= j。最后,将 tmp 值赋予 a[i]
4. 经过第一趟排序后,我们数组的值为 a = [294 353 112 96 141 294 555 696 914 883]。此时我们发现,a[0..5]的值小于等于tmp,a[6..9]的值大于等于 tmp

在第一轮排序后我们得到两个数组,分别为 S1 = a[0..5], S2 = a[6..9],这时我们再对这两个数组各自执行上述步骤,不断递归下去,则最终可以得到一个排序数组。

上述步骤可总结为:

  • 如果当前数组元素个数小于等于1,直接返回
  • 选择数组中任一元素,称为枢纽元,这里为了方便我们选择i = 0为枢纽元,值设为 tmp
  • 设数组左端点为 i,右端点为 j
  • 在每轮排序中,我们将当前数组分为两个数组 S1,S2。其中 S1 数组的所有值均小于等于 tmp,S2 的所有元素均大于等于 tmp
  • 执行 quickSort(S1), quickSort(S2)

以第一个元素为枢纽元的实现如下

void quickSort(int[] a, int left, int right) {
     if (left >= right)
         return;
     int x = a[left];
     int i = left;
     int j = right;
     while (i  < j) {
         while (i < j && a[j] > x) j--;
         if (i < j) a[i++] = a[j];
         while (i < j && a[i] < x) i++;
         if (i < j) a[j--] = a[i];
     }
     a[i] = x; // 此处注意将a[i]替换回枢纽元元素
     quickSort(a, i+1, right);
     quickSort(a, left, i-1);
 }

其平均运行时间为O(N log N)。最坏运行时间为O(N^2)

上面为了理解简单,我们的枢纽元直接选择了数组的第一个元素,当数组是随机的时候,则不存在问题,因为现在所有元素都是等价的,但如果该数组是预排序或者反序的,则我们可发现,所有元素只能被划入集合S1或集合S2。假设数组是预排序的,且 a[0] != [a1](相等则是另一种类似情况),则第一轮排序后 S1=a[0], S2=a[1...n],则此时 O(n^2) ;同理,当数组是逆序时,同样有 O(N^2)。故直接使用数组的第一个元素是不好的选择。
通常情况下,随机选择数组任意一位作为枢纽元素是安全的,这里我们选择数组的中间位置的元素,代码如下

void Quick(int *a, int left, int right)
{
    if (left >= right) return;
    int prvot = (left+right) / 2;
    int tmp = a[prvot];
    int i = left;
    int j = right;
    while (i < j) {
        while (i < j && a[j] > tmp) j--;
        if (i < j) {
            a[prvot] = a[j];
            prvot = j;

        }
        while (i < j && a[i] < tmp) i++;
        if (i < j) {
            a[prvot] = a[i];
            prvot = i;
            j--; // 这里注意,否则出现重复值时可能进入死循环
        }

    }
    a[prvot] = tmp;
    Quick(a, prvot+1, right);
    Quick(a, left, prvot-1);
}

完整代码参考: quickSort.cpp

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值