我在使用set
做一些实验时遇到了这个问题。
我使用一个以2个整数为结构的结构:
struct Key {
int k1;
int k2;
};
使用类来构建键之间的顺序:
struct keyComp {
bool operator () (const struct Key& lhs, const struct Key& rhs) const {
if (lhs.k1 < rhs.k1)
return true;
else if (lhs.k2 < rhs.k2)
return true;
else
return false;
}
};
但是使用这个比较器,该集合未能找到一些现有的密钥。例如,在此程序中,我将9个密钥存储在集合中,从(0, 0)
到(2, 2)
:
Key pos;
set <Key, keyComp> aset;
// insert elements from (0, 0) to (2, 2)
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
pos.k1 = i;
pos.k2 = j;
aset.insert (pos);
}
}
// now try to find each of them
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
pos.k1 = i;
pos.k2 = j;
set <Key, keyComp> :: iterator it = aset.find (pos);
if (it != aset.end ())
cout << "v "; // element found
else
cout << "! "; // not found
}
cout << endl;
}
// print the set
cout << "element in set : ";
for (set <Key, keyComp> :: iterator it = aset.begin (); it != aset.end (); it++) {
cout << "(" << it->k1 << ", " << it->k2 << ") ";
}
cout << endl;
我希望它会打印9 v
,这意味着找到了所有密钥。但我得到了:
v v v
! ! v
! ! v
element in set : (0, 0) (1, 0) (2, 0) (0, 1) (1, 1) (2, 1) (0, 2) (1, 2) (2, 2)
可以找到一些密钥,但有些密钥甚至不在集合中。
另外,如果我将比较器更改为:
struct keyComp {
bool operator () (const struct Key& lhs, const struct Key& rhs) const {
// combine the two keys for comparison
// say LARGE_NUMBER is a number bigger than all k2
return lhs.k1 * LARGE_NUMBER + lhs.k2 < rhs.k1 * LARGE_NUMBER + rhs.k2;
}
};
然后找到所有密钥。
为什么会这样?是因为原始比较器无法在键之间构造顺序吗?
答案 0 :(得分:2)
你的比较器没有提供正确的排序,这意味着set
的内部在尝试找出插入或查找的位置时会做各种奇怪的事情(也就是“未定义的行为”)的东西。
你需要这样的东西:
if (lhs.k1 < rhs.k1)
return true;
if (lhs.k1 > rhs.k1)
return false;
return (lhs.k2 < rhs.k2);
答案 1 :(得分:1)
您的比较器没有定义严格的弱排序。 (例如,(2,1)
和(1,2)
会在比较器的两个方向上给出true
。)您需要像词典排序这样的内容:
return (lhs.k1 < rhs.k1) || ( !(rhs.k1 < lhs.k1) && (lhs.k2 < rhs.k2) );