桶键值映射?
Posted
技术标签:
【中文标题】桶键值映射?【英文标题】:Bucket Key Value Map? 【发布时间】:2015-12-18 08:05:49 【问题描述】:我需要一个结构,我可以在其中推送键按升序排列的键值。如果我请求一个键的值,我想获得地图内最近的更大(但不相等)键的值。
例如,我会推送 100、500 和 1000。如果我请求 750,我会得到 1000 值。如果我请求 450,我会得到 500 值。如果我请求 500,我会得到 1000 的值。这些键是动态的,在这里无法切换。
我的方法是将带有键和值的类推送到向量,但这将持续 O(n)。
有没有更好的方法/更快的方法来实现这一点,而不是通过一个键向量向前迭代并进行比较?
【问题讨论】:
看看std::upper_bound
。
见en.cppreference.com/w/cpp/container/map/upper_bound
@BoBTFish 他想要最近的更大应该是upper_bound
@Danh 这个问题对我来说并不完全清楚,但我认为如果500
和550
都在场,并且他请求500
,他想得到500
(不是`550)。所以我想我应该指出另一种选择,然后他才能决定他真正指的是哪一种。
请记住,虽然std::map
是实现此功能的最简单方法,并且可能应该是您的第一次尝试,但它的缓存特性很差。如果你有严格的性能要求,你最好保持一个排序的std::vector
并使用std::upper_bound
。但先介绍一下!并且仅当您对 map
有疑问时。
【参考方案1】:
我认为你应该使用std::map
作为容器。
并使用std::map::upper_bound
找到最近的较大密钥。
如果相等可以接受,请使用std::map::lower_bound
。
std::map::upper_bound
和 std::map::lower_bound
保证复杂度为 O(log(n))。
顺便说一句,如果你还想使用std::vector
,std::upper_bound
和std::lower_bound
的复杂度保证为std::vector
的 O(log(n))
【讨论】:
std::upper_bound
在std::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::map
和std::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 来描述这是如何工作的?以上是关于桶键值映射?的主要内容,如果未能解决你的问题,请参考以下文章