十大排序算法:快速排序算法
一、快速排序算法思想或步骤
- 分解: 数组A[p…r]被划分为两个子数组A[p…q-1]和A[q+1…r],使得A[q]为大小居中的数,左侧A[p…q-1]中的每个元素都小于等于它,而右边A[q+1…r]每个元素都大于等于它。
- 解决: 通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行排序。
- 合并: 因为子数组都是在原址进行排序,所以不需要合并,原数组已经有序。
通过上述描述发现:划分是问题的关键
算法的就可以写出如下框架:
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的情况下,执行下面步骤:
- 不断向后移动pi指针,直到pi所指元素大于基元。
- 交换pi和pj所指内容,pj前移一位
- 执行第1步
- 当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
*/
三、快排存在的问题
- 如果原数组已经有序,算法效率不好
- 数组长度较大时,时间复杂度高
- 选取基元的方法本身存在缺陷。
四、优化
- 待排序元素个数比较少时,使用插入排序
- 快排时,选取基元使用绝对中值法 和三点中值法
- 排序元素较多时,使用堆排序
结合这三点,可以封装一个跟标准库中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<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;}}
十大排序算法:快速排序算法相关推荐
- 十大排序算法之快速排序(两种方法)
十大排序算法之快速排序 本文采用Java书写选择排序,其他语言类似可以借鉴着写 思想:在待排序序列中选择一个分割元素,将待排序序列中所有比分割元素关键字小的元素移动到分割元素左侧位置:将待排序序列中所 ...
- 【十大排序算法系列】快速排序
写在前面 上一篇更新了这个系列的排序算法([十大排序算法系列]冒泡排序).分析了冒泡的逻辑和优化点,下面来写下快速排序(为什么跳这么快?因为比较走心hhhh) 照例给出系列内所有算法的对比.. 常见的 ...
- 十大经典排序算法-快速排序算法详解
十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...
- 这或许是东半球分析十大排序算法最好的一篇文章
作者 | 不该相遇在秋天 转载自五分钟学算法(ID:CXYxiaowu) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强 ...
- 「干货总结」程序员必知必会的十大排序算法
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 绪论 身 ...
- 「归纳|总结」程序员必知必会的十大排序算法
微信搜一搜「bigsai」关注这个有趣的程序员 新人原创公众号,求支持一下!你的点赞三连肯定对我至关重要! 文章已收录在 我的Github bigsai-algorithm 欢迎star 本文目录 绪 ...
- 归并排序执行次数_十大排序算法,看这篇就够了
排序算法分类[1][2] 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序:不通过比较来决定元素间的相对次序,它可以 ...
- 八十八、Python | 十大排序算法系列(下篇)
@Author:Runsen @Date:2020/7/10 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...
- 经典十大排序算法(含升序降序,基数排序含负数排序)【Java版完整代码】【建议收藏系列】
经典十大排序算法[Java版完整代码] 写在前面的话 十大排序算法对比 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 插入排序 希尔排序 计数排序 桶排序 基数排序 完整测试类 写在前面的话 ...
- 十大排序算法(Java)
文章目录 十大排序算法(Java) 一.冒泡排序(Bubble Sort) 二.选择排序(Selection Sort) 三.堆排序(Heap Sort) 四.插入排序(Insertion Sort) ...
最新文章
- python是什么编程教程-编程python是什么_谁的Python教程最好?
- 策略模式的扩展——策略枚举
- 正则表达式。部分实例及说明(摘)
- PAT_B_1090_C++(25分)
- PHP PDO函数库详解
- 分布式 | Dubbo 架构设计详解
- django框架概述
- javascript的事件冒泡,阻止事件冒泡和事件委托, 事件委托是事件冒泡的一个应用。...
- 疲劳驾驶样本集_谷歌AI最新3D数据集,1.5万张动图,让AR主宰你的生活
- 病毒侵袭(HDU-2896)
- 从入门到入土:[SEED-Lab]MD5碰撞试验|MD5collgen实验|linux|Ubuntu|MD5 Collision Attack Lab|详细讲解
- 题解报告:hdu 1754 I Hate It(线段树)
- 一、optimizer_trace介绍
- 好货推荐!两款免费的 Linux 桌面录制工具
- 2020网赚模式不再亮眼,中小开发者如何在红海竞争中活下去?
- Modbus设备通过边缘网关接入阿里云IoT平台
- GEF 命令模式介绍
- 7-3 求最小码距(完整版) (10 分)
- Holt_Winters三次平滑指数实现
- Classpath entry org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER will not be exported
热门文章
- 趣图:你永远不知道前端在对你的接口做什么
- IBM BladeCenter® HC10 刀片工作站 常见问题 (2)
- MATLAB----其他形式的二维曲线
- 判断闰年 php,php判断是否为闰年
- ProcessOn 数据恢复
- 工作日报http://www.cnblogs.com/suyang/archive/2008/05/18/1201990.html
- 说python好的文章大多在吹牛
- 从汇编角度理解 ebpesp 寄存器、函数调用过程、函数参数传递以及堆栈平衡
- 电气工程及其自动化学python有用吗_电气工程及其自动化专业个人技能怎么写
- 教你用grub4dos定制自己的启动U盘