循环链表相较于单链表,将末尾结点的连接域指向了头结点,就类似于将播放器的顺序播放改成了列表循环
双向链表相较于之前的链表多了上一节点连接域,在双向链表中,游标的移动方向可以不只是单一的向后移动,还增加了向前移动的功能。
计划实现以下功能
class Node:
def __init__(self, elem):
self.elem = elem
self.next = None
class LoopLinked:
def __init__(self, node=None):
self.__head = node
if node:
node.next = self.__head
def is_empty(self):
"""判断链表是否为空"""
# 判断头结点的值是否为空
return self.__head is None
def length(self):
"""判断链表长度"""
# 初始化游标
cur = self.__head
# 判断是否为空
if self.__head is None:
return
# 长度计算变量
count = 1
# 判断游标指向是否为空
while cur.next is not self.__head:
# 指向下一个结点,同时计数器加一
cur = cur.next
count += 1
return count
def add(self, elem):
"""头部添加元素"""
# 创建新结点
newNode = Node(elem)
# 判断是否为空链表
if self.is_empty():
self.__head = newNode
newNode.next = self.__head
else:
# 创建游标
cur = self.__head
# 将原头结点坐标给新结点,同时将新结点坐标给头结点,再将尾结点指向新结点
while cur.next != self.__head:
cur = cur.next
newNode.next, self.__head = self.__head, newNode
cur.next = newNode
def append(self, elem):
"""尾部添加元素"""
# 新建结点
newNode = Node(elem)
# 判断是否为空链表
if self.is_empty():
# 如果是空链表就将头游标指向新结点
self.__head = newNode
newNode.next = self.__head
else:
# 初始化游标
cur = self.__head
# 将游标移动到末尾
while cur.next is not self.__head:
cur = cur.next
# 将尾结点指向新结点,同时将新结点执行头结点
cur.next, newNode.next = newNode, self.__head
def travel(self):
"""遍历整个链表"""
# 初始化游标
cur = self.__head
# 输出每个结点的elem
while cur.next is not self.__head:
print(cur.elem, end=' ')
cur = cur.next
print(cur.elem)
def insert(self, pos, elem):
"""指定位置添加元素"""
# 判断插入位置
if pos <= 0:
self.add(elem)
elif pos > (self.length() - 1):
self.append(elem)
else:
# 新建结点
newNode = Node(elem)
# 创建游标
cur = self.__head
# 创建计数器
count = 0
# 将游标定位到指定位置前一位结点上
while count < (pos - 1):
count += 1
cur = cur.next
# 将游标位置的的next给新结点,将新结点的位置给游标
newNode.next, cur.next = cur.next, newNode
def position(self, pos):
"""根据位置读取元素"""
# 判断输入位置是否在链表中
if 0 <= pos <= (self.length() - 1):
# 创建游标
cur = self.__head
# 创建计数器
count = 0
# 将游标移动到指定位置
while count < pos:
count += 1
cur = cur.next
return cur.elem
else:
return False
def element(self, elem):
"""输出元素所在位置"""
# 创建游标和计数器
cur = self.__head
count = 0
while True:
# 判断游标指向元素是否为输入元素
if cur.elem == elem:
return count
# 判断测试的长度是否已经超出
elif cur.next is self.__head:
return False
cur = cur.next
count += 1
def del_add(self):
"""删除首结点"""
# 创建游标
cur = self.__head
# 将尾结点重新指向新的头结点
while cur.next != self.__head:
cur = cur.next
# 将首节点后移
self.__head = self.__head.next
# 让尾结点指向新的首节点
cur.next = self.__head
def del_app(self):
"""删除尾结点"""
# 创建游标
cur = self.__head
pre = None
while cur.next != self.__head:
pre, cur = cur, cur.next
pre.next = self.__head
def remove(self, elem):
"""根据指定元素删除"""
cur = self.__head
pre = None
while cur:
# 判断游标指向元素是否为输入元素
if cur.elem == elem:
# 判断是否删除的为首节点
if pre is None:
self.del_add()
return
# 判断是否删除的为尾结点
if cur.next is self.__head:
self.del_app()
return
else:
pre.next = cur.next
break
elif cur.next == self.__head:
return
# 游标后移
else:
pre, cur = cur, cur.next
def delete(self, pos):
"""根据位置删除"""
# 创建游标以及副游标
cur = self.__head
pre = None
# 判断输入是否在链表中
if 0 <= pos <= (self.length() - 1):
# 判断是否为首结点
if pos == 0:
self.del_add()
return
# 判断是否为尾结点
elif pos == self.length():
self.del_app()
return
else:
count = 0
while count < pos:
count += 1
pre, cur = cur, cur.next
pre.next = cur.next
def clear(self):
"""清空链表"""
self.__head = None
class DoubleNode:
def __init__(self, elem):
self.elem = elem
self.next = None
self.prev = None
我们将双向循环链表和循环链表对比,如有相同的就不在重复编写。
双向结点和单向结点主要在添加和删除结点的时候有所不同。
class Linked:
def __init__(self, node=None):
self.__head = node
if node:
node.next = node
node.prev = node
def add(self, elem):
"""头部添加元素"""
# 创建新结点
newNode = DoubleNode(elem)
# 判断是否为空链表
if self.is_empty():
self.__head = newNode
newNode.prev, newNode.next = self.__head, self.__head
else:
# 将新结点指向原头结点
newNode.next = self.__head
# 将尾结点指向新结点
self.__head.prev.next = newNode
# 将新结点指向尾结点
newNode.prev = self.__head.prev
# 将原头结点指向新结点
self.__head.prev = newNode
# 将原头结点定义为新结点
self.__head = newNode
def append(self, elem):
"""尾部添加元素"""
# 新建结点
newNode = DoubleNode(elem)
# 判断是否为空链表
if self.is_empty():
self.__head = newNode
newNode.prev, newNode.next = self.__head, self.__head
else:
# 将原尾结点指向新结点
self.__head.prev.next = newNode
# 将新结点指向原尾结点
newNode.prev = self.__head.prev
# 将尾结点指向头结点
newNode.next = self.__head
# 将头结点指向尾结点
self.__head.prev = newNode
def insert(self, pos, elem):
"""指定位置添加元素"""
# 判断插入位置
if pos <= 0:
self.add(elem)
elif pos > (self.length() - 1):
self.append(elem)
else:
# 新建结点
newNode = DoubleNode(elem)
# 创建游标以及副游标
cur = self.__head
# 创建计数器
count = 0
# 将游标定位到指定位置前一位结点上
while count < (pos - 1):
count += 1
cur = cur.next
# 将新结点指向游标以及游标之后的结点
newNode.prev, newNode.next = cur, cur.next
# 将游标所在结点之后的结点指向新结点
cur.next.prev = newNode
# 将指针所在结点指向新结点
cur.next = newNode
def del_add(self):
"""删除首结点"""
# 创建指向尾结点的游标
cur = self.__head.prev
# 将头结点后移一位
self.__head = self.__head.next
# 将尾结点指向新的头结点
cur.next = self.__head
# 将新的头结点执行尾结点
self.__head.prev = self.__head
def del_app(self):
"""删除尾结点"""
# 创建游标并且指向尾结点
cur = self.__head.prev
# 将游标前移一位
cur = cur.prev
# 将游标所在结点指向头结点
cur.next = self.__head
# 将头结点指向游标所在位置
self.__head.prev = cur
def remove(self, elem):
"""根据指定元素删除"""
cur = self.__head
while cur:
# 判断游标指向元素是否为输入元素
if cur.elem == elem:
# 判断是否删除的为首节点
if self.__head.elem == elem:
self.del_add()
return
# 判断是否删除的为尾结点
if cur.next is self.__head:
self.del_app()
return
else:
cur.next.prev = cur.prev
cur.prev.next = cur.next
break
elif cur.next == self.__head:
return
# 游标后移
else:
cur = cur.next
def delete(self, pos):
"""根据位置删除"""
# 判断输入是否在链表中
if 0 <= pos <= (self.length() - 1):
# 判断是否为首结点
if pos == 0:
self.del_add()
return
# 判断是否为尾结点
elif pos == self.length():
self.del_app()
return
else:
# 创建游标以及计数器
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
cur.next.prev = cur.prev
cur.prev.next = cur.next