single linked list
本文关键字:list linked single | 更新日期: 2023-09-27 17:49:01
Internet上可用的一些示例对单个链表使用头节点和尾节点,而有些示例不知道为什么会有这样的差异。
尾部节点使得将一个项目附加到列表末尾的操作为O(1),而不是在附加之前必须从头部一直迭代到尾部,使其成为O(n)操作。因此,它有助于提高效率,但并不是制作可用列表的根本要求。我怀疑例子的区别在于学术纯粹和拥有一个相对有用的列表。
这将是完全没有意义的有一个单链表没有记住头节点虽然:)
保留头和尾的原因主要是当列表需要在列表末尾添加新项时速度。
虽然查找列表的末尾很简单,但与在列表修改期间跟踪它所花费的精力相比,它花费的时间太多了。
单链表使用更少的空间-每个单元格少1个指针。它也更有效地添加到列表的头部和从列表的前半部分删除(更少的操作,因为不需要维护另一个链接)。
对于表的后半部分的删除或添加,双重链表更有效。
在广泛使用列表的Lisp中,只使用单链表。实际上,有些实现(如Symbolics)在列表小于一定长度时使用数组。
使用哪个取决于应用程序。如果追加是一个常见的操作,并且速度比空间更重要,那么双链表可能是合适的。然而,我认为单链表在大多数情况下更合适,因此更常用。
正如其他人指出的那样,尾部引用提供了一种在常量时间内将节点附加到列表末尾的方法。如果链表实现没有尾部引用,则必须遍历列表中的所有节点,以便将其添加到末尾。下面是一个java链表示例,使用3种不同的方法向列表添加元素。
- push(Node Node) -将节点添加到列表的开头。由于头部引用,这需要常数时间O(1)。
- add(int index, Node Node) -添加指定索引处的节点。这需要O(n)时间,因为它必须遍历每个节点直到找到正确的索引。
-
add(Node Node) -将节点添加到列表末尾。如上所述,由于使用的是尾部引用,因此此操作只需要常量时间。
// 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中使用尾部引用的链表实现。