我发现这种快速排序分区方法令人困惑和错误,但它似乎有效。我指的是这个伪代码。注意:他们在文章末尾也有一个 C 实现,但它与他们的伪代码有很大不同,所以我不在乎。
我也是这样用 C 语言编写的,尽可能地忠实于伪代码,即使这意味着要做一些奇怪的 C 语言:
#include <stdio.h>
int partition(int a[], int p, int r)
{
int x = a[p];
int i = p - 1;
int j = r + 1;
while (1)
{
do
j = j - 1;
while (!(a[j] <= x));
do
i = i + 1;
while (!(a[i] >= x));
if (i < j)
{
int t = a[i];
a[i] = a[j];
a[j] = t;
}
else
{
for (i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", j);
return j;
}
}
}
int main()
{
int a[100] = //{8, 6,10,13,15,8,3,2,12};
{7, 7, 6, 2, 3, 8, 4, 1};
partition(a, 1, a[0]);
return 0;
}
如果你运行它,你会得到以下输出:
1 6 2 3 4 8 7 - 5
然而,这是错误的,不是吗?显然a[5]
它之前的所有值都没有低于它,因为a[2] = 6 > a[5] = 4
. 更不用说7
应该是枢轴(初始a[p]
),但它的位置既不正确又丢失了。
以下分区算法取自维基百科:
int partition2(int a[], int p, int r)
{
int x = a[r];
int store = p;
for (int i = p; i < r; ++i)
{
if (a[i] <= x)
{
int t = a[i];
a[i] = a[store];
a[store] = t;
++store;
}
}
int t = a[r];
a[r] = a[store];
a[store] = t;
for (int i = 1; i <= a[0]; ++i)
printf("%d ", a[i]);
printf("- %d\n", store);
return store;
}
并产生这个输出:
1 6 2 3 8 4 7 - 1
我认为这是一个正确的结果:枢轴 ( a[r] = a[7]
) 已到达其最终位置。
但是,如果我在以下算法中使用初始分区函数:
void Quicksort(int a[], int p, int r)
{
if (p < r)
{
int q = partition(a, p, r); // initial partitioning function
Quicksort(a, p, q);
Quicksort(a, q + 1, r); // I'm pretty sure q + r was a typo, it doesn't work with q + r.
}
}
...这似乎是一个正确的排序算法。我在很多随机输入上对其进行了测试,包括所有长度为 20 的 0-1 数组。
我还尝试将此分区函数用于选择算法,但未能产生正确的结果。它似乎可以工作,但是作为快速排序算法的一部分,它甚至非常快。
所以我的问题是:
- 任何人都可以发布一个算法不起作用的例子吗?
- 如果没有,为什么它会起作用,因为分区部分似乎是错误的?这是我不知道的另一种分区方法吗?