我正在尝试编写一个Hoare分区函数,它将数组作为输入,并将第一个元素作为pivot进行分区(我知道这不是一个好主意,我应该使用随机枢轴,如{{1} }方法)。问题是当第一个元素最高时,此函数会进入无限循环,就像数组median-of-medians
一样。我可以看到错误,在外[14,6,8,1,4,9,2,1,7,10,5]
的第一次迭代后,while
和i
都等于10,因此循环将永远持续。我应该修补哪一部分才能达到预期的效果?这是代码:
j
答案 0 :(得分:2)
我认为问题在于你已经将一个do-while(或重复 - 直到,在Hoare的术语中)循环转换为while循环,所以它永远不会在第一个j - = 1。
Python中最简单的转换应该是改变这两个内部while循环:
while True:
i += 1
if not (i < j and arr[i] < pivot): break
while True:
j -= 1
if not (j >= i and arr[j] >= pivot): break
(我在这里假设if i < j:
应该在第二个while循环之外,并且所有其他初始缩进都是正确的。)
我没有通过完全推理,或者进行各种测试,但是翻译中可能不仅仅是这一个错误。您可能还需要将外部循环转换为do-while(Hoare实际上使其成为明确的while TRUE
并在末尾进行检查),但我不确定。无论如何,对于您的示例输入,修改后的版本返回9
,arr
为[10, 6, 8, 1, 4, 9, 2, 1, 7, 14, 5]
,这是不正确的,但它解决了您的无限循环问题。
下一个问题是一个一个错误。如果您要在内部循环中首先执行+= 1
和-= 1
,则必须从-1
,len(arr)
开始,而不是0, len(arr)-1
(或和你一样,1, len(arr)-1
)。
可能还有其他问题。但我不想深入研究你的代码,找出所有可能的错误并解释它们。如果您需要,请告诉我们我们的来源是什么,并解释您从该来源所做的每一次转换,并且更容易解释您出错的地方。如果没有,直接将Hoare的算法转换为Python就更简单了,然后希望你能搞清楚。
这是我在网上找到的Hoare伪代码的副本(只是用两个空格替换所有标签):
Hoare-Partition (A, p, r)
x ← A[p]
i ← p − 1
j ← r + 1
while TRUE
repeat j ← j − 1
until A[j] ≤ x
repeat i ← i + 1
until A[i] ≥ x
if i < j
exchange A[i] ↔ A[j]
else
return j
这是Python的简单翻译;唯一的变化是次要的语法(包括“交换”拼写的方式),并将每个重复/转为一段时间True / break。
def hoare(a, p, r):
x = a[p]
i, j = p-1, r+1
while True:
while True:
j -= 1
if a[j] <= x:
break
while True:
i += 1
if a[i] >= x:
break
if i < j:
a[i], a[j] = a[j], a[i]
else:
return j
对于与您的签名相同的函数:
def hoare0(arr):
return hoare(arr, 0, len(arr)-1)
答案 1 :(得分:0)
此行有错误:
while i < j and arr[i] < pivot:
应该是:
while i <= j and arr[i] < pivot:
整个分区代码如下:
def partition(a, l, r):
pivot = a[r]
i = l - 1
j = r
while i <= j:
if i <= j and a[i] < pivot:
i += 1
if i <= j and a[j] >= pivot:
j -= 1
if i < j:
a[i], a[j] = a[j], a[i]
a[l], a[j] = a[j], a[l]
return j
为什么会有无限循环?
此处选择的pivot
是14。
因此,执行此代码后:
while i < j and arr[i] < pivot:
i += 1
i
是10,j
是10。
现在,当执行此块时:
while i <= j and arr[j] >= pivot:
j -= 1
与a[10] < 14
一样,什么也没有发生。由于i
等于j
,因此不会发生交换。现在,由于最外面的循环的条件为i <= j
,因此循环不断重复。
纠正会发生什么?
因此,执行此代码后:
while i <= j and arr[i] < pivot:
i += 1
i
为11(因为当i
等于j
时条件仍然成立,并且j
为10。
现在,当执行此块时:
while i <= j and arr[j] >= pivot:
j -= 1
与a[10] < 14
一样,什么也没发生。
现在,i
是11,而j
是10,因此没有交换发生。但是,最外面的循环中断了,a[j]
与pivot
交换了。
您的数组变为:
[5, 6, 8, 1, 4, 9, 2, 1, 7, 10, 14]
您可以播放here。它包含带有调试打印的代码,用于正确和错误的分区方案。