使用霍尔分区进行快速排序,我选择pivot的方式会影响我的python实现
我正在尝试使用python中的霍尔分区实现快速排序,代码来自 但是,当我将pivot=a_列表[低]更改为pivot=a_列表[高]时,我就是无法让它工作 有人能帮忙吗使用霍尔分区进行快速排序,我选择pivot的方式会影响我的python实现,python,algorithm,quicksort,Python,Algorithm,Quicksort,我正在尝试使用python中的霍尔分区实现快速排序,代码来自 但是,当我将pivot=a_列表[低]更改为pivot=a_列表[高]时,我就是无法让它工作 有人能帮忙吗 def quicksort(a_list): """Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort""" def _quicksort(a_list, low, high): # must run partit
def quicksort(a_list):
"""Hoare partition scheme, see https://en.wikipedia.org/wiki/Quicksort"""
def _quicksort(a_list, low, high):
# must run partition on sections with 2 elements or more
if low < high:
p = partition(a_list, low, high)
_quicksort(a_list, low, p)
_quicksort(a_list, p+1, high)
def partition(a_list, low, high):
pivot = a_list[low] # changing to pivot = a_list[high] breaks the program
while True:
while a_list[low] < pivot:
low += 1
while a_list[high] > pivot:
high -= 1
if low >= high:
return high
a_list[low], a_list[high] = a_list[high], a_list[low]
low += 1
high -= 1
_quicksort(a_list, 0, len(a_list)-1)
return a_list
--更新--
为了确保我真正理解快速排序,我还尝试了使用pivot=array[low]进行lomuto分区。这是另一个挑战,所以也请检查@rcgldr更新的答案。这似乎足以进行更正:
_quicksort(a_list, low, p-1)
_quicksort(a_list, p+1, high)
将名称更改为[],lo,hi,p轴 对于问题中的代码,pivot可以是除[hi]之外的任何元素。对于PIVOT=A[Hi]问题的一个例子,考虑LO=0,HI=1,和A〔0〕< A[ 1 ]的情况。
a[] = {2,3}
partition:
p = a[1] = 3
since a[lo] < p, lo += 1 = 1
since a[hi] == p, hi = 1
return hi = 1
_quicksort(a, lo, p) == _quicksort(a, 0, 1) (infinite recursion)
切换到返回lo,p-1,p,允许枢轴为除[lo]之外的任何元件:
a[] = {2,3}
partition:
p = a[1] = 3
since a[lo] < p, lo += 1 = 1
since a[hi] == p, hi = 1
return lo = 1
_quicksort(a, lo, p-1) == _quicksort(a, 0, 0) (ok)
_quicksort(a, p, hi) == _quicksort(a, 1, 1) (ok)
a[] = {3,3}
partition:
p = a[1] = 3
since a[lo] == p, lo = 0
since a[hi] == p, hi = 1
swap(a[lo], a[hi]) a = {3,3}
lo += 1 = 1
hi -= 1 = 0
since a[lo] == p, lo = 1
since a[hi] == p, hi = 0
return lo = 1
_quicksort(a, lo, p-1) == _quicksort(a, 0, 0) (ok)
_quicksort(a, p, hi) == _quicksort(a, 1, 1) (ok)
a[] = {4,3}
partition:
p = a[1] = 3
since a[lo] > p, lo = 0
since a[hi] == p, hi = 1
swap(a[lo], a[hi]) a = {3,4}
lo += 1 = 1
hi -= 1 = 0
since a[lo] > p, lo = 1
since a[hi] == p, hi = 0
return lo = 1
_quicksort(a, lo, p-1) == _quicksort(a, 0, 0) (ok)
_quicksort(a, p, hi) == _quicksort(a, 1, 1) (ok)
在单个功能中,旋转轴=a[lo]的Lomuto。在分区步骤之后,它只在较小的分区上重复,然后更新lo或hi并循环回处理较大的分区。这将堆栈空间复杂度限制为Ologn,但最坏情况下的时间复杂度仍为^2
def quicksort(a, lo, hi):
while(lo < hi):
pivot = a[lo]
i = lo+1
for j in range(lo+1, hi+1):
if a[j] < pivot:
a[i],a[j] = a[j],a[i]
i += 1
i -= 1
a[i],a[lo] = a[lo],a[i]
if(i - lo <= hi - i):
quicksort(a, lo, i-1)
lo = i+1
else:
quicksort(a, i+1, hi)
hi = i-1
但这不是Lomuto分区方案吗?不是。Hoare和Lomuto分区都可以选择任何值作为分区的第一、最后、中间、随机索引。但是你必须从下一个工作中排除分区值,它已经位于最终位置,否则它会有限地参与处理,导致堆栈溢出。我的意思是wiki说,主要算法递归的下两个部分是lo..p和p+1..hi,而不是lo..p-1和p+1..hi,就像Lomuto的方案一样。经典算法书籍的文本显示的递归调用方案与我在分区方案中单独提到的相同。也许这样的修改是有效的:_quicksorta_list,low,p-1 _quicksorta_list,p,high,但我不知道为什么我们要重用分区元素。@MBo-使用霍尔分区方案,轴和等于轴的元素可以在任何地方结束。Hoare分区返回的索引不指向该索引,因此不能从递归调用中排除任何元素。在子数组大小减小到1之前,不能保证每个枢轴都就位。Lomuto分区方案确实将pivot放置到位并返回pivot的索引,因此可以从递归调用中排除pivot元素。当high=low+1时,使用pivot=a_list[high}可以使用Hoare分区方案以无限递归结束作为pivot,我认为分区将需要返回低位,递归调用将使用…低位,p-1,…,p,高位,但您需要对其进行测试。您是对的!谢谢!!但您能详细说明原因吗?非常好!这也意味着如果我选择pivot=low+high/2,我必须选择pivot=low的版本,因为pivot将arr[0]当有2个元素时!谢谢!很抱歉再次打扰您,我发现如果我选择Lomuto分区并设置pivot=a[lo],我将无法使它再次工作。:$您能再次提供帮助吗?@Qiulang-如果分区返回高,则是pivot=low+high/2,它将向下舍入,从而避免了一个_列表[high]。如果分区返回“低”,则是pivot=1+low+high/2,这将四舍五入,从而避免出现_列表[low]。再次感谢。现在它看起来太复杂了,不值得麻烦。我也搜索了它,发现人们建议将随机的pivot转换为[hi],然后执行普通的Lomuto分区。@Qiulang-Hoare分区方案通常更快。