【问题标题】:std::unordered_set insert, get the position where item was insertedstd::unordered_set insert,获取item被插入的位置
【发布时间】:2014-10-16 20:38:17
【问题描述】:

假设我有类 MyClass

class MyClass
{
public:

    MyClass( std::string str ) : _str(str) {}
    void SetPosition ( int i ) { _pos = i; }
    std::string _str;
    int _pos;
};

namespace std
{
    template<> struct hash<shared_ptr<MyClass>>
    {
        size_t operator()( const shared_ptr<MyClass> & ptr ) const
        {
            return hash<string>()( ptr->_str ) + hash<int>()( ptr->_pos );
        }
    };
}

当使用 std::vector 时,我能够做到这一点:

std::string str = "blah";
auto ptr = std::make_shared<MyClass>( str );
std::vector<std::shared_ptr<MyClass>> vector;
vector.push_back( ptr );
ptr->SetPosition ( std::addressof( vector.back() ) - std::addressof( vector[0] ) );
std::cout <<  ptr->_str <<  " is at " << ptr->_pos << std::endl;

为了计算向量中的位置,我的对象指针被放置了。

但是,如果我想使用 std::unordered_set(我这样做),那么:

std::string str = "blah";
auto ptr = std::make_shared<MyClass>( str );
std::unordered_set<std::shared_ptr<MyClass>> set;
auto res = set.insert( ptr );
ptr->SetPosition ( std::addressof( res.first ) - std::addressof( set[0] ) );
std::cout <<  ptr->_str <<  " is at " << ptr->_pos << std::endl;

不会工作。 也不会

std::addressof( set.begin() );

也不会,

std::addressof( set.begin().first );

或我尝试使用前端迭代器的任何其他方式。

  1. 这有意义吗?或者我应该依赖 set.size() 并 假设 我的指针被插入到最后?
  2. 是否有任何方法可以使用与上述代码类似的方法安全地获取插入该指针的位置?

【问题讨论】:

  • 位置对于无序集没有多大意义,因为它是无序的。
  • 不仅是无序的,您的项目在集合中的位置可能会在插入后发生变化。例如,哈希可能会切换哈希函数并复制到更大的结构中。
  • 当然,将来插入无序集合的数据可能会在您的项目之前进入哈希桶,从而将其推到更远的位置。

标签: c++ c++11 unordered-set


【解决方案1】:

unordered_set,顾名思义,是无序的。您可以跟踪元素在向量中的位置,因为只要您不擦除任何内容,它们就不会改变位置。但对于 unordered_set,情况并非如此。例如,在我的实现中,这是在每次插入后按顺序打印所有元素的结果:

std::unordered_set<int> s;
s.insert(0); // 0
s.insert(1); // 1 0
s.insert(2); // 2 1 0
s.insert(3); // 3 2 1 0
...
s.insert(22); // 22 0 1 2 3 ... 19 20 21
...
s.insert(48); // 48 47 46 45 ... 22 0 1 2 3 4 ... 21

所以我想说的是,秩序绝对不是你可以依赖的东西。

但是,使用您的矢量,您可以在设置位置方面做得更好:

vector.push_back(ptr);
ptr->SetPosition(vector.size() - 1);    

【讨论】:

  • 非常感谢,这很有意义。出于好奇,插入是在随机位置执行的吗?
  • @Alex - 随机?不,它们是根据哈希函数插入到桶中的,以确保find 是摊销常数时间。您可以使用bucket(const Key&amp;) 检查自己将密钥插入到哪个存储桶中,并且可以使用begin(size_t)end(size_t) 遍历特定存储桶。
猜你喜欢
  • 2018-03-12
  • 2014-08-10
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多