带环的单向链表:如果单向链表的尾节点next的指针指向自身的某个节点,则会在自身链表上形成一个环。
首先构造带环的单向链表:
- 指定一个闭合结点,也就是尾节点指向的结点
- 找到这个闭合结点
- 找到尾节点,尾节点指向闭合结点
代码如下:
在链表类中增加setCricle()函数,用来将创建环
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:cfl
@file:slinklist.py
@time:2021/12/13
@software:PyCharm
"""
class Node:
def __init__(self, data):
self.data = data
self.next = None
class SlinkList:
def __init__(self):
self.phead = None # 头指针
self.length = 0
# 尾插法
def appendtail(self, data):
node = Node(data)
# 头结点为空,说明该链表还没有元素
if self.phead != None:
pl = self.phead
while pl.next != None:
pl = pl.next
pl.next = node
else:
self.phead = node
self.length += 1
# 获取指定位置的结点值
def getData(self, index):
if index >= self.length:
print('越界,上界')
return None
elif index < 0:
print('越界,下界')
return None
p1 = self.phead
n = 0
while n < index:
n += 1
p1 = p1.next
return p1.data
# 单向链表的随机插入,按位置插入,插入到指定位置的前端
def insert(self, data, index):
# 针对位置越界的情况进行判定
if index > self.length:
print('越界,上界')
index = self.length
elif index < 0:
print('越界,下界')
index = 0
node = Node(data)
if index > 0:
p1 = self.phead
n = 0
while n < (index - 1):
p1 = p1.next
n += 1
node.next = p1.next
p1.next = node
else:
# 插在头部,也就是index=0
node.next = self.phead
self.phead = node
self.length += 1
# 单向链表按位置删除
def remove(self, index):
if index >= self.length:
print('越界,上界')
return None
elif index < 0:
print('越界,下界')
return None
else:
node = None
if index > 0:
p1 = self.phead
n = 0
while n < (index - 1):
p1 = p1.next
n += 1
node = p1.next
p1.next = node.next
node.next = None
else:
node = self.phead
self.phead = node.next
node.next = None
self.length -= 1
return node.data
# 返回结点列表
def display(self):
lst = []
node = self.phead
while node != None:
lst.append(node.data)
node = node.next
return lst
# 构造带环结点,n是闭合结点的位置
def setCricle(self,n):
if n>self.length or n<0:
return False
# 规定超过3个结点才能构造环
if self.length>3:
p1=self.phead
for i in range(n):
p1=p1.next
# 记录闭合结点
node=p1
while p1.next!=None:
p1=p1.next
# 构造环
p1.next=node
print('尾节点指向值为{}的结点'.format(node.data))
return True
if __name__ == '__main__':
main()
判断单向链表是否有环,若有环则找出闭合结点
- 判断是否有环,经典的快慢指针
- 在有环的情况下,寻找闭合结点:在快慢指针相遇之后,让慢指针从头开始,快指针一次移动一个节点,当他们再次相遇时,一定是在闭合结点处。其实这个有个数学分析,大家可自行百度百度,我有点晕,记得看过一篇说的很清晰的,忘了。。。
代码如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:cfl
@file:判断链表是否有环.py
@time:2021/12/24
@software:PyCharm
"""
import ssl
from slinklist import SlinkList
def judgecircle(ssl):
fast=ssl.phead
slow=ssl.phead
while fast!=None and fast.next!=None:
fast=fast.next.next
slow=slow.next
if fast==slow:
print('有环,第一次相遇节点值为{}'.format(fast.data))
break
if fast==None or fast.next==None:
print('无环')
else: # 找出闭合结点
slow=ssl.phead
while slow!=fast:
fast=fast.next
slow=slow.next
print('闭合点:',slow.data)
def main():
ssl=SlinkList()
for i in range(10):
ssl.appendtail(i*i)
print(ssl.display())
judgecircle(ssl)
ssl.setCricle(6)
judgecircle(ssl)
if __name__ == '__main__':
main()
结果如下: