【发布时间】:2011-08-08 01:07:14
【问题描述】:
有没有办法(例如,修改参数类型)使以下“cons”函数花费恒定时间而不是 O(n) 时间。即构建列表应该花费 O(n) 时间,而不是 O(n^2) 时间。
我可以在以下情况下这样做吗:
(1) 无动态内存分配
(2) x 必须仍然有效(即可能没有对临时对象的引用)
(3) HEAD 类型可能有一个单独编译的构造函数(不可内联)
#include <type_traits>
template <typename HEAD, typename TAIL>
struct List
{
List(HEAD head, TAIL tail) : head(head), tail(tail) {}
typename std::remove_reference<HEAD>::type head;
typename std::remove_reference<TAIL>::type tail;
};
template <typename HEAD, typename TAIL>
List<HEAD, TAIL> cons(HEAD head, TAIL tail)
{
return List<HEAD, TAIL>(head, tail);
}
struct Empty {};
int main()
{
auto x = cons(1, cons(2, cons(3, Empty())));
// x should still be valid here
}
如何工作的示例。
编译器知道 x 的类型,因此在堆栈上分配空间。
所以堆栈看起来像这样:
| Int1 | Int2 | Int3 |
| p | p+4 | p+8 |
其中p 是任意地址。
编译器创建调用cons(2, cons(3, Empty())),将返回值指向p+4。
在cons(2, cons(3, Empty())) 内部,编译器创建对cons(3, Empty()) 的调用,将返回值指向p+8。
这样,每次调用cons,就不需要复制tail了。
我只是不确定代码,因此编译器可以(如,被允许)进行此优化。不过,如果有另一种获得恒定运行时间的方法,我很乐意使用它。
【问题讨论】:
-
我不明白您的“无动态内存分配”要求。这不是
cons通常所做的吗? -
你能解释一下你现在的
cons是线性的吗?有固定数量的参数不以任何方式检查。你是说最后的表达吗? -
所以你正在制作一个链接列表。它包含的不是对事物的引用,而是它们的副本。所以我猜 O(n^2) 来自这样一个事实,即每个嵌套的
cons调用都会复制其参数,它将每个先前创建的对象复制到新的对象中。