【问题标题】:Possible to have two keys in an unordered_set, that are considered equal?unordered_set 中可能有两个键,它们被认为是相等的?
【发布时间】:2015-10-24 16:21:18
【问题描述】:

From here:

Pred:unordered_set 对象使用此表达式来确定两个元素键是否等价。 unordered_set 容器中的任何两个元素都不能具有使用此谓词产生 true 的键。

也来自 23.5.6.1/1:

unordered_set 是一个无序关联容器,它支持唯一键(unordered_set 最多包含每个键值一个),其中元素的键是元素本身。 unordered_set 类支持前向迭代器。

但如果我定义自己的散列器和使用类类型的不同功能的等效操作,我可以绕过这个。

#include <iostream>
#include <unordered_set> //for unordered_set and unordered_multiset

using namespace std;

struct A{
    A() = default;
    A(int a, int b): x(a), y(b) {}
    int x = 0, y = 0;

};

size_t hasher(const A &sd){
    return hash<int>()(sd.x);
}

bool eqOp(const A &lhs, const A &rhs){
    return lhs.y == rhs.y;
}


int main(){

    unordered_set<A, decltype(hasher)*, decltype(eqOp)*> unorderedA(10, hasher, eqOp);

    unorderedA.emplace(2,3);
    unorderedA.emplace(3,3);

    for(const auto& c : unorderedA)
        cout << c.x << " " << c.y << endl;
}

输出;

3 3
2 3

我了解发生了什么:哈希器将每个键放在不同的桶中,因为它们的 x 值。但是,由于它们的 y 值,我的 eqOp 函数应该认为这两个键相等,但是由于它们被放置在不同的存储桶中,因此从未检查它们是否相等。一个无序的容器可以包含两个等效的键,只要它们进入不同的桶,这是否是正常的功能。还是编码器有责任确保编写散列器和谓词以将等效键放在同一个存储桶中?或者我的 eqOp 函数是否违反了编译器未检测到的规则?

在 set 和 map 中很明显:提供给它们的谓词定义了严格的弱排序,因此两个被视为等效的键只有一个元素与它们关联。在无序映射中,我不太清楚:两个等效键可以具有与之关联的不同元素,只要这些键位于不同的存储桶中。但是上面的那些消息来源感觉就像他们告诉我的那样。

【问题讨论】:

  • “或者是编码人员有责任确保哈希器和谓词被写入以将等效键放在同一个桶中?”我敢打赌。否则,如果您在两个等效元素之间发生冲突(对于您的 operator==),您将不会插入两个元素。

标签: c++ hash unordered-set


【解决方案1】:

不,这是不可能的。您的示例无效,因为标准要求您为等效键返回相同的哈希值:

23.2.5 无序关联容器

  1. 两个 Key 类型的值 k1 和 k2 被认为是等效的,如果 容器的 key_equal 函数对象在传递这些时返回 true 价值观。 如果 k1 和 k2 等价,则哈希函数应返回 两者的值相同。 [注意:因此,当无序关联 容器通常使用非默认 Pred 参数实例化 还需要一个非默认的 Hash 参数。 ——尾注]

无论如何,图书馆用户都无法确保值落入不同的桶中,因为它没有定义如何将所有可能的哈希值映射到桶索引或映射上的操作如何改变桶的数量。

【讨论】:

    猜你喜欢
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多