【发布时间】:2016-12-05 03:39:37
【问题描述】:
假设我们有函数f,它接受整数并返回一个单调递增的值。我们希望找到最小的x,这样f(x) >= C。为简单起见,假设答案在[l;r) 范围内。显然我们可以编写自己的二分搜索实现,但我们想使用现有的 (std::patition_point)。
如此幼稚的实现(可能)会起作用:
// f;
std::vector<int> v(r - l);
std::iota(v.begin(), v.end(), l);
answer = l + partition_point(v.begin(), v.end(), [&](int x) {
return f(x) <= C;
}) - v.begin();
明显的问题是我们必须存储所有的数字,这会占用大量内存并且需要时间来填充数组
下一个逻辑想法是以这种方式将整数包装到迭代器:
struct IntIterator: std::iterator<std::random_access_iterator_tag, int> {
int current;
IntIterator(int i) : current(i) {}
int operator*() const { return current; }
IntIterator& operator++() { ++current; return *this; }
IntIterator& operator+=(size_t n) { current += (int)n; return *this; }
IntIterator operator+(size_t n) const { return current+(int)n; }
size_t operator-(IntIterator that) const { return size_t(current - that.current); }
// others operators to conform
};
answer = partition_point(IntIterator{l}, IntIterator{r}, [&](int x) {
return f(x) <= C;
});
这将适用于我的编译器(标准库),但不符合随机访问迭代器,因为
- operator* 应该返回
std::iterator_traits<IntIterator>::reference。 -
如果我们将
std::iterator_traits<IntIterator>::reference更改为int(例如通过将模板参数更改为std::iterator)将无法满足前向迭代器的要求:如果 X 是一个可变迭代器,
reference是对 T 的引用;如果 X 是 const 迭代器,reference是对 const T 的引用, -
如果我们将
operator*的返回类型更改为[const ]T&,它将无法满足前向迭代器的另一个要求如果 a 和 b 都是可解引用的,则
a == b当且仅当*a和*b绑定到同一个对象。
所以我不明白如何使其符合并提出是否可能的问题。
【问题讨论】:
-
你说天真的实现可能会起作用是什么意思?你没试过吗?
-
我可以想办法解决这里的所有问题,除了
operator*返回的引用的生命周期绑定到所有与取消引用迭代器比较相等的迭代器的生命周期。 IE。如果被取消引用的迭代器是该值的唯一迭代器,那么当迭代器本身超出范围,或者如果它发生变化(递增、递减),则先前返回的引用不再有效。尚未检查这是否会违反随机访问迭代器的要求。 -
@VeniVidiVici 这意味着它会工作,除非我打错字
-
@SamVarshavchik 如果你有时间分享,我想看看你的想法
-
Yakk 偷了我的答案 :-)
标签: c++ iterator language-lawyer