【问题标题】:which c++ stl data structure will be the most efficient for storing unique values and their counts?哪种 c++ stl 数据结构对于存储唯一值及其计数最有效?
【发布时间】:2020-07-08 10:04:28
【问题描述】:

我有一个值列表,其中有一些重复,例如: {1,2,2,3,3,3,3,7,8,1}

我想将此列表中的唯一值及其计数存储在数据结构中。

    --------------
    |value |count|
    --------------
    |  1   |  2  |
    --------------
    |  2   |  2  |
    --------------
    |  3   |  4  |
    --------------
    |  7   |  1  | 
    --------------
    |  8   |  1  |
    --------------

哪种 c++ 标准库数据结构这样做效率最高?

编辑:我不会以任何方式修改结构,我只想知道计数,因为计数将帮助我确定编程问题的输出。

【问题讨论】:

  • 一对向量或一对向量,取决于您最常见的访问模式。但一般都可以。
  • 可以使用std::mapstd::unordered_map
  • 哪种 c++ stl 数据结构这样做效率最高 -- 您只列出了 10 个数字。在您的实际应用程序中,您希望拥有多少个唯一编号?一千?一百万?
  • @Damien 这两种结构的效率都低得多。除非您需要它们提供的附加功能,否则不要使用它们。
  • @KonradRudolph 如果我们不知道如何使用这种结构,就很难讨论效率。例如,std::map 通常用作获取每个值的计数的简单方法:m[x[i]]++;

标签: c++ performance data-structures c++-standard-library


【解决方案1】:

首先请注意,要求“最有效”的数据结构并不是对您需求的正确描述。你想要一个解决方案:

  • 用起来最快吗?在哪些用例中?
  • 占用的内存最少?
  • 是最易维护/可读的吗?
  • 最不容易出错?
  • 写得最快吗?
  • 存在于原始数据结构旁边(对于未计数的值),还是取而代之?

你看,效率有不同的种类和方面。

话虽如此,你可以试试:

  • @songyuanyao 和 @RahulGupta 向您建议了一个简单直接的解决方案:使用地图 - 如果您想按递增顺序插入您的价值计数,请使用 std::map,如果您不这样做,请使用 std::unordered_map关心订单。这将很容易编写和维护,并且在插入或删除元素的时间方面还不错。尽管如此,这两种地图结构都是quite slow,因此您可能会重新考虑是否需要标准库地图实现。

  • 另一种解决方案 - 如果您执行大量读取和少量插入/更新,则在空间和时间方面更有效 - 是 @KonradRudolph 在评论中建议的:std::pair<std::vector<value_type>, std::vector<count_type>>std::vector<std::pair<value_type, count_type>>;并确保count_type 足够大,不会超过它,但要尽可能小,以减少阅读整个结构所需的时间。这些将使用比地图少很多的空间,因为没有桶列表,没有空的

    请注意,在向量对或向量对之间进行选择是数据结构设计中的常见难题,也称为“数组结构 vs 结构数组”,或 SoA vs AoS。在网站上查看concrete example,还有很多其他的。当您通常访问两个字段并且需要一起对应的值时,AoS 会更好;当您经常只需要一个字段时,SoA 会更好(例如,您想总结某个值范围之间的计数;或者您想获得所有素值的集合等)这也与数据库的体系结构有关 - @987654323 @,前者更适合事务处理,后者更适合分析工作负载。

【讨论】:

  • @ThePhobiCeron:“谢谢”消息在 StackOverflow 上是多余的——我们表达这种情绪的方式是通过投票,如果答案解决了问题,则接受。没有更多的必要......(PS - 我知道现在有一个“感谢”小部件,但这是an unpopular experiment,希望它会消失。)
【解决方案2】:

您可以在 C++ 中使用地图 声明可以做为

map<int,int>map_name;

为了插入,你可以运行一个循环

for(auto itr:list_name)
    map_name[itr]++;

for(auto c:map_name)
cout << c.first << " " << c.second << endl;

【讨论】:

  • itr 是一个坏名字,因为它暗示它将是一个迭代器,但它不是。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 2019-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多