【问题标题】:Efficient Search through list of Ranges通过范围列表进行有效搜索
【发布时间】:2017-01-24 05:20:01
【问题描述】:

我有范围列表 { start, end } 和一个值(点),现在我正在寻找有效的方法来从存在给定值的范围中获取最后 n 个索引。

例如: 列表:[ { 0, 4 }, {5, 10 }, {11, 14 }, {15, 20} , {21, 25} ] n : 2 值:22

所以在这里,22 在范围 {21, 25} 中,它位于索引 4(基于 0)处。 由于 n 为 2,函数应返回 {11, 14 } 的索引,因为这是匹配范围的第 n 个范围。

在这里,我可以轻松编写二进制函数,因为我已经对范围列表进行了排序。但是我不想写 while / for ,我正在寻找一些 C++ 11 / 14 算法 / lambdas 如果有的话,可以解决这个问题。

什么是有效的解决方案?

【问题讨论】:

  • 所以如果值是例如17 那么你会返回范围 {5,10} (即“列表”中的索引 1)??
  • @JoachimPileborg 是的
  • 这些范围是有序的、不重叠的并且不留空隙是偶然的吗?如果不是,那会改变方法,应该在问题中说明。

标签: c++ c++11 c++14


【解决方案1】:

假设您的点存储为 std::pair 并且返回迭代器而不是索引是可以接受的:

template <typename container_t, typename value_t, typename n_t>
auto KailasFind(const container_t& vec, value_t value, n_t n) {
    auto match = std::find_if(vec.begin(), vec.end(), [&](const auto& p) {
        return value >= p.first && value <= p.second;
    });
    return match - n;
}

用法:

using point_t = std::pair<int, int>;
std::vector<point_t> vec {{0, 4}, {5, 10}, {11, 14}, {15, 20}, {21, 25}};
auto it_to_result = KailasFind(vec, 22, 2);
auto result = *it_to_result;

【讨论】:

  • 排序列表中的线性搜索效率如何?
  • @Henrik 问题的作者没有指定容器保证被排序。此答案旨在尽可能广泛地适用。
【解决方案2】:

我喜欢 Jan 的回答,但是如果您的数据 已知要进行排序,那么适当的解决方案会显着不同,因此这里是针对所提问题的答案:

#include <cstddef>
#include <utility>
#include <stdexcept>
#include <algorithm>
#include <iterator>

template<typename RngT, typename ValT, typename OffsetT>
std::size_t find_prev_interval(RngT const& rng, ValT const& value, OffsetT const offset) {
    using std::begin; using std::end;
    auto const first = begin(rng), last = end(rng);
    auto const it = std::lower_bound(
        first, last, value,
        [](auto const& ivl, auto const& v) { return ivl.second < v; }
    );

    // optional if value is *known* to be present
    if (it == last || value < it->first) {
        throw std::runtime_error("no matching interval");
    }

    auto const i = std::distance(first, it);
    return offset <= i
      ? i - offset
      : throw std::runtime_error("offset exceeds index of value");
}

由于实现只需要前向迭代器,这将适用于任何标准库容器或 C 数组;但是对于std::set&lt;&gt; 或类似boost::containers::flat_set&lt;&gt; 的东西,您需要更改逻辑以调用rng.lower_bound() 而不是std::lower_bound()。此外,如果 offset 通常太大而无法返回有效索引,则将异常替换为 boost::optional 之类的内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多