快速排序
介绍
快速排序是分治思想的一种体现,通过递归不断将原数列划分为一大一小两部分, 从而实现对数列的排序。
算法时间复杂度为O(nlogn)
。特点是数据越混乱,效率越高;数据越有序,效率越低。
值得注意的是快速排序是不稳定的,即相同大小的数据在排序前后的相对位置可能会发生变动。
代码实现
void quick_sort(int a[],int l,int r)//快速排序,从小到大
{
if (l == r)
return;//若数列中只有一个数,则必定有序,返回
int x = a[(l + r) / 2], i = l - 1, j = r + 1;
//取中项值为标准值x,采用do while,故i,j起始位置在l,r两端
while(i<j)//当指针相遇且越过,则说明数列已遍历完
{
do i++; while (a[i] < x);
do j--; while (a[j] > x);
//i,j从两端分别向中间遍历,使i左边值小于x,j右边值大于x,遇到不满足则停止
if (i < j) swap(a[i], a[j]);
//当i,j分别移动到不满足项时,交换二者位置,则二者都满足,i,j继续向中间遍历
}
//指针相遇,遍历结束,此时j及其左侧值都小于x,j+1及其右侧值都大于x
quick_sort(a, l, j);
quick_sort(a, j + 1, r);
//分别对左右两部分递归处理,知道整个数列都有序
}
思路解析
void quick_sort(int a[],int l,int r)//快速排序,从小到大
{
if (l == r)
return;
//......
}
函数的传入值包括数组和左右端点下标。
显而易见,当l==r
时,数列中只有1个数据,必定有序,所以我们直接返回。
int x = a[(l + r) / 2], i = l - 1, j = r + 1;
此时,我们需要将该数列分为一大一小两部分,保证右边的所有数都能大于左边。
所以,我们需要设定一个标准值,来判断某一个数应该放在左边还是右边。
这个标准值可以选择数组中的任何一个数据,可以取第一个值a[l]
,也可以取中项a[(l+r)/2]
,甚至可以随机。
但我们这里选择取中项值作为标准值,假如取首项为标准值,当所有数据大小都一样时,算法的时间复杂度会从O(nlogn)
退化到O(n²)
。
同时,我们设立两个指针i和j,分别置于数列两端,用于遍历下标,至于为什么要多偏移一位,我们下面解释。
while(i<j)//当指针相遇且越过,则说明数列已遍历完
{
do i++; while (a[i] < x);
do j--; while (a[j] > x);
//i,j从两端分别向中间遍历,使i左边值小于x,j右边值大于x,遇到不满足则停止
if (i < j) swap(a[i], a[j]);
//当i,j分别移动到不满足项时,交换二者位置,则二者都满足,i,j继续向中间遍历
}
指针位于数列的两端,同时往中间移动,我们采用do{} while{};
语句,每次先移动指针再进行判断,所以我们的起始位置应该置于l和r的外侧一位。
指针向中间移动后,比较当前位置的数据值和标准值x的大小。
以i指针举例,若a[i]<x
,则无事发生,指针i继续遍历,将该数据留在i的左边,直到遇到一个不满足的数,停下。
指针j同理。
当两个指针都已停止后,说明a[i]
处有一个大于x
的值,a[j]
处有一个小于x
的值,此时只需要将二者调换位置即可有效地调整数列顺序,当然,需要先对i,j是否越过进行判断。
若两个指针相遇且越过,就说明数列已经遍历完了,每个下标都已经经过。
此时,我们就已经将数组划分为左右一大一小两个部分。
quick_sort(a, l, j);
quick_sort(a, j + 1, r);
最后,我们将划分出的两个数组递归处理,再次划分为一大一小,直到划分到只有1个数据,然后开始回溯。
最终,就会返回一个有序数列。
值得注意的是,递归的起始位置也可以用i表示,但需要改为
quick_sort(a, l, i - 1);
quick_sort(a, i, r);
并且x
的取值也需要从x = a[(l + r) / 2]
改为x = a[(l + r) / 2 + 1]
,即额外加1。
否则会出现边界问题,导致无限递归。
以上便是对快速排序的介绍,本文由凉茶coltea撰写,思路来自AcWing大佬yxc的课
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容