List 列表和数组之间的区别

List 列表和数组之间的区别,list,vector,lisp,common-lisp,List,Vector,Lisp,Common Lisp,lisp中的列表似乎可以使用push向其中添加另一个元素,而数组可以使用vector push extend执行相同的操作(如果使用:可调t,除了在末尾添加元素。类似地,pop删除列表中的第一项,而vector pop删除向量中的最后一项 那么lisp中的列表和向量有什么区别呢?列表由cons单元格和nil组成。必须按顺序在列表中移动才能访问元素。在前面添加和删除元素非常便宜。在其他列表位置的操作成本更高。列表可能会有空间开销,因为每个元素都是存储的在囚室里 向量是具有一定长度的一维数组。如果数

lisp中的列表似乎可以使用
push
向其中添加另一个元素,而数组可以使用
vector push extend
执行相同的操作(如果使用
:可调t
,除了在末尾添加元素。类似地,
pop
删除列表中的第一项,而
vector pop
删除向量中的最后一项


那么lisp中的列表和向量有什么区别呢?

列表由cons单元格和nil组成。必须按顺序在列表中移动才能访问元素。在前面添加和删除元素非常便宜。在其他列表位置的操作成本更高。列表可能会有空间开销,因为每个元素都是存储的在囚室里


向量是具有一定长度的一维数组。如果数组是可调的,它可能会改变其大小,但可能必须复制元素。当必须调整数组时,添加元素的成本很高。可调数组有空间开销,因为数组通常不会按一的增量进行调整。可以访问所有元素直接通过索引。

向量是有形的东西,但您想到的列表是一个名称,用于查看几个松散连接但独立的东西

向量就像一个鸡蛋盒,它是一个有固定数量插槽的盒子,每个插槽内可能有东西,也可能没有。相比之下,你所想到的列表更像是拿着几双鞋,把它们的鞋带绑在一起。“列表”实际上是一个cons单元格的视图,它持有一个值,就像鸡蛋盒里的一个插槽,指向另一个cons单元格,它也持有一个值,指向另一个cons单元格,它持有一个值,可能不指向任何其他内容,使它成为列表的结尾。你所认为的列表实际上不是一回事,而是一个关系几个不同的细胞之间的相互作用

没错,有一些操作可以在两种结构上执行,但它们的时间复杂度不同。对于列表,将项推到前面实际上不会修改现有列表的任何内容;相反,这意味着创建一个新的cons单元格来表示列表的新头,并将该cons单元格指向existing列表作为新的尾部。这是一个O(1)操作;列表有多长并不重要,因为在列表前面放置一个新单元格总是需要相同的时间。类似地,从列表前面弹出一个项目并不会改变现有列表;它只意味着将视图从当前标题移到一个单元格,以查看作为新标题的第二个项目是什么

相比之下,对于向量,将新项目推到前面需要首先将所有现有项目移动一个空间,以便在开始时留出一个空白空间,前提是向量中有足够的空间容纳所有现有项目和一个以上的项目。这种移动具有时间复杂性O(n),这意味着向量中的项目越多,移动它们并为新项目腾出空间所需的时间就越长。类似地,从向量的前面弹出需要将除第一个项目外的所有现有项目移到前面,以便第二个项目变为第一个,第三个项目变为第二个,并且再一次,这是时间复杂性的o(n)

有时,在向量中进行簿记是可能的,这样,从前面弹出一个项目就不需要移动所有现有项目;相反,只需更改哪个项目是第一个项目的记录。可以想象,这样做有很多挑战:用于访问项目的索引需要调整,向量的容量TY不再是简单的解释,重新分配向量以适应新的项目,现在需要考虑在将现有数据复制到新的存储区后,在何处留下新可用的空空间。 在列表和向量之间进行选择需要考虑你打算用它做什么,以及你对内容的性质和大小预先知道多少。它们在不同的场景中歌唱,尽管它们的目的有明显的重叠



在我写上面的答案时,问题是关于从向量和列表的前面推送和弹出元素。在向量的末尾操作
vector push
vector pop
do比我在上面的比较中所做的区别更类似于操作列表的头部。Depending取决于向量的容量是否可以容纳另一个元素,而无需在向量末尾重新分配、推送和弹出元素,取常数(O(1))时间。

这听起来很混乱,你在说哪个Lisp?通常Lisp既不推也不弹出向量。@rainer哦,该死,我是说向量推扩展,我会更新问题Lisp不提供原语推或弹出到向量的前面。CL有原语推或弹出元素到某些类型的ve的结尾是的,我知道,但问题的原始形式是关于从前面推动和弹出的,我假设作者正在考虑通过暴力来实现这样做。