Nivasch’s cycle detection algorithm

一 简介

1.1 说明

此算法与Floyd和Brent算法一样,都是寻找由函数F(X)产生的序列S中是否存在循环,而且多用在非循环序列比循环序列长的序列中。上面提到的两个算法已经有很多人科普,唯独这个算法没有人科普,我就献丑了。

与前面所提到的两个算法不同,此算法需要维护一个堆栈结构Stack,该栈结构存储着目前序列出现的最小点distinguished points),而这些点很可能会出现在循环里。当然,事关效率与资源问题,这些点不能多也不能少。为了增加效率,Stack中的序列必须有序(递增),才能使用二分查找算法进行比对以减少时间复杂度。

1.2 结论

假设非循环序列长度为s,循环序列为l。

  1. 算法发现碰撞时,相遇点(不是碰撞点)在第一轮循环之后,范围在[s+l,s+2l-1];
  2. 内存消耗很少;
  3. 该算法找碰撞点与计算s和l的大小都比前面提到的两个算法简单且快速。

二 算法描述

2.1 文字描述

  1. 初始化栈S,并将第一个产生的X0以(X0, 0)的形式放到栈里。
  2. 生成Xi,并在S中进行二分搜索,若没有发现Xi则进行3,若发现已存在Xi则进行4。
  3. 将S中值大于Xi的值剔除,并添加(Xi, i)入S,重复2。
  4. 发现已存在点(Xi, j)。发现存在循环,算法结束。

2.2 伪代码

Require: Input initial sequence value X0, max. iterations M
Create empty stack S
Let x ←− X0
Add pair (x, 0) to the stack
for i from 1 to M do
	Let x ←− F(x)Search x by dichotomy in the (sorted) first component
	if (x, j) is found then
		Output ‘Collision between i and j’
		Exit
	else
		We know that Sk < x < Sk+1
		Truncate S after Sk
		Add pair (x, i) at the end of S
	end if
end for
Output Failed

2.3 计算非循环序列长度s以及碰撞点

已发现(Xi, j)存在在S中,则Xi则是S中从左到右第一个在循环里面的点,记录该点a,则只需遍历a~j即可到达碰撞点,得到s。

2.4 计算循环序列长度l

不像上面提到的两个算法,这里的i-j=t,t=l,而不是l的倍数关系!(i为后Xi,j为前面的Xi)

2.5 例子

假设函数F产生的序列为:

1 4 2 5 6 3 6

no.(i) S F(x) 是否能在S中找到F(X)
1 <(1,0)> 4 no
2 <(1,0),(4,1)> 2 no
3 <(1,0),(2,2)> 5 no
4 <(1,0),(2,2),(5,3)> 6 no
5 <(1,0),(2,2),(5,3),(6,4)> 3 no
6 <(1,0),(2,2),(3,5)> 6 no
7 <(1,0),(2,2),(3,5),(6,6)> 3 yes

得到:(3,7)与(3,5)相遇,则环的长度l=7-5=2,碰撞点(环开始的地方)在2~5之间。

全部评论

相关推荐

榕城小榕树:1200单休,我去干点啥别的不好
点赞 评论 收藏
分享
05-12 11:09
已编辑
门头沟学院 后端
已注销:没必要放这么多专业技能的描述。这些应该是默认已会的,写这么多行感觉在凑内容。项目这块感觉再包装包装吧,换个名字,虽然大家的项目基本都是网上套壳的,但是你这也太明显了。放一个业务项目,再放一个技术项目。技术项目,例如中间件的一些扩展和尝试。
简历中的项目经历要怎么写
点赞 评论 收藏
分享
05-22 09:23
门头沟学院 Java
点赞 评论 收藏
分享
测试糕手手:社会第一课,随便吹牛逼,直接说四个月,别老实。老实人只会被欺负
点赞 评论 收藏
分享
评论
2
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务