桶键值映射?

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 这个问题对我来说并不完全清楚,但我认为如果500550 都在场,并且他请求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_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 来描述这是如何工作的?

以上是关于桶键值映射?的主要内容,如果未能解决你的问题,请参考以下文章

[677]. 键值映射

[677]. 键值映射

PigLatin 映射键值

RestKit 对象映射:如何从键值映射到新对象/关系?

如何迭代无序映射特定键值?

map和multimap映射容器