C ++使用自定义比较器在结构向量中查找最小值

C++ Finding minimum in vector of structs using custom comparator

我有一个结构向量:

struct element_t {
    int val;
    bool visited;
};

使用自定义比较器:

bool cmp(const element_t& lhs, const element_t& rhs)
{
    return ((lhs.val < rhs.val) && (!lhs.visited) && (!rhs.visited));
}

用于:

std::vector<element_t> vct_priority(n_elems, {2147483647, 0});

在我的算法中,我想迭代地找到尚未 visited 的具有最小 value 的元素,使用它,然后通过设置 [=16] 来“禁用”它=] 为 true,以便在下一次迭代中找不到该元素。

it = std::min_element(std::begin(vct_priority), std::end(vct_priority), cmp);
indx_smallest = std::distance(std::begin(vct_priority), it);
// do something here
vct_priority[indx_smallest].visited = 1;

通常我会使用优先级队列,但由于我需要在算法中索引到这个数组,我找不到更好的方法。

问题是,这种方法有问题。在 vct_priority 看起来像这样的情况下:

{1,true}
{0,true}
{1,false}
{0,true}
{2,false}
{2147483647,false}
{2147483647,false}
{0,true}
{1,false}
{0,true}
{2,false}
{2147483647,false}
{1,false}

计算出的 indx_smallest 错误地为 0,而不是 2。

你能帮我找到错误,或者建议一些更合适的解决方案吗?

您的比较器未实现 std::min_element() 要求的 strict weak ordering。即,它没有考虑到两个输入元素可能具有不同的 visited 状态。由于您希望将未访问的结构优先于已访问的结构,因此仅当 both 元素具有 visited=false 时才需要比较它们的 val 字段。否则,如果 left-hand 元素有 visited=true 而 right-hand 元素有 visited=false 那么你需要优先考虑 right-hand 元素。但是你没有那样做。

但是,需要注意一些事情 - 如果输入范围不为空,std::min_element() 总是 returns 一个 non-end 迭代器。因此,如果您的所有元素都已被访问,则生成的迭代器必须指向已访问的元素。所以你也必须考虑到这一点。

话虽如此,试试这个:

bool cmp(const element_t& lhs, const element_t& rhs)
{
    if (!lhs.visited && !rhs.visited) return (lhs.val < rhs.val);
    return lhs.visited ? rhs.visited : true;

    /* alternatively:
    return (lhs.visited || rhs.visited)
        ? rhs.visited
        : (lhs.val < rhs.val);
    */

    /* alternatively:
    return (!lhs.visited) && (rhs.visited || lhs.val < rhs.val);
    */
}

...

auto it = std::min_element(std::begin(vct_priority), std::end(vct_priority), cmp);
if (it == std::end(vct_priority)) {
    // vct_priority is empty
}
else if (it->visited) {
    // there are no unvisited items in vct_priority
}
else {
    // use *it element as needed ...
    it->visited = true;
}

Online Demo

可见你需要正确定义比较函数

给你。

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

int main()
{
    struct element_t {
        int val;
        bool visited;
    };

    std::vector<element_t> vct_priority =
    {
        { 1, true }, { 0, true }, { 1, false }, { 0, true },
        { 2, false }, { 2147483647, false }, { 2147483647, false },
        { 0, true }, {1, false }, { 0, true }, { 2, false },
        { 2147483647, false }, { 1, false }
    };

    auto less_not_visited = []( const auto &e1, const auto &e2 )
    {
        return ( not e1.visited ) && ( e2.visited or e1.val < e2.val );
    };

    auto min = std::min_element( std::begin( vct_priority ),
        std::end( vct_priority ),
        less_not_visited );

    std::cout << std::distance( std::begin( vct_priority ), min ) << '\n';
}

程序输出为

2

如果你想定义一个单独的函数而不是 lambda 表达式,那么它看起来像

bool less_not_visited( const element_t &e1, const element_t &e2 )
{
    return ( not e1.visited ) && ( e2.visited or e1.val < e2.val );
};

对于比较器,使用 std::tuple 作为投影确保尊重 strict weak ordering:

bool cmp(const element_t& lhs, const element_t& rhs)
{
    return std::tie(lhs.visited, lhs.val) < std::tie(rhs.visited, rhs.val);
}

Demo