构建此数据结构的最佳方法

时间:2014-02-05 18:27:29

标签: c++

我有兴趣构建std::unordered_map< K, V> Map;,其中V与Map::iterator类似。具体来说,我希望将此vector< Pair< double, Map::iterator> >; 作为V。如上所述,这是C ++中的递归类型,标准不允许。

但是,begin()end()operator++()对unordered_map的操作不需要明确定义Map::mapped_type的任何知识,因此,原则上它似乎应该能够独立于unordered_map定义Map::iterator

所以我想知道有没有办法定义:

typedef std::unordered_map_iterator< K> iterator;
typedef std::unordered_map_const_iterator< K> const_iterator;

然后创建:

typedef std::unordored_map< K, iterator> Map;

这样,map.insert( std::make_pair( K(), map.begin());有意义吗?

例如,如下所示?

typedef std::unordered_map< K, V> Premap;
typedef std::unordered_map< K, Premap::iterator> Map;

在部分答案中,上述建议会产生模板推断错误,如预期的那样。但是,这样的事情应该是可行的。

#include <unordered_map>
#include <iostream>
#include <string>
#include <utility> 

typedef std::string K; //these two types are arbitrary
typedef double V; //chosen just for completeness sake.

typedef std::unordered_map< K, V> Premap;
typedef std::unordered_map< K, Premap::iterator> Map;

int main( int argc, char ** argv){

        Map test;
        test.insert( std::make_pair( std::string( "foo"), test.end()));
        return 0;
}

1 个答案:

答案 0 :(得分:0)

创建一个包含迭代器的标准容器是不可能的。但是,有其他方法表现相同。

解决方案1 ​​

unordered_map需要唯一键。因此,只需使用std::string作为值类型,并在必要时在地图中查找。在两种情况下,查找的平均算法复杂度都是相同的 - O(1)。

示例:假设您要表示此数据:

foo -> bar
bar -> baz
baz -> barney
fred -> (nothing)
barney -> (nothing)

然后你会写这个来构建数据结构:

std::unordered_map<std::string, std::string> Map;
Map m;
m.insert(std::make_pair(std::string("foo"), std::string("bar")));
m.insert(std::make_pair(std::string("bar"), std::string("baz")));
m.insert(std::make_pair(std::string("baz"), std::string("barney")));
m.insert(std::make_pair(std::string("fred"), std::string("")));
m.insert(std::make_pair(std::string("barney"), std::string("")));

要沿着此结构中的链走,您可以使用以下代码:

Map::iterator i = m.find("foo");
while (i != m.end() && !i->second.empty()) {
    i = m.find(i->second);
}

请注意,任何未显示为键的字符串都可用于标记链的末尾。

解决方案2

使用boost::ptr_unordered_set并将指针存储到值本身的下一个值。添加适当的相等和比较运算符,以便在集合中忽略指针。请注意,这会增加额外的间接级别,但这是不可避免的。

struct ChainElement
    : boost::equality_comparable<ChainElement>
{
    std::string key;
    ChainElement *next;

    ChainElement(std::string const &k, ChainElement *n = NULL)
        : key(k), next(n)
    {}

    bool operator==(ChainElement const &other) const {
        return key == other.key;
    }
};

namespace std {
template <>
hash<ChainElement>::operator()(ChainElement const &ce) const {
    return std::hash(ce.key);
};
}

设置结构,例如像这样:

#include <boost/ptr_container/ptr_unordered_set.hpp>

// ...

boost::ptr_unordered_set<ChainElement> m;
m.insert(new ChainElement("foo"));
m.insert(new ChainElement("bar"));
m.insert(new ChainElement("baz"));
m.insert(new ChainElement("fred"));
m.insert(new ChainElement("barney"));
m.find("foo")->next = &*m.find("bar");
m.find("bar")->next = &*m.find("baz");
m.find("baz")->next = &*m.find("barney");

然后走结构:

ChainElement *elem = &*m.find("foo");
while (elem != NULL) {
    // do something
    elem = elem->next;
}

使用boost::ptr_unordered_set而不是std::unordered_set可以保证删除包含它们的容器时删除对象。