十大排序算法:快速排序算法

2023-11-01

一、快速排序算法思想或步骤

  1. 分解: 数组A[p…r]被划分为两个子数组A[p…q-1]和A[q+1…r],使得A[q]为大小居中的数,左侧A[p…q-1]中的每个元素都小于等于它,而右边A[q+1…r]每个元素都大于等于它。
  2. 解决: 通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行排序。
  3. 合并: 因为子数组都是在原址进行排序,所以不需要合并,原数组已经有序。
    通过上述描述发现:划分是问题的关键

算法的就可以写出如下框架:

void quickSort(A,p,r){
	if(p<r){
		q = divAlgo(A,p,r);
		quick(A,p,q-1);
		quick(A,q+1,r);
	}
}

二、划分算法divAlgo:快排算法的关键

下面介绍几种划分的思路和算法

1. 一遍单向扫描法

首先确定一个基元,一般基元确定为区间的第一个元素,然后通过两个指针pi,pj来进行移动划分,初始值pi为该区间的第二个位置,即pi=1;pj为该区间的最后一个为pj = size()-1。划分过程大致如下:
在pi小于等于pj的情况下,执行下面步骤:

  1. 不断向后移动pi指针,直到pi所指元素大于基元。
  2. 交换pi和pj所指内容,pj前移一位
  3. 执行第1步
  4. 当pi小于等于pj条件不满足时,交换pj所指元素和基元,并返回pj。

有了上述步骤,则可以轻松写出相应的划分算法。

int divAlgo(vector<int> &src,int p,int r){
    int baseVal = src[p];
    int pi = p + 1,pj = r;
    while (pi <= pj){
        if(src[pi] <= baseVal) ++pi;
        else swap(src[pi],src[pj--]);
    }
    swap(src[p],src[pj]);
    return pj;
}

那么接着使用这个划分算法测试一下能否完成排序。

#include<bits/stdc++.h>
using namespace std;
int divAlgo(vector<int> &src,int p,int r){
    int baseVal = src[p];
    int pi = p + 1,pj = r;
    while (pi <= pj){
        if(src[pi] <= baseVal) ++pi;
        else swap(src[pi],src[pj--]);
    }
    swap(src[p],src[pj]);
    return pj;
}
void quickSort(vector<int> &src,int p,int r){
    if(p<r){
        int q = divAlgo(src,p,r);
        quickSort(src,p,q-1);
        quickSort(src,q+1,r);
    }
}
int main(){
    vector<int> ad{4,3,2,5,1,8,9};
    quickSort(ad,0,ad.size()-1);
    copy(ad.begin(),ad.end(),ostream_iterator<int>(cout," "));
    return 0;
}
/*
1 2 3 4 5 8 9
*/

2. 双向扫描法

双向扫描的思路为:头指针往中间进行扫描,尾指针往中间进行扫描,左边找到大于对应基元的位置,右边找到小于基元的位置,进行交换,继续扫描。
有了单向扫描的基础,该代码就比较好写,代码如下:

int divAlgo2(vector<int> &src,int p,int r){
    int baseVal = src[p];
    int pi = p + 1,pj = r;
    while (pi <= pj){
        while(pi <= pj && src[pi] <= baseVal) ++pi;
        while(pi <= pj && src[pj] > baseVal) --pj;
        if(pi < pj)
            swap(src[pi],src[pj]);
    }
    swap(src[p],src[pj]);
    return pj;
}

测试代码如下:

#include<bits/stdc++.h>
using namespace std;
int divAlgo2(vector<int> &src,int p,int r){
    int baseVal = src[p];
    int pi = p + 1,pj = r;
    while (pi <= pj){
        while(pi <= pj && src[pi] <= baseVal) ++pi;
        while(pi <= pj && src[pj] > baseVal) --pj;
        if(pi < pj)
            swap(src[pi],src[pj]);
    }
    swap(src[p],src[pj]);
    return pj;
}
void quickSort(vector<int> &src,int p,int r){
    if(p<r){
        int q = divAlgo2(src,p,r);
        quickSort(src,p,q-1);
        quickSort(src,q+1,r);
    }
}
int main(){
    vector<int> ad{4,3,2,5,1,8,9};
    quickSort(ad,0,ad.size()-1);
    copy(ad.begin(),ad.end(),ostream_iterator<int>(cout," "));
    return 0;
}
/*
1 2 3 4 5 8 9
*/

三、快排存在的问题

  1. 如果原数组已经有序,算法效率不好
  2. 数组长度较大时,时间复杂度高
  3. 选取基元的方法本身存在缺陷。

四、优化

  1. 待排序元素个数比较少时,使用插入排序
  2. 快排时,选取基元使用绝对中值法三点中值法
  3. 排序元素较多时,使用堆排序

结合这三点,可以封装一个跟标准库中sort函数思想差不多的排序算法。
这三种优化,1和3后面会有相应的排序算法,针对2,修改divAlgo函数,三点中值法:选取基元尽可能地可以将数组分为个数相同的两半【选取左、中、右三个元素中中间大的元素作为基元】,或者绝对中值法:选取数组中间位置元素作为基元。

五、使用快排思想找数组中第k大元素框架

主框架都是这个,不同的是找枢纽的部分需要修改

int findKth(vector<int>& a, int low, int high, int k){//找第k个
		int p = divAlgo(a, low, high);
		if (k == p - low + 1)
			return a[p];
        
		else if (k - 1 < p - low)//则第k大的元素在前半段
			return findKth(a, low, p - 1, k);
 
		else //则第k大的元素在后半段
			return findKth(a, p + 1, high, k - p + low - 1);
	}

int divAlgo(vector<int> &src,int p,int r){
    int baseVal = src[p];
    int pi = p + 1,pj = r;
    while (pi <= pj){
        if(src[pi] <= baseVal) ++pi;//找第k小的,当变为>=时找第k大
        else swap(src[pi],src[pj--]);
    }
    swap(src[p],src[pj]);
    return pj;
}

最小的k个数
方法1:优先队列,大顶堆

vector<int> GetLeastNumbers_Solution_1(vector<int> input, int k) {
        if(k == 0 || input.empty()) return vector<int>();
        // priority_queue默认为大顶堆,声明为priority_queue<T,vector<T>,less<T>>
        // priority_queue<T, vector<T>, greater<T>>为小顶堆
        priority_queue<int> pq_int;// 默认是大顶堆,也就是top处的元素为当前优先队列的最大值
        vector<int> res;
        for(int i = 0; i < input.size(); ++i){
            if(pq_int.size() < k){
                pq_int.push(input[i]);
            }else{
                if(pq_int.top() > input[i]){
                    pq_int.pop();
                    pq_int.push(input[i]);
                }
            }
        }
        while(!pq_int.empty()){
            res.push_back(pq_int.top());
            pq_int.pop();
        }
        return res;
    }

方法2:快排

// 快排思想,进行局部性排序
    bool flag = true;
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k){
        if(0 == k || input.empty()) return {};
        quickSort(input, 0, input.size() - 1, k);
        return vector<int>(input.begin(), input.begin() + k);
    }
    
    int divide(vector<int> &data, int l, int r){
        int base_val = data[l];
        int pi = l + 1, pj = r;
        while(pi <= pj){
            while(pi <= pj && data[pi] <= base_val) ++pi;
            while(pi <= pj && data[pj] >= base_val) --pj;
            if(pi < pj) swap(data[pi++], data[pj++]);
        }
        swap(data[l], data[pj]);
        return pj;
    }
    
    void quickSort(vector<int> &data, int pi, int pj, const int &k){
        if(!flag || pi >= pj) return;
        int index = divide(data, pi, pj);
        if(index > k){
            quickSort(data, pi, index - 1, k);
        }else if(index < k){
            quickSort(data, index + 1, pj, k);
        }else{
            flag = false;
            return;
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

十大排序算法:快速排序算法 的相关文章

  • 如何指定 set precision 舍入

    当流到 std 输出时 我可以指定 set precision 对双精度值进行舍入吗 ofile lt lt std setprecision 12 lt lt total run time TIME lt lt n Output 0 75
  • 在 C# 中转换 VbScript 函数(Right、Len、IsNumeric、CInt)

    同样 我在 VbScript 中得到了以下代码 您能建议一下 C 中的等效代码吗 Function GetNavID Title getNavID UCase Left Title InStr Title 1 End Function 我已
  • C 语言中的套接字如何工作?

    我对 C 中的套接字编程有点困惑 You create a socket bind it to an interface and an IP address and get it to listen I found a couple of
  • 纹理映射 C++ OpenGL

    我已经阅读了相关内容 包括 Nehe 和此处的解决方案 但我找不到具体的答案 我正在尝试加载一张名为stars jpg 的照片 我想通过使用 uv 坐标映射它来使其成为场景的背景 方法是 glBegin GL QUADS glTexCoor
  • 如何在 C++ 中对四元结构进行有效排序?

    我有一个包含 x y z 和 w 成员的结构 如何高效排序 在 C 中首先按 x 然后按 y 按 z 最后按 w 如果你想实现字典排序 那么最简单的方法是使用std tie实现小于或大于比较运算符或函子 然后使用std sort http
  • 使用 C# 和反射打印完整的对象图

    我有一个复杂的对象 class A int Field1 int field2 property ClassB ClassB property classC classC etc etc 我想使用反射打印完整的对象图 有什么好的代码吗 一种
  • 如何在Qt3D中优化点云渲染

    我正在尝试使用 Qt3D 显示大型点云 20M pts 我第一次发现这个图书馆https github com MASKOR Qt3DPointcloudRenderer https github com MASKOR Qt3DPointc
  • 获取不带波形符的泛型类名称[重复]

    这个问题在这里已经有答案了 我正在尝试获取类型名称T使用这个 typeof T Name 班级名称是ConfigSettings 而不是返回ConfigSettings它正在返回ConfigSettings 1 有什么具体原因吗 我怎样才能
  • 如何使用 Linq to Sql 修剪值?

    在数据库中 我有一个名为 联系人 的表 名字和其他此类字符串字段设计为使用 Char 数据类型 不是我的数据库设计 我的对象 Contact 映射到属性中的字符串类型 如果我想做一个简单的测试 通过 id 检索 Contact 对象 我会这
  • 为什么这段代码不会产生编译错误?

    template
  • 如何使用 HttpClient 验证 Pardot API

    我花了大约一天的时间尝试对 Pardot API 进行身份验证 它不喜欢我尝试发布消息正文的方式 所以我想发布对我有用的解决方案 如果您有任何建议或替代方案 我想听听 ServicePointManager SecurityProtocol
  • 获取RFC返回的嵌套结构的值?

    我是 C 新手 我有 rfc 它以嵌套结构的形式从 SAP 系统返回数据 但是当我使用以下方式获取该数据时 IrfcTable table rfc getTable exporting parameter et customer 它仅返回第
  • vs2010 c++ 通过debug查看指针内容

    我正在使用 Vs2010 c 处理 2D 数组 我从一维指针开始 并使用操作 如下 class CMatrix void clear public int nRows int nCols short MyMat CMatrix CMatri
  • C# 的 user32 和内核方法列表 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有没有一个很好的清单来说明我们可以从中进口什么user32 dll and kernel dll并在 C 中使用 我是 Windows A
  • 随机排列

    我无法找到一种随机洗牌元素的好方法std vector经过一些操作后 恢复原来的顺序 我知道这应该是一个相当简单的算法 但我想我太累了 由于我被迫使用自定义随机数生成器类 我想我不能使用std random shuffle 无论如何这没有帮
  • 如何查明我的字符串是否包含“micro”Unicode 字符?

    我有一个包含实验室数据的 Excel 电子表格 如下所示 g L ppb 我想测试希腊字母 是否存在 如果发现我需要做一些特别的事情 通常 我会写这样的东西 if cell StartsWith matchSequence lt unive
  • 有没有办法将复选框列表绑定到 asp.net mvc 中的模型

    我在这里寻找一种快速简便的方法来在模型中发生回发时绑定复选框列表项的列表 显然现在常见的做法似乎是这样的form GetValues checkboxList 0 Contains true 这看起来很痛苦而且不太安全 有没有一种方法可以绑
  • Eclipse CDT C/C++:包含另一个项目的头文件

    我在 Eclipse CDT 中有两个 C 项目main and shared In shared我有一个名为calc h 我想在中使用这个标头main 所以我做了以下事情 added include calc h到相关文件main In
  • 如何将 IDispatch* 放入托管代码中

    我一直在考虑尝试使用 C 编写一个实现 OPOS 服务对象的 COM 对象 我已经使用自动化和 MFC 在 C 中完成了它 这并不太困难 所以我坚持尝试将其转换为一种方法 我将排除界面中的其他方法 因为它们很简单 或者我希望如此 id 6
  • C++11 中引入了哪些重大更改?

    我知道 C 11 中至少有一项更改会导致一些旧代码停止编译 引入explicit operator bool 在标准库中 替换旧实例operator void 诚然 这将破坏的代码可能是一开始就不应该有效的代码 但它仍然是一个破坏性的变化

随机推荐

  • java:方法重载和方法重写的区别

    方法重载 代码示例 public void set System out println 好好学习 public void set String name System out println 好好学习 方法重写 在不同的类中 在有继承关系
  • 服务器部署JavaWeb的war包(完整版)

    本文章内容操作环境采用的技术是docker部署war 提前下载好Xshell7 终端 如果你买的服务器有终端窗口 那么用你的服务器终端窗口也行 和Xftp7 传输文件 并下载navicat15 版本过低会因为1045 连不上服务器 一 导出
  • 网络基础:协议层次

    目录 一 理论 1 OSI参考模型 2 TCP IP模型 3 OSI模型对应协议 4 TCP IP模型对应协议 5 OSI模型传输数据过程 二 实验 1 TCP IP模型封装 一 理论 一个协议层能够用软件 硬件或者两者的结合来实现 各个层
  • 谷歌浏览器插件Automa_2.点击和输入文字

    操作 普通玩家对于组件的操作无非就输入文字 点击控件跳转页面 但高端玩家会为这些操作加上各种限制条件以让其适应各种网页 而这些内容将在进阶篇介绍 点击 1 找到你要点击的位置 2 定位它 这里有讲如何定位 3 复制那个位置 粘贴到元素选择器
  • Pytorch学习笔记(1)第四章 神经网络工具箱nn

    今天学习内容 https github com chenyuntc pytorch book blob master chapter4 E7 A5 9E E7 BB 8F E7 BD 91 E7 BB 9C E5 B7 A5 E5 85 B
  • 账号和权限管理——设置目录和文件的归属(五)

    设置目录和文件的归属 1 chown 命令 需要设置文件或者目录的归属时 主要通过 chown 命令进行 可以只设置属主或属组 也可以同时设置属主 属组 使用 chown 命令的基本格式如下 chown 属主 属组 文件或目录 同时设置属主
  • django入门:Admin管理系统及表单(干货)

    点击上方蓝字关注公众号 码个蛋第310次推文 作者 Kuky xs 博客 https www jianshu com p 8cdf099e974f 前言 django入门 环境及项目搭建 django入门 数据模型 django入门 视图及
  • Anaconda安装虚拟环境下的Jupyter Notebook没有快捷方式怎么办

    Anaconda安装虚拟环境下的Jupyter Notebook没有快捷方式怎么办 今天为了安装tensorflow 在anaconda环境下创建了一个名称为tensorflow虚拟环境 一波操作装完了tensorflow之后 为了在jup
  • 食品行业仓储条码管理系统解决方案

    食品行业总是保持一贯的稳健增势 而且整体行业在产品结构 市场竞争力 运营成本等方面仍有相当的潜力可以发掘 但食品安全问题 消费者口味的不断变化 多变的渠道模式和供应链效率问题 这些都为食品饮料行业建立了一个动荡的充满挑战和机遇的商业环境 而
  • Oracle 数据库升级

    转载来源 Oracle 数据库升级 https mp weixin qq com s LIDIsmeZRRfZmOVtOkeznQ 一 环境准备 本次测试尽量按照生产环境升级进行模拟 故而使用2台主机进行测试 注意 源库为生产环境 linu
  • 【Java编程】JavaSE基础总结(六):多线程

    JavaSE基础总结 六 进程是程序执行的实体 每一个进程都是一个应用程序 比如我们运行QQ 浏览器 LOL 网易云音乐等软件 都有自己的内存空间 CPU 一个核心同时只能处理一件事情 当出现多个进程需要同时运行时 CPU一般通过 时间片轮
  • [精通Objective-C]块(block)

    精通Objective C 块 block 参考书籍 精通Objective C 美 Keith Lee 目录 精通Objective C块block 目录 块的语法 块的词汇范围 块的内存管理 块的使用 使用块为数组排序 使用块的并行编程
  • 让你真正明白cinder与swift、glance的区别

    http www aboutyun com thread 10060 1 1 html 问题导读 1 你认为cinder与swift区别是什么 2 cinder是否存在单点故障 3 cinder是如何发展而来的 在openstack中 我们
  • 计算机辅助绘图考试题,计算机辅助设计绘图考试题(A)(大学期末复习试题).doc...

    教师试做时间出题教师 取题时间审核教研室主任出题单位使用班级考试日期院 部 主任考试成绩期望值印刷份数规定完成时间交教务科印刷日期 学号 姓名 班级 密 封 线 专业 年级 班 学年 第 学期 计算机辅助设计绘图 A 课试卷 题号一二三四五
  • Swagger 的简介和使用

    文章目录 Swagger 的简介和使用 什么是Swagger 简介 Swagger页面 Swagger快速上手 pom xml文件中引入依赖 构建Swagger配置类 Swagger使用 常用注解说明 注解的使用 总结 Swagger 的简
  • Spark jar包加载顺序及冲突解决

    一 spark jar包加载顺序 1 SystemClasspath Spark安装时候提供的依赖包 通常是spark home目录下的jars文件夹 SystemClassPath 2 Spark submit jars 提交的依赖包 U
  • Java-Map集合

    基本使用 public class Demomap public static void main String args Map
  • 关于VMware workstation Player的虚拟网络编辑器没有的情况

    VMware workstation Player 是没有 虚拟网络编辑器的 如果要按照韦东山老师的方法去配置NAT网络 可以再下载VMware workstation pro 尽管不在试用期 依然会给你虚拟网络编辑器的应用安装
  • 光照 (5) 光照贴图

    物体在不同的部件上都有不同的材质属性 1 1 漫反射 允许我们对物体的漫反射分量 以及间接地对环境光分量 它们几乎总是一样的 和镜面光分量有着更精确的控制 漫反射贴图 Diffuse Map 使用一张覆盖物体的图像 让我们能够逐片段索引其独
  • 十大排序算法:快速排序算法

    一 快速排序算法思想或步骤 分解 数组A p r 被划分为两个子数组A p q 1 和A q 1 r 使得A q 为大小居中的数 左侧A p q 1 中的每个元素都小于等于它 而右边A q 1 r 每个元素都大于等于它 解决 通过递归调用快