我有一个结构向量:
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});
在我的算法中,我想迭代地找到具有最小value
但还不是visited
的元素,并对其进行处理,然后";禁用";通过将visited
设置为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。
你能帮我找出错误吗,或者提出一些更合适的解决方案?
很明显,您需要正确定义比较函数。
给你。
#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::min_element()
所需的严格弱排序。也就是说,它没有考虑到两个输入元件可能具有不同的visited
状态。由于您希望将未访问的结构优先于已访问的结构,因此仅当两个元素都具有visited=false
时,才需要比较它们的val
字段。否则,如果左侧元素具有visited=true
,右侧元素具有visited=false
,则需要对右侧元素进行优先级排序。但你没有这么做。
但是,需要注意的是,如果输入范围不为空,std::min_element()
总是返回一个非结束迭代器。因此,如果您的所有元素都已被访问,则生成的迭代器必须指向一个已访问的元素。所以你也必须考虑到这一点。
话虽如此,试试这个:
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;
}
在线演示
对于比较器,使用std::tuple
作为投影确保遵守严格的弱排序:
bool cmp(const element_t& lhs, const element_t& rhs)
{
return std::tie(lhs.visited, lhs.val) < std::tie(rhs.visited, rhs.val);
}
演示