【问题标题】:Is it possible to do an inplace merge without temporary storage?是否可以在没有临时存储的情况下进行就地合并?
【发布时间】: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&lt;_BidirectionalIter, _Tp&gt; __buf(__first, __last); 如果您查看它们的实现。
  • 经过进一步研究,似乎没有“就地”的单一定义(参见en.wikipedia.org/wiki/In-place_algorithm)。算法理论家使用的传统定义是使用 O(1) 额外存储的定义,而 C++ 标准使用的定义显然是对输入和输出使用相同存储的定义。
  • @Adam:很公平。感谢您澄清解释“就地”的方式不止一种
  • 我的推断和你一样。也许最近发现了一个需要 O(1) 额外内存的线性时间合并,但我认为是一群非常聪明的 STL 创造者并不知道,所以我认为这不太可能.

标签: c++ algorithm


【解决方案1】:

有几种已知的就地合并算法,尽管其中一些相当复杂。它们工作的一般方式是进行异地合并,使用一些数组元素本身作为外部存储空间。我知道 Alex Stepanov 和 Paul McJones 的“编程要素”详细介绍了一种算法。

我最近阅读了一篇名为 "Practical In-Place Merging" 的关于就地合并的论文,其中详细介绍了一种相当简单的算法来执行这种合并。我编码an implementation of this algorithm 的方式接近std::inplace_merge 的界面,尽管有一些不同之处。也许里面有一些你可能会觉得有用的东西?

【讨论】:

  • 可能是我看到的最完整的代码片段之一。里面有一些 C-isms(cmets、casts),但呈现得非常好。
  • +1 这个答案是由纯粹的令人敬畏和完全的胜利组成的。我对提到的论文很熟悉,但花时间去实现它,即使不是为了这个答案,然后将它作为真人参考提供它简直是一流的。谢谢。
猜你喜欢
  • 2019-01-16
  • 1970-01-01
  • 1970-01-01
  • 2011-09-28
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 2014-01-21
  • 2011-01-04
相关资源
最近更新 更多