快速排序(Quick sort)

description

  • 找一个基准点,每次把小于这个基准点的放在一边(根据是要降序还是升序来定),大于这个基准点的放在另一边来处理。对分出来的两个部分再次递归使用这个函数,直到每个部分只剩下一个数

code

  • 这里做的是升序排序,把第一个数字作为基准点(单独拿出来),从另一边也就是末尾开始运行,如果小于基准点的话直接把值赋给刚才访问的元素(这里第一步就是头,也刚好是基准点),这样交替达到调换值得效果

<双路快排>

  • cpp代码
// Quick_Sort.cpp : Defines the entry point for the application.
// 快速排序算法

#include <iostream>
using namespace std;

//快速排序算法(从小到大)
// arr:需要排序的数组,begin:需要排序的区间左边界,end:需要排序的区间的右边界
void quickSort(int* arr, int begin, int end) {
    //如果区间不只一个数
    if(begin < end) {
        int pivot = arr[begin];  //将区间的第一个数作为基准数
        int i = begin;  //从左到右进行查找时的“指针”,指示当前左位置
        int j = end;  //从右到左进行查找时的“指针”,指示当前右位置
        //不重复遍历
        while(i < j) {
            //当右边的数大于基准数时,略过,继续向左查找
            //不满足条件时跳出循环,此时的j对应的元素是小于基准元素的
            while(i < j && arr[j] >= pivot)
                j--;
            //将右边小于等于基准元素的数填入右边相应位置
            arr[i] = arr[j];
            //当左边的数小于等于基准数时,略过,继续向右查找
            //(重复的基准元素集合到左区间)
            //不满足条件时跳出循环,此时的i对应的元素是大于等于基准元素的
            while(i < j && arr[i] <= pivot)
                i++;
            //将左边大于基准元素的数填入左边相应位置
            arr[j] = arr[i];
        }
        //将基准元素填入相应位置
        arr[i] = pivot;
        //此时的i即为基准元素的位置
        //对基准元素的左边子区间进行相似的快速排序
        quickSort(arr, begin, i - 1);
        //对基准元素的右边子区间进行相似的快速排序
        quickSort(arr, i + 1, end);
    }
    //如果区间只有一个数,则返回
}
int main() {
    int num[12] = {23, 45, 17, 11, 13, 89, 72, 26, 3, 17, 11, 13};
    int n = 12;
    quickSort(num, 0, n - 1);
    cout << "排序后的数组为:" << endl;
    for(int i = 0; i < n; i++)
        cout << num[i] << ' ';
    cout << endl;

    return 0;
}
  • 输出
排序后的数组为:
3 11 11 13 13 17 17 23 26 45 72 89

最坏的时候可能会每次分成1n-1的情况
改进:
进行pivot随机化处理

i = Random(begin,end);
swap(num[i],num[begin]);
QuickSort(begin,end);

补充


<三路快排>

  1. 一路的比较简单,就是像一个方向的,我没有写
  2. 三路快排的提出是为了解决数据中有大量重复元素,在双路中我们把重复的当做某一边的,这样会造成重复操作
  3. 这篇文章对原理进行了很好的讲解,我的代码和注释都是来自于这里https://www.cnblogs.com/deng-tao/p/6536302.html

代码:

/******************************************
 * @Author       : 鱼香肉丝没有鱼
 * @Date         : 2021-09-22 10:01:37
 * @LastEditors  : 鱼香肉丝没有鱼
 * @LastEditTime : 2021-11-29 20:27:04
 ******************************************/

#include <cstdlib>
#include <ctime>
#include <iostream>

using namespace std;

void Swap(int& a, int& b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

void QuickSort3(int* arr, int left, int right)
{
    if(left < right) {
        //基准随机化
        int mid = rand() % (right - left + 1) + left;  //随机化处理,生成一个[left,right]的数字
        Swap(arr[left], arr[mid]);
        int v = arr[left];  //基准

        int lt = left;  // less than// 将<v的分界线的索引值lt初始化为第一个元素的位置(也就是<v部分的最后一个元素所在位置的后一个位置)
        int gt = right + 1;  // great than将>v的分界线的索引值gt初始化为最后一个元素right的后一个元素所在位置(也就是>v部分的第一个元素所在位置)
        int i = left + 1;  //等于部分的指针,将遍历序列的索引值i初始化为 left+1

        while(i < gt) {  // 循环继续的条件
            if(arr[i] < v) {  // 如果当前位置元素<v,则将当前位置元素与=v部分的第一个元素交换位置
                Swap(arr[i], arr[lt + 1]);
                i++;  // i++  考虑下一个元素
                lt++;  // lt++  表示<v部分多了一个元素
            }
            else if(arr[i] > v) {  // 如果当前位置元素>v,则将当前位置元素与>v部分的第一个元素的前一个元素交换位置
                Swap(arr[i], arr[gt - 1]);  // 此时i不用动,因为交换过来的元素还没有考虑他的大小
                gt--;  // gt--  表示>v部分多了一个元素
            }
            else
                i++;  //  如果当前位置元素=v  , 则只需要将i++即可,表示=v部分多了一个元素
        }
        Swap(arr[left], arr[lt]);  // 上面的遍历完成之后,将整个序列的第一个元素(也就是"基准"元素)放置到合适的位置
        // 也就是将它放置在=v部分即可

        QuickSort3(arr, left, lt - 1);  // 对<v部分递归调用_
        QuickSort3(arr, gt, right);  // 对>v部分递归调用
    }
}

int main()
{
    int arr[15] = {23, 45, 17, 11, 13, 89, 72, 26, 3, 17, 11, 13, 13, 17, 13};
    int n = 15;
    srand(time(NULL));  //使用随机种子
    QuickSort3(arr, 0, n - 1);
    cout << "排序后的数组为:" << endl;
    for(int i = 0; i < n; i++)
        cout << arr[i] << ' ';
    cout << endl;
    return 0;
}

summary

  • 快速排序算法得时间复杂度是不确定的,可能是 O ( n log ⁡ n ) {\rm{O}}(n\log n) O(nlogn) , 也可能是 O ( n 2 ) {\rm{O}}({n^2}) O(n2).
  • 属于分治法的范畴,分解时间长,不需要合
  • 当给定的数组有序时为最坏情况,这个时候的复杂度为O(n2),为了避免这个情况,我们可以进行随机化处理,随机选取一个数作为pivot,,注:c++中的qsort()就进行了随机化处理
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值