-
Python 链表
python 链表可以实现如下:
# 链表节点类
class Node:
def __init__(self, value, Next):
self.value = value
self.next = Next
# 链表类
class LinkedList(Node):
# 初始化链表
def __init__(self):
# 覆盖父类构造函数
super(LinkedList, self).__init__(0, None)
self.size = 0
# 尾指针、头指针(哨兵)
self.tail = self.sentinel = Node(value=self.value, Next=None)
# 尾部追加
def append_(self, value):
self.tail.next = Node(value=value, Next=None)
self.tail = self.tail.next
self.size += 1
# 打印函数
def __str__(self):
cell = self.sentinel.next
while cell:
print(cell.value)
cell = cell.next
2.环路检测算法
-
标记法
def hasLoopMark(self):
# 采用标记单元格的方式来 判断是否有环
"""
在Node中多加一个数据域 visited = [False]*self.size
算法执行过程:
从sentinel开始访问链表每一个节点,判断节点visited是否为True,
若是,则说明链表存在环,node.next = None 破环
时间复杂度 = O(N)
空间复杂度 = N
:return: boolean
"""
# 能检测环, 并能破环,算法直接易于理解,实现过程简单
pass
-
使用哈希表(散列表)
def hasLoopHashTable(self) -> bool:
# 使用哈希表(散列表)
"""
定义一个哈希表,哈希表的大小应为 1.5*self.size,即链表长度的1.5倍,哈希表具有比较好的性能
算法执行过程:
从sentinel开始访问每一个节点,检查是否哈希表是否已存在该节点,若存在则存在环,
返回True,否则,将该节点加入哈希表
时间复杂度 = O(N)
空间复杂度 = N
:return:boolean
"""
# 需要一个hashTable,能检测并破环,容易实现
pass
-
回溯法
-
def hasLoopLinkRetracing(self): # 链表回溯法 """ 使用两个Node对象,遍历链表,当两个对象不相等,且next一致时,说明检测到了环 时间复杂度 = O(N**2) 空间复杂度 = 1 :param self: :return: """ node_ = self.sentinel while node_.next: # node不断往前推进,对每个node,tracer都从sentinel开始检测,直到与node相遇或检测到环(if条件)结束算法 tracer = self.sentinel while tracer != node_: if tracer.next == node_.next: node_.next = None return True tracer = tracer.next node_ = node_.next # 能检测并破环
-
龟兔赛跑算法(弗洛伊德循环查找算法)
算法原理:
龟兔跑道如图(有环路的链表)
直跑道:T个单元格
环跑道:L个单元格
检测是否有环:若兔子从sentinel开始跑,若找到空节点,则无环
破环:
第一阶段(寻找循环起始位置start):兔子一步两个单元格,乌龟一步一个单元格。
- 从sentinel开始,乌龟跑T个单元格后,位于start,此时兔子已走过2T个单元格,位于距离start H = T mod L处,则龟兔相距L-H,
由于兔子一步比乌龟多走一格,故当乌龟走L-H步时,而这相遇,相遇在距离start L-H处;
- 兔子再相遇过后,立即从sentinel以一步一格的速度出发,T步后,兔子来到start处,而乌龟位置为L-H+TmodL,即等于L,也即龟兔再次相遇在start,即找到start。
第二阶段(找到循环结束位置End):
兔子(或乌龟)继续往前走,直到兔子(或乌龟)的下一个单元格为乌龟(或兔子)所在单元格,则这个单元格为end
令end.next = None即可破环
算法执行过程:
1)让兔子一步两个单元格,乌龟一步一个单元格地移动
2)若兔子从sentinel开始跑,若找到空节点,则无环
3)否则,当兔子赶上乌龟时,兔子从链表开始出一步一个单元格的重新跑,乌龟继续移动
4)当兔子乌龟再次相遇时,相遇节点为start节点
5)兔子(或乌龟)继续往前走,直到兔子(或乌龟)的下一个节点为乌龟(或兔子)所在节点,则这个节点为end
-
反转链表法
算法原理:若有有环,则反转后,sentinel(头指针、哨兵)位置不变;若无环,反转后sentinel(头指针、哨兵)位置会挪到最初链表最后
原理图解:
- 最初有环链表
2.反转 一
明白人会发现,此时并不算反转完成
3.反转 二
可见,有环路的链表,反转过后sentinel位置不变,因此可以通过反转链表,凭借sentinel位置是否改变来检测是否有环,
遗憾的是,这个算法不能破环。
反转链表Python实现:
# 反转链表
def reverseList(self):
pre_node = None
curr_node = self.sentinel.next
while curr_node:
next_node = curr_node.next
curr_node.next = pre_node
pre_node = curr_node
curr_node = next_node
# 将sentinel移到反转后的链表头部
self.sentinel.next = pre_node
PS:代码clone地址:git@github.com:Rlyslata/DataStauct-And-Algorithm.git