Hoare划分严格或不严格不等式

Hoare partitioning strict or not strict inequalities?

本文关键字:不等式 Hoare 划分      更新时间:2023-10-16

我很难实现霍尔的分区算法。基本上,我想做的是将数组分为两部分,第一部分包含小于给定x的数字,另一部分包含更大的数字。然而,我就是想不出一个好的实现。这是我的代码:

void hoare(vector<int>&arr,int end, int pivot)
{
    int i = 0;
    int j = end;
    while (i < j)
    {
        while (arr[i] < pivot)
            i += 1;
        while (arr[j] > pivot)
            j -= 1;            
        swap(arr[i],arr[j]);
    }
    // return arr;
    for (int i=0; i<end; i++)
    printf("%d ", arr[i]);
}

现在我发现很多网站都有(arr[i] <= pivot),而不是我放在那里的。然而,当我这样做的时候,对于这样的数组:

1 3 5 7 9 2 4 6 8

我得到:

1 3 5 4 9 2 7 6 8

但话说回来,在我的版本中,对于这样一组:

12 78 4 55 4 3 12 1 0

程序冻结,因为外循环中的两个条件都不满足,所以它只是一遍又一遍地执行,而不递增ji

枢轴是指向数组中特定数字的指针,从1开始计数;例如,在第一个例子中,传递给函数的数字3意味着pivot等于arr[2],即5

如果这是一个棘手的问题或已经得到回答,我很抱歉,但我花了一整天的时间(也在网上搜索解决方案(都无济于事,现在我有了自杀的想法。

提前谢谢。

分割序列的简单答案当然是使用

auto it = std::partition(vec.begin(), vec.end(),
                         std::bind2nd(std::less<int>(), pivot));

函数并不真正关心谓词,而是将序列重新排列为两个序列:一个是谓词生成true,另一个是断言生成false。该算法在第一个子序列(由谓词为true的元素组成(的末尾返回迭代器。有趣的是,该算法应该在前向迭代器上工作(不过,如果它真的有前向迭代器,它可以使用相当多的交换(。您正在实现的算法显然需要双向迭代器,也就是说,我将忽略同样适用于前向序列的要求。

在实现算法时,我会遵循完全相同的接口,因为迭代器抽象对序列算法非常有效。算法本身简单地使用std::find_if()来查找范围[begin, end)中的迭代器it,使得谓词不成立:

it = std::find_if(begin, end, not1(pred));

如果存在这样的迭代器,则使用std::find_if()[std::reverse_iterator<It>(end), std::reverse_iterator<It>(it))中搜索迭代器rit,使得谓词保持:

rit = std::find_if(std::reverse_iterator<It>(end), std::reverse_iterator<It>(it),
                   pred);

如果存在这样的迭代器,则它std::swap()会相应地更新beginend

std::swap(*it, *rit);
begin = ++it;
end = (++rit).base();

如果未找到itrit,则算法终止。将这个逻辑放入一个一致的算法中似乎是相当直接的。请注意,该算法甚至不能使用您尝试使用的运算符,即概念上只能比较x < pivotx >= pivot(与!(x < privot)相同(的元素。

下面的实现没有经过测试,但完整的算法看起来像这样:

template <typename BiIt, typename Pred>
BiIt partition(BiIt it, BiIt end, Pred pred) {
    typedef std::reverse_iterator<BiIt> RIt;
    for (RIt rit(end);
         (it = std::find_if(it, end, std::not1(pred))) != end
         && (rit = std::find_if(RIt(end), RIt(it), pred)) != RIt(it);
         ++it, end = (++rit).base()) {
         std::swap(*it, *rit);
    }
    return it;
}