当前位置:首页 > 行业知识 > 综合

快速排序图解

关注:92 发布时间:2021-06-22 12:19:57

之前我们在交换类排序中引入了冒泡排序,这次引入了另一种交换类排序,叫做快速排序。快速排序的优点是原地排序,不占用额外空间,时间复杂度为o(nlogn)。

当然对于快速排序也有缺点。对于包含大量重复元素的数组排序效率非常低,时间复杂度会降低到o(n ^ 2)。此时,我们需要使用改进的快速排序-双向快速排序。在双向快速排序的基础上,进一步优化了三向快速排序。

快速排序

快速排序的基本思想是通过一遍排序将待排序的数据分成两个独立的部分,其中一部分的所有数据都小于另一部分的所有数据,然后按照这种方法分别对这两部分数据进行快速排序,整个排序过程可以递归进行,使整个数据成为有序序列。

快速排序步骤如下:

1.以第一个元素为分界点,用l指向它。

2.遍历右边的元素。在遍历的过程中,我们排列数组,有的小于v,有的大于v,用j指向小于v和大于v的分界点,用i指向当前访问的元素e,此时数组arr[l 1…j]v,arr [j 1 … i-1] v。

3.如果ev,直接在大于v的部分后面合并e,然后我继续比较下面的元素。

4.如果ev,把e移到j指向的元素的后面元素,然后j,然后我继续比较后面的元素。

5.这样遍历整个数组一次。遍历后,数组分为三部分,左边部分为v,中间部分为v,右边部分为v。

6.比较后我们把l指向的元素和j指向的元素进行交换,这样元素v就很快排序了。v的左边元素小于v,右边元素大于v。

现在我们用上面的方法快速排序数组[2,1,4,3,7,8,5,6]。下图显示了快速排序的整个过程:

快速排序代码:

公共静态无效排序(可比[] arr) {

int n=arr.length

sort(arr,0,n1);

}

//递归使用快速排序对arr的范围进行排序[l…r]

私有静态空排序(可比[] arr,int l,int r) {

if (l=r) {

返回;

}

//分区arr[l…r]并返回p,这样arr[l…p-1]arr[p];arr[p 1…r] arr[p]

int p=partition(arr,l,r);

排序(arr,l,p1);

sort(arr,p 1,r);

}

私有静态int分区(可比[] arr,int l,int r) {

//比较左边的元素用作校准点

可比v=arr[l];

int j=l;

for(int i=l 1;i=r;i ) {

if (arr[i]。compareto(v) 0)

swap(arr,j 1,i);

j .

}

}

swap(arr,l,j);

返回j;

}

优化快速排序

经过上面的介绍,我们可以发现快速排序并不能保证每个分割都有相同大小的子阵,所以可能一边小一边大。对于有序数组,快速排序的时间复杂度变成o(n ^ 2),相当于树退化成链表。下图显示了这一变化:

上面,我们使用左边的第一个元素作为校准元素。现在我们随机选择一个元素作为校准元素。此时第一次选择第一个元素的概率为1/n,第二个元素为1/n-1。以此类推,在出现之前退化成链表的概率是1/n(n-1)(n-2)…。当n较大时,这个概率几乎为零。

另一个优化是对小规模数组使用插入排序,因为递归会使小规模问题中的方法调用过于频繁,并且插入排序对于小规模数组非常快。

优化的快速排序代码:

公共静态无效排序(可比[] arr) {

int n=arr.length

sort(arr,0,n1);

}

//贺盛文贺盛文,-什么停止[l.r]阿云阿云阿云阿云阿云阿云阿云

私有静态void排序(相当于[] arr,int l,int r)}

//云娥与云娥,云娥与云娥

如果(rl=15)}

insertonstart。sort(arr、l、r);

返回;

}

//-什么停止[l.r]阿悦分割区诶诶哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟哟,阿忠p,你知道吗?僧儿页:1:停止[p1.r]停止[p]

int p=分区(arr、l、r);

输出(arr,l,p-1);

(经常预算):

}

专用静态(同internationalorganizations)国际组织部件

(可比[] arr,int l,int r) {

//在arr[l…r]范围内随机选择一个值作为校准点轴心

swap(arr,l,(int)(math . random*(rl ^ 1))l);

可比v=arr[l];

int j=l;

for(int i=l 1;i=r;i ) {

if (arr[i]。compareto(v) 0)

swap(arr,j 1,i);

j .

}

}

swap(arr,l,j);

返回j;

}

双向快速排序

对于包含大量重复元素的数组,上面的快速排序效率很低,因为在我们上面的判断中,如果元素小于v,那么元素就放在v部分,如果元素大于等于v,那么就放在v部分。这时如果数组中有大量重复的元素,v部分会变得很长,导致左右两边不平衡,性能降低。

双向快速排序的步骤如下:

1.把v和v放在数组的两端,用i指向v的下一个元素,用j指向v的前一个元素。

2.从i向后遍历,如果遍历的元素ev继续向后遍历,直到遍历的元素e=v,那么停止遍历。从j开始向前遍历,如果遍历的元素为ev,继续向前遍历,直到遍历的元素e=v,然后停止遍历。

3.交换一下我指向的元素和j指向的元素,然后我,j继续比较下一个。

双向快速排序代码:

公共静态无效排序(可比[] arr) {

int n=arr.length

sort(arr,0,n1);

}

私有静态空排序(可比[] arr,int l,int r) {

//对于小规模数组,使用插入排序

if(rl=15){

insertionsort.sort(arr,l,r);

返回;

}

int p=partition(arr,l,r);

排序(arr,l,p1);

sort(arr,p 1,r);

}

私有静态int分区(可比[] arr,int l,int r) {

//在arr[l…r]范围内随机选择一个值作为校准点轴心

swap(arr,l,(int)(math . random*(rl ^ 1))l);

可比v=arr[l];

int i=l 1,j=r;

while (true) {

//注意这里的边界,arr[i]。compareto(v) 0,不能是arr[i]。compareto(v)=0

//如果不加等号,此时会退出while循环,也就是交换i和j的值,这样对于一个包含大量相同元素的数组,交换两边相等的数据,可以在一定程度上保证两路的数据平衡。

//从i向后遍历,如果遍历的元素ev,继续向后遍历,直到遍历的元素e=v,然后停止遍历

while (i=r arr[i]。compareto(v) 0)

i;

}

//从j开始向前遍历,如果遍历的元素为ev,继续向前遍历,直到遍历的元素e=v,然后停止遍历

while(j=l ^ 1 arr[j]。compareto(v) 0)

j ;

}

if (i=j) {

打破;

}

swap(arr,i,j);

i;

j ;

}

//此时j指向的元素是数组中小于v的比较后一个元素,i指向的元素是数组中大于v的第一个元素。

swap(arr,l,j);

返回j;

}

三向快速排序

三向快速排序的步骤如下:

1.在双向快速排序的基础上,我们将等于v的元素作为单一部分。lt指向小于v部分的比较后一个元素,gt指向大于v部分的第一个元素。

2.从i向后遍历,如果遍历的元素e=v,e直接合并到=v部分,然后i继续遍历。如果你遍历元素ev,交换e部分的第一个元素和=v(lt 1指向的元素),然后lt,我继续遍历。如果遍历的元素ev,则交换e和v的前一个元素(gt-1指向的元素),然后gt ,但此时不需要改变i,因为i位置的元素与gt位置之前的空白元素交换。

3.遍历之后,i=gt,然后用lt-pointing元素交换l-pointing元素。

4.在v形零件和v形零件上执行上述操作。

三向快速排序相对于双向快速排序的优势在于,减少了重复元素的比较操作,因为重复元素在一次排序中已经被排列为单一部分,然后只需要对不等于重复元素的其他元素进行排序。

三向快速排序代码:

公共静态无效排序(可比[] arr) {

int n=arr.length

sort(arr,0,n1);

}

私有静态空排序(可比[] arr,int l,int r) {

//对于小规模数组,使用插入排序

if(rl=15){

insertionsort.sort(arr,l,r);

返回;

}

//在arr[l…r]范围内随机选择一个值作为校准点轴心

swap(arr,l,(int)(math . random*(rl ^ 1))l);

可比v=arr[l];

int lt=l;//arr[l 1…lt] v

int gt=r 1;//arr[gt…r] v

int i=l 1;//arr[lt 1…i)=v

while (i gt) {

if (arr[i]。compareto(v) 0)

swap(arr,i,lt 1);

i;

lt。

} else if (arr[i]。compareto(v) 0)

互换(arr,i,gt1);

gt ;

} else { //arr[i]==v

i;

}

}

互换(arr,l,lt);

排序(arr,l,lt1);

sort(arr,gt,r);

}

摘要

本文介绍了快速排序、快速排序的优化、双向快速排序和三向快速排序。

为了快速排序,我们需要选择合适的校准点,使校准点的两侧平衡;当在快速排序中递归到小数组时,我们可以用插入排序来代替递归,以减少不必要的开销。

对于双向快速排序和三向快速排序,我们在数组中使用了大量重复的元素。

比较后,建议jdk底部的排序使用插入排序 双路快速排序

合并和排序的组合。

猜你喜欢

  • 这将是十年来最好的创富时机

    这将是十年来最好的创富时机76人支持

    过去十年见证了中国经济的巨大变化。从2009年开始,经济学家开始预测,明年将是中国经济发展最困难的一年。随着移动互联网的逐渐普及,人们的生活方式发生了巨大的变化。与此同时…

  • 华为手机安全模式怎么解除

    华为手机安全模式怎么解除73人支持

    手机安全模式是手机系统中的一种特殊模式,其原理类似于windows安全模式。手机的安全模式只加载系统的基本功能和一些预设的应用,其他用户安装的第三方应用无法在安全模式下显…

  • 木三事件是怎么回事

    木三事件是怎么回事77人支持

    网上有很多匪夷所思的灵异事件,有些是网友的亲身经历,有些没有得到证实,但被网友的口碑渲染得有点吓人。三目事件和当年的左阳事件类似,但是后来她没有再出现在网络上,大家都很担…

  • 美柚和大姨吗哪个好用?

    美柚和大姨吗哪个好用?87人支持

    市面上诞生了很多女性健康管理app,但最终deus ex和美柚占据了主要市场份额。未来女性健康管理领域的“霸主”是谁?是“吞并”还是“共存”?目前似乎没有定论。初期社区战:美柚…

  • 工勤岗位是什么意思

    工勤岗位是什么意思112人支持

    事业单位分为管理岗位、专业技术岗位和工业后勤岗位。管理岗位和专业技术岗位是干部,工业和后勤岗位是工人。所有政府机关和事业单位都要求每个报名的人都必须参加考试。所以…

  • 目前笔记本电脑哪款好

    目前笔记本电脑哪款好93人支持

    题主没有给出买电脑的目的和预算,只能说说个人经历。因为是工作需要,主要用于办公需要,所以我现在用的是联想thinkpad x1 carbon(不是广告,这个型号我用了好几年了),也推荐这个…

  • 抖音怎么设置不让别人保存我的视频

    抖音怎么设置不让别人保存我的视频63人支持

    注册tik tok账户时,开发者许可协议中明确规定,当您发布视频时,默认情况下,每个人都可以在未经您授权的情况下转载和使用它。尽量有办法。您可以在视频中添加水印。例如:“未经授…

  • 在别人眼里的“

    在别人眼里的“43人支持

    之前认识一个合伙人,月薪八万多,设计图纸做的挺好。我给她的工作都是可以熟练完成的,每次完成的时间超出了我的想象。有一次请她吃饭,发现她在几个平台上盈利,而且是在工作之外做…

  • k40系列怎么样

    k40系列怎么样31人支持

    今天在小米之家体验了红米在线发布的最新k40系列,想说一下对你的一些感受。1.外貌方面,个人感觉幻境最好,其次是晴天和下雪天,最后是明亮和黑暗。幻想那个颜色真好看,角度不一样,…

  • 电话催收是烂工作吗

    电话催收是烂工作吗56人支持

    还有其他网点或者其他工作,建议大家不要打电话催收。第一,人性的恶会在工作中被无限放大;第二,这条线的水靠电很深,赚了辛苦钱上岸可能不安全。有可能尝试收银行违约,但是很多电催…

  • 淘宝网新手开店入门

    淘宝网新手开店入门4人支持

    一、注册账号首先,第一步一定要注册淘宝账号。这里按照注册的基本操作,相信大家都能完成。但是,不能修改旺旺的名称。在确定要做什么品类之后,旺旺的名字要和店铺、产品、品类相…

  • 天猫网店开店费用

    天猫网店开店费用65人支持

    开一家天猫旗舰店,也就是天猫最高级的店,首先要满足天猫入驻的条件!假设你能达到天猫的入门要求,那么基本成本是多少?你可以算一下:1.天猫押金10万!2.技术服务费3万元!3.质检费用100…