【问题标题】:Creating an Indexed Ordered Map创建索引有序映射
【发布时间】:2018-06-10 20:12:13
【问题描述】:

在过去的几天里,我浏览了这里和类似的网站,并花了很多时间试图提出解决方案,并想寻求建议。

我得出了一个令人失望的结论,即如果不进入 C++ 的 boost 库,就不可能创建一个保留索引排序的关联容器。

更清楚和更具体地,我需要的是一个地图,它可以使用 operator[key] 进行查找,但也可以按添加元素的顺序进行索引以用于迭代目的。

今天早上我决定我需要自己编写一个,并且我尝试了一些使用地图和对矢量等的方法。但实际上没有任何效果,并且获得我正在寻找的所有功能令人惊讶用这种语言不容易实现。我一定是错的吧?有没有其他人有过需要此功能或熟悉此概念的经验,可以为我指明我正在寻找的正确方向?

提前非常感谢!大家新年快乐。

【问题讨论】:

  • 当然可以在语言中使用 - 您是否尝试过使用 Map<Key, Node*> 进行键查找,并使用支持 Vector<Node> 并按插入顺序插入/删除项目?
  • @KillzoneKid 令人惊讶的是没有!这是我在这方面的第一个错误解决方案。
  • 你看过 boost::multi_index 吗?我不确定它是否可以满足您的需求。
  • @SornelHaetir 我确实简要地看了它,我相信我正在寻找的大部分内容都可以在那里找到,但老实说,我对像 boost 和语法和构造这样的外部库的经验为零因为那个 multi_index 对象对我来说看起来非常混乱。哈哈。我希望在进行这种教育之前找到一个更简单的解决方案。
  • @hnefatl 当然,我的错,甚至不知道我在想什么

标签: c++ dictionary indexing unordered-map


【解决方案1】:

警告:这是对所需行为的非常粗略模型。这不是很好的代码,但它很快并且应该演示一种实现此目的的技术。

在考虑推出自己的解决方案之前,您应该使用现有的解决方案,例如 Boost 的 multi_index。它会更容易、更快、更不容易出错并且设计得更好。

template<typename Key, typename Val>
class OrderedMap
{
private:
    std::vector<std::pair<Key, Val>> ordered;
    std::map<Key, std::size_t> lookup;

public:
    void insert(Key k, Val v)
    {
        ordered.push_back(std::pair<Key, Val>(k, v));
        lookup.emplace(k, ordered.size() - 1);
    }

    Val find(Key k)
    {
        std::size_t index = lookup[k];
        return ordered[index].second;
    }
    // "typename" needed as the "iterator" is a dependent type
    typename std::vector<std::pair<Key, Val>>::iterator begin()
    {
        return ordered.begin();
    }
    typename std::vector<std::pair<Key, Val>>::iterator end()
    {
        return ordered.end();
    }
};

我们只需要一个std::vector&lt;std::pair&lt;Key, Val&gt;&gt; 来跟踪插入元素的实际顺序,以及一个std::map&lt;Key, std::size_t&gt; 来跟踪键和值索引之间的关联。然后我们可以将我们想要的功能从这个类委托给这些内部支持/查找结构的功能。

这个类在期望的行为和内部容器之间提供的接口可以像你喜欢的那样健壮 - 在这里,我只是充实了演示所需的丑陋骨架。


See a quick demo here.

OrderedMap<std::string, int> m;
m.insert("1", 1);
m.insert("2", 2);
m.insert("3", 3);

std::cout << m.find("2") << std::endl << std::endl;

for (auto i = m.begin(); i != m.end(); i++)
    std::cout << i->first << " " << i->second << std::endl;
std::cout << std::endl;

产生输出:

2

1 1
2 2
3 3

【讨论】:

  • 更好地映射到向量的索引,因为指针很容易失效。
  • 您可能只需要值(副本)而不是指向该值的指针。 (编辑)是的索引会更好,如果它永远不会改变。
  • 当向量重定位时指针会中断,而且你存储了两次密钥。映射到纯向量中的索引会使删除变得很麻烦。这证明起草一些明智的东西并不容易。需要做出一些设计决策。
  • @luk32 是的,我刚刚更新为返回副本而不是指针。我不太担心存储密钥两次,因为我说过这是一个简单的演示 - 我宁愿让它快速阅读和理解,而不是担心优化。
  • 我真的很喜欢这个想法!我会考虑这个并使用这个视角来帮助我创建我的有序地图。我没有想到使用指向向量中保存的实际值的指针。我认为这很难实现对值的删除或修改,但我会考虑到这一点,非常感谢
猜你喜欢
  • 1970-01-01
  • 2020-09-23
  • 1970-01-01
  • 1970-01-01
  • 2018-11-08
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多