线性表
链表
双向链表
一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个前驱节点,当此节点为第一个节点时,指向空值;而另一个指向下一个后继节点,当此节点为最后一个节点时,指向空值。
双向链表的操作
操作 | 说明 |
---|---|
is_empty() | 链表是否为空 |
length() | 链表长度 |
travel() | 遍历链表 |
add(item) | 链表头部添加 |
append(item) | 链表尾部添加 |
insert(pos, item) | 指定位置添加 |
remove(item) | 删除节点 |
search(item) | 查找节点是否存在 |
双向链表操作具体实现
- 指定位置插入节点
- 删除元素
class DoubleNode:
'''双向链表结点'''
def __init__(self, item):
self.item = item
self.prev = None
self.next = None
class DoubleLinkList:
'''双向链表'''
# 构造函数、判空、求长、遍历、查找与单链表相同,不涉及“前驱结点连接域”和“后继结点链接域”
# 可以直接继承Single_link_list模块,实现代码复用
def __init__(self, doublenode=None):
self.__head = doublenode
def is_empty(self):
"""判断链表是否为空"""
return self.__head == None
def length(self):
"""链表长度"""
# 遍历计数
cur = self.__head
count = 0
while cur != None:
count += 1
cur = cur.next
return count
def travel(self):
"""遍历整个链表"""
# 遍历打印
cur = self.__head
while cur != None:
print(cur.item, end=' ')
cur = cur.next
print()
def search(self, item):
"""查找节点是否存在,并返回True或者False"""
cur = self.__head
while cur != None:
if cur.item == item:
return True
else:
cur = cur.next
else:
return False
# add、append、insert、remove与单链表有所差别
def add(self, item):
"""链表头部添加元素,头插法"""
doublenode = DoubleNode(item)
doublenode.next = self.__head
self.__head = doublenode
doublenode.next.prev = doublenode # 双向链表多一个指向前驱结点的链接域,指向上一个结点
def append(self, item):
"""链表尾部添加元素,尾插法"""
doublenode = DoubleNode(item)
if self.is_empty():
self.__head = doublenode
else:
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = doublenode
doublenode.prev = cur # 双向链表尾插法多指定一个前驱节点
def insert(self, pos, item):
"""指定位置添加元素"""
# cur.prev就可以指向前个结点,不用设定pre游标
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
# 退出循环时此时cur指向pos位置
doublenode = DoubleNode(item)
doublenode.next = cur
doublenode.prev = cur.prev
cur.prev.next = doublenode
cur.prev = doublenode
def remove(self, item):
"""删除节点"""
# 双向链表有前后两个链接域,则只需一个游标进行遍历
cur = self.__head
while cur != None:
if cur.item == item:
if cur == self.__head:
self.__head = cur.next
if cur.next:
# 考虑只有一个结点的特殊情况,此时cur.next指向None,None没有None.next,报错。
# 当cur.next为None,则if False跳过条件语句不报错
cur.next.prev = None
else:
cur.prev.next = cur.next
if cur.next:
# 考虑在链表末尾添加结点的特殊情况,此时cur.next指向None,None没有None.next,报错。
# 当cur.next为None,则if False跳过条件语句不报错
cur.next.prev = cur.prev
break
else:
cur = cur.next
测试
if __name__ == '__main__':
dll = DoubleLinkList()
print(dll.is_empty())
print(dll.length())
dll.append(1)
print(dll.is_empty())
print(dll.length())
dll.append(2)
dll.add(8)
dll.append(3)
dll.append(4)
dll.append(5)
dll.append(6) # 8 1 2 3 4 5 6
dll.insert(-1, 9) # 索引为负,默认头部添加:9 8 1 2 3 4 5 6
dll.travel()
dll.insert(3, 100) # 在3索引处添加,其余节点后移:9 8 1 100 2 3 4 5 6
dll.travel()
dll.insert(10, 200) # 索引超出链表长度,默认尾部添加:9 8 1 100 2 3 4 5 6 200
dll.travel()
print(dll.search(100))
dll.remove(100) # 删除第一个匹配的节点:9 8 1 2 3 4 5 6 200
dll.travel()
print(dll.search(100))
dll.remove(9) # 删除头节点:8 1 2 3 4 5 6 200
dll.travel()
dll.remove(200) # 删除尾节点:8 1 2 3 4 5 6
dll.travel()
执行结果:
True
0
False
1
9 8 1 2 3 4 5 6
9 8 1 100 2 3 4 5 6
9 8 1 100 2 3 4 5 6 200
True
9 8 1 2 3 4 5 6 200
False
8 1 2 3 4 5 6 200
8 1 2 3 4 5 6
单向循环链表
单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。
单向循环链表的操作
操作 | 说明 |
---|---|
is_empty() | 链表是否为空 |
length() | 链表长度 |
travel() | 遍历链表 |
add(item) | 链表头部添加 |
append(item) | 链表尾部添加 |
insert(pos, item) | 指定位置添加 |
remove(item) | 删除节点 |
search(item) | 查找节点是否存在 |
单向循环链表操作具体实现
class SingleCircleNode:
"""单向循环链表的结点"""
def __init__(self, item):
self.item = item
self.next = None
class SingleCircleLinkList:
"""单向循环链表"""
# 验证特殊情况空列表是否也成立
def __init__(self, singlecirclenode=None): # 构造单个节点的单向循环链表
self.__head = singlecirclenode
if singlecirclenode != None: # 当不是空链表,单向循环列表需要连接循环
singlecirclenode.next = singlecirclenode
# 判空代码和单向链表相同
def is_empty(self):
"""判断链表是否为空"""
return self.__head == None
def length(self):
"""链表长度"""
# 遍历计数
# 计数项count初始值调整为1后,空列表不成立,if判断另外考虑
if self.is_empty():
return 0
else:
cur = self.__head
# 因为循环条件改成cur.next!=self.__head,当遍历到最后一个结点时不进入循环体,少一次计数,所以count初始值改为1
count = 1
# 因为cur的初始赋值为self.__head,所以循环判断条件只能选cur.next!=self.__head
while cur.next != self.__head:
count += 1
cur = cur.next
return count
def travel(self):
"""遍历整个链表"""
# 遍历打印
cur = self.__head
# 当为空链表时None.next报错
if cur == None:
return
else:
while cur.next != self.__head:
print(cur.item, end=' ')
cur = cur.next
# 退出循环时cur指向尾结点,但尾结点未进入循环体打印,需单独打印
print(cur.item)
def add(self, item):
"""链表头部添加元素,头插法"""
# 由于尾结点指针需指向头,所以头插法也要进行遍历
singlecirclenode = SingleCircleNode(item)
cur = self.__head
# 当链表为空,None.next报错
if self.is_empty():
self.__head = singlecirclenode
singlecirclenode.next = singlecirclenode
# 当链表只有单个结点也成立
else:
while cur.next != self.__head:
cur = cur.next
# 退出循环时cur指向尾结点
singlecirclenode.next = self.__head
self.__head = singlecirclenode
cur.next = singlecirclenode # 尾结点链接指向头部
def append(self, item):
"""链表尾部添加元素,尾插法"""
singlecirclenode = SingleCircleNode(item)
# 特殊情况,链表为空
if self.is_empty():
self.__head = singlecirclenode
singlecirclenode.next = singlecirclenode
# 特殊情况,只有单个结点也成立
else:
cur = self.__head
while cur.next != self.__head:
cur = cur.next
cur.next = singlecirclenode
singlecirclenode.next = self.__head
# 除pos <= 0和pos > (self.length() - 1)的特殊情况外,链表中间插入结点不涉及尾结点的链接循环,与单链表相同
def insert(self, pos, item):
"""指定位置添加元素"""
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
# 游标pre控制指定位置的前一节点的next属性
pre = self.__head
count = 0
# 当循环体退出后,要求pre指向pos-1位置
while count < (pos - 1):
count += 1
pre = pre.next
singlecirclenode = SingleCircleNode(item)
singlecirclenode.next = pre.next
pre.next = singlecirclenode
def remove(self, item):
"""删除节点"""
# 当删除的结点为头结点或尾结点时会影响单向循环链表的链接域,删除中间结点与单链表相同
if self.is_empty():
return
cur = self.__head
pre = None # 与游标cur相隔一个节点
while cur.next != self.__head:
if cur.item == item:
if pre == None: # 找到需删除的结点,且为头节点
# 需要新建游标,遍历找尾结点
rear = self.__head
while rear.next != self.__head:
rear = rear.next
self.__head = cur.next
rear.next = self.__head
else: # 中间结点,尾部结点不进入循环体
pre.next = cur.next
return # break跳出当前循环,return 跳出整个函数
else:
pre = cur
cur = cur.next
# 尾结点不进入循环,单独判断尾结点是否符合
if cur.item == item:
if cur==self.__head: # 通过判断cur是否移动,来确定是否只有单个结点
# 链表中只有一个需删除的节点,单个结点既是头结点又是尾结点,尾结点不进循环体
self.__head=None
else:
# 当尾结点是唯一结点时,pre=None,None.next报错
pre.next = cur.next
def search(self, item):
"""查找节点是否存在,并返回True或者False"""
if self.is_empty(): # 空链表,None.next会报错
return False
else:
cur = self.__head
while cur.next != self.__head: # 处理未进入循环的尾部结点
if cur.item == item:
return True
else:
cur = cur.next
if cur.item == item:
return True
else:
return False
测试
if __name__ == '__main__':
ll = SingleCircleLinkList()
print(ll.is_empty())
print(ll.length())
ll.append(1)
print(ll.is_empty())
print(ll.length())
ll.append(2)
ll.add(8)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6) # 8 1 2 3 4 5 6
ll.insert(-1, 9) # 索引为负,默认头部添加:9 8 1 2 3 4 5 6
ll.travel()
ll.insert(3, 100) # 在3索引处添加,其余节点后移:9 8 1 100 2 3 4 5 6
ll.travel()
ll.insert(10, 200) # 索引超出链表长度,默认尾部添加:9 8 1 100 2 3 4 5 6 200
ll.travel()
print(ll.search(100))
ll.remove(100) # 删除第一个匹配的节点:9 8 1 2 3 4 5 6 200
ll.travel()
print(ll.search(100))
ll.remove(9) # 删除头节点:8 1 2 3 4 5 6 200
ll.travel()
ll.remove(200) # 删除尾节点:8 1 2 3 4 5 6
ll.travel()
执行结果:
True
0
False
1
9 8 1 2 3 4 5 6
9 8 1 100 2 3 4 5 6
9 8 1 100 2 3 4 5 6 200
True
9 8 1 2 3 4 5 6 200
False
8 1 2 3 4 5 6 200
8 1 2 3 4 5 6