Quick Sort的两种实现方法---Python
2019-01-28 20:40
204 查看
1.思想:
-
取一个参考值,让序列所有的元素排序后,左侧子序列的值都比参考值小,右侧子序列的值都比参考值大。
-
分别对左侧和右侧的子序列做1中的递归操作。
基于上述思想,常用的实现方法有两种,一种是简单、容易理解的Lomuto scheme,另一种是效率更高的Hoare scheme。下面的代码参考自维基百科的伪代码实现,不清楚的可以移步维基,仔细研究。
2.Lomuto partition scheme:
《Programming Pearls》and 《Introduction to Algorithms》都采用这种框架。这个框架通常选择最后一个元素作为
pivot,设置游标
i,使用
j作为索引遍历数组,保证游标
i左侧的元素都
<= pivot,右侧的元素全都
>pivot。
Python Implementation-1
[code]# Segment 1 def partition(array, l, r): pivot = array[r] i = l - 1 for j in range(l, r): if array[j] <= pivot: i += 1 array[i], array[j] = array[j], array[i] array[i + 1], array[r] = array[r], array[i + 1] return i + 1 # Segment 2 def partition(array, l, r): pivot = array[r] i = l for j in range(l, r): if array[j] <= pivot: array[i], array[j] = array[j], array[i] i += 1 array[i], array[r] = array[r], array[i] return i def QuickSort(array, l, r): if l < r: q = partition(array, l, r) QuickSort(array, l, q - 1) QuickSort(array, q + 1, r) return array # from wikipedia: segment 1 or 2 is both ok.
3.Hoare partition scheme
--- From wikipedia
该方法设置两个索引,从数组的两端相向移动,直到它们分别发现了可转换的元素:左索引
array[i]>pivot,右索引array[j]<=pivot,显然,这两个位置的元素应该交换。当两个索引相遇,停止移动,返回最后一个index。优点
效率高,交换次数相当于Lumoto 方法的1/3,平均来看;
对于等值数组,交换次数为0;
对于已排序数组,
pivot=array[first],array[last]都会导致的时间复杂度,而pivot=array[mid]反而会达到最优时间复杂度。
Python Implementation-2
[code]# Modified from wiki def partition(array,l,r): pivot = array[l] left = l +1 right = r while left <= right: while left <= right and array[left] <= pivot: left += 1 while left <= right and array[right] >= pivot: right -= 1 if left <= right: array[left],array[right] = array[right],array[left] array[l],array[right] = array[right],array[l] return right # Copy from online resource def partition(array,l,r): pivot = array[l] left = l+1 right = r done = False while not done: while left<=right and array[left]<=pivot: left += 1 while left<=right and array[right]>=pivot: right -= 1 if right < left: done = True else: array[left],array[right]= array[right],array[left] array[right],array[l]= array[l],array[right] return right def QuickSort(array, l, r): if l<r: k = partition(array, l, r) QuickSort(array,l,k-1) QuickSort(array,k+1,r) return array
边界条件分析:
为什么
array[l],array[right] = array[right],array[l]是对的
-
array[left]<=pivot
时,left
会不断增加,但是由于前面有array[right]>pivot
阻隔,至多到left=right
,然后right
还可以左移一位,从而使left>right
,此时array[left]>pivot,array[right]<=pivot
显然交换是对的; -
array[left]>pivot
时,left
暂停,array[right]>=pivot
不断左移,至right=left
,此时right
再左移一位,right<left, array[left]>pivot,array[right]<=pivot
-
所有的情况只有上面两种结局,最后的状态都是
array[right]<=pivot,array[left]>pivot
(等值数组显然不是这种情况)。
Python Implementation-3
[code]def QuickSort(array,l,r): if l>=r: return left = l right = r pivot = array[left] while left < right: while left < right and array[right] > pivot: right -= 1 array[left] = array[right] while left < right and array[left] <= pivot: left += 1 array[right] = array[left] array[right] = pivot QuickSort(array, l, left-1) QuickSort(array, left+, r) return array
边界条件分析:
-
while left<right
终止条件为left=right
,保证不会出现索引溢出。 -
若
array[right]>pivot
使right -= 1
直至left=right
,由于此时array[left]<=pivot
,那么整个过程相当于交换了array[left] and array[right]
。 -
若
array[right]<=pivot
且left<right
,那么array[right]
先复制进left
位置,当array[left]<=pivot
使得left+=1
直至left=right
时,注意此时array[right]<=pivot
但是left<right
的限制使得至多left=right
。 -
所有的情况都可以归结为这两种结束方式,
left added to right
orright decreased to left
,构成一个交换的闭环。
另外一点需要注意的是,
array[right]>pivot and array[left]<=pivot一定是完整的
> and <=,不然无法处理元素和
pivot相等的情况,而且由于不是
>= and <=,
right and left至多以
=结束,不会出现上面实现方式中的
left>right,所以终止判别条件是
left<right , instead of left<=right。
相关文章推荐
- 飘逸的python - 两种with语句实现方法
- 总结python实现父类调用两种方法的不同
- 矩阵或多维数组两种常用实现方法 - python
- python实现读取并显示图片的两种方法
- python实现协程的两种方法
- python实现列表对应元素求和的两种方法
- 使用python实现菱形的两种方法
- Python实现阶乘函数的两种方法
- Python实现字符串反转的两种简单方法
- python用两种方法实现url短连接
- Python程序实现打开浏览器的两种方法
- 飘逸的python - 两种with语句实现方法
- Python实现列表去重的两种方法
- 两种方法实现Python二分查找算法
- python实现嵌套列表平铺的两种方法
- 两种方法实现Python二分查找算法
- python 获取本机ip地址的两种实现方法
- python用两种方法实现url短连接
- Python实现删除排序数组中重复项的两种方法示例
- python 将对象设置为可迭代的两种实现方法