【问题标题】:Best structure for storing values which need exact and closest-too matches存储需要精确匹配和最接近匹配的值的最佳结构
【发布时间】:2015-02-09 11:15:21
【问题描述】:

我需要满足以下用例的数据结构:

  1. 按键存储项目
  2. 按键检索准确值的功能
  3. 按键检索最接近的先验值的功能
  4. 通过键检索最接近的后续值的功能

1 和 2 是显而易见的。对于 3(和 4),假设键是自定义 Date 对象,最接近的先验值,例如搜索 2014 年 12 月 1 日,将返回日期最接近 2014 年 12 月 1 日的值。因此,如果先验values 的键为 11 月 10 日、11 日、14 日、15 日和 29 日,那么它将返回 11 月 29 日。对于 4,功能相同,但最接近的日期应在 12 月 1 日之后。

目前我使用的是std::map<Date, T>,但对 3 和 4 的要求是新的。我考虑过的事情:

  • 继续使用std::map<Date, T>(log-n 存储和精确检索。最接近的匹配将是蛮力,因此在速度方面大约为 n)
  • 使用std::vector<T>,使用我自己的排序例程(常量存储,log-n 检索精确和最接近的;我可以滚动我自己的获取例程并通过索引访问std::vector<T> 的成员以进行快速二分搜索)

我倾向于std::vector<T>,因为我的 T 对象具有内置日期(对于std::map<Date, T> 而言,日期只是T.date() 属性的副本)。

这些数据存储的行为是预先大量加载,并且在对象的整个生命周期中偶尔会发生,但会不断地获取内容。因此,任何前端繁重但查找量少的数据结构都可以工作。

想法?

【问题讨论】:

  • std::lower_bound + std::upper_boundstd::map::lower_bound + std::map::upper_bound
  • 谢谢;这正是我所需要的。我之前没有听说过std::lower_boundstd::upper_bound 项目。巧合的是,cppreference.com 上的描述与我实现自己的 roll-your-own 版本的方式相同!
  • 我懒得把它写成你的问题的答案,我的建议是你自己写(stackoverflow实际上鼓励自我回答的问题(帮助未来的访问者通过以下方式找到你的问题)搜索引擎))
  • 抱歉 - 不确定我在哪里找人写的?
  • 你没有要求它,虽然这是一个 Q&A 网站..

标签: c++ c++11 dictionary vector


【解决方案1】:

地图中的元素已排序。 如果您的 Date 对象有适当的比较运算符(或者您的地图有一个),您可以使用 map::find 来获取您的对象迭代器,然后将该迭代器向前和向后移动(转换为 reverse_iterator)以获得最接近的值。

如果容器中不存在该元素,您应该查看以下内容: STL "closest" method?

【讨论】:

  • 感谢您的提示;不幸的是,这不起作用,因为当数据存储区没有我的对象时,我试图找到最近的项目。
【解决方案2】:

我就是这样解决的:

#include <map>
#include <iostream>
#include <string>
#include <iterator> // for std::prev

using namespace std; // for brevity

void test(const map<int,string>& data, int key)
{
    cout << "searching for " << key << endl;

    auto range = data.equal_range(key);
    auto it1 = range.first;
    auto it2 = range.second;

    if (it1 != it2)
        cout << "\tfound: " << it1->second << endl;

    auto closestPrior = (it1 != data.begin()) ? prev(it1) : data.end();
    auto closestAfter = it2;

    if (closestPrior != data.end())
        cout << "\tprior: " << closestPrior->second << endl;
    if (closestAfter != data.end())
        cout << "\tafter: " << closestAfter->second << endl;
}

int main()
{
    map<int, string> data;
    data[1] = "one";
    data[5] = "five";
    data[9] = "nine";

    for (int i=0; i<11; ++i)
        test(data, i);
}

我使用.equal_range() 而不是同时调用.lower_bound().upper_bound()。唯一的特殊处理是下限是否为begin 迭代器。

See it live.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 1970-01-01
    • 2017-09-29
    • 1970-01-01
    相关资源
    最近更新 更多