经典快速排序及双路三路快速排序

文章总结:

快速排序是20世纪最重要的10大算法思想之一,也是目前公认的最快的排序算法之一,其主要思想是递归与分治,把一个复杂的问题分成多个的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。本文介绍了经典的快速排序与及其两个改进:双路与三路快速排序。第一次尝试这种二次元风格希望大家多多支持:)

1.经典的快速排序算法

经典的快速排序算法的基本思想是:在序列中选定一个基准值,遍历序列,将序列分为两部分,一部分大于基准值,一部分小于基准值,再递归地对这两部分数据进行快速排序,直到整个序列有序。

图一

如图一所示,随机从序列中选择一个值作为基准值并将其放到序列的开始位置l,声明索引j与k,以闭区间[l+1:j]表示比基准值小的元素,以闭区间[j+1:k-1]表示比基准值大的元素,k表示当前遍历到元素下标,起始时两个区间中应无元素,即初始化j=l,k=l+1,初始状态如图二所示。
在这里插入图片描述

图二

之后以索引k遍历序列,如图三所示,如果array[k]<B,则交换索引j与索引k指向的元素,然后移动k指向下一个元素,否则如图四所示,不需要交换位置,直接移动k至下一个元素。在这里插入图片描述

图三

在这里插入图片描述

图四

一次遍历结束后,得到的序列如图五所示,需要再将基准元素放到正确位置,则交换索引l与j指向位置的元素将基准元素放置在正确位置,之后再递归排序大于基准值与小于基准值的两部分至有序即可。
在这里插入图片描述

图五
Python 代码:
1.	def partition(array, l, r):  
2.	    random_index = random.randint( l, r )  
3.	    array[l], array[random_index] = array[random_index], array[l]  
4.	    basic = array[l]  
5.	    j = l  	 # < basic:[l,j]  
6.	    k = l + 1  # > basic:[j+1,k-1]  
7.	    for k in range( l + 1, r + 1 ):  
8.	        if (array[k] < basic):  
9.	            array[j + 1], array[k] = array[k], array[j + 1]  
10.	            j += 1  
11.	    array[l], array[j] = array[j], array[l]  
12.	    return j  
13.	  
14.	  
15.	def quickSort(array, l, r):  
16.	    if (l > r):  
17.	        return;  
18.	    j = partition( array, l, r )  
19.	    quickSort( array, l, j - 1 )  
20.	    quickSort( array, j + 1, r )  

2.双路快速排序

在经典的快速排序使用过程中,人们也发现了一些问题,比如在面临有很多重复值的情况下,经典的快速排序算法会变得很慢,原因是以其中某个值作为基准值时,由于存在多个重复元素,导致分成的两部分大小不均衡,从而使得算法的复杂度接近O(N^2),为了解决这个问题,就有了双路快速排序,双路快速排序的基本思路是:在序列中选定一个基准值,建立两个遍历索引j和k,j从头遍历到尾,k从尾遍历到头,将<=基准值的元素保存在j索引的左边,将>=基准值的元素保存在k索引的右边,从而实现了将多个重复元素分散到两部分序列中,避免了两部分大小不均衡的问题。
在这里插入图片描述

图六
区间:<=B:[l+1,j] >=B:[k+1,r]
初始化:j=l+1,k=r
操作:如果array[j]<=B,则j++,否则交换array[j]与array[k],k--,j++
如果array[k]>=B,则k--,否则交换array[j]与array[k],k--,j++
python 代码:
1.	def partition(array, l, r):  
2.	    random_index = random.randint( l, r )  
3.	    array[l], array[random_index] = array[random_index], array[l]  
4.	    basic = array[l]  
5.	  
6.	    j = l + 1  # <= basic:[l+1,j-1]  
7.	    k = r  	 # >= basic:[k+1,r]  
8.	    while True:  
9.	        while j <= r and array[j] < basic:  
10.	            j += 1  
11.	        while k >= l + 1 and array[k] > basic:  
12.	            k -= 1  
13.	        if j > k:  
14.	            break  
15.	  
16.	        array[j], array[k] = array[k], array[j]  
17.	        j += 1  
18.	        k -= 1  
19.	    array[k], array[l] = array[l], array[k]  
20.	    return k  
21.	  
22.	  
23.	def quickSort(array, l, r):  
24.	    if l > r:  
25.	        return  
26.	    j = partition( array, l, r )  
27.	    quickSort( array, l, j - 1 )  
28.	    quickSort( array, j + 1, r )  

三路快速排序

三路快排同样用于处理重复值的问题,只是与双路快排中将序列分成两部分不同,在三路快排中,将序列分为大于基准值,小于基准值与等于基准值三部分,一次递归结束后,所有等于基准值的元素找到了其正确位置,之后只需要再递归处理小于基准值与大于基准值两部分即可。
在这里插入图片描述

图七

区间:<B:[l+1,j] >B:[k,r] =B:[j+1,i-1]

初始化:j=l+1,i=l+1,k=r+1

操作:如果array[i]<B,则交换array[j+1]与array[i],j++,i++
如果array[i]>B,则交换array[k-1]与array[i],k--

如果array[i]=B,则i++

python代码:

1.	def partition(array, l, r):  
2.	    random_index = random.randint( l, r )  
3.	    array[l], array[random_index] = array[random_index], array[l]  
4.	    basic = array[l]  
5.	    j = l  	 # <basic:[l+1,j]  
6.	    k = r + 1  # >basic:[k,r]   
7.	    i = l + 1  # =basic:[j+1,i-1]  
8.	  
9.	    while (i < k):  
10.	        if (array[i] < basic):  
11.	            array[i], array[j + 1] = array[j + 1], array[i]  
12.	            j += 1  
13.	            i += 1  
14.	        elif (array[i] > basic):  
15.	            array[i], array[k - 1] = array[k - 1], array[i]  
16.	            k -= 1  
17.	        else:  
18.	            i += 1  
19.	  
20.	    array[l], array[j] = array[j], array[l]  
21.	    return j, k  
22.	  
23.	  
24.	def quickSort(array, l, r):  
25.	    if l > r:  
26.	        return;  
27.	  
28.	    j, k = partition( array, l, r )  
29.	    quickSort( array, l, j - 1 )  
30.	    quickSort( array, k, r )  

最后,欢迎大家关注国科大卜东波老师算法课公众号:LOA算法学习笔记!

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clear butterfly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值