所以我正在玩JS中的链表并提出以下问题:
让我们说,我们有一个数组和一个包含5000个元素的链表。我们想在索引10处插入新元素。数组方式非常简单。我们在给定索引处插入新元素,并将其余元素向前移动一个索引。所以我尝试使用链表进行此操作,最后得到以下结果:
从Nicholas Zakas获取链接列表的实现并添加其他方法addOnPosition(data,index)。最后这里是代码:
function LinkedList() {
this._head = null;
this._length = 0;
}
LinkedList.prototype = {
constructor: LinkedList,
add: function(data) {
var node = {
data: data,
next: null
},
current;
if (this._head === null) {
this._head = node;
}
else {
current = this._head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this._length++;
},
remove: function(index) {
if (index > -1 && index < this._length) {
var current = this._head,
previous,
i = 0;
if (index === 0) {
this._head = current.next;
}
else {
while (i++ < index) {
previous = current;
current = current.next;
}
previous.next = current.next;
}
this._length--;
return current.data;
}
else {
return null;
}
},
item: function(index) {
var current = this._head,
i = 0;
if (index > - 1 && index < this._length) {
while (i++ < index) {
current = current.next;
}
return current.data;
}
else {
return null;
}
},
addOnPosition: function(data,index) {
if (index > -1 && index <= this._length) {
var node = {
data: data,
next: null
},
current = this._head,
i = 0,
temp,
previous;
if (this._head === null) {
this._head = node;
}
else {
if (index === 0) {
this._head = node;
node.next = current;
}
else {
while (i++ < index) {
previous = current;
current = current.next;
}
previous.next = node;
node.next = current;
}
}
this._length++;
}
else {
return null;
}
},
toArray: function() {
var result = [],
current = this._head;
while (current) {
result.push(current.data);
current = current.next;
}
return result;
},
toString: function() {
return this.toArray().toString();
}
}
最后,我的问题是:这种方法比使用数组完成所有这些更快吗?如果是,那么两者的复杂性是多少? 可能更重要的是,我是否错过了adOnPosition方法实现的内容?
答案 0 :(得分:6)
实际上插入链表的中间是O(n)时间复杂度,这意味着它将平均花费的时间或在最坏的情况下与已经在列表中的元素的数量(即n)成比例。 “O(指数)”甚至不是实时复杂性。
插入数组中间的时间复杂度也是O(n)。 “O(长度 - 索引)”也不是实时复杂性。在平均或最差情况下移动列表中元素所涉及的操作数量将与列表中的项目数量成正比(即n)。
对于数组上的链表的优点是,在列表的前/后添加/附加元素是O(1)时间复杂度,但是对于数组是O(n)。
数组优于链表的优点是,通过索引从数组中检索元素是O(1),但是链表的O(n)。
决定链接列表和数组之间的最简单方法是确定是否需要快速追加/前置或基于快速索引的数据检索。如果您需要两者,那么这些数据结构会有一些变化,可以在这两个方面提供良好的性能/妥协。
答案 1 :(得分:5)
有关LinkedList和ArrayList数据结构的复杂性,请参阅http://en.wikipedia.org/wiki/Dynamic_array#Performance。对于游戏,还可以查看When to use LinkedList over ArrayList?
在单链表中的节点之后插入是一个恒定时间操作。如果在双向链表中有节点,则在它之前插入也是一个恒定时间操作。
但是,你的addOnPosition函数会在链表“索引”时间内运行;也就是说,你多次从一个节点跳到下一个节点。因此,您的算法的复杂性基本上是O(索引) - 我们将其写为O(n)。
解释我的观点:如果你想在第0个元素处插入一个节点,你的操作基本上是在恒定的时间运行;你得到了this._front
节点,你就完成了。要插入到线性单链表的末尾,必须迭代到列表的末尾,从一个节点到下一个节点执行更多“跳转”。您可以使用circular linked lists来优化此案例。
至于使用arraylist执行类似的插入,插入复杂度基本上是O(长度 - 索引),因为长度索引元素必须向下移动到数组,我们将其写为O(n)。