【问题标题】:c++ std::map question about iterator orderc++ std::map 关于迭代器顺序的问题
【发布时间】:2011-01-30 13:09:58
【问题描述】:

我是一个 C++ 新手,我正在尝试使用映射,因此我可以获取 find() 方法的恒定时间查找。

问题是当我使用迭代器遍历地图中的元素时,元素出现的顺序与它们在地图中的放置顺序不同。

在不维护另一种数据结构的情况下,有没有办法在保持恒定时间查找能力的同时实现按序迭代?

请告诉我。

谢谢, jbu

编辑:感谢您让我知道 map::find() 不是恒定时间。

【问题讨论】:

  • std::map::find 具有对数时间复杂度,而不是常数。

标签: c++ map iterator


【解决方案1】:

在不维护另一种数据结构的情况下,有没有办法在保持恒定时间查找能力的同时实现按序迭代?

不,这是不可能的。为了获得有效的查找,容器需要以一种使高效查找成为可能的方式对内容进行排序。对于 std::map,这将是某种排序顺序;对于 std::unordered_map,这将是基于键哈希的顺序。

在任何一种情况下,顺序都会与添加它们的顺序不同。

【讨论】:

    【解决方案2】:

    首先,std::map 保证 O(log n) 的查找时间。您可能正在考虑std::tr1::unordered_map。但是根据定义,这会牺牲任何排序来获得恒定时间的查找。

    你必须花一些时间在上面,但我认为你可以 bash boost::multi_index_container 做你想做的事。

    【讨论】:

    • 在 Java 世界中,有一种方法可以使用 LinkedHashMap(时空权衡)进行摊销常数时间查找,并且仍然保留插入顺序。我想知道在 C++ 中实现这将是多么容易。
    • @Chris:我很确定它和实现 unordered_map 一样简单:原则上,除了你已经在做的实现一个哈希。所以并不完全“容易”,但如果你知道自己在做什么,就不会具有挑战性。
    • 是的,boost::multi_index_container 应该可以很好地工作(一旦你理解了它奇怪的使用语法)。
    【解决方案3】:

    使用vector 用于原始顺序的键和map 用于快速访问数据怎么样?

    类似这样的:

    vector<string> keys;
    map<string, Data*> values;
    
    // obtaining values
    ...
    keys.push_back("key-01");
    values["key-01"] = new Data(...);
    keys.push_back("key-02");
    values["key-02"] = new Data(...);
    ...
    
    // iterating over values in original order
    vector<string>::const_iterator it;
    for (it = keys.begin(); it != keys.end(); it++) {
        Data* value = values[*it];
    }
    

    【讨论】:

      【解决方案4】:

      我实际上要……倒退。

      如果您想保留插入元素的顺序,或者一般控制顺序,您需要一个您可以控制的序列:

      • std::vector(是的,还有其他的,但默认使用这个)

      您可以使用std::find 算法(来自&lt;algorithm&gt;)在向量中搜索特定值:std::find(vec.begin(), vec.end(), value);

      哦,是的,它具有线性复杂度O(N),但对于小型集合而言,它应该无关紧要。

      否则,您可以按照前面的建议开始查看Boost.MultiIndex,但对于初学者来说,您可能会有点挣扎。

      所以,暂时避开复杂性问题,想出一些可行的方法。当您更熟悉该语言时,您会担心速度。

      【讨论】:

        【解决方案5】:

        应用到键时,项目按operator&lt;(默认)排序。

        附言。 std::map 不保证恒定时间查找。
        它保证了 O(ln(n)) 的最大复杂度

        【讨论】:

          【解决方案6】:

          首先,std::map 不是恒定时间查找。它是 O(log n)。只是觉得我应该直截了当。

          无论如何,如果你想使用不同的排序,你必须指定你自己的比较函数。没有可以按插入时间排序的内置比较函数,但是,如果您的对象包含时间戳字段,您可以安排在插入时设置时间戳,并使用按时间戳比较。

          【讨论】:

          • 如果不是时间戳,那么就是一个简单的递增索引。
          【解决方案7】:

          地图并不意味着以某种顺序放置元素 - 为此使用矢量。

          如果您想在地图中查找某些内容,您应该使用 [the operator] 按键“搜索”

          如果您同时需要:迭代和按键搜索,请参阅topic

          【讨论】:

          • 请注意,使用operator[] 的副作用是创建一个不存在的元素。如果搜索失败,find() 返回 map::end()
          • 实际上人们一直使用地图来按顺序排列 - 只是没有按插入顺序。
          【解决方案8】:

          是的,你可以创建这样的数据结构,但不能使用标准库……原因是标准容器可以嵌套但不能混合。

          实现例如所有节点都按插入顺序在双向链表中的地图数据结构,或者例如所有节点都在数组中的地图,没有问题。在我看来,这些结构中的一个可能是您正在寻找的(取决于您希望哪种操作更快),但是使用标准容器构建它们都不是微不足道的,因为每个标准容器(vector,@987654322 @, set, ...) 希望成为访问包含元素的唯一方式。

          例如,我发现在许多情况下,节点同时位于多个双向链表中很有用,但您不能使用 std::list 来做到这一点。

          【讨论】:

            猜你喜欢
            • 2022-09-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-11-23
            • 2023-01-14
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多