# 有环单链表
class Node(object):
def __init__(self, data, next=None):
self.data = data
self.next = next
class CircleLinklist(object):
def __init__(self):
self.head = None
self.length = 0
def insert(self, node):
if self.length == 0:
self.head = node
self.length += 1
return
cur = self.head
while cur.next:
cur = cur.next
cur.next = node
self.length += 1
def traverse(self):
cur = self.head
while cur is not None:
print(cur.data)
cur = cur.next
def judge_circle_quick_slow_pointer(self):
"""
判断单链表是否有环
如果在某个时候,快指针追上了慢指针,那么便说明有环
"""
# 快指针,每次走两个节点
quick = self.head
# 慢指针,每次走一个节点
slow = self.head
# 标志,判断是否有环
flag = False
# 每个指针的步数
count = 0
# 加上try-except,因为在没环的情况下,快指针会出错
try:
# 循环终止条件,如果某个节点的next为空,就说明没有环了
while quick.next.next is not None and slow.next is not None:
count += 1
# 排除第一次相等的情况
# 用后面那个条件做判断不是个好想法,万一环的起点就是head,然后节点个数又是偶数的话,不会停止了吧
if quick.data == slow.data and count != 1: # quick != self.head
print('快指针追上慢指针时的节点的值: ',quick.data)
flag = True
break
# 一次跨两个节点
quick = quick.next.next
# 一次跨一个节点
slow = slow.next
except Exception as e:
print(e.args)
print('quick条件报错,说明没有环')
finally:
print('步数: ', count)
print('是否有环: ', flag)
def judge_circle_by_traversing(self):
"""
将每个遍历过的节点保存到集合中,如果下一次遍历的节点在集合中了,就说明有环
这个方法很傻,但却可以得到环的点是哪个
快慢指针只能判断是否有环,不能得到环的起点
"""
nodes = []
cur = self.head
while cur is not None:
if cur not in nodes:
nodes.append(cur)
else:
print('有环,环的值是: ', cur.data)
break
cur = cur.next
else:
print('没有环')
if __name__ == '__main__':
cl = CircleLinklist()
nodes = []
for i in 'ABCDEFGHIJKLMN':
nodes.append(Node(i))
nodes[len(nodes) - 1].next = nodes[5] # 将最后一个节点的next指向F
for node in nodes:
cl.insert(node)
# cl.traverse()
cl.judge_circle_quick_slow_pointer()
print('-' * 80)
cl.judge_circle_by_traversing()
网友评论