前言

有Python基础

有数据结构单链表基础,没接触过的可以看下面链接

https://blog.csdn.net/sf9898/article/details/104946291

原理和实现

有一个链表,但是我们不知道这个链表是否内部有形成一个环(形成回路),因此需要有一个函数来检测是否有环(由此可知,这个函数的返回值应是布尔型)。

先去继承一下单链表的蚂蚁花呗(属性和方法),详见链接:https://blog.csdn.net/sf9898/article/details/104946291 将单链表的定义拷贝下来。

直接可以做测试,构建一个链表(或许有环,这一部分先写没环的),代码如下:

ll = Link()

# 先构建测试用的链表

for i in range(5):

ll.addFront(i)

ll.addFront(100)

ll.addBack(250)

for i in range(5):

ll.addBack(i)

# 到目前为止是一串没有环的链表

ll.travel() # 100 4 3 2 1 0 250 0 1 2 3 4

在代码中加入了几个明显与其他成员格格不入的data,这样子也更容易区分下。

接下来构建有环的链表,设置一个函数getLastNode使得我们可以取到链表的最后一个节点(这个例子中就是4这个节点),然后将它的next指向250的这个节点(又要有个函数能够取到这个节点,因此有了getNode这个函数),这样就可以形成环了。效果大致如下图。

# class Link的方法

def getLastNode(self):

cur = self.__head

pre = None

while cur:

pre = cur

cur = cur.next

return pre

def getNode(self, item):

cur = self.__head

res = None

while cur:

if cur.item == item:

res = cur

break

else:

cur = cur.next

return res

ll = Link()

# 先构建测试用的链表

for i in range(5):

ll.addFront(i)

ll.addFront(100)

ll.addBack(250)

for i in range(5):

ll.addBack(i)

# 到目前为止是一串没有环的链表

ll.travel() # 100 4 3 2 1 0 250 0 1 2 3 4

# 接下来构建有环的链表

# 设置一个函数getLastNode使得我们可以取到链表的最后一个节点(这个例子中就是4这个节点),

# 然后将它的next指向250的这个节点(又要有个函数能够取到这个节点,因此有了getNode这个函数),这样就可以形成环了

# print(ll.getNode(250).item) # 这一行用来验证getNode 函数的正确性,应打印250

ll.getLastNode().next = ll.getNode(250)

ll.travel() # 事实上现在遍历一下就可以发现事情不简单了

既然是要写一个函数来判断,那建议还是将这个函数写成class Link的方法。

def hasLoop(self):

if self.__head is None:

return False

# 能到这说明头结点不是空的,但是有可能只有一个节点,也有可能 N个(N > 1)

aNode = self.__head

bNode = self.__head

res = False

# 2个结点,往前跑,一个跑的快,一个跑的慢,如果没有环,慢的结点不会追上快的

# 如果有环,肯定有一个时刻,快的点绕回来追上了慢的点

# 如果只有一个或两个结点,则不会进行下面的循环,直接返回False (res)

while bNode.next and bNode.next.next:

bNode = bNode.next.next # 这里用B结点代表跑的快的,A是跑的慢的

aNode = aNode.next

if bNode == aNode:

res = True

break

return res

测试一下,完整代码:

class Node(object):

def __init__(self, item):

self.item = item

self.next = None

class Link(object):

def __init__(self):

self.__head = None

def isEmpty(self):

return self.__head is None

# 头部插入

def addFront(self, item):

node = Node(item)

node.next = self.__head

self.__head = node

# 尾部插入

def addBack(self, item):

node = Node(item)

if self.__head is None:

self.__head = node

return

cur = self.__head

pre = None

while cur:

pre = cur

cur = cur.next

# 当cur 为最后一个节点时带入,pre更新为最后一个节点,cur更新为最后一个节点的下一个节点即为空,

# 下一次while cur 时会退出循环,此时的pre表示的就是最后一个节点,将node挂到pre的后面即可

pre.next = node

def size(self):

count = 0

cur = self.__head

while cur:

count += 1

cur = cur.next

return count

def travel(self):

cur = self.__head

while cur:

print(cur.item, end=' ')

cur = cur.next

print('')

# 删除头部节点

def removeFront(self):

cur = self.__head

self.__head = self.__head.next

cur.next = None

# 删除尾部节点

def removeBack(self):

# 空节点时

if self.__head is None:

return

# 只有一个节点

if self.__head and self.__head.next is None:

self.__head = None

return

# 链表节点有两个及以上

cur = self.__head # 当前节点

pre = None # 前一个节点

cn = cur.next # 后一个节点

# 刚开始cur取到的是第一个节点,cn是第二个

while cn:

pre = cur

cur = cur.next

cn = cur.next

pre.next = None

def getLastNode(self):

cur = self.__head

pre = None

while cur:

pre = cur

cur = cur.next

return pre

def getNode(self, item):

cur = self.__head

res = None

while cur:

if cur.item == item:

res = cur

break

else:

cur = cur.next

return res

def hasLoop(self):

if self.__head is None:

return False

# 能到这说明头结点不是空的,但是有可能只有一个节点,也有可能 N个(N > 1)

aNode = self.__head

bNode = self.__head

res = False

# 2个结点,往前跑,一个跑的快,一个跑的慢,如果没有环,慢的结点不会追上快的

# 如果有环,肯定有一个时刻,快的点绕回来追上了慢的点

# 如果只有一个或两个结点,则不会进行下面的循环,直接返回False

while bNode.next and bNode.next.next:

bNode = bNode.next.next # 这里用B结点代表跑的快的,A是跑的慢的

aNode = aNode.next

if bNode == aNode:

res = True

break

return res

ll = Link()

# 先构建测试用的链表

for i in range(5):

ll.addFront(i)

ll.addFront(100)

ll.addBack(250)

for i in range(5):

ll.addBack(i)

# 到目前为止是一串没有环的链表

ll.travel() # 100 4 3 2 1 0 250 0 1 2 3 4

# 接下来构建有环的链表

# 设置一个函数getLastNode使得我们可以取到链表的最后一个节点(这个例子中就是4这个节点),

# 然后将它的next指向250的这个节点(又要有个函数能够取到这个节点,因此有了getNode这个函数),这样就可以形成环了

# print(ll.getNode(250).item) # 这一行用来验证getNode 函数的正确性,应打印250

ll.getLastNode().next = ll.getNode(250)# 注释掉这行,就无法形成环了,这时下面的打印结果应是False

# ll.travel() # 事实上现在遍历一下就可以发现事情不简单了

print(ll.hasLoop())

结果

后面发现这样其实是不严谨的,当节点数为2的时候,并且第二个node的next指向第一个,这个时候也算是一个环,在上面的代码中吧这种情况当做不是环。为了实现这个要求,需要对上面的代码进行修改。

def hasLoop(self):

if self.__head is None:

return False

# 能到这说明头结点不是空的,但是有可能只有一个节点,也有可能 N个(N > 1)

if self.__head and self.__head.next is None:

# 只有一个头结点,不认为是环

return False

# 能到这里就说明,至少有2个节点了

# 有两个及以上结点,这里第二个节点的next指向None可以说明没有环,否则这里就有可能会出现环

if self.__head.next.next == self.__head:

# 如果第二个节点的next指向第一个节点则认为是环,否则可能是指向空或者是下一个节点

return True

aNode = self.__head

bNode = self.__head

res = False

# 设置2个结点,往前跑,一个跑的快,一个跑的慢,如果没有环,慢的结点不会追上快的

# 如果有环,肯定有一个时刻,快的点绕回来追上了慢的点

# 如果只有两个结点(也就是说第二个节点的next指向None),则不会进行下面的循环,直接返回False

while bNode.next and bNode.next.next:

bNode = bNode.next.next # 这里用B结点代表跑的快的,A是跑的慢的

aNode = aNode.next

if bNode == aNode:

res = True

break

return res

完整代码:

class Node(object):

def __init__(self, item):

self.item = item

self.next = None

class Link(object):

def __init__(self):

self.__head = None

def isEmpty(self):

return self.__head is None

# 头部插入

def addFront(self, item):

node = Node(item)

node.next = self.__head

self.__head = node

# 尾部插入

def addBack(self, item):

node = Node(item)

if self.__head is None:

self.__head = node

return

cur = self.__head

pre = None

while cur:

pre = cur

cur = cur.next

# 当cur 为最后一个节点时带入,pre更新为最后一个节点,cur更新为最后一个节点的下一个节点即为空,

# 下一次while cur 时会退出循环,此时的pre表示的就是最后一个节点,将node挂到pre的后面即可

pre.next = node

def size(self):

count = 0

cur = self.__head

while cur:

count += 1

cur = cur.next

return count

def travel(self):

cur = self.__head

while cur:

print(cur.item, end=' ')

cur = cur.next

print('')

# 删除头部节点

def removeFront(self):

cur = self.__head

self.__head = self.__head.next

cur.next = None

# 删除尾部节点

def removeBack(self):

# 空节点时

if self.__head is None:

return

# 只有一个节点

if self.__head and self.__head.next is None:

self.__head = None

return

# 链表节点有两个及以上

cur = self.__head # 当前节点

pre = None # 前一个节点

cn = cur.next # 后一个节点

# 刚开始cur取到的是第一个节点,cn是第二个

while cn:

pre = cur

cur = cur.next

cn = cur.next

pre.next = None

def getLastNode(self):

cur = self.__head

pre = None

while cur:

pre = cur

cur = cur.next

return pre

def getNode(self, item):

cur = self.__head

res = None

while cur:

if cur.item == item:

res = cur

break

else:

cur = cur.next

return res

def hasLoop(self):

if self.__head is None:

return False

# 能到这说明头结点不是空的,但是有可能只有一个节点,也有可能 N个(N > 1)

if self.__head and self.__head.next is None:

# 只有一个头结点,不认为是环

return False

# 能到这里就说明,至少有2个节点了

# 有两个及以上结点,这里第二个节点的next指向None可以说明没有环,否则这里就有可能会出现环

if self.__head.next.next == self.__head:

# 如果第二个节点的next指向第一个节点则认为是环,否则可能是指向空或者是下一个节点

return True

aNode = self.__head

bNode = self.__head

res = False

# 设置2个结点,往前跑,一个跑的快,一个跑的慢,如果没有环,慢的结点不会追上快的

# 如果有环,肯定有一个时刻,快的点绕回来追上了慢的点

# 如果只有两个结点(也就是说第二个节点的next指向None),则不会进行下面的循环,直接返回False

while bNode.next and bNode.next.next:

bNode = bNode.next.next # 这里用B结点代表跑的快的,A是跑的慢的

aNode = aNode.next

if bNode == aNode:

res = True

break

return res

ll = Link()

# # 先构建测试用的链表

# for i in range(5):

# ll.addFront(i)

# ll.addFront(100)

# ll.addBack(250)

# for i in range(5):

# ll.addBack(i)

# # 到目前为止是一串没有环的链表

# ll.travel() # 100 4 3 2 1 0 250 0 1 2 3 4

# # 接下来构建有环的链表

# # 设置一个函数getLastNode使得我们可以取到链表的最后一个节点(这个例子中就是4这个节点),

# # 然后将它的next指向250的这个节点(又要有个函数能够取到这个节点,因此有了getNode这个函数),这样就可以形成环了

#

# # print(ll.getNode(250).item) # 这一行用来验证getNode 函数的正确性,应打印250

#

# # ll.getLastNode().next = ll.getNode(250)

# # ll.travel() # 事实上现在遍历一下就可以发现事情不简单了

# print(ll.hasLoop())

# 一种特殊的情况,只有两个结点,但是形成环

ll.addBack(1)

ll.addBack(2)

ll.getLastNode().next = ll.getNode(1)

print(ll.hasLoop())# 现在结果应该是True

结果

python 单链表是否有回路_(Python3)数据结构--单链表之判断链表是否有环相关推荐

  1. python 单链表是否有回路_第5章 第1节 链表

    ● 请你说出几种基本的数据结构, 参考回答: 常见的基本的数据结构有链表.栈.队列.树(只列出面试常考的基本数据结构) 1.链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链 ...

  2. java单链表逆序输出_在数据结构单链表中如何实现倒序输出

    引用du瓶邪的回答: 如下: #include #include typedef struct node { int data; node* pNext; }Node; //链表的操作,以有头节点为例 ...

  3. 无头结点单链表的逆置_从无头单链表中删除节点及单链表的逆置

    题目: 假设有一个没有头指针的单链表.一个指针指向此单链表中间的一个节点(非第一个节点, 也非最后一个节点).请将该节点从单链表中删除. 解答: 典型的"狸猫换太子", 若要删除该 ...

  4. java 链表逆序代码_如何实现一个高效的单向链表逆序输出?(详解)

    需要考虑因素,高效应权衡多方面因素 数据量是否会很大 空间是否有限制 原始链表的结构是否可以更改 时间复杂度是否有限制 一个链表节点需要输出的元素有多个,例如链表中存的是自定义对象,有多个字段 题目. ...

  5. python打开并读取csv文件_!python3中使用使用read_csv( )读取csv文件,文件路径中含有中文,无法读取怎么处理?...

    python3如何根据csv文件的列的内容,自动建数据库表 你好,csv格式的和excel格式是差不多的, 下面是读取excel的一些函数,希望帮到你: # -*- coding: cp936 -*- ...

  6. java递归单链表查找中间元素_《数据结构与算法——C语言描述》答案 3.11 查找单链表中的特定元素(递归)...

    转载请注明出处:http://blog.csdn.net/xdz78 #include #include //查找单链表中的特定元素,<数据结构与算法--c语言描述> 3.11 答案 in ...

  7. python爬取今日头条专栏_[python3]今日头条图片爬取

    前言 代码设计流程,先模拟ajax发送搜索"街拍美女",提取返回json里面的article_url,再访问article_url,提取article_url响应的图片url,访问 ...

  8. python有链表和指针吗_了解如何更改指针和命令链表实现python

    我有以下链接列表实现,现在我已经完美地工作了.然而,我并没有理解,为了教学的目的,我可以证明一个链表中包含"下一个指针"的节点. 我的理解是元素按照它们的顺序存储,所以在这种情况下 ...

  9. 【数据结构与算法】判断两个无环单链表是否相交的算法

    带环单链表的故事 @不了解前尘往事的Reader,烦请阅读--<判断单链表是否有环的算法> 不过我们这里不考虑带环单链表,且无环单链表相交也只是相交一次,不穿过,这是一种不算复杂的情况吧. ...

最新文章

  1. ——————————————————————————————————1203————————————————————————————————...
  2. 建模揭秘----构建用户模型
  3. 比较两个引用的几种方法
  4. eclipse重置页面恢复到最初布局状态
  5. python 漂亮界面demo_在这个什么都看脸的时代,如何用 GUI 提高 python 程序的颜值?...
  6. 下班啦!做那么多老板不会心疼你的
  7. 梁宁:真正驱动你变强的,是痛苦
  8. 架构之旅~底层提供一个统一的GetModel()的重要性
  9. (转) Eclipse Maven 编译错误 Dynamic Web Module 3.1 requires Java 1.7 or newer 解决方案
  10. sublime text_Sublime Text Editor赠品报告和获胜者
  11. 菊子曰获取模板的草稿{29C28FD771BA4B0D8693}
  12. 【SLAM学习笔记】8-ORB_SLAM3关键源码分析⑥ Optimizer(三)全局优化
  13. 脱机使用打印机是什么意思?
  14. Prometheus技术系列文章——prometheus调研总结
  15. 你值得拥有!-阿里P8架构师荣耀典藏:Java多线程与Socket实战微服务框架笔记
  16. 照片换背景色(Photoshop工具)
  17. 我用scratch做了个二分查找
  18. 定时开关机的八种方法
  19. 岁月如沙容颜易逝,年关将至的感伤你有吗?
  20. linux gdb网络调试,一文入门Linux下gdb调试(二)

热门文章

  1. 一:ActiveMQ知识整理
  2. AngularJs编辑器
  3. iOS 应用程序的生命周期浅析
  4. 【CSWS2014 Summer School】大数据下的游戏营销模式革新-邓大付
  5. 【转】Web实现音频、视频通信
  6. SQL 行转列,列分行,行合并列(转)
  7. eclipse中git的配置、提交代码、从远程导入代码
  8. 卷积码主要是对抗_【零基础学会LTE】【3】LTE 36.212 咬尾卷积码详解
  9. 京瓷 打印 打印机 账户_UV打印机买回来成废铁?不是选择不对,而是你想太多了……...
  10. java 解决内存泄露_Java内存泄露的理解与解决