【问题标题】:Bucket Key Value Map?桶键值映射?
【发布时间】:2015-12-18 08:05:49
【问题描述】:

我需要一个结构,我可以在其中推送键按升序排列的键值。如果我请求一个键的值,我想获得地图内最近的更大(但不相等)键的值。

例如,我会推送 100、500 和 1000。如果我请求 750,我会得到 1000 值。如果我请求 450,我会得到 500 值。如果我请求 500,我会得到 1000 的值。这些键是动态的,在这里无法切换。

我的方法是将带有键和值的类推送到向量,但这将持续 O(n)。

有没有更好的方法/更快的方法来实现这一点,而不是通过一个键向量向前迭代并进行比较?

【问题讨论】:

  • 看看std::upper_bound
  • @BoBTFish 他想要最近的更大应该是upper_bound
  • @Danh 这个问题对我来说并不完全清楚,但我认为如果500550 都在场,并且他请求500,他想得到500(不是`550)。所以我想我应该指出另一种选择,然后他才能决定他真正指的是哪一种。
  • 请记住,虽然std::map 是实现此功能的最简单方法,并且可能应该是您的第一次尝试,但它的缓存特性很差。如果你有严格的性能要求,你最好保持一个排序的std::vector 并使用std::upper_bound。但先介绍一下!并且仅当您对 map 有疑问时。

标签: c++ containers


【解决方案1】:

我认为你应该使用std::map 作为容器。 并使用std::map::upper_bound 找到最近的较大密钥。

如果相等可以接受,请使用std::map::lower_bound

std::map::upper_boundstd::map::lower_bound 保证复杂度为 O(log(n))。

顺便说一句,如果你还想使用std::vectorstd::upper_boundstd::lower_bound 的复杂度保证为std::vector 的 O(log(n))

【讨论】:

  • std::upper_boundstd::map 上是一个糟糕的选择;由于它没有随机访问迭代器,因此算法默认为线性搜索。这就是提供std::map::upper_bound 的原因。所以你提到的保证只对了一半。除此之外,很好的答案。
  • 根据 C++11 标准,[upper.bound] 部分,复杂性:最多 log2(last − first) + O(1) 比较。 我认为我的理解是正确的
  • 是的,但您只是声称“复杂性为 O(log(n))”。那就是比较的数量。但是迭代速度较慢,您没有阅读上面的段落,它说“它们在非随机访问迭代器上工作,最小化比较次数,这对于所有类型的迭代器都是对数的。它们特别适用于随机访问迭代器,因为这些算法通过数据结构执行对数步数。对于非随机访问迭代器,它们执行线性步数。 - 在std::map 等基于节点的容器中四处走动很慢。
  • 很好的发现,我专注于算法的细节部分。我将编辑我的答案。顺便说一句,我认为在这种情况下,标准措辞对我来说太混乱了。
  • 是的,阅读标准可能,嗯,“棘手”。它不是为程序员准备的文档。 en.cppreference.com/w 非常适合作为快速参考,但有时您确实需要查看标准以了解详细信息。
【解决方案2】:

使用std::mapstd::map::upper_bound()std::map 被实现为一棵树,因此std::map::upper_bound() 保证为 O(log(n))。

std::map 使用给定的比较函数按键排序(默认值:std::less)。它包括您需要的一切。

【讨论】:

  • 保证O(log(n))
  • @BoBTFish 我没有查找lower_bound() 的保证。你是对的。我会改变我的答案。
  • 提问者澄清说他们确实想要upper_bound
【解决方案3】:

您可以使用堆(最小堆或最大堆)。 插入删除或查找是 O(log(n)),并且易于实现。 其实它和map很像,但是你可以根据自己的想法来编码。

【讨论】:

  • 也许您可以使用标准 heap operations 来描述这是如何工作的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 1970-01-01
  • 2017-08-08
  • 2013-07-31
  • 2013-03-12
相关资源
最近更新 更多