一、单项循环链表长度&判空实现
1.循环链表定义
是一种特殊的单链表,唯一的区别是:
单链表的尾结点指针指向空地址,表示这就是最后的结点了;
循环链表的尾结点指针是指向链表的头结点。
2.is_empty()
与单链表一致。
def is_empty(self):
'''判断是否为空'''
return self.__head == None
3.length()
cur.next = self.__head
时循环结束,且因最后一次循环不会执行,所以count不会加1,所以count要哦才能够1开始计数。
并且为空时,直接返回0。
def length(self):
'''链表长度'''
#判断是否为空链表
if self.is_empty():
return 0
# cur即游标,指向首节点,用来遍历
cur = self.__head
count = 1
# 当未到达尾部时
while cur.next != self.__head:
count += 1
# 将游标向后移动一位
cur = cur.next
return count
二、单项循环链表遍历、头插法&尾插法
1.遍历travel()
cur.next = self.__head
时循环结束。
空链表时直接返回。
def travel(self):
'''遍历链表'''
#链表为空时
if self.is_empty():
return
cur = self.__head
while cur.next != self.__head:
print(cur.item, end=' ')
cur = cur.next
#退出循环时,cur指向尾节点,单独打印
print(cur.item)
2.头部添加add():
将新节点指向head的下一个节点,head指向新节点,尾节点指向新节点,第三步顺序可以在第一或第二步。
为空链表时,__head指向新节点,新节点指向自己(即__head)。
def add(self, item):
'''链表尾部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
# 判断链表是否为空,若为空,则将__head指向新节点,新节点指向头部
if self.is_empty():
self.__head = node
node.next = self.__head #等价于node.next = node
#若不为空
else:
cur = self.__head
#找到尾部
while cur.next != self.__head:
cur = cur.next
#新节点指向__head
node.next = self.__head
#__head指向新节点
self.__head = node
# 将尾节点指向新节点,此句可以在self.__head = node或node.next = self.__head之前
cur.next = node
3.append()尾部添加
找到尾节点:
尾节点指向新节点,新节点指向头部。
也要判断是否为空链表。
def append(self, item):
'''链表尾部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
#判断是否为空链表
if self.is_empty():
self.__head = node
node.next = self.__head # 等价于node.next = node
else:
cur = self.__head
# 找到尾节点
while cur.next != self.__head:
cur = cur.next
# 尾节点指向新节点
cur.next = node
#新节点指向__head
node.next = self.__head
三、单项循环链表删除&搜索
1.insert()
新节点指向目标位置,目标位置前一个位置指向新节点。
def insert(self, pos, item):
'''指定位置添加元素'''
# 若指定位置为第一个位置之前,则执行头部插入
if pos <= 0:
self.add(item)
# 若指定位置超过链表尾部,则执行尾部插入
elif pos > self.length() - 1:
self.append(item)
# 找到指定位置
else:
node = Node(item)
cur = self.__head
count = 0
while count < pos - 1:
count += 1
cur = cur.next
# 将新节点node的next指向插入位置的节点
node.next = cur.next
# 将插入位置的前一个节点的next指向新节点
cur.next = node
2.search()
如果为空,直接返回False。
并且在循环后判断尾节点是否符合。
def search(self, item):
'''查找节点是否存在'''
if self.is_empty():
return False
cur = self.__head
while cur.next != self.__head:
# 判断第一个节点
if cur.item == item:
return True
# 未找到,继续向后移动
else:
cur = cur.next
#循环退出,cur指向尾节点
if cur.item == item:
return True
return False
3.remove()
如果删除的节点为头节点:
如果不止头节点一个节点,__head指向当前的下一个节点;
如果只有head一个节点,则__head指向None。
如果删除的节点不是头节点:pre.next = cur.next
,并且需要循环,同时要对尾节点进行判断。
def remove(self, item):
'''删除节点'''
#如果链表为空,直接返回
if self.is_empty():
return
cur = self.__head
pre = None
#头节点的元素就是要删除的元素
if cur.item == item:
#链表中的节点不止一个
if cur.next != self.__head:
while cur.next != self.__head:
cur = cur.next
#循环结束,cur指向尾节点
cur.next = self.__head.next
self.__head = cur.next
#只有一个节点
else:
self.__head = None
#头节点不是要删除的元素
else:
while cur.next != self.__head:
if cur.item == item:
#删除
pre.next = cur.next
return
#继续往后遍历
else:
pre = cur
cur = cur.next
#要删除的节点是最后一个元素时
if cur.item == item:
pre.next = cur.next #pre.next = self.__head也可
整个单项循环链表的实现如下:
class Node(object):
'''节点'''
def __init__(self,item):
'''初始化'''
self.item = item
#next是下一个节点的标识
self.next = None
class SinCycLinkList(object):
'''循环链表'''
def __init__(self,node = None):
self.__head = None
if node:
node.next = node
def is_empty(self):
'''判断是否为空'''
return self.__head == None
def length(self):
'''链表长度'''
#判断是否为空链表
if self.is_empty():
return 0
# cur即游标,指向首节点,用来遍历
cur = self.__head
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.item, end=' ')
cur = cur.next
#退出循环时,cur指向尾节点,单独打印
print(cur.item)
def add(self, item):
'''链表头部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
# 判断链表是否为空,若为空,则将__head指向新节点,新节点指向头部
if self.is_empty():
self.__head = node
node.next = self.__head #等价于node.next = node
#若不为空
else:
cur = self.__head
#找到尾部
while cur.next != self.__head:
cur = cur.next
#新节点指向__head
node.next = self.__head
#__head指向新节点
self.__head = node
# 将尾节点指向新节点,此句可以在self.__head = node或node.next = self.__head之前
cur.next = node
def append(self, item):
'''链表尾部添加元素'''
# 创建一个保存数据的节点
node = Node(item)
#判断是否为空链表
if self.is_empty():
self.__head = node
node.next = self.__head # 等价于node.next = node
else:
cur = self.__head
# 找到尾节点
while cur.next != self.__head:
cur = cur.next
# 尾节点指向新节点
cur.next = node
#新节点指向__head
node.next = self.__head
def insert(self, pos, item):
'''指定位置添加元素'''
# 若指定位置为第一个位置之前,则指向头部插入
if pos <= 0:
self.add(item)
# 若指定位置超过链表尾部,则执行尾部插入
elif pos > self.length() - 1:
self.append(item)
# 找到指定位置
else:
node = Node(item)
cur = self.__head
count = 0
while count < pos - 1:
count += 1
cur = cur.next
# 将新节点node的next指向插入位置的节点
node.next = cur.next
# 将插入位置的前一个节点的next指向新节点
cur.next = node
def remove(self, item):
'''删除节点'''
#如果链表为空,直接返回
if self.is_empty():
return
cur = self.__head
pre = None
#头节点的元素就是要删除的元素
if cur.item == item:
#链表中的节点不止一个
if cur.next != self.__head:
while cur.next != self.__head:
cur = cur.next
#循环结束,cur指向尾节点
cur.next = self.__head.next
self.__head = cur.next
#只有一个节点
else:
self.__head = None
#头节点不是要删除的元素
else:
while cur.next != self.__head:
if cur.item == item:
#删除
pre.next = cur.next
return
#继续往后遍历
else:
pre = cur
cur = cur.next
#要删除的节点是最后一个元素时
if cur.item == item:
pre.next = cur.next #pre.next = self.__head也可
def search(self, item):
'''查找节点是否存在'''
if self.is_empty():
return False
cur = self.__head
while cur.next != self.__head:
# 判断第一个节点
if cur.item == item:
return True
# 未找到,继续向后移动
else:
cur = cur.next
#循环退出,cur指向尾节点
if cur.item == item:
return True
return False
s = SinCycLinkList()
print(s.is_empty())
print(s.length())
s.add(1)
s.add(2)
s.add(3)
s.add(4)
s.travel()
s.append(5)
s.append(6)
s.insert(-1,7)
s.insert(12,8)
s.insert(5,9)
s.travel()
print(s.search(3))
print(s.search(10))
s.remove(6)
s.travel()
对单项循环链表进行测试,结果如下:
True
0
4 3 2 1
7 4 3 2 1 9 5 6 8
True
False
7 4 3 2 1 9 5 8
小结:
单项循环链表的实现要结合单链表,要对它们的相同和不同之处进行比较。
很显然,单向循环链表实现的时候要考虑的情况比单链表更多,也更复杂,要在对比中学习,举一反三。
并且在每一个方法中cur.next != self.__head
这个循环判断条件都出现了,所以找到实现的边界条件极为重要。
同时,要考虑各种特殊情况,比如链表为空,只有一个节点,对尾节点的处理等情况。