互联网中可用的一些示例使用单个链表的头部和尾部节点,并且一些示例不解释为什么存在这样的差异。
答案 0 :(得分:3)
一个尾节点让O(1)将一个项附加到列表的末尾,而不是必须从头开始迭代以在追加之前找到尾,使其成为O(n)操作。因此,它对提高效率非常有用,但从根本上并不需要制作可用的列表。我怀疑这些例子的不同之处在于学术纯度和相对有用的列表。
在没有记住头节点的情况下拥有单链表是完全没有意义的:)
答案 1 :(得分:3)
当列表需要将新项目添加到列表末尾时,保持头部和尾部的原因主要是速度。
虽然找到列表末尾是微不足道的,但与在列表修改期间跟踪它所花费的成本相比,它需要花费太多时间。
答案 2 :(得分:0)
单链表使用较少的空间 - 每个单元少1个指针。添加到列表的头部并从列表的前半部分删除也更有效(因为不需要维护另一个链接所以操作更少)。
双向链表更有效地删除或添加列表的后半部分。
在广泛使用列表的Lisp中,只使用单链表。实际上,如果列表短于某个长度,某些实现(如Symbolics)会使用数组。
使用哪种选择取决于应用。如果追加是一种常见操作,并且速度比空间更重要,那么双重链表可能是合适的。但是,我认为单链表在大多数情况下更合适,因此更常见。
答案 3 :(得分:0)
正如其他人指出的那样,尾部引用提供了一种在恒定时间内将节点附加到列表末尾的方法。如果链接列表实现没有尾部引用,则必须遍历列表中的所有节点才能将其添加到末尾。下面是一个java链接列表示例,它使用3种不同的方法将元素添加到列表中。
add(节点节点) - 将节点添加到列表末尾。如上所述,由于我们使用尾部引用,因此此操作只需要一段时间。
// Insert element at the beginning of the list
public void push(T _data) {
Node<T> addNode = new Node<T>(_data);
// Set head and tail to new pointer if list is empty
if(this.head == null) {
this.head = addNode;
this.tail = addNode;
} else {
addNode.setNext(this.head); // Set new node's next pointer to the current head
this.head = addNode; // Set head to new node
}
this.numberNodes++;
}
// Insert element at the specified index
public void add(int _index, T _data) {
// Continue if _index is valid
if(_index >= 0 && _index <= this.numberNodes) {
if(_index == 0) { // Push element to front of list if _index is 0
this.push(_data);
} else if(_index == this.numberNodes) { // Add element to end of list if index is last element
this.add(_data);
} else {
// Continue if list is not empty
if(this.head != null && this.tail != null) {
Node<T> addNode = new Node<T>(_data);
Node<T> currentNode = this.head.getNext();
Node<T> previousNode = this.head;
int count = 1;
while(currentNode != null) { // Traverse list to find element at _index
// Insert element when _index is found
if(count == _index) {
previousNode.setNext(addNode);
addNode.setNext(currentNode);
this.numberNodes++;
break;
}
// Prepare for next iteration
previousNode = currentNode;
currentNode = currentNode.getNext();
count++;
}
}
}
}
}
// Insert element at the end of the list
public void add(T _data) {
Node<T> addNode = new Node<T>(_data);
// Set head and tail to new pointer if list is empty
if(this.head == null) {
this.head = addNode;
this.tail = addNode;
} else {
this.tail.setNext(addNode); // Set tail's next pointer to new node
this.tail = this.tail.getNext(); // Set tail to new node
}
this.numberNodes++;
}
添加尾部引用会显着减少在链接列表末尾插入元素的时间。使用Java,C ++,Python和JavaScript中的尾部引用,查看my blog的Linked List实现。