许多功能性编程语言支持并推荐数据构造函数Cons
(适用于(1, (2, (3)))
之类的列表,例如Haskell和Scala。< / p>
但它有什么优势?此类列表既不能随机访问,也不能附加到O(1)
。
答案 0 :(得分:6)
Cons
(“构造”的简写)不是数据结构,它是用于创建 cons-cell 的操作的名称。并且通过将几个单元链接在一起,可以构建数据结构,尤其是链接列表。讨论的其余部分假定使用cons
操作创建链接列表。
虽然可以在头部附加O(1),但是通过索引随机访问元素是一项代价高昂的操作,需要遍历所有元素,然后才能访问所有元素。
链表的优势?它是一个功能数据结构,在修改时创建或重新创建便宜;它允许在几个列表之间共享节点,并允许轻松垃圾收集。它非常灵活,通过正确的抽象,可以表示其他更复杂的数据结构,如堆栈,队列,树,图。并且有许多专门用于操作列表的程序 - 例如map
,filter
,fold
等,这使得使用列表成为一种乐趣。最后,列表是递归数据结构,递归(特别是尾递归)是解决函数式编程语言中问题的首选方法;所以在这些语言中,将递归数据结构作为主要数据结构是很自然的。
答案 1 :(得分:2)
首先,让我们将“cons”区分为通常称为::
的ML样式列表数据构造函数的昵称,以及昵称来自的原始Lisp样式cons
函数。
在Lisps中,cons单元是一种通用数据结构,不限于同类元素类型列表。 ML风格语言中的等价物将是嵌套对或2元组,由“单元”类型表示的空列表通常写为()
。 ÓscarLópez对Lisp cons
的效用给出了很好的概述,所以我将其留在那里。
在大多数ML风格的语言中,不可变缺点列表的优点与它们在Lisps中的列表的使用没有太大区别,为了保证静态类型和ML样式模式匹配的语法而牺牲了动态类型的灵活性。
然而,在Haskell中,由于懒惰的评估,情况相当不同。构造函数是惰性的,它们之间的模式匹配是强制评估的几种方法之一,因此与严格评估的语言相比,通常情况下你应该避免尾递归。相反,通过将递归调用放在列表的尾部,可以仅在需要时计算每个递归调用。如果使用适当的惰性函数(如map
或foldr
)处理延迟生成的列表,则可以在常量内存中构造和使用大型列表,尾部强制以相同的速率处理头部放弃让GC清理。
Haskell的一个共同观点是,懒惰的缺点列表不是一个数据结构,而是一个控制结构 - 一个与其他这样的循环有效组合的具体循环。
也就是说,在很多情况下,缺点列表不是合适的 - 例如当需要重复随机访问时 - 并且在那些使用列表的情况下肯定不推荐。