通俗点聊聊算法 - 排序(3)快速排序,亲测
这些天做题的时候吃了不少 快速排序不熟的亏,我痛下决心,一定要自己写出快速排序的几种实现方法!
1、什么是快速排序
快速排序是很重要的算法,和傅里叶变化等算法并称二十世纪最伟大的十大算法。
快速排序的核心思维就是“分而治之”,就像封建王朝的“分封制”。将一大块“领土”,依据“嫡庶长幼”,分为不同部分,各个部分在自行细分,直到分无可分之后,便等级森严了。
说白点,就是在序列中找个元素充当中间量,大的往后,小的往前,一分为二,二分为四,四分为八···
那么,快速排序的技术核心,便呼之欲出了。其一就是这个中间量怎么找,其二就是怎么移动各个元素。
2、基准元素的选择
这个元素的选择啊,并不是说要遵循什么准则,你可以选序列头,序列尾,序列中间元素,都可以。 不过选完之后把基准元素放到序列头的位置。
为了简单,后面我就直接选首元素了。
3、元素的分配
3.1双边遍历
这个方法呢,如果对快慢指针和双指针不是很了解的朋友可以现在了解一下。
首先啊,确定基准为4,左指针指向第一个元素,右指针指向尾巴。
右指针开始,向前遍历,找到第一个大于基准的元素就停下,轮到左指针,同理。
当两个指针都停下之后,将两个指针所指向的值互换位置。
重复上述步骤直到左右指针重合。
重合之后,将基准元素与左右指针当前位置元素进行互换。
一次循环之后,重复上述动作,对划分出的部分再次循环,直到每个部分都只有一个元素为止。
3.2 单边遍历
这个是快慢指针实现。
这个mark,是慢指针。快指针没标出来。,依旧找好了基准,快指针从慢指针后一位开始快速遍历,直到遍历到小于基准元素的元素时停滞。
将慢指针前移一位,将当前快慢指针位置元素互换(如果重叠就算了)。然后快指针继续向后走。
重复上述步骤直到左右指针重合。
重合之后,将基准元素与左右指针当前位置元素进行互换。
一次循环之后,重复上述动作,对划分出的部分再次循环,直到每个部分都只有一个元素为止。
4、代码实现
以下代码现场手写,如果有什么纰漏还望不吝赐教。
4.1双边循环代码实现
不好意思一段简单代码写了一晚上,不过我已经初步测试好了。
如果有要测试/调试的朋友,我可以讲一下我的调试思路:
先对两个数据进行一次调试,因为这是最后一道坎,这个要是有问题,后面都是白费。 然后·对三个数据进行测试,相信有了前面的基础这个测试会比较顺利。 然后四个数据,五个数据,越来越顺利。我测到六个数据之后便不再测试了,看它没什么情况发生。
如果你有兴趣,建议你去拿其他人的代码测试,他们是把递归和归并分开的,反正我用了几个别人的代码来测试,全崩了。
#include<iostream>
#include<vector>
using namespace std;
void doubleSideSort(vector<int> &vec1,int left,int right) //序列与左右指针传入
{
//结束语
if (right == left)
return;
//基准确定
int flag = vec1[left];
int keep_right = right;
int keep_left = left;
int change_temp;
//当左右指针还没重合
while (left<right)
{
//左指针先走
while (left<right && vec1[left]<=flag)
{
left++;
}//当遇到比基准大的数,停下来
//轮到右指针走
while (left < right && vec1[right] >= flag) //可以都等,反正最后都会归并
{
right--;
}//当遇到比基准小的数,停下来
if (left < right)
{
change_temp = vec1[left];
vec1[left] = vec1[right];
vec1[right] = change_temp;
}
//然后继续循环
}
//left--;
//接着将基准放进去,此时必定是左右相合,则左值若大于左值左边一位,和左值左边一位换,若小,则和左值换
if (vec1[left] > vec1[left - 1])
{
vec1[keep_left] = vec1[left-1];
vec1[left-1] = flag;
}
else
{
vec1[keep_left] = vec1[left];
vec1[left] = flag;
}
doubleSideSort(vec1,0,left-1);
doubleSideSort(vec1, right, keep_right);
}
int main()
{
vector<int> vec1 = { 4,6,8,7,9,3,1}; //测试用2个数测试最直观,因为最后都要通过这一步才能正常
int left = 0;
int right = vec1.size() - 1;
doubleSideSort(vec1, left, right);
for (; left <= right; left++)
cout << vec1[left] << " ";
cout << endl;
return 0;
}
4.2单边循环代码实现
快慢指针我还是比较有信心的,所以我就测试了四组数据。 如果有任何问题,欢迎留言。
void oneSideSort(vector<int>& vec1, int slow, int hight)
{
//设置退出条件
if (slow >= hight)
return;
//将标志位留住
int flag = vec1[slow];
int keep_slow = slow;
int keep_hight = hight;
//使用快指针遍历,将小于标志位的前移
for (int quick = slow + 1; quick <= hight; quick++)
{
if (vec1[quick] < flag)
{
slow++;
int change_temp = vec1[slow];
vec1[slow] = vec1[quick];
vec1[quick] = change_temp;
}
}
vec1[keep_slow] = vec1[slow];
vec1[slow] = flag;
oneSideSort(vec1, keep_slow,slow-1);
oneSideSort(vec1,slow+1, keep_hight);
}
int main()
{
vector<int> vec1 = {2,1,2,3}; //测试用2个数测试最直观,因为最后都要通过这一步才能正常
int left = 0;
int right = vec1.size() - 1;
oneSideSort(vec1, left, right);
for (; left <= right; left++)
cout << vec1[left] << " ";
cout << endl;
return 0;
}
- JOJ 2676 Problem B
- React项目配置2(自己封装Ajax)
- React项目配置1(如何管理项目公共js方法)
- c++中stack、queue、vector的用法一、栈(stack)二、队列(queue)三、向量(vector)
- React技巧7(TodoList实现3组件之间传递数据之优化)
- React技巧6(TodoList实现2组件之间传递数据)
- POJ A Knight's Journey
- React技巧5(TodoList实现)
- 求一个数n次方后的末尾数(数论/快速幂)问题描述解题思路代码实现运行结果参考
- Catch That Cow
- React技巧4(如何处理List里面的Item)
- ZOJ 3620 Escape Time II
- React技巧3(如何优雅的渲染一个List)
- FZU 电动车通行证制度
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【TOOLS】Linux环境下升级python2.7到python3.6
- 溯源黑帽利用 Web 编辑器漏洞非法植入 SEO 页面事件
- Milvus 查询合并机制
- Django model 层之Models与Mysql数据库小结
- 【010期】JavaSE面试题(十):集合之Map18连环炮!
- 每日打卡 373. 查找和最小的K对数字
- IE11出现"__doPostBack”未定义
- latex()、ploy2sym()、symsum()的妙用
- 性能最佳实践:MongoDB数据建模和内存大小调整
- 节省你生命的一个小技术No.193
- K8S 生态周报| Traefik v2.3.0-rc2 发布
- 如何从 Notion 批量导出 Markdown?
- 【LeetCode】1518. 换酒问题
- OBS推流工具使用说明
- Python多进程