Big O表示法数组与链接表单插入:
根据阵列的学术文献,它是常数O(1),对于链表,它是线性O(n)。
数组只需要一次乘法和加法。
未在连续内存中布局的链接列表需要遍历。
这个问题是,O(1)和O(n)分别准确地描述了数组和链表的索引/搜索成本吗?
答案 0 :(得分:36)
O(1)
准确地描述了在数组末尾的插入。但是,如果要插入数组的中间,则必须在该元素之后移动所有元素,因此在这种情况下插入的复杂性对于数组来说是O(n)
。如果数组已满,则必须对数组进行大小调整。
对于链表,您必须遍历列表才能进行中间插入,因此O(n)
为 Linked list Array Dynamic array Balanced tree
Indexing Θ(n) Θ(1) Θ(1) Θ(log n)
Insert/delete at beginning Θ(1) N/A Θ(n) Θ(log n)
Insert/delete at end Θ(1) N/A Θ(1) amortized Θ(log n)
Insert/delete in middle search time
+ Θ(1) N/A Θ(n) Θ(log n)
Wasted space (average) Θ(n) 0 Θ(n)[2] Θ(n)
。您不必将元素向下移动。
维基百科有一个很好的图表:http://en.wikipedia.org/wiki/Linked_list#Linked_lists_vs._dynamic_arrays
{{1}}
答案 1 :(得分:2)
假设您正在谈论已经知道插入点的插入,即这没有考虑到列表的遍历以找到正确的位置:
数组中的插入取决于您要插入的位置,因为您需要移动现有值。最坏的情况(在数组[0]处插入)是O(x)。
列表中的插入是O(1),因为您只需要修改相邻项的下一个/上一个指针。
答案 2 :(得分:0)
我想象的数组插入速度较慢。当然,你必须迭代链表,但你必须分配,保存和释放内存以插入数组。
答案 3 :(得分:0)
您引用了哪些文献?创建数组时确定数组的大小,之后不会更改。实际上只能插入数组末尾的空闲插槽。任何其他类型的插入可能需要调整大小,这当然不是O(1)
。链表的大小取决于实现,但必须始终至少足以存储其所有元素。元素可以插入列表中的任何位置,找到适当的索引需要遍历。
答案 4 :(得分:0)
tldr 未排序的数组类似于一个集合。像集合一样,可以添加和删除元素,迭代和读取元素。但是,与集合一样,讨论在特定位置插入元素是没有意义的,因为这样做会尝试对定义为未排序的内容强加排序顺序。
根据阵列的学术文献,它是常数O(1),对于链表,它是线性O(n)。
值得理解为什么学术文献引用数组插入为数组的 O (1)。有几个概念需要理解:
数组的长度(定义为数组包含的元素数)可以在 O (1)时间内任意增加或减少,并且最大值没有限制数组的大小。
(在真实的计算机中,由于各种因素,例如内存大小,虚拟内存,交换空间等,情况并非如此。但是出于算法asymptotic analysis的目的,这些因素并不重要 - 我们关心算法的运行时间如何随着输入大小向无穷大而变化,而不是在具有特定内存大小和操作系统的特定计算机上如何执行。)
插入和delete O (1)因为数组是未排序的数据结构。
插入不是作业
考虑将元素添加到未排序的数据结构实际意味着什么。由于没有定义的排序顺序,实际发生的任何顺序都是任意的并且无关紧要。如果您考虑面向对象的API,方法签名将类似于:
Array.insert(Element e)
请注意,这与其他数据结构的插入方法相同,例如链表或排序数组:
LinkedList.insert(Element e)
SortedArray.insert(Element e)
在所有这些情况下, insert 方法的调用者都没有指定插入的值最终存储的位置 - 它是数据结构的内部细节。此外,调用者尝试在数据结构中的特定位置插入元素是没有意义的 - 对于已排序或未排序的数据结构。对于(未排序的)链接列表,列表根据定义未排序,因此排序顺序无关紧要。对于排序数组,根据定义,插入操作将在数组的特定点插入元素。
因此,将数组插入操作定义为:
是没有意义的Array.insert(Element e, Index p)
通过这样的定义,调用者将覆盖数据结构的内部属性,并对未排序的数组施加排序约束 - 数组定义中不存在的约束,因为数组未排序。
为什么数组而不是其他数据结构会出现这种误解?可能是因为程序员习惯使用赋值运算符来处理数组:
array[0] = 10
array[1] = 20
赋值运算符为数组的值提供显式顺序。这里要注意的重要事项是赋值与 insert 不同:
未排序的数组没有排序顺序,因此 insert 不需要允许覆盖该位置。 insert 与 assignment 不同。数组 insert 简单地定义为:
Array.insert(v):
array.length = array.length + 1
// in standard algorithmic notation, arrays are defined from 1..n not 0..n-1
array[array.length] = v
O (1)。
答案 5 :(得分:-1)
很久以前,在一个拥有更多内存磁盘空间的系统上,我实现了一个索引链表,该链表是手动输入或从磁盘加载时编入索引的。每条记录都附加到内存中的下一个索引,磁盘文件打开附加到结尾的记录。
该程序在一台Model I Radio Shack计算机上的拍卖销售以及对磁盘的写入只能防止电源故障和存档记录,以便满足时间限制,数据必须从RAM中获取并打印在反向订单,以便买方可以询问出现的第一个项目是否是他购买的最后一个项目。每个买方和卖方都与他们销售的最后一个项目相关联,并且该项目与之前的项目相关联。它只是一个自下而上遍历的链接链接列表。
对逆转条目进行了更正。我使用相同的方法做了几件事情,如果方法适用于手头的工作并且索引保存到磁盘而且没有必要重建,因为文件重新加载到内存中,我从未找到更快的系统。电力故障。
后来我编写了一个程序来按常规编辑。它还可以重新组织数据,以便将它们组合在一起。