You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否使用std::lower_bound替代迭代器处理函数调用?技术问询

针对高耗时单调函数的高效二分查找方案

核心问题分析

你需要的是针对单调递增函数f(i),找到最小索引i使得f(i)≥阈值t,且满足:

  • 函数调用耗时极高,需尽可能减少调用次数
  • 搜索空间极大(超过10^15),无法预先存储所有结果
  • 希望复用标准库组件,避免从零实现二分查找

你之前尝试的自定义forward迭代器方案效率极低,核心原因是:std::lower_bound对forward迭代器只能执行线性搜索——因为forward迭代器不支持直接跳转到任意位置,只能通过operator++逐个移动,这就导致算法复杂度从O(log n)直接退化成了O(n),完全无法处理大搜索空间。

解决方案1:自定义随机访问迭代器

要让std::lower_bound发挥二分查找的O(log n)效率,我们需要实现一个随机访问迭代器,它支持直接计算并跳转到中间位置,而不需要逐个递增。下面是改进后的迭代器实现:

#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <iterator>

long long foo(long long i) {
    std::cout << "function evaluation:\t" << i << std::endl;
    return i;
}

using function_type = long long(*)(long long);

template <function_type F>
struct FunIterator {
    // 随机访问迭代器的类型定义
    using difference_type = long long;
    using value_type = long long;
    using pointer = const value_type*;
    using reference = const value_type&;
    using iterator_category = std::random_access_iterator_tag;

    static std::unordered_map<long long, long long> cache;
    long long index;

    FunIterator(long long idx) : index(idx) {}

    // 随机访问迭代器必需的操作
    FunIterator& operator++() { ++index; return *this; }
    FunIterator operator++(int) { FunIterator tmp = *this; ++index; return tmp; }
    FunIterator& operator--() { --index; return *this; }
    FunIterator operator--(int) { FunIterator tmp = *this; --index; return tmp; }

    FunIterator operator+(difference_type n) const { return FunIterator(index + n); }
    FunIterator& operator+=(difference_type n) { index += n; return *this; }
    FunIterator operator-(difference_type n) const { return FunIterator(index - n); }
    difference_type operator-(const FunIterator& other) const { return index - other.index; }
    FunIterator& operator-=(difference_type n) { index -= n; return *this; }

    reference operator*() const {
        auto it = cache.find(index);
        if (it != cache.end()) return it->second;
        auto res = F(index);
        cache[index] = res;
        return cache[index];
    }

    pointer operator->() const { return &(**this); }
    value_type operator[](difference_type n) const { return *(*this + n); }

    // 比较操作
    bool operator==(const FunIterator& other) const { return index == other.index; }
    bool operator!=(const FunIterator& other) const { return !(*this == other); }
    bool operator<(const FunIterator& other) const { return index < other.index; }
    bool operator>(const FunIterator& other) const { return other < *this; }
    bool operator<=(const FunIterator& other) const { return !(*this > other); }
    bool operator>=(const FunIterator& other) const { return !(*this < other); }
};

template <function_type F>
std::unordered_map<long long, long long> FunIterator<F>::cache;

template <function_type F>
std::pair<FunIterator<F>, FunIterator<F>> makeFunRange(long long begin, long long end) {
    return {FunIterator<F>(begin), FunIterator<F>(end)};
}

int main() {
    // 测试大搜索空间
    auto range = makeFunRange<foo>(0, 1000000000000LL);
    auto it = std::lower_bound(range.first, range.second, 400000000000LL);
    std::cout << "Found index: " << it.index << std::endl;
}

关键改进点说明

  1. 迭代器类型变更:将iterator_category改为std::random_access_iterator_tag,告诉std::lower_bound可以使用随机访问优化,执行O(log n)的二分查找。
  2. 实现随机访问操作:添加了operator+、operator-、operator[]等方法,允许直接跳转到任意索引位置,避免了逐个递增的开销。
  3. 缓存优化:保留了原有的缓存机制,避免重复调用高耗时函数。

运行效果

运行上述代码后,你会发现函数调用次数只有几十次(对应二分查找的log2(1e12)≈40次),而不是线性遍历的数十亿次,效率得到了质的提升。

解决方案2:直接封装标准库二分逻辑

如果你觉得自定义迭代器还是太冗长,其实可以基于std::lower_bound的核心逻辑封装一个专用函数,完全不需要迭代器,直接接收函数和范围:

#include <iostream>
#include <functional>

long long foo(long long i) {
    std::cout << "function evaluation:\t" << i << std::endl;
    return i;
}

template <typename Func, typename T, typename Index>
Index lower_bound_func(Func f, Index left, Index right, T target) {
    while (left < right) {
        Index mid = left + (right - left) / 2; // 避免超大数值溢出
        auto val = f(mid);
        if (val < target) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    return left;
}

// 使用示例
int main() {
    auto idx = lower_bound_func(foo, 0LL, 1000000000000LL, 400000000000LL);
    std::cout << "Found index: " << idx << std::endl;
}

这个方案更简洁,完全复用了和std::lower_bound一致的二分逻辑,同时避免了迭代器的额外开销,也完全符合你的需求场景。


内容的提问来源于stack exchange,提问作者David S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:52:48