【发布时间】:2010-12-07 04:11:43
【问题描述】:
我只是在想,如果我要实现std::inplace_merge,它可能看起来像这样:
template <class Bi, class Cmp>
void inplace_merge(Bi first, Bi middle, Bi last, Cmp cmp) {
if(first != last) {
typedef typename iterator_traits<Bi>::value_type T;
typedef typename iterator_traits<Bi>::difference_type Dist;
const Dist count = distance(first, last);
if(count != 1) {
// can I avoid this allocation?
T *const temp = new T[count];
merge(first, middle, middle, last, temp, cmp);
copy(temp, temp + count, first);
delete [] temp;
}
}
}
我知道我可以只使用现有的实现,但这不是重点。 我只是好奇是否有比我所知道的更好的算法。
想到这一点的原因是大多数 c++ 标准库(如果我没记错的话,所有的 STL)都允许用户指定执行分配的方式和位置,但是如果 std::inplace_merge 需要按设计分配,它如果这是一个问题,似乎没有办法控制它。
我认为答案的暗示来自标准本身关于std::inplace_merge的复杂性:
复杂性:当有足够的额外 内存可用,(最后 - 第一个) - 1比较。如果没有额外的内存 是可用的,一个算法 复杂度 N log N(其中 N 等于 to last -first) 可以使用。
对我来说,这意味着已知的高效算法版本需要额外的存储空间。我读对了吗?如果是这样,有没有提到存储应该来自哪里?
【问题讨论】:
-
就地,根据定义,不需要任何额外的内存分配(它只需要 O(1) 在堆栈上的临时存储)。您的实施没有到位。
-
@Adam:不正确,这意味着结果与源在同一个存储中(而不是
merge将结果放入调用者提供的缓冲区中)。例如,STLPort 使用以下形式的临时空间:_Temporary_buffer<_BidirectionalIter, _Tp> __buf(__first, __last);如果您查看它们的实现。 -
经过进一步研究,似乎没有“就地”的单一定义(参见en.wikipedia.org/wiki/In-place_algorithm)。算法理论家使用的传统定义是使用 O(1) 额外存储的定义,而 C++ 标准使用的定义显然是对输入和输出使用相同存储的定义。
-
@Adam:很公平。感谢您澄清解释“就地”的方式不止一种
-
我的推断和你一样。也许最近发现了一个需要 O(1) 额外内存的线性时间合并,但我认为是一群非常聪明的 STL 创造者并不知道,所以我认为这不太可能.