单向循环链表是单向链表的一个拓展,主要区别在于单向循环链表尾节点的next不再指向None,而是指向链表的头节点。
下面通过代码一步步实现单向循环链表并附上注释和测试,主要实现以下几个基本方法:
- is_empty() 链表是否为空
- length() 链表长度
- travel() 遍历整个链表
- add(item) 链表头部添加元素
- append(item) 链表尾部添加元素
- insert(pos, item) 指定位置添加元素
- remove(item) 删除从头节点开始的第一个相同的节点
- search(item) 查找节点是否存在
首先照例定义节点类对象:
class Node():
def __init__(self, item):
self.item = item
self.next = None
然后开始写单向循环链表(Single Cyclic LInked List)的类:
class SCLL():
###别忘了先定义一个带默认值的头节点!!!
def __init__(self, node = None):
self.__head = node
if self.__head: #这里要注意和无循环链表的区别了
node.next = self.__head #如果头节点不为空,则使尾节点指向头节点
def is_empty(self):
return self.__head == None
def length(self):
if self.is_empty():
return 0
else:
count = 1 #根据条件循环结束方式,使count从1开始计数
cur = self.__head
while cur.next != self.__head:
count +=1
cur = cur.next
return count
def travel(self):
cur = self.__head
if self.is_empty():
return None
else:
while cur.next != self.__head:
print(str(cur.item), end = " ")
cur = cur.next
# if cur.next == self.__head: 这里不需要再用if了,直接输出就好
print(str(cur.item))
def add(self, item):
cur = self.__head
node = Node(item)
if self.is_empty(): #先判空,是的话直接添加
self.__head = node
node.next = self.__head
else:
while cur.next != self.__head: #链表非空的话,先遍历找到尾节点
cur = cur.next
node.next = self.__head #在头部添加,注意赋值顺序
self.__head = node
cur.next = self.__head #这里使遍历找到的尾节点重新指向新的头节点
def append(self, item):
cur = self.__head
node = Node(item)
if self.is_empty(): #照例先判空
self.__head = node
node.next = self.__head
else:
while cur.next != self.__head: #遍历找到尾节点
cur = cur.next
cur.next = node #在尾节点处添加,并指向头节点
node.next = self.__head
def insert(self, pos, item):
cur = self.__head
node = Node(item)
if pos <= 0: #pos<=0相当于头插法
self.add(item)
elif pos >= self.length(): #pos比length还大相当于尾插法
self.append(item)
else:
pre_cur = None #这里像单链表一样定义一个位于cur前一个的游标
count = 0 #开始遍历,找到下标为pos的节点
while count != pos:
pre_cur = cur
cur = cur.next
count += 1
node.next = pre_cur.next #遍历找到之后开始相互赋值了,注意先后顺序
pre_cur.next = node
def remove(self, item):
cur = self.__head
node = Node(item)
if self.is_empty(): #先判空,是的话直接return
return
else:
pre_cur = None
while cur.item != node.item: #这里先开始遍历
if cur.next == self.__head: #如果到头了还没找到那就return了,注意要先判断
return
pre_cur = cur
cur = cur.next
if ((pre_cur == None) and (cur.next == self.__head)): #特殊情况1:只有一个节点时
cur = None
elif ((pre_cur == None) and (cur.next != self.__head)): #特殊情况2:删除首节点
# self.__head = cur.next
tail = cur #定义一个临时游标,用于遍历找到尾节点
while tail.next != self.__head:
tail = tail.next
tail.next = cur.next #注意要先操作临时游标,此时的cur还是首节点
self.__head = cur.next #让self.__head指向首节点的next
### 下面两行是要删除的节点为尾节点的情况,验证可知此情况可当做一般情况处理
# elif ((pre_cur != None) and (cur.next == self.__head)):
# pre_cur.next = cur.next
else: #一般情况下处理节点
pre_cur.next = cur.next
def search(self, item):
cur = self.__head
if self.is_empty(): #链表为空时直接返回
return False
else:
node = Node(item)
while cur.item != node.item: #遍历寻找
if cur.next == self.__head: #到尾节点时返回
return False
cur = cur.next
return True
下面开始测试:
if __name__ == "__main__":
#定义单向循环链表scll
scll = SCLL()
#测试尾插法
scll.append(0)
scll.append(1)
scll.append(2)
scll.append(3)
print("链表scll长度?\n" + str(scll.length()) + "\n")
print("遍历链表scll:")
scll.travel()
print("\n")
#测试insert,注意每插入一个新的元素,后面的元素下标都变了
scll.insert(0, -0.5)
print("遍历链表scll:")
scll.travel()
print("\n")
scll.insert(1, 555)
scll.insert(3, 555)
scll.insert(6, 2.5)
print("遍历链表scll:")
scll.travel()
print("\n")
#测试头插法
scll.add(-1)
scll.add(-2)
print("遍历链表scll:")
scll.travel()
print("\n")
#测空
print("链表scll是否为空?\n" + str(scll.is_empty()) + "\n")
#测长
print("链表scll长度?\n" + str(scll.length()) + "\n")
#遍历打印
print("遍历链表scll:")
scll.travel()
print("\n")
#测试search,返回True或False
print(str(scll.search(555)) + "\n")
print(str(scll.search(-2)) + "\n")
print(str(scll.search(3)) + "\n")
print(str(scll.search(123456)) + "\n")
#测试remove中间节点,结束后打印
scll.remove(555)
print("遍历链表scll:")
scll.travel()
print("\n")
#测试remove头节点,并打印
scll.remove(-2)
print("遍历链表scll:")
scll.travel()
print("\n")
#测试remove尾节点并打印
scll.remove(3)
print("遍历链表scll:")
scll.travel()
print("\n")
#测试remove一个不存在的节点
scll.remove(123456)
print("遍历链表scll:")
scll.travel()
print("\n")
可以看到测试部分基本包含了每个方法的特殊情况,下面运行一下看看结果如何:
链表scll长度?
4
遍历链表scll:
0 1 2 3
遍历链表scll:
-0.5 0 1 2 3
遍历链表scll:
-0.5 555 0 555 1 2 2.5 3
遍历链表scll:
-2 -1 -0.5 555 0 555 1 2 2.5 3
链表scll是否为空?
False
链表scll长度?
10
遍历链表scll:
-2 -1 -0.5 555 0 555 1 2 2.5 3
True
True
True
False
遍历链表scll:
-2 -1 -0.5 0 555 1 2 2.5 3
遍历链表scll:
-1 -0.5 0 555 1 2 2.5 3
遍历链表scll:
-1 -0.5 0 555 1 2 2.5
遍历链表scll:
-1 -0.5 0 555 1 2 2.5
结果如期。