Hoare分区陷入无限循环

时间:2012-09-20 20:37:43

标签: python partitioning quicksort hoare-logic

我正在尝试编写一个Hoare分区函数,它将数组作为输入,并将第一个元素作为pivot进行分区(我知道这不是一个好主意,我应该使用随机枢轴,如{{1} }方法)。问题是当第一个元素最高时,此函数会进入无限循环,就像数组median-of-medians一样。我可以看到错误,在外[14,6,8,1,4,9,2,1,7,10,5]的第一次迭代后,whilei都等于10,因此循环将永远持续。我应该修补哪一部分才能达到预期的效果?这是代码:

j

2 个答案:

答案 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并在末尾进行检查),但我不确定。无论如何,对于您的示例输入,修改后的版本返回9arr[10, 6, 8, 1, 4, 9, 2, 1, 7, 14, 5],这是不正确的,但它解决了您的无限循环问题。

下一个问题是一个一个错误。如果您要在内部循环中首先执行+= 1-= 1,则必须从-1len(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。它包含带有调试打印的代码,用于正确和错误的分区方案。