双向链表
双向链表有两个指针域,一个指向前驱结点,一个指向后继结点
创建一个结点类:
因为是双向链表,所以需要前后相通,就是比单链表多了一个前驱指针
数据域data、前驱指针pre,后继指针next
class Node(object):
"""创建一个结点类"""
def __init__(self, data):
self.data = data
self.pre = None
self.next = None
创建一个创建双向链表的类:
判断是否为空、获取长度、遍历链表、查找指定结点是否存在,这些函数和单链表的一样
(只是最简单的方法一样,双向链表还有其它方法遍历或者查找指定结点)
class CreateDoubleLinkedList(object):
"""创建一个创建双向链表的类"""
def __init__(self):
self.head = None
def is_empty(self):
"""判断双向链表是否为空链表"""
return self.head is None
def length(self):
"""获取双向链表的长度"""
cur = self.head
count = 0
while cur is not None:
count += 1
cur = cur.next
return count
def traversal(self):
"""遍历双向链表"""
cur = self.head
if self.is_empty():
print("链表为空!")
return
while cur is not None:
print(cur.data)
cur = cur.next
def node_is_exist(self, data):
"""查找指定结点是否存在"""
cur = self.head
while cur is not None:
if cur.data == data:
return True
else:
cur = cur.next
return False
在头部添加结点:
插入的大体过程和单链表很相似,只是在插入结点的过程中,我们需要注意的就是:每个结点都有两个指针,都需要设置正确的指向。
def add_first(self, data):
"""在头部添加结点"""
node = Node(data)
if self.is_empty():
self.head = node
else:
# 新结点向后指向头结点
node.next = self.head
# 头结点向前指向新结点
self.head.pre = node
# 将头结点的称号给新结点
self.head = node
在尾部添加结点:
def add_last(self, data):
"""在尾部添加结点"""
node = Node(data)
if self.is_empty():
self.head = node
else:
cur = self.head
# 指针移动到尾部
while cur.next is not None:
cur = cur.next
# 尾结点的后继指针指向新结点
cur.next = node
# 新结点的前驱指针指向尾结点
node.pre = cur
在指定位置添加结点:
def insert_node(self, index, data):
"""在指定位置添加结点"""
if index < 0 or index > self.length():
print("结点位置错误!")
return False
elif index == 0:
self.add_first(data)
elif index == self.length():
self.add_last(data)
else:
node = Node(data)
cur = self.head
pres = None
count = 0
# 移动到要添加的位置
while count < index:
pres = cur
cur = cur.next
count += 1
# 新结点和它前面的结点互指
pres.next = node
node.pre = pres
# 新结点和它后面的结点互指
node.next = cur
cur.pre = node
删除指定结点:
当链表不为空的时候,我们需要考虑三种情况:
- 要删除是是头结点
- 要删除的是尾结点
- 要删除的是中间任意结点
(需要注意的就是:每个结点都需要改变两个指针链)
def remove_node(self, data):
"""删除指定结点"""
if self.is_empty():
print("删除失败,链表为空!")
return False
elif data == self.head.data:
self.head.next.pre = None
self.head = self.head.next
else:
cur = self.head
# 移动到要删除结点的位置
while cur.data != data:
cur = cur.next
# 当前结点的后继结点为空,说明是尾结点
if cur.next is None:
cur.pre.next = None
cur.pre = None
else:
cur.pre.next = cur.next
cur.next.pre = cur.pre
假如我们只断掉了一根指针链,会怎么样?
就比如这样写(以上面删除尾结点的代码为例):
# 当前结点的后继结点为空,说明是尾结点
if cur.next is None:
cur.pre.next = None
# 将尾结点指向前驱结点的那个指针链留着
# cur.pre = None
# 打印一下被删掉的尾结点的前驱结点数据
print("测试:", cur.pre.data)
如果尾结点已经被删掉了,那么cur指向为空,最后print那一行,空类型是没有前驱结点pre属性的,测试运行之后,肯定会报错。
但是因为我们只删掉了一个指针链,所以测试结果还是会打印出:被删除掉结点的前驱结点数据,因为被删除结点的前驱指针链没有被断掉。
接下来我们正向遍历一次链表,发现:没有被刚才删除的结点数据,为什么?因为向右的指针链已经被断掉了,遍历不到它,我们以为被它被删除掉了,其实没有。
所以:双向链表必须要端两根指针链,才能彻底删除掉。
(可以自行写一个反向遍历的函数,看一看效果)
主函数测试:
if __name__ == '__main__':
lists = CreateDoubleLinkedList()
lists.add_last(3)
lists.add_first(2)
lists.add_first(1)
lists.add_last(5)
lists.insert_node(3, 4)
lists.traversal()
print("链表是否为空:", lists.is_empty())
print("获取链表长度:", lists.length())
print("改结点是否存在:", lists.node_is_exist(2))
lists.remove_node(1)
lists.remove_node(5)
print("删除结点之后的遍历:")
lists.traversal()
测试结果截图:
完整代码:
class Node(object):
"""创建一个结点类"""
def __init__(self, data):
self.data = data
self.pre = None
self.next = None
class CreateDoubleLinkedList(object):
"""创建一个创建双向链表的类"""
def __init__(self):
self.head = None
def is_empty(self):
"""判断双向链表是否为空链表"""
return self.head is None
def length(self):
"""获取双向链表的长度"""
cur = self.head
count = 0
while cur is not None:
count += 1
cur = cur.next
return count
def traversal(self):
"""遍历双向链表"""
cur = self.head
if self.is_empty():
print("链表为空!")
return
while cur is not None:
print(cur.data)
cur = cur.next
def node_is_exist(self, data):
"""查找指定结点是否存在"""
cur = self.head
while cur is not None:
if cur.data == data:
return True
else:
cur = cur.next
return False
def add_first(self, data):
"""在头部添加结点"""
node = Node(data)
if self.is_empty():
self.head = node
else:
# 新结点向后指向头结点
node.next = self.head
# 头结点向前指向新结点
self.head.pre = node
# 将头结点的称号给新结点
self.head = node
def add_last(self, data):
"""在尾部添加结点"""
node = Node(data)
if self.is_empty():
self.head = node
else:
cur = self.head
# 指针移动到尾部
while cur.next is not None:
cur = cur.next
# 尾结点的后继指针指向新结点
cur.next = node
# 新结点的前驱指针指向尾结点
node.pre = cur
def insert_node(self, index, data):
"""在指定位置添加结点"""
if index < 0 or index > self.length():
print("结点位置错误!")
return False
elif index == 0:
self.add_first(data)
elif index == self.length():
self.add_last(data)
else:
node = Node(data)
cur = self.head
pres = None
count = 0
# 移动到要添加的位置
while count < index:
pres = cur
cur = cur.next
count += 1
# 新结点和它前面的结点互指
pres.next = node
node.pre = pres
# 新结点和它后面的结点互指
node.next = cur
cur.pre = node
def remove_node(self, data):
"""删除指定结点"""
if self.is_empty():
print("删除失败,链表为空!")
return False
elif data == self.head.data:
self.head.next.pre = None
self.head = self.head.next
else:
cur = self.head
# 移动到要删除结点的位置
while cur.data != data:
cur = cur.next
# 当前结点的后继结点为空,说明是尾结点
if cur.next is None:
cur.pre.next = None
cur.pre = None
else:
cur.pre.next = cur.next
cur.next.pre = cur.pre
if __name__ == '__main__':
lists = CreateDoubleLinkedList()
lists.add_last(3)
lists.add_first(2)
lists.add_first(1)
lists.add_last(5)
lists.insert_node(3, 4)
lists.traversal()
print("链表是否为空:", lists.is_empty())
print("获取链表长度:", lists.length())
print("改结点是否存在:", lists.node_is_exist(2))
lists.remove_node(1)
lists.remove_node(5)
print("删除结点之后的遍历:")
lists.traversal()