【问题标题】:is there range map in c++?c++中有范围图吗?
【发布时间】:2021-06-17 12:21:57
【问题描述】:

在 C++ 中,unordered_map 和 map 是从地图中搜索关键字的好工具。

我可以建一个map,key是date,value是double(或者我自己定义的struct)。

但我想要一个范围图,这意味着键是一个范围,例如:

#inlcude <map>
m[20190101] =3;
m[20201201] = 4.
cout << m[20200101]; // i want this can return me 3. because 20200101 is
// lower-close to 20190101 

我该如何实现?

【问题讨论】:

  • 似乎是一厢情愿。
  • 有一个问题是地图的键应该识别一个且只有一个元素。但是,如果您对地图中的范围从不重叠感到满意,那么自定义比较器应该可以解决问题,尽管它可能难以实现。
  • 不在标准库中。您必须自己编写代码。但是你会如何使用这样的地图呢?您能否提供您希望用于设置值并稍后检索它们的代码?
  • @Galik 请看更新,我正在设计一个股票交易系统,我需要一个很小的数据库来保存每只股票的交易费用,费用很少改变(10年,它只改变不到 10 次),这意味着构建一个 [date, value] 非常浪费,我需要这么快,因为我需要大量搜索。
  • 为此使用地图毫无意义。存储与该值配对的已排序日期数组,然后使用二分搜索找到您的日期与std::lower_bound 或类似的。

标签: c++ stl unordered-map


【解决方案1】:

std::map 将数据存储在二叉树中,因此您可以使用upper_bound 和lower_bound 方法轻松找到大于/大于或等于某个值的最接近的键

  • m.lower_bound(k):返回一个迭代器,指向第一个 key 不小于 k 的元素,如果没有找到这样的元素,则返回 m.end()。
  • m.upper_bound(k):返回一个迭代器,指向第一个 key 大于 k 的元素,如果没有找到这样的元素,则返回 m.end()。

然后您可以递减迭代器(如果它不等于begin())以找到下一个更小的元素。

所以对于你的例子:

auto it = m.upper_bound(20200101);
if (it != m.begin())
    std::cout << *--it;
else
    std::cout << "no key <= 20200101";

【讨论】:

  • 太好了,谢谢克里斯。所以我认为这会比:将所有日期值一一存储到地图中。存储所有的浪费空间,但是搜索会是O(1),这种方法节省空间,但是lower_boud是O(log(n))的操作,有点慢
  • 这取决于数据,但由于缓存影响,浪费大量空间可能最终会变慢。最好的办法是分析不同的方法,看看哪种方法最快(以及速度差异是否重要或受其他因素(如 I/O)支配)
【解决方案2】:

早在 2013/2014 年,我创建了一个 range_map 容器类模板,它以 C++ 标准库的容器类模板为模型。 range_map 的每一项都存储在一个名为range_map_item 的类模板中,该模板有 3 个字段:左边界、右边界和存储项。 (仅供参考,一切都在beneficii 命名空间中。)它在很大程度上像std::map 一样工作,但没有环绕它。我创建了自己的 rb-tree 来管理它的内容。

范围的工作方式如下。每个键覆盖一个范围,如下所示:

[左界,右界)

意思是,左边界是范围的一部分,但右边界不是。

范围不能完全重叠,也就是说,你不能有 2 个范围是这样的:

左1

如果 2 个范围确实重叠,则一个必须完全是另一个的子范围。

迭代器通过范围边界,而不是范围本身。它可以告诉您当前是指向左边界还是右边界。

我已经对它进行了相当多的测试。我已经能够创建 BMP 文件,该文件是通过在其中放置随机范围并显示结果的 range_map 进行迭代而创建的。它似乎基本上可以工作,但我不能保证它会 100%,而且我已经 5 年多没有碰过它了。

它没有文档,但与之交互所需的功能与它们的 C++ 标准库容器对应物类似。我最常使用emplace()。您可以只将左边界、右边界和项目传递给它。 (仅供参考,“encaps”参数用于确定是否要封装预先存在的项目,如果这些项目恰好是您要输入/创建的项目的子范围。)您也可以在emplace() 上使用分段构造。 (感谢我在网上找到的一个博客,它教我如何设置。)

这是图书馆的链接。您应该将它保存在“beneficii”子文件夹中,然后将该子文件夹放在您的包含目录或项目目录或其他目录中。编译器可以在哪里搜索包含文件。该库仅包含标题,因此不存在链接问题。

这里是下载链接:

https://drive.google.com/file/d/1SlBvIqnXwfJfsWv6yJsTm9SfutVok21U/view?usp=sharing

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-02
    • 2019-09-30
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多