双向链表与单向链表很类似,唯一的区别是双向链表中的每个节点均能访问前一个(pre)和后一个(next)节点。因此,双向链表能够在表尾增加新的节点,也能删除表尾节点;同理,你也能轻松地在表头新增或删除节点。除此之外,你还能反向遍历整个链表。
本文将通过以下几方面来介绍双向链表:
In a 'doubly linked list', each node contains, besides the next-node link, a second link field pointing to the 'previous' node in the sequence. The two links may be called 'forward('s') and 'backwards', or 'next' and 'prev'('previous').
以上定义说明了,双向链表的节点不仅包含了数据部分,而且还包含了之前上一个节点和下一个节点的部分,比单向链表的节点多出了指向上一个节点的部分,相应地,也花费了更多的内存。如下图所示:
组成双向链表的操作如下所示:
add_to_tail
,从表尾新增一个节点remove_from_tail
,从表尾删除一个节点add_to_head
,从表头新增一个节点remove_from_head
,从表头删除一个节点empty
,判断双向链表是否为空链表print_all
,遍历双向链表class DoublyLinkedListNode:
def __init__(self, val):
self.pre = None
self.next = None
self.value = val
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
self.count = 0
def add_to_tail(self, val):
new_node = DoublyLinkedListNode(val)
if self.empty():
self.tail = self.head = new_node
else:
new_node.pre = self.tail
self.tail.next = new_node
self.tail = new_node
self.count += 1
def remove_from_tail(self):
val = self.tail.value
self.count -= 1
if self.empty():
self.head = self.tail = None
else:
self.tail.pre.next = None
return val
def add_to_head(self, val):
new_node = DoublyLinkedListNode(val)
if self.empty():
self.tail = self.head = new_node
else:
new_node.next = self.head
self.head.pre = new_node
self.head = new_node
def remove_from_head(self):
val = self.head.value
self.head = self.head.next
self.count -= 1
if self.empty():
self.tail = None
else:
self.head.pre = None
return val
def empty(self):
return self.count == 0
def print_all(self, reverse = False):
current_node = self.head
next_node = lambda x : x.next
if reverse:
current_node = self.tail
next_node = lambda x : x.pre
while current_node:
print(current_node.value)
current_node = next_node(current_node)
使用方式如下所示:
double_linked_list = DoublyLinkedList()
double_linked_list.add_to_tail(1)
double_linked_list.add_to_tail(10)
double_linked_list.add_to_tail(90)
double_linked_list.add_to_tail(100)
double_linked_list.add_to_tail(2)
print('traverse from head')
double_linked_list.print_all()
输出结果如下所示:
traverse from head
1
10
90
100
2
print('traverse from tail')
double_linked_list.print_all(True)
输出结果如下所示:
traverse from tail
2
100
90
10
1
接下来,让我们看看以上定义的每一种方法,它们的空间复杂度和时间复杂度是多少。
add_to_tail
,从表尾新增一个节点,它的空间复杂度是O(1),而时间复杂度是O(1)remove_from_tail
,从表尾删除一个节点,它的空间复杂度是O(1),而时间复杂度是O(1)add_to_head
,从表头新增一个节点,它的空间复杂度是O(1),而时间复杂度是O(1)remove_from_head
,从表头删除一个节点,它的空间复杂度是O(1),而时间复杂度是O(1)empty
,判断双向链表是否为空链表,它的空间复杂度是O(1),而时间复杂度是O(1)print_all
可以顺序或反向遍历整个链表,它的空间复杂度是O(1),而时间复杂度是O(n)从以上分析可知,除了遍历的时间复杂度与链表的节点个数成正比,其它操作的时间复杂度均是O(1)。另外,双向链表可以在表头或表尾增加或删除节点,因此,这种特性非常适合双端队列。
{{ c.user.name }}
{{ c.content }}