快速排序(递归和非递归两种方法实现)

快速排序:

1.首先找一个基准点(一般选取最左边第一个)

2.先从后往前遍历,找到第一个小于基准值的元素;

3.再从前往后,找到第一个大于基准值的元素;

4.将这两个元素两两交换

5.当i与j相遇时,说明找到了排序后当前这个基准值的正确位置,将基准点进行归位;

6.开始新的一轮,以上一轮的基准点为中轴,分成左边区域和右边区域,分别选取一个新的基准点对新的基准点进行归位即可。

非递归(利用队列实现)

cpp 复制代码
//进行分区,也就是找到基准点排序后的正确位置
int pation(vector<int>& nums, int left, int right)
{
    int tmp = nums[left];//先将基准点保存起来
    //循环结束条件:i和j相遇
    while (left < right)
    {
        //从后往前找,找到第一个小于基准点的下标
        while (left<right && nums[right]>tmp)--right;
        //将当前这个值赋给左下标的元素
        if (left < right) nums[left] = nums[right];
        //从前往后,找到第一个大于基准值的下标
        while (left < right && nums[left] <= tmp)++left;
        将当前这个值赋给右下标的元素
        if (left < right) nums[right] = nums[left];
    }
    //此时left和right就是基准值的正确位置
    //将基准值归位
    nums[left] = tmp;
    return left;
}
//非递归
void quickSort(vector<int>& nums, int left, int right)
{
    queue<int> qu;//通过队列实现非递归,如果用栈就是先放右边的值再放左边的值
    qu.push(left);
    qu.push(right);
    while(!qu.empty())
    {
        left = qu.front(); qu.pop();
        right = qu.front(); qu.pop();
        //分区
        int pos = pation(nums, left, right);
        //对左边序列进行排序
        if (left < pos - 1)
        {
            qu.push(left);
            qu.push(pos - 1);
        }
        //对右边序列进行排序
        if (right > pos + 1)
        {
            qu.push(pos + 1);
            qu.push(right);
        }
    }
}
int main()
{
    cout << "请输入数组大小:" << endl;
    int n;
    cin >> n;
    vector<int> nums(n);
    for (int i = 0; i < n; i++)
    {
        cin >> nums[i];
    }

    quickSort(nums, 0, n - 1);

    cout << "排序后的数组:" << endl;
    for (auto& i:nums)
    {
        cout << i << " ";
    }
    cout << endl;
    return 0;
}

递归:

cpp 复制代码
void dfs(vector<int>& nums, int left, int right)
{
    //左右边界相遇时,直接return结束
    if (left >= right) return;
    int key = nums[left];//保存基准值
    int i = left, j = right;
    while (i < j)
    {
        //从后往前找第一个小于基准值的元素
        while (nums[j]>=nums[left] &&i<j)
        {
            j--;
        }
        //从前往后找第一个大于基准值的元素
        while (nums[i] <= nums[left] && i<j)
        {
            i++;
        }
        //左右边界没有相遇,将这两个值两两交换
        if (i < j)
        {
            swap(nums[j], nums[i]);
        }
    }
    //此时循环结束,i或j下标就代表基准值的正确下标位置
    nums[left] = nums[i];
    nums[i] = key;
    //递归左边区域
    dfs(nums, left, i - 1);
    //递归右边区域
    dfs(nums, i + 1, right);
}

注意:

快速排序的时间复杂度通常情况下是O(nlogn)

但在特殊情况下,比如选取的这个基准点刚好是最大值或是最小值时,对n个元素排序,需要遍历n次,此时时间复杂度为O(n*n);

相关推荐
这个DBA有点耶7 分钟前
COUNT慢不是因为用了*,是这5个原因——1000万行数据实测+执行计划深度解析
数据库·mysql·算法
贾伟康12 分钟前
【口算王|01】HarmonyOS ArkTS 口算题生成实战:按年级、运算类型和难度生成可控题目
算法·harmonyos·arkts·随机生成·口算题
lzx_00214 分钟前
C++11(一)
开发语言·c++·算法
529宝宝起名网23 分钟前
用 Python 实现名字寓意评分算法:基于 NLP 语义分析的名字内涵深度评估
python·算法·自然语言处理
带多刺的玫瑰2 小时前
Leecode#26刷题之删除有序数组中的重复项
数据结构·算法·leetcode
小七在进步2 小时前
C++入门(2)
java·jvm·c++
en.en..2 小时前
C语言核心解析:#define与typedef本质区别
开发语言·c++·算法
码匠许师傅2 小时前
【设计模式精讲】26.策略模式(Strategy)
c++·设计模式·策略模式·uml
洋不写bug3 小时前
二叉树(二) 常见基础操作解析|结点数、树高、查找结点、判断完全二叉树
java·开发语言·数据结构·完全二叉树·二叉树结点数·树高·查找结点
果果燕3 小时前
实习笔记(六)主机按钮状态上报完整流程
开发语言·c++·php