Python与数据结构[0] -> 链表[2] -> 链表有环与链表相交判断的 Python 实现

链表有环与链表相交判断的 Python 实现



目录

  1. 有环链表
  2. 相交链表

有环链表

判断链表是否有环可以参考链接

有环链表主要包括以下几个问题(C语言描述):

  1. 判断环是否存在: 可以使用追赶方法,定义两个指针slow和fast,分别以1步和2步前进,若存在环则两者会相遇,否则fast遇到NULL时则退出;
  2. 获取环的长度:若存在环,则以相遇点为起点,fast和slow再次开始前进,第二次碰相遇slow走过的步数(1圈)即为环长度;
  3. 找出入环点:相遇点到连接点的距离 = 头指针到连接点的距离,因此,让头指针和slow同时开始前进,相遇的点即为连接点;
  4. 带环链表长度:问题3的连接点与头指针长度 + 问题2的环长度即为总长。

下面为关于有环链表几个问题的具体实现代码,

完整代码

 1 from linked_list import LinkedList
 2
 3
 4 def check_loop(chain):
 5     has_loop, entry_node, loop_length, chain_length = False, None, 0, 0
 6
 7     # Get header for fast and slow
 8     step = 0
 9     fast = slow = head = chain.header
10     while fast and fast.next:
11         fast = fast.next.next
12         slow = slow.next
13         step += 1
14         # Note:
15         # Do remember to use ,is‘ rather than ‘==‘ here (assure the id is same).
16         if fast is slow:
17             break
18     has_loop = not(fast is None or fast.next is None)
19     pass_length = (step * 2) if fast is None else (step * 2 + 1)
20
21     if has_loop:
22         step = 0
23         while True:
24             if head is slow:
25                 entry_node = slow
26                 pass_length = step
27             if not entry_node:
28                 head = head.next
29             fast = fast.next.next
30             slow = slow.next
31             step += 1
32             if fast is slow:
33                 break
34         loop_length = step
35
36     chain_length = pass_length + loop_length
37     return has_loop, entry_node, loop_length, chain_length
38
39
40 if __name__ == ‘__main__‘:
41     print(‘------------ Loop check ------------------‘)
42     print(‘‘‘
43     0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
44     ‘‘‘)
45     loop_chain = LinkedList(range(10))
46     print(‘Linked list has loop: %s, entry node: %s, loop length: %s, chain length: %s‘ % check_loop(loop_chain))
47
48     # Create a loop for linked list.
49     print(‘‘‘
50                     _____________________________
51                    |                             |
52                    V                             |
53     0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
54     ‘‘‘)
55     node_9 = loop_chain.find(9)
56     node_3 = loop_chain.find(3)
57     node_9.next = node_3
58     print(‘Linked list has loop: %s, entry node: %s, loop length: %s, chain length: %s‘ % check_loop(loop_chain))

分段解释

首先导入单链表类,

1 from linked_list import LinkedList

然后定义一个函数,用于检测链表是否有环,并最终返回4个信息,1. 是否有环,2. 入环点,3. 环长度,4. 链表长度,

具体过程为,

  1. 分别获取fast、slow和head结点,均以头结点为起始
  2. 开始循环,slow和fast分别以1步和2步前进,并记录slow所走步数
  3. 每一步都判断fast和slow是否相遇,此处需要用is而不能用==,这样才能判断是否是相同对象(指针引用)
  4. 当fast遇到None或两结点相遇时,退出循环,并记录下是否有环和经过的步数
  5. 判断是否有环,若无环则链表长度即经过长度的2倍或2倍加1,环长为0
  6. 若有环,则同时驱动fast(2步)、slow(1步)和head(1步)前进
  7. 当slow和head相遇的点即为入环点,停止head,slow继续前进
  8. 在slow和fast再次相遇的点,记录走过的长度,即为环长
  9. 更新pass_length及链表长度信息,并返回结果
 1 def check_loop(chain):
 2     has_loop, entry_node, loop_length, chain_length = False, None, 0, 0
 3
 4     # Get header for fast and slow
 5     step = 0
 6     fast = slow = head = chain.header
 7     while fast and fast.next:
 8         fast = fast.next.next
 9         slow = slow.next
10         step += 1
11         # Note:
12         # Do remember to use ,is‘ rather than ‘==‘ here (assure the id is same).
13         if fast is slow:
14             break
15     has_loop = not(fast is None or fast.next is None)
16     pass_length = (step * 2) if fast is None else (step * 2 + 1)
17
18     if has_loop:
19         step = 0
20         while True:
21             if head is slow:
22                 entry_node = slow
23                 pass_length = step
24             if not entry_node:
25                 head = head.next
26             fast = fast.next.next
27             slow = slow.next
28             step += 1
29             if fast is slow:
30                 break
31         loop_length = step
32
33     chain_length = pass_length + loop_length
34     return has_loop, entry_node, loop_length, chain_length

完成函数定义后,首先生成一个基本链表,检测是否有环,

1 if __name__ == ‘__main__‘:
2     print(‘------------ Loop check ------------------‘)
3     print(‘‘‘
4     0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
5     ‘‘‘)
6     loop_chain = LinkedList(range(10))
7     print(‘Linked list has loop: %s, entry node: %s, loop length: %s, chain length: %s‘ % check_loop(loop_chain))

得到结果

------------ Loop check ------------------

    0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

Linked list has loop: False, entry node: None, loop length: 0, chain length: 10

再将链表的3和9结点相接,形成一个新的有环链表,然后利用函数进行判断。

 1     # Create a loop for linked list.
 2     print(‘‘‘
 3                     _____________________________
 4                    |                             |
 5                    V                             |
 6     0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9
 7     ‘‘‘)
 8     node_9 = loop_chain.find(9)
 9     node_3 = loop_chain.find(3)
10     node_9.next = node_3
11     print(‘Linked list has loop: %s, entry node: %s, loop length: %s, chain length: %s‘ % check_loop(loop_chain))

得到结果

                    _____________________________
                   |                             |
                   V                             |
    0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

Linked list has loop: True, entry node: 3, loop length: 7, chain length: 10

2 相交链表

判断链表是否相交及交点的方法主要有两种,

  1. 遍历两个链表,得到最后的结点,若两个结点指向同一个结点(指针相等),则说明两个链表相交,此时记录下链表长度long_length和short_length,以较长的链表为起始点,先前进 (long_length - short_length) 步,再驱动两个结点同时前进,相遇点即为交点。
  2. 将其中一个链表首尾相接,形成一个环,再判断另一个链表是否有环;若有环则入环点即为交点;

利用代码分别实现上面的两种判断方法,

完整代码

 1 from linked_list import LinkedList
 2 from linked_list_loop_check import check_loop
 3
 4
 5 def check_intersect_one(c_1, c_2):
 6     def _traversal(c):
 7         node = c.header
 8         while node and node.next:
 9             yield node
10             node = node.next
11         yield node
12
13     is_intersect, intersect_node = False, None
14     # Get tail node and length
15     step_1 = step_2 = 0
16     for node_1 in _traversal(c_1):
17         step_1 += 1
18     for node_2 in _traversal(c_2):
19         step_2 += 1
20     tail_1, length_1 = node_1, step_1
21     tail_2, length_2 = node_2, step_2
22
23     if tail_1 is tail_2:
24         # Intersected, fetch the first same node encountered as intersect node.
25         is_intersect = True
26         offset = length_1 - length_2
27         long, short = (_traversal(c_1), _traversal(c_2)) if offset >= 0 else (_traversal(c_2), _traversal(c_1))
28         for i in range(offset):
29             next(long)
30         for node_1, node_2 in zip(long, short):
31             if node_1 is node_2:
32                 break
33         intersect_node = node_1
34     return is_intersect, intersect_node
35
36
37 def check_intersect_two(c_1, c_2):
38     def _traversal(c):
39         node = c.header
40         while node and node.next:
41             yield node
42             node = node.next
43         yield node
44
45     # Create a loop for one of linked lists.
46     for node in _traversal(c_1): pass
47     node.next = c_1.header
48     is_intersect, intersect_node = check_loop(c_2)[:2]
49     # Un-loop
50     node.next = None
51     return is_intersect, intersect_node
52
53
54 if __name__ == ‘__main__‘:
55     print(‘------------ intersect check ------------------‘)
56     print(‘‘‘
57     chain_1:  0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
58     chain_2:  3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13
59     ‘‘‘)
60     chain_1 = LinkedList(range(7))
61     chain_2 = LinkedList(range(3, 14))
62     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_one(chain_1, chain_2))
63     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_two(chain_1, chain_2))
64
65     # Merge two linked lists
66     print(‘‘‘Merge two linked lists:
67     chain_1:  0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 _
68                                                \69     chain_2:                 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13
70     ‘‘‘)
71     node_6 = chain_1.find(6)
72     node_7 = chain_2.find(7)
73     node_6.next = node_7
74
75     # Method one:
76     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_one(chain_1, chain_2))
77     # Method two:
78     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_two(chain_1, chain_2))

分段解释

首先导入链表类和有环检测函数,

1 from linked_list import LinkedList
2 from linked_list_loop_check import check_loop

接着定义第一种检测方法,

  1. 定义遍历函数,用于遍历链表
  2. 分别遍历两个链表,记录下步数即为链表长度,最后的结点即链表尾结点
  3. 判断尾结点是否相同,若不同则不想交
  4. 若相同则根据长度判断,让长链表先前进长度差的步数
  5. 随后同时前进两个链表,找到第一个相遇点即为相交结点。
 1 def check_intersect_one(c_1, c_2):
 2     def _traversal(c):
 3         node = c.header
 4         while node and node.next:
 5             yield node
 6             node = node.next
 7         yield node
 8
 9     is_intersect, intersect_node = False, None
10     # Get tail node and length
11     step_1 = step_2 = 0
12     for node_1 in _traversal(c_1):
13         step_1 += 1
14     for node_2 in _traversal(c_2):
15         step_2 += 1
16     tail_1, length_1 = node_1, step_1
17     tail_2, length_2 = node_2, step_2
18
19     if tail_1 is tail_2:
20         # Intersected, fetch the first same node encountered as intersect node.
21         is_intersect = True
22         offset = length_1 - length_2
23         long, short = (_traversal(c_1), _traversal(c_2)) if offset >= 0 else (_traversal(c_2), _traversal(c_1))
24         for i in range(offset):
25             next(long)
26         for node_1, node_2 in zip(long, short):
27             if node_1 is node_2:
28                 break
29         intersect_node = node_1
30     return is_intersect, intersect_node

再定义第二种检测方法,

  1. 定义遍历函数,遍历其中一个链表并找到尾结点
  2. 首尾相接形成一个环
  3. 判断另一个链表是否有环,并获取结果信息
  4. 解除前面的链表环,还原链表,并返回结果
 1 def check_intersect_two(c_1, c_2):
 2     def _traversal(c):
 3         node = c.header
 4         while node and node.next:
 5             yield node
 6             node = node.next
 7         yield node
 8
 9     # Create a loop for one of linked lists.
10     for node in _traversal(c_1): pass
11     node.next = c_1.header
12     is_intersect, intersect_node = check_loop(c_2)[:2]
13     # Un-loop
14     node.next = None
15     return is_intersect, intersect_node

最后,通过下面的函数进行测试,首先生成两个不相交的链表并用两种方法进行判断,接着讲其中一个链表和另一个链表相交,再进行判断。

 1 if __name__ == ‘__main__‘:
 2     print(‘------------ intersect check ------------------‘)
 3     print(‘‘‘
 4     chain_1:  0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
 5     chain_2:  3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13
 6     ‘‘‘)
 7     chain_1 = LinkedList(range(7))
 8     chain_2 = LinkedList(range(3, 14))
 9     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_one(chain_1, chain_2))
10     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_two(chain_1, chain_2))
11
12     # Merge two linked lists
13     print(‘‘‘Merge two linked lists:
14     chain_1:  0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 _
15                                                \16     chain_2:                 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13
17     ‘‘‘)
18     node_6 = chain_1.find(6)
19     node_7 = chain_2.find(7)
20     node_6.next = node_7
21
22     # Method one:
23     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_one(chain_1, chain_2))
24     # Method two:
25     print(‘Linked lists are intersected: %s, intersected node is: %s‘ % check_intersect_two(chain_1, chain_2))

输出结果

------------ intersect check ------------------

    chain_1:  0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
    chain_2:  3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13

Linked lists are intersected: False, intersected node is: None
Linked lists are intersected: False, intersected node is: None
Merge two linked lists:
    chain_1:  0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 _
                                                   chain_2:                 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12 -> 13

Linked lists are intersected: True, intersected node is: 7
Linked lists are intersected: True, intersected node is: 7

参考链接



http://blog.csdn.net/liuxialong/article/details/6555850

http://www.cppblog.com/humanchao/archive/2008/04/17/47357.html

原文地址:https://www.cnblogs.com/stacklike/p/8284081.html

时间: 2024-09-28 05:03:17

Python与数据结构[0] -> 链表[2] -> 链表有环与链表相交判断的 Python 实现的相关文章

Python与数据结构[0] -> 链表[0] -> 单链表与带表头单链表的 Python 实现

单链表 / Linked List 目录 单链表 带表头单链表 链表是一种基本的线性数据结构,在C语言中,这种数据结构通过指针实现,由于存储空间不要求连续性,因此插入和删除操作将变得十分快速.下面将利用Python来完成单链表的实现. 1 单链表 不带表头的单链表通常形式如下, node_1 -> node_2 -> node_3 -> node_4 完整代码 1 class Node: 2 def __init__(self, val=None, nxt=None): 3 self.v

Python与数据结构[0] -> 链表[1] -> 双链表与循环双链表的 Python 实现

双链表 / Doubly Linked List 目录 双链表 循环双链表 1 双链表 双链表和单链表的不同之处在于,双链表需要多增加一个域(C语言),即在Python中需要多增加一个属性,用于存储指向前一个结点的信息. Doubly linked list: node_1 <---> node_2 <---> node_3 完整代码 1 from linked_list import LinkedList, test 2 3 4 class NodeDual: 5 def __i

python实现数据结构单链表

#python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" def __init__(self, elem): self.elem = elem self.next = None # 节点一开始初始化的时候并不知道下一个元素的地址,所以先设置为空 class SingLinkList(object): """单链表""

深入浅出数据结构C语言版(5)——链表的操作

上一次我们从什么是表一直讲到了链表该怎么实现的想法上:http://www.cnblogs.com/mm93/p/6574912.html 而这一次我们就要实现所说的承诺,即实现链表应有的操作(至于游标数组--我决定还是给它单独写个博文比较好~). 那么,我们的过程应该是怎么样的呢?首先当然是分析需要什么操作,然后再逐一思考该如何实现,最后再以代码的形式写出来. 不难发现,我们希望链表能支持的(基础,可以由此延伸)操作就是: 1.给出第n个元素 2.在第n个元素的后面插入一个元素(包含在最后一个

java数据结构与算法之顺序表与链表深入分析

转载请注明出处(万分感谢!): http://blog.csdn.net/javazejian/article/details/52953190 出自[zejian的博客] 关联文章: java数据结构与算法之顺序表与链表设计与实现分析 java数据结构与算法之双链表设计与实现 ??数据结构与算法这门学科虽然在大学期间就已学习过了,但是到现在确实也忘了不少,因此最近又重新看了本书-<数据结构与算法分析>加上之前看的<java数据结构>也算是对数据结构的进一步深入学习了,于是也就打算

数据结构之 线性表--顺序创建链表

数据结构实验之链表一:顺序建立链表 Time Limit: 1000MS Memory limit: 65536K 题目描述 输入N个整数,按照输入的顺序建立单链表存储,并遍历所建立的单链表,输出这些数据. 输入 第一行输入整数的个数N: 第二行依次输入每个整数. 输出 输出这组整数. 示例输入 8 12 56 4 6 55 15 33 62 示例输出 12 56 4 6 55 15 33 62 写的时候,定义一个结构体变量就要为它申请空间,不然程序会运行时出问题 ! #include <ios

数据结构与算法系列四(单链表)

1.引子 1.1.为什么要学习数据结构与算法? 有人说,数据结构与算法,计算机网络,与操作系统都一样,脱离日常开发,除了面试这辈子可能都用不到呀! 有人说,我是做业务开发的,只要熟练API,熟练框架,熟练各种中间件,写的代码不也能“飞”起来吗? 于是问题来了:为什么还要学习数据结构与算法呢? #理由一: 面试的时候,千万不要被数据结构与算法拖了后腿 #理由二: 你真的愿意做一辈子CRUD Boy吗 #理由三: 不想写出开源框架,中间件的工程师,不是好厨子 1.2.如何系统化学习数据结构与算法?

数据结构-编程实现一个双链表的建立,双链表的打印,双链表的测长

1:双链表的建立,打印,代码如下: // ConsoleApplication24.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<malloc.h> #include <iostream> #include <assert.h> using namespace std; typedef struct DbNode //双向链表结构体 { int data;//节点数据 DbNode *lef

Python与数据结构[2] -&gt; 队列/Queue[0] -&gt; 数组队列的 Python 实现

队列 / Queue 数组队列 数组队列是队列基于数组的一种实现,其实现类似于数组栈,是一种FIFO的线性数据结构. Queue: <--| 1 | 2 | 3 | 4 | 5 |<-- 下面将使用Python中的list来替代C语言中的数组实现数组队列的数据结构. Note: 这里的实现并没有像C语言中的申请一块固定大小的数组,手动的定制数组中队列的头尾位置,而是利用list的特性直接完成,因此较为简单. 数组队列的实现与数组栈的实现基本类似,同时入列和出列也十分简单,仅需要对数组进行操作即