排序算法 - 快速排序

参考书籍:《数据结构与算法分析——C语言描述》

快速排序是在实践中最快的已知排序算法,它的平均时间复杂度O(NlogN)。当然在最坏的情况下为O(N^2),但稍加努力就可以避免这种情形。

像归并排序一样,快速排序也是一种分治的递归算法,可简单表示如下:

将数组S排序的基本算法由下列简单的四步组成。

1、数组元素至少大于或等于4个,否则直接利用插入排序完成。

2、利用特定方法(三数中值分割法)取数组某一特定元素V,称之为枢纽元。

3、将数组中其他元素(即S-{V})分成两个不相交的子集。S1={x∈S-{V} | x≤V}和S2={x∈S-{V} | x≥V}。

4、继而对两个子集S1和S2进行同理1-3的递归运算。

如何选取枢纽元呢?

此处我们介绍是三数中值分割法。选取数组中最左端、最右端和中心位置的三个元素,比较三个元素的大小,并按照小的在左边交换彼此位置,取中间值作为枢纽元。

例如:

对于初始序列:

left=8;right=0;center=6。

显然此处枢纽元应为piovt=6;并且此时的排序为:

然后我们选取两个指示器i和j。从序列的首尾两端出发,除枢纽元外的元素与枢纽元进行比较。此时可把枢纽元6移至right-1的位置(因为right已经比piovt大了,left已经比piovt小了)。

即:

如果i指示的数比枢纽元小,则i++;直至遇到大于等于枢纽元的数停止。

如果j指示的数比枢纽元大,则j++;直至遇到小于等于枢纽元的数停止。

若此时i<j(说明元素没有全部比完),则交换i和j位置的数。继续上述的比较,直至i≥j(说明元素全部比完)。

比完时序列如下:

此时在交换位置i的数和枢纽元。如下图所示:

枢纽元已将原序列分割为两个子集:

1、大于枢纽元:7,9,8

2、小于枢纽元:0,1,4,2,3,5

同理可以将两个子集继续进行如此的分割排序。

代码实现:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// 获取枢纽元 枢纽值被放在序列末尾 - 1的位置
void dealPivot(vector<int> &nums, int l, int r)
{
    int mid = (l + r) / 2;
    if (nums[l] > nums[mid])
    {
        swap(nums[l], nums[mid]);
    }

    if (nums[l] > nums[r])
    {
        swap(nums[l], nums[r]);
    }

    if (nums[mid] > nums[r])
    {
        swap(nums[mid], nums[r]);
    }
    swap(nums[mid], nums[r - 1]);
}

void quickSort(vector<int>& nums, int l, int r) 
{
    if (l < r) 
    {
        dealPivot(nums, l, r);
        int pivot = r - 1;
        int i = l;      // 左指针
        int j = r - 1;  // 右指针
        while (1)
        {
            // 这里无需对i做安全校验,是因为pivot = r - 1; 所有++i不可能越界
            while (nums[++i] < nums[pivot]);
            // j > l是因为只有两个数时, pivot == l == j == 0
            while (j > l && nums[--j] > nums[pivot]);
            if (i < j)
            {
                swap(nums[i], nums[j]);
            }
            else
            {
                break;
            }
        }
        if (i < r - 1)
        {
            swap(nums[i], nums[r - 1]);
        }
        quickSort(nums, l, i - 1);
        quickSort(nums, i + 1, r);
    }
}

int main()
{
    vector<int> nums{ 9, 6, 7, 3, 8, 4, 5, 1, 2};
    quickSort(nums, 0, nums.size() - 1);
    for_each(nums.begin(), nums.end(), [](const int index) {
        cout << index << " ";
    });
    cout << endl;
    return 0;
}

快速排序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值