Hoare分区算法 - 严格或不严格的不等式?

时间:2012-12-25 18:41:13

标签: c++ algorithm inequality

我很难实现Hoare的分区算法。基本上,我想要做的是将一个数组分成两部分,第一部分包含的数字小于给定的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

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

提前致谢。

1 个答案:

答案 0 :(得分:2)

当然,使用

对序列进行简单的回答
auto it = std::partition(vec.begin(), vec.end(),
                         std::bind2nd(std::less<int>(), pivot));

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

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

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;
}