【问题标题】:Data structures in lisplisp 中的数据结构
【发布时间】:2011-04-23 13:20:54
【问题描述】:

我有一个简单的问题:将对象收集到一个列表中并向后遍历该列表。看起来很简单,但这段代码是高负载计算的一部分。使用 conses 很自然,因为添加新元素和顺序访问需要 O(1)。但是,如果我需要一个有效的双向链表来轻松地双向遍历它,我该怎么办?使用(反向)?它需要 O(n) 内存和时间,所以在我的情况下实际上需要 O(n^2) (这真的很糟糕)。使用(最后)还是(附加)?同样的故事:O(n)。我真的不明白在哪里可以找到(源代码除外)有关标准库函数计算复杂性的任何信息。它依赖于实现吗?对于各种标准数据结构的实现,我必须做些什么?有没有有效使用 conses 的指南?

【问题讨论】:

标签: lisp common-lisp


【解决方案1】:

如果你使用 Common Lisp,你可以使用向量来代替。矢量可以具有填充指针和/或可以调整。因此,您可以使用 vector-push 将元素添加到向量中。填充指针将增长。如果矢量是可调的,那么必要时它也会变大。由于向量是一维数组,您可以随意访问带有索引的元素。

查看 MAKE-ARRAY 的选项来创建这样的向量。

VECTOR-PUSH 和 VECTOR-PUSH-EXTEND 是添加元素的函数。

【讨论】:

  • 我看到 :adjustable 只允许 adjust-array。当 vector-push 到达数组边界时,它返回 NIL 而不是自动分配额外的空间。
  • 好的。现在我明白了。 VECTOR-PUSH-EXTEND 在恒定的时间和空间中扩展向量。谢谢。
【解决方案2】:

如果你执行一次(reverse),然后按顺序遍历反向列表,总时间应该是 O(2n) 时间(O(n) 用于设置,然后是另一个 O(n) 遍历)和 O(n) 内存。

双向链表并不是很复杂。如您所知,列表由 cons 单元格组成,其中 car 指向对象,而 cdr 指向列表中的下一个 cons 单元格。

创建双向链表的一种方法是让 cdr 指向另一个 cons 单元格,其 cdr 指向列表中的下一个 cons 单元格,其 car 指向列表中的前一个 cons 单元格。然后你使用 cddr 前进,使用 cdar 后退。

我不知道标准库函数有任何保证的复杂性。除非规范指定,否则它将是实现定义的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多