当前位置:首页 » 操作系统 » 检测环算法

检测环算法

发布时间: 2024-04-12 20:58:19

⑴ 无向图中查找环的算法有哪些

比较直观的办法是,从初始结点 S 开始,用深度优先的方法遍历图的结点,如果在这个过程中,你遇到了一个先前就已经发现过的结点(假定它叫 V),说明存在一个环。
如果你想输出这个环,那么就从 V 沿路返回,直到又遇到 V,途中经过的所有结点就组成了这个环。

⑵ 判断单链表有没有环的算法中,至少需要几个指针

算法的思想是设定两个指针p,
q,其中p每次向前移动一步,q每次向前移动两步。那么如果单链表存在环,则p和q相遇;否则q将首先遇到null。
这里主要理解一个问题,就是为什么当单链表存在环时,p和q一定会相遇呢?
假定单链表的长度为n,并且该单链表是环状的,那么第i次迭代时,p指向元素i
mod
n,q指向2i
mod
n。因此当i≡2i(mod
n)时,p与q相遇。而i≡2i(mod
n)
=>
(2i
-
i)
mod
n
=
0
=>
i
mod
n
=
0
=>
当i=n时,p与q相遇。这里一个简单的理解是,p和q同时在操场跑步,其中q的速度是p的两倍,当他们两个同时出发时,p跑一圈到达起点,而q此时也刚
好跑完两圈到达起点。
那么当p与q起点不同呢?假定第i次迭代时p指向元素i
mod
n,q指向k+2i
mod
n,其中0<k<n。那么i≡(2i+k)(mod
n)
=>
(i+k)
mod
n
=
0
=>
当i=n-k时,p与q相遇。
解决方案:
推广:
1.
如果两个指针的速度不一样,比如p,q,(
0<p<q)二者满足什么样的关系,可以使得两者肯定交与一个节点?

Sp(i)
=
pi

Sq(i)
=
k
+
qi

如果两个要相交于一个节点,则
Sp(i)
=
Sq(i)
=>
(pi)
mod
n
=
(
k+
qi
)
mod
n
=>[
(q
-p)i
+
k
]
mod
n
=0

=>
(q-p)i
+
k
=
Nn
[N
为自然数]

=>
i
=
(Nn
-k)
/(p-q)

i取自然数,则当
p,q满足上面等式

存在一个自然数N,可以满足Nn
-k

p
-
q
的倍数时,保证两者相交。

特例:如果q
是p
的步长的两倍,都从同一个起点开始,即
q
=
2p
,
k
=0,
那么等式变为:
Nn=i:
即可以理解为,当第i次迭代时,i是圈的整数倍时,两者都可以交,交点就是为起点。
2.如何判断单链表的环的长度?

这个比较简单,知道q
已经进入到环里,保存该位置。然后由该位置遍历,当再次碰到该q
位置即可,所迭代的次数就是环的长度。
3.
如何找到链表中第一个在环里的节点?

假设链表长度是L,前半部分长度为k-1,那么第一个再环里的节点是k,环的长度是
n,
那么当q=2p时,
什么时候第一次相交呢?当q指针走到第k个节点时,q指针已经在环的第
k
mod
n
的位置。即p和q
相差k个元素,从不同的起点开始,则相交的位置为
n-k
从图上可以明显看到,当p从交点的位置(n-k)
,向前遍历k个节点就到到达环的第一个几点,节点k.
算法就很简单:
一个指针从p和q
中的第一次相交的位置起(n-k),另外一个指针从链表头开始遍历,其交点就是链表中第一个在环里的交点。
4.
如果判断两个单链表有交?第一个交点在哪里?

这个问题画出图,就可以很容易转化为前面的题目。

将其中一个链表中的尾节点与头节点联系起来,则很容发现问题转化为问题3,求有环的链表的第一个在环里的节点。

⑶ c++判断有向图是否有环的算法

通常是用邻接矩阵来表示一个有向图。从图中的每一个点出发,用深度优先遍历的算法,如果能够回到出发点,图中就是有环的;如果每一个点都不能回到出发点,那么它就是无环的。

⑷ 浣撴祴镓嬬幆镄勫师鐞嗘槸浠涔

浣撴祴镓嬬幆镄勫师鐞嗕富瑕佹槸阃氲繃镒熷簲鍣ㄦ劅搴斾笉钖屾柟钖戠殑锷犻熷害鎴栨尟锷ㄧ瓑杩愬姩鐘跺喌銆傝繖浜涙劅搴斿櫒阃氩父浠ヤ笁杞存垨鍏杞寸殑褰㈠纺鍑虹幇锛屽彲浠ユ劅娴嬩笉钖屾柟钖戠殑锷犻熷害鎴栨尟锷ㄣ傝繖浜涙劅搴斿櫒阃氲繃鐢靛瑰纺锷犻熷害璁″伐浣滐纴鑳藉熻板綍鍜岃В閲婅繖浜涜繍锷ㄧ姸镐佺殑鏁版嵁銆
铹跺悗锛岃繖浜涙暟鎹缁忚繃婊ゆ尝鍜屽嘲璋锋娴嬬瓑杩囩▼锛岄氲繃钖勭岖畻娉曞拰绉戝︾绁瀵嗙殑阃昏緫杩愮畻锛屾渶缁埚皢杩欎簺鏁版嵁杞鍙樻垚镓嬬幆APP绔镄勫彲璇绘暟瀛椼傝繖浜涙暟鎹鍖呮嫭姝ユ暟銆佽窛绂汇佹秷钥楃殑鍗¤矾閲屾暟鍊肩瓑锛岃兘澶熻鐢ㄦ埛鐩磋傚湴鐞呜В鍜屼娇鐢ㄣ
姝ゅ栵纴浣撴祴镓嬬幆杩橀氩父閰嶅囧氱崭紶镒熷櫒锛屽傚绩鐜囦紶镒熷櫒銆佸姞阃熷害浼犳劅鍣ㄣ侀檧铻轰华鍜屾皵铡嬭$瓑锛岃兘澶熷疄镞剁洃娴嬬敤鎴风殑蹇幂巼銆佹ユ暟銆佸Э锷跨瓑鏁版嵁锛屽苟灏呜繖浜涙暟鎹杞鍖栦负链変环鍊肩殑淇℃伅銆傞氲繃绠楁硶浼桦寲鍜屾牎鍑嗭纴杩欎簺浼犳劅鍣ㄨ兘澶熸彁渚涘嗳纭銆佸彲闱犵殑鐩戞祴缁撴灉锛屽府锷╃敤鎴锋洿濂藉湴浜呜В镊宸辩殑韬浣撶姸鍐点
浣撴祴镓嬬幆鍐呴儴阃氩父閰嶅囦简涓涓楂樻晥镄勫勭悊鍣ㄥ拰涓鍧楀皬鍨嫔瓨鍌ㄨ姱鐗囷纴鑳藉熷规坠鐜鏀堕泦鍒扮殑鏁版嵁杩涜屽勭悊銆佸垎鏋愬拰瀛桦偍锛屼互渚跨敤鎴烽殢镞舵煡鐪嫔巻鍙叉暟鎹銆佸垎鏋愰敾镣兼晥鏋滀互鍙婂埗瀹氢釜镐у寲镄勯敾镣艰″垝銆
镐荤殑𨱒ヨ达纴浣撴祴镓嬬幆镄勫师鐞嗘槸鍒╃敤镒熷簲鎶链鍜屽悇绉崭紶镒熷櫒瀹炴椂鐩戞祴鍜岃板綍鐢ㄦ埛镄勮繍锷ㄧ姸鍐靛拰韬浣撶姸镐侊纴鍐嶉氲繃鏁版嵁澶勭悊鍜屽垎鏋愶纴灏呜繖浜涗俊鎭杞鍖栦负瀵圭敤鎴锋湁鐢ㄧ殑褰㈠纺锛屽府锷╃敤鎴锋洿濂藉湴浜呜В镊宸辩殑韬浣撶姸鍐碉纴鍒跺畾涓镐у寲镄勯敾镣艰″垝锛屾彁楂桦仴搴锋按骞炽

⑸ 设计一个基于深度优先遍历的算法,判断一个给定的有向图是否包含回路。

你好,关于DFS判断有向图是否存在回路的问题,我本人编写的考研资料中有相关的原创总结,希望对你有帮助,转载还请注明原创出处:《大连理工大学软件学院887专业课(2021版)》。如有问题可以加我QQ601964408交流。
法一:利用递归方式,在DFS对图进行遍历时,将遍历过的顶点放入栈中,如果新遍历的顶点已经存在于递归栈中,则说明存在一个反向边,即存在一个环。此时栈中结点刚好是环路中的所有结点!
注意该方法没办法用DFS的非递归方法实现,因为非递归方法中,利用出栈的结点获取下一个邻接点入栈,和递归方式不同的地方在于,即使图中有环,非递归方法中的栈也无法存储环上的结点。(DFS的非递归详见本小结后续的代码总结部分)
代码实现如下:
void HasCycle ( Graph G ) {
bool visited [MAX_VERTEX_NUM] ; //访问标记数组
bool recursionStack [MAX_VERTEX_NUM] ; //标记该点是否在栈中
for ( i=0 ; i<G.vexnum ; i++) {
//mark all the vertices as not visited and not part of recursion stack
//标记所有结点均未访问以及不在栈中
visited [i] = FALSE ;
recursionStack [i] = FALSE ;
}
//call the recursive helper function to detect cycle in different DFS trees
//调用辅助递归函数以检测不同DFS树种的环路
for ( int i =0 ; i < G.vexnum ; i++ ) //每次检测一个连通图
if ( CheckCyclic ( G , i , VISITED , recursionStack ) ) ;
return true ; //存在回路
return false ; //不存在回路
}

bool CheckCyclic ( Graph G , int v , bool [ ] visited , bool [ ] recursionStack ) {
if ( visited [v] == FALSE) {
//mark the current nodes as visited and part of recursion stack
//将当前结点的标记数组和递归栈标记,置为已访问
visited [v] = TRUE ;
recursionStack [v] = TRUE ;

//recursion for all the vertices adjacent to this vertex
//递归该顶点附近的所有顶点
for ( Edge e = G.FirstEdge(v) ; G.IsEdge(e) ; e=G.NextEdge(e) ) {
//判断下一结点未被访问,进入递归函数判断是否有环
if ( visited [G.ToVertex(e) ] == FALSE &&
CheckCyclic ( G , G.ToVertex(e) , visited , recursionStack) )
return TRUE ;
//当下一结点已经访问过,并且已经在栈中,判断有环
else if ( recusionStack (G.ToVertex(e) ) == TRUE )
return TRUE ;
}//end_for
}//end_if

//remove the vertex from recursion stack
//从递归栈种移除该结点
recursionStack [v] = FALSE ;
return false ; //判断无环
}
--------------------------------------------------------------------------------------------------
法二:本方法与法一非常相似,方法一中存在三种情况,还未入栈时表示未被访问过的点;在栈中时表示已经被访问过但是还没有递归结束;从栈中出栈时表示递归结束,即后代也全部被访问过了。上述三种情况分别用 -1,0,1三种状态来标记点。
针对上述思路,假设正在处理点v,那么v的状态是0,其余正在处理的结点的状态也是0,如果从状态0的结点遍历到状态为0的结点,那么就存在环。此时所有状态为0的结点构成了一个环!发现存在环时遍历输出state数组即可,不过该方法输出时不是按照环路的顺序输出;如果需要顺序输出环路,可增加一个cycle数组,每次记录环路的起点位置i。用cycle[i]记录结点i的下一个结点编号。利用递归的方式输出cycle数组即可得到回路顺序。
代码实现:
bool Found = FALSE ; //标记是否发现环路
void HasCycle ( Graph G ) {
int state [MAX_VERTEX_NUM] ; //结点状态标识数组
for ( i=0 ; i<G.vexnum ; i++) {
state [i] = -1 ;
}
for ( int i =0 ; i < G.vexnum ; i++ ) { //每次检测一个连通图
CheckCyclic ( G , i , state );
if ( Found == TRUE ) ; //存在回路
return true ;
}
return false ; //不存在回路
}

void CheckCyclic ( Graph G , int v , int [ ] state ) {
if ( state [v] == -1) { //如果未访问过
state [v] = 0 ; //改变该点的状态
for ( Edge e = G.FirstEdge(v) ; G.IsEdge(e) ; e=G.NextEdge(e) ) {
if ( state [ G.ToVertex(e) ] == -1 )
CheckCyclic ( G , G.ToVertex(e) , state )
else if ( state [ G.ToVertex(e) ] == 0 ) //该图有环
Found = TRUE ;
}//end_for
}//end_if

state [v] = 1 ; //该点递归结束,即后代也访问完
}

热点内容
linux命令全称 发布:2024-05-17 12:07:54 浏览:110
ftpnas区别 发布:2024-05-17 12:06:18 浏览:949
512g存储芯片价格 发布:2024-05-17 12:04:48 浏览:963
脚本运行周期 发布:2024-05-17 11:39:09 浏览:808
阿里云服务器怎么配置发信功能 发布:2024-05-17 11:37:24 浏览:313
编程中的变量 发布:2024-05-17 11:33:06 浏览:777
加密视频怎么解密 发布:2024-05-17 11:02:52 浏览:571
柳工挖机密码多少合适 发布:2024-05-17 11:00:40 浏览:188
android工程叹号 发布:2024-05-17 10:56:21 浏览:481
在苹果手机应用怎么比安卓贵 发布:2024-05-17 10:56:20 浏览:548