霍尔分区不起作用?

Posted

技术标签:

【中文标题】霍尔分区不起作用?【英文标题】:Hoare partition doesn't work? 【发布时间】:2015-12-19 20:52:06 【问题描述】:

我一直在尝试实现 Hoare 分区方法,但我和计算机似乎都无法理解它,因为它是用 Cormen 和 Wikipedia 编写的。 两个来源中的算法如下所示:

algorithm partition(A, lo, hi) is
    pivot := A[lo]
    i := lo - 1
    j := hi + 1
    loop forever
        do
            j := j - 1
        while A[j] > pivot
        do
            i := i + 1
        while A[i] < pivot
        if i < j then
            swap A[i] with A[j]
        else
            return j

对于以下数组: 9 3 11 55 4 ,使用上述函数对其进行分区后,它将如下所示: 4 3 11 55 9 并且枢轴索引将为2,这是完全错误的。首先,9 和 4 将被交换,因此 i 将变为 2,j 将变为 4。但是,在下一次迭代期间,由于 do while 循环,9 将被跳过并且永远不会再次交换。 我的想法有问题吗? (我认为我在 C++ 中的实现没有任何错误)

#include <iostream>
using namespace std;
int a[100];
int partitie(int st, int dr)
    int i,j,x;
    x=a[st];
    i=st-1;
    j=dr+1;
    while(true)
        do
            j--;
        while(a[j]>x);
        do
            i++;
        while(a[i]<x);
        if(i<j) swap(a[i],a[j]);
        else return j;
    

int main() 
    int i,n;
    cin>>n;
    for(i=1;i<=n;i++) cin>>a[i];
    cout<<partitie(1,n)<<endl;
    for(i=1;i<=n;i++) cout<<a[i]<<" ";
    return 0;

【问题讨论】:

[lo, hi)[lo, hi]? @BrianRodriguez - 快速排序通常是 [lo, hi]。 第一次调用 partition 时返回的枢轴索引将是 1,而不是 2。数组分为两个,4,3 和 11,55,9。 @rcgldr 我再次运行上面发布的程序,函数返回 2。再次检查并记住索引从 1 开始,而不是 0。 @rptoma - 我错过了您的 C / C++ 示例使用 1 的起始索引,但结果应该相同,数组分为两个,4,3 和 11,55.9. 【参考方案1】:

您需要使用正确的快速排序例程,因为 Hoare 将数组拆分为左半部分和右半部分,这与 Lomuto 将数组拆分为左半部分、枢轴、右半部分不同。

algorithm quicksort(A, lo, hi) is
    if lo < hi then
        p := partition(A, lo, hi)
        quicksort(A, lo, p)        // not quicksort(A, lo, p-1)
        quicksort(A, p + 1, hi)

在中间选择一个主元意味着已经排序或反向排序的数组可以快速排序,而不是最坏的情况:

    pivot := A[lo+(hi-lo)/2]  // or := A[(lo+hi)/2] if overflow not an issue

仍然会有最坏的情况模式,但至少处理了简单的模式。中位数 3 有点慢,但减少了最坏情况模式的数量:

    md = lo + (hi-lo)/2
    if (A[lo] > A[hi])
        swap(A[lo], A[hi])
    if (A[lo] > A[md])
        swap(A[lo], A[md])
    if (A[md] > A[hi])
        swap(A[md], A[hi])
    pivot := a[md]

也许您正在寻找的是快速选择以找到第 k 个元素,其中 k = 数组大小 / 2。它类似于快速排序,但它只递归搜索包含第 k 个元素的数组的左侧或右侧部分.维基文章:

http://en.wikipedia.org/wiki/Quickselect

【讨论】:

感谢您的回答,但我希望该函数不依赖于另一个函数(在本例中为快速排序)。我希望它返回正确的枢轴索引并创建一个适当的分区(就像 Lomuto 的方法一样)。我的目标不是通过 Quicksort 对数组进行排序。 @rptoma - 我不确定如何修改 Hoare 分区函数才能与 Lomuto 一样工作。你可以只使用 Lomuto 分区函数。 是的,Lomuto 可以,但我读到 Hoare 的交换次数是 Hoare 的 3 倍。不过,我很想知道如何实现 Hoare。 @rptoma - 我对原始问题添加了评论,返回的枢轴是 1,而不是 2。Hoare 将数组拆分为左侧和右侧。 Lomuto 将数组拆分为左部分、枢轴、右部分。

以上是关于霍尔分区不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥将原始字节写入分区不起作用[扇区写入]?

使用左外连接时 Oracle 分区修剪不起作用

分区在我的快速排序功能中不起作用

简单的 x86-64 分区不起作用

SQL Server - 使用 ROWS BETWEEN UNBOUNDED PRECEDING 的分区过度不起作用?

当明确给出 s3 路径时,模式合并不起作用