单向循环链表是单向链表的一个变形,其链表中最后一个节点的next区域不再为None,而是指向链表的头节点。
(上图中的单向循环链表前还有一个表描述信息)
参考代码:
class Node(object):
""" 节点 """
def __init__(self, elem):
self.elem = elem # 用来保存数据
self.next = None # 一开始让它指空
# 单向循环链表,即:单向链表的尾节点的next区指向头节点。
class SingleLinkCirList(object):
""" 单向循环链表 """
def __init__(self, node=None):
# 链表头是自己用的,不让用户访问,故使用私有
self.__head = node
# 注意是循环链表,如果初始化用户传入了一个node
if node:
node.next = node
def is_empty(self):
""" 判断链表是否为空 """
return self.__head == None
def length(self):
""" 返回链表的长度 """
# 如果是空链表
if self.is_empty():
return 0
cur = self.__head # cur 游标,用来遍历链表中的节点
# 因为空链表的情况已经排除,故可以确定一定有头节点,则count计数从1开始。
count = 1 #用来记录数的数
while cur.next != self.__head:
count += 1
cur = cur.next
return count
# 由于尾结点指向了头节点,故循环遍历节点判断是否结尾要注意
def travel(self):
""" 遍历整个链表 """
# 如果是空链表就直接返回
if self.is_empty():
return
cur = self.__head
while cur.next != self.__head:
# print(cur.elem)
print(cur.elem, end=' ') # 用空格代替换行
cur = cur.next
# 由于最后一个节点没有进入循环,故退出循环一定要打印它
print(cur.elem)
def add(self, item):
""" 链表头部添加元素 (头插法)"""
# 一个新节点
node = Node(item)
# 如果是空链表
if self.is_empty():
node.next = node
self.__head = node
return
# 先找到尾结点
cur = self.__head
while cur.next != self.__head:
cur = cur.next
# 循环结束后,cur就是最后一个节点
# 尾结点指向node
cur.next = node
# node指向头节点
node.next = self.__head
self.__head = node
def append(self, item):
""" 链表尾部添加元素 (尾插法)"""
node = Node(item)
# 判断链表是否为空
if self.is_empty(): # 如果为空
self.__head = node # 就把链表的头部指向这个新节点(node)
node.next = self.__head
else: # 链表不空
cur = self.__head
while cur.next != self.__head: # 遍历链表,找到最后一个节点
cur = cur.next
cur.next = node # 将新节点加入链表尾部
node.next = self.__head
def insert(self, pos, item): # pos 的数数也是从0开始
""" 指定位置添加元素
:param pos 从0开始
"""
# 由于pos是用户传入的,故要对pos的值进行考虑
if pos <= 0: # 认为用户要在链表头部插入,即为头插法
self.add(item)
elif pos > (self.length()-1): #认为用户想要在链表尾部插入,即为尾插法
self.append(item)
else:
# 由于是在中间部分插入,那就和单链表一样,故代码不用改。
node = Node(item) # 创建要加入的节点
pre = self.__head
count = 0
#遍历找位置
while count < (pos-1):
count += 1
pre = pre.next
# 当循环退出后,pre指向pos-1的位置
node.next = pre.next
pre.next = node
def remove(self, item):
""" 删除节点 (遇到的第一个节点)
"""
# 空链表
if self.is_empty():
return
cur = self.__head
pre = None
while cur.next != self.__head:
if cur.elem == item:
#找到要删除的节点
# 判断是否是头节点
if cur == self.__head:
#需要找到尾结点
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 True
else: #不是要找的节点,就移动到下一个
pre = cur
cur = cur.next
# 退出循环,cur为尾结点:
if cur.elem == item:
# 只有一个节点
if cur == self.__head:
self.__head = None
else:
# 有很多节点
pre.next = cur.next
return True
return False
def search(self, item):
""" 查找节点是否存在 """
# 是否是空链表
if self.is_empty():
return False
# 不是空链表
cur = self.__head
while cur.next != self.__head:
if cur.elem == item:
return True
else:
cur = cur.next
# 对尾结点进行判断
if cur.elem == item:
return True
return False
# 加入测试
if __name__ == "__main__":
ll = SingleLinkCirList()
print(ll.is_empty())
print(ll.length())
print("*"*50)
ll.append(1)
print(ll.is_empty())
print(ll.length())
print("*"*50)
ll.append(2)
ll.append(2)
ll.append(2)
ll.append(2)
ll.append(2)
ll.add(8) # 8 1 2 2 2 2 2
#!! 对程序进行测试时,要考虑所有情况,特别是边界情况
ll.insert(-1, 9) # 9 8 1 2 2 2 2 2
ll.insert(0, 100) # 100 9 8 1 2 2 2 2 2
ll.insert(2, 200) # 100 9 200 8 1 2 2 2 2 2
print(ll.is_empty())
print(ll.length())
print("遍历链表:")
ll.travel()
ll.insert(6, 600) # 100 9 200 8 1 2 600 2 2 2 2
# ll.insert(100, 1000)
print()
print("遍历链表:")
ll.travel()
# 测试search
print()
print("查找元素600", ll.search(600))
print("查找元素500", ll.search(500))
print("查找元素9", ll.search(9))
# 测试remove
print("先遍历当前链表:")
ll.travel()
print("\n删除2", ll.remove(2))
ll.travel()
print("\n删除9", ll.remove(9))
ll.travel()
print("\n再删除2", ll.remove(2))
ll.travel()
print("\n再删除100", ll.remove(100))
ll.travel()
print("尾部加入70")
ll.append(70)
ll.travel()
print("删除70")
ll.remove(70)
ll.travel()
print("*"*20)
scl = SingleLinkCirList()
print("一个新的单向循环链表,就加入一个元素1")
scl.add(1)
scl.travel()
print("删除1")
scl.remove(1)
scl.travel()
print("此时是空链表,在空链表上删除2")
scl.remove(2)
scl.travel()