学习笔记-深度优先搜索DFS寻找有向图环路实现

合集下载

深度优先搜索探索中的路径

深度优先搜索探索中的路径

深度优先搜索探索中的路径深度优先搜索(Depth First Search,DFS)是一种用于图和树等数据结构的搜索算法。

在图的深度优先搜索过程中,寻找一条从起始顶点到目标顶点的路径是常见且重要的问题。

本文将探讨深度优先搜索中如何找到路径的方法和实现。

一、路径的定义和表示在深度优先搜索中,路径是指从起始顶点到目标顶点的一条通路。

路径可以用顶点序列或边的序列来表示。

以图为例,设图G=(V,E)表示一个有向图,其中V为顶点集合,E为边集合。

对于路径P={v1,v2,v3,...,vn},其中vi∈V且(vi,vi+1)∈E。

路径中的第一个顶点为起始顶点,最后一个顶点为目标顶点。

二、深度优先搜索中的路径探索1. 基本思想深度优先搜索是一种递归的搜索方式,它以某个顶点为起始点,深度优先地遍历该顶点的邻接顶点,然后递归地遍历邻接顶点的邻接顶点,直到找到目标顶点或遍历完所有路径。

2. 算法步骤(1)判断当前顶点是否为目标顶点。

如果是,则找到了一条路径;(2)如果当前顶点不是目标顶点,继续遍历当前顶点的邻接顶点;(3)对于每个邻接顶点,重复步骤(1)和步骤(2),直到找到目标顶点或遍历完所有路径。

三、路径搜索的实现深度优先搜索中的路径搜索可以通过编程实现。

下面以Python语言为例,给出一个简单的深度优先搜索算法的实现:```pythondef dfs(graph, start, end, path=[]):path = path + [start]if start == end:return [path]if start not in graph:return []paths = []for vertex in graph[start]:if vertex not in path:new_paths = dfs(graph, vertex, end, path)for new_path in new_paths:paths.append(new_path)return paths```在上述代码中,graph为表示图的字典,start为起始顶点,end为目标顶点,path为当前路径。

深度优先搜索和广度优先搜索

深度优先搜索和广度优先搜索

深度优先搜索和⼴度优先搜索 深度优先搜索和⼴度优先搜索都是图的遍历算法。

⼀、深度优先搜索(Depth First Search) 1、介绍 深度优先搜索(DFS),顾名思义,在进⾏遍历或者说搜索的时候,选择⼀个没有被搜过的结点(⼀般选择顶点),按照深度优先,⼀直往该结点的后续路径结点进⾏访问,直到该路径的最后⼀个结点,然后再从未被访问的邻结点进⾏深度优先搜索,重复以上过程,直⾄所有点都被访问,遍历结束。

⼀般步骤:(1)访问顶点v;(2)依次从v的未被访问的邻接点出发,对图进⾏深度优先遍历;直⾄图中和v有路径相通的顶点都被访问;(3)若此时图中尚有顶点未被访问,则从⼀个未被访问的顶点出发,重新进⾏深度优先遍历,直到图中所有顶点均被访问过为⽌。

可以看出,深度优先算法使⽤递归即可实现。

2、⽆向图的深度优先搜索 下⾯以⽆向图为例,进⾏深度优先搜索遍历: 遍历过程: 所以遍历结果是:A→C→B→D→F→G→E。

3、有向图的深度优先搜索 下⾯以有向图为例,进⾏深度优先遍历: 遍历过程: 所以遍历结果为:A→B→C→E→D→F→G。

⼆、⼴度优先搜索(Breadth First Search) 1、介绍 ⼴度优先搜索(BFS)是图的另⼀种遍历⽅式,与DFS相对,是以⼴度优先进⾏搜索。

简⾔之就是先访问图的顶点,然后⼴度优先访问其邻接点,然后再依次进⾏被访问点的邻接点,⼀层⼀层访问,直⾄访问完所有点,遍历结束。

2、⽆向图的⼴度优先搜索 下⾯是⽆向图的⼴度优先搜索过程: 所以遍历结果为:A→C→D→F→B→G→E。

3、有向图的⼴度优先搜索 下⾯是有向图的⼴度优先搜索过程: 所以遍历结果为:A→B→C→E→F→D→G。

三、两者实现⽅式对⽐ 深度优先搜索⽤栈(stack)来实现,整个过程可以想象成⼀个倒⽴的树形:把根节点压⼊栈中。

每次从栈中弹出⼀个元素,搜索所有在它下⼀级的元素,把这些元素压⼊栈中。

并把这个元素记为它下⼀级元素的前驱。

深度优先搜索(深搜)——DeepFirstSearch【例题:迷宫】

深度优先搜索(深搜)——DeepFirstSearch【例题:迷宫】

深度优先搜索(深搜)——DeepFirstSearch【例题:迷宫】深度优先搜索 基本思想:先选择⼀种可能情况向前探索,在探索过程中,⼀点那发现原来的选择是错误的,就退回⼀步重新选择,继续向前探索,(回溯)反复进⾏。

【例题】迷宫问题思路:先随意选择⼀个⽅向,⼀步步向前试探,如果碰到死胡同说明该前进⽅向已经⽆路可⾛,这时⾸先看别的⽅向还是否有路可⾛,若有路可⾛,则该⽅向再次向前试探,若没有,则退回上⼀步,再看其他⽅向是否有路可⾛,,按此原则不断回溯和探索,知道找到⼊⼝为⽌。

框架:int search(int ......){for(i=1;i<=⽅向总数;i++)if(满⾜条件){保存结果;if(到达⽬的地)输出解;else search(k+1);恢复:保存结果之前的状态{回溯⼀步};}}具体代码实现如下:#include<iostream>#include<cstdio>#include<cstring>#define MAXN 20using namespace std;int map[MAXN][MAXN];//表⽰迷宫地图bool temp[MAXN][MAXN];//标记是否⾛过int dx[4]={0,0,1,-1};//横坐标的上下左右int dy[4]={-1,1,0,0};//纵坐标的上下左右int m,n,total,sx,sy,fx,fy,l,r,t;//m,n:地图的长宽,total:⽅案总数,sx,sy起点的横纵坐标,fx,fy:终点的横纵坐标,t:障碍总数,l,r:障碍坐标void search(int x,int y)//x,y:现在所在的点的坐标{if(x==fx&&y==fy)//到达终点{total++;//⽅案总数return; //返回继续寻找}for(int i=0;i<=3;i++)if(temp[x+dx[i]][y+dy[i]]==0&&map[x+dx[i]][y+dy[i]]==1)//判断下⾯要⾛的路是否有障碍if(x+dx[i]>=1&&y+dy[i]>=1&&x+dx[i]<=n&&y+dy[i]<=m)//判断是否超越迷宫边界{temp[x+dx[i]][y+dy[i]]=1;search(x+dx[i],y+dy[i]);temp[x+dx[i]][y+dy[i]]=0;//回溯⼀步}}int main(){cin>>n>>m>>t;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)map[i][j]=1;cin>>sx>>sy;cin>>fx>>fy;for(int i=1;i<=t;i++){cin>>l>>r;map[l][r]=0;}map[sx][sy]=0; search(sx,sy); printf("%d",total); return0;}。

深度优先搜索算法详解及代码实现

深度优先搜索算法详解及代码实现

深度优先搜索算法详解及代码实现深度优先搜索(Depth-First Search,DFS)是一种常见的图遍历算法,用于遍历或搜索图或树的所有节点。

它的核心思想是从起始节点开始,沿着一条路径尽可能深入地访问其他节点,直到无法继续深入为止,然后回退到上一个节点,继续搜索未访问过的节点,直到所有节点都被访问为止。

一、算法原理深度优先搜索算法是通过递归或使用栈(Stack)的数据结构来实现的。

下面是深度优先搜索算法的详细步骤:1. 选择起始节点,并标记该节点为已访问。

2. 从起始节点出发,依次访问与当前节点相邻且未被访问的节点。

3. 若当前节点有未被访问的邻居节点,则选择其中一个节点,将其标记为已访问,并将当前节点入栈。

4. 重复步骤2和3,直到当前节点没有未被访问的邻居节点。

5. 若当前节点没有未被访问的邻居节点,则从栈中弹出一个节点作为当前节点。

6. 重复步骤2至5,直到栈为空。

深度优先搜索算法会不断地深入到图或树的某一分支直到底部,然后再回退到上层节点继续搜索其他分支。

因此,它的搜索路径类似于一条深入的迷宫路径,直到没有其他路径可走后,再原路返回。

二、代码实现以下是使用递归方式实现深度优先搜索算法的代码:```pythondef dfs(graph, start, visited):visited.add(start)print(start, end=" ")for neighbor in graph[start]:if neighbor not in visited:dfs(graph, neighbor, visited)# 示例数据graph = {'A': ['B', 'C'],'B': ['A', 'D', 'E'],'C': ['A', 'F'],'D': ['B'],'E': ['B', 'F'],'F': ['C', 'E']}start_node = 'A'visited = set()dfs(graph, start_node, visited)```上述代码首先定义了一个用于实现深度优先搜索的辅助函数`dfs`。

环路识别 算法

环路识别 算法

环路识别算法
环路识别算法是指通过分析一个给定的网络或图结构,判断其中是否存在环路。

以下是几种常见的环路识别算法:
1. 深度优先搜索(DFS):从一个节点开始进行深度优先搜索,记录访问过的节点并标记为已访问。

如果在搜索路径中遇到已访问的节点,则说明存在环路。

2. 广度优先搜索(BFS):从一个节点开始进行广度优先搜索,使用队列来保存待访问的节点。

在搜索过程中,如果遇到已访问的节点,则说明存在环路。

3. 强连通分量算法:强连通分量是指一个图中的节点集合,其中的任意两个节点都可以相互到达。

通过使用强连通分量算法(如Tarjan算法或Kosaraju算法),可以将图划分为多个强连通分量。

如果存在一个强连通分量的大小大于1,则说明存在环路。

4. 拓扑排序:拓扑排序是一种对有向无环图(DAG)进行排序的算法。

在拓扑排序过程中,将入度为0的节点依次加入排序结果中,并将其邻接节点的入度减1。

如果最终排序结果包含所有的节点,则说明不存在环路;反之,存在环路。

这些算法可以根据具体的需求和应用场景进行选择和优化。

原题目:描述深度优先搜索算法的过程。

原题目:描述深度优先搜索算法的过程。

原题目:描述深度优先搜索算法的过程。

描述深度优先搜索算法的过程深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索图的算法,它是一种递归算法,通过深度的方式探索图的节点以获得解决方案。

步骤使用深度优先搜索算法来遍历图的节点的步骤如下:1. 选择一个起始节点作为当前节点,并将其标记为已访问。

2. 检查当前节点是否是目标节点。

如果是目标节点,则算法结束。

3. 如果当前节点不是目标节点,则遍历当前节点的邻居节点。

4. 对于每个未访问的邻居节点,将其标记为已访问,并将其加入到待访问节点的列表中。

5. 从待访问节点的列表中选择一个节点作为新的当前节点,并重复步骤2-4,直到找到目标节点或所有节点都被访问。

6. 如果所有节点都被访问但没有找到目标节点,则算法结束。

递归实现深度优先搜索算法可以使用递归的方式来实现。

以下是一个递归实现深度优先搜索的示例代码:def dfs(graph, node, visited):visited.add(node)print(node)for neighbor in graph[node]:if neighbor not in visited:dfs(graph, neighbor, visited)在上述代码中,`graph` 是表示图的邻接表,`node` 是当前节点,`visited` 是已访问节点的集合。

算法以起始节点作为参数进行递归调用,并在访问每个节点时打印节点的值。

非递归实现除了递归方式,深度优先搜索算法还可以使用栈来实现非递归版本。

以下是一个非递归实现深度优先搜索的示例代码:def dfs(graph, start_node):visited = set()stack = [start_node]while stack:node = stack.pop()if node not in visited:visited.add(node)print(node)for neighbor in graph[node]:if neighbor not in visited:stack.append(neighbor)在上述代码中,`graph` 是表示图的邻接表,`start_node` 是起始节点。

深度优先搜索算法实现技巧概述

深度优先搜索算法实现技巧概述

深度优先搜索算法实现技巧概述深度优先搜索算法(Depth-First Search,DFS)是一种用于图遍历和搜索的常用算法。

它的基本思想是从初始节点开始,逐个访问与当前节点相邻且尚未访问过的节点,直到无法继续访问为止,然后回溯到上一节点继续搜索,直到遍历完所有节点。

深度优先搜索算法可以用递归或栈实现。

下面将介绍几种常用的深度优先搜索算法实现技巧,帮助读者更好地理解和应用该算法。

1. 递归实现深度优先搜索算法递归是深度优先搜索算法最直观的实现方式之一。

通过递归调用自身来完成节点遍历。

可以按照以下步骤实现:1) 定义一个记录已访问节点的集合visited,初始时为空;2) 从起始节点开始,将其标记为已访问,并输出节点值;3) 遍历该节点的相邻节点,如果相邻节点未被访问过,则递归调用搜索函数访问该节点。

2. 栈实现深度优先搜索算法栈也是深度优先搜索算法的常用实现方式。

通过栈的先进后出特性,实现节点的回溯和遍历。

可以按照以下步骤实现:1) 定义一个记录已访问节点的集合visited,初始时为空;2) 定义一个栈,并将起始节点压入栈中;3) 循环执行以下步骤,直到栈为空:a) 弹出栈顶节点;b) 如果该节点未被访问过,则标记为已访问,并输出节点值;c) 遍历该节点的相邻节点,将未被访问过的相邻节点压入栈中。

3. 剪枝优化深度优先搜索算法在实际应用中,深度优先搜索算法通常会遇到搜索空间非常大的情况,导致算法的效率较低。

为了减小搜索空间,可以引入剪枝优化技巧。

常见的剪枝优化包括:a) 设置深度阈值,当搜索深度超过阈值时,立即返回不再继续搜索;b) 设置节点访问次数限制,每个节点最多被访问固定次数,防止陷入无意义的循环中。

4. 应用场景深度优先搜索算法在许多领域都有广泛应用,下面介绍几个常见的应用场景:a) 图的连通性判断:通过深度优先搜索算法可以判断图中两个节点是否连通;b) 拓扑排序:通过深度优先搜索算法可以对有向无环图进行拓扑排序;c) 迷宫求解:通过深度优先搜索算法可以求解迷宫问题,寻找从起点到终点的路径;d) 词语接龙:通过深度优先搜索算法可以找到两个词语之间的最短变换序列。

DFS讲义(基础)

DFS讲义(基础)

回溯及深度优先搜索内容提要:图的概述、搜索概述、回溯算法、深度优先搜索、搜索的剪枝预备知识1、图的概念1736年瑞士数学家欧拉(Euler)发表了图论的第一篇论文“哥尼斯堡七桥问题”。

在当时的哥尼斯堡城有一条横贯全市的普雷格尔河,河中的两个岛与两岸用七座桥联结起来,见图(1)。

当时那里的居民热衷于一个难题:游人怎样不重复地走遍七桥,最后回到出发点。

为了解决这个问题,欧拉用A,B,C,D 4个字母代替陆地,作为4个顶点,将联结两块陆地的桥用相应的线段表示,如图(2),于是哥尼斯堡七桥问题就变成了图(2)中,是否存在经过每条边一次且仅一次,经过所有的顶点的回路问题了。

欧拉在论文中指出,这样的回路是不存在的。

图可以定义为G=(V,E),其中V是顶点的非空集合,E是边的集合;一般用(Vx,Vy)表示边,其中Vx,Vy∈V。

根据边和顶点的不同特性,图可以分为有向图、无向图、带权图等。

DA图2 无向图BDA图3 有向图V1V32图4 带权图V2图的遍历:即从某个顶点出发,依次访问每个顶点一次。

【例题】两只蚂蚁比赛问题。

两只蚂蚁甲、乙分别处在图G中的顶点a,b处,并设图中各边长度相等。

甲提出同乙比赛:从它们所在顶点出发,走过图中所有边最后到达顶点c处。

如果它们速度相同,问谁最先到达目的地?2、树的概念树形结构是结点之间有分支,并具有层次关系的结构,它非常类似于自然界中的树。

树结构在客观世界中是大量存在的,例如家谱、行政组织机构都可用树形象地表示。

以上表示很像一棵倒画的树。

其中“树根”是张源,树的“分支点”是张明、张亮和张平,该家族的其余成员均是"树叶",而树枝(即图中的线段)则描述了家族成员之间的关系。

显然,以张源为根的树是一个大家庭。

它可以分成张明、张亮和张丽为根的三个小家庭;每个小家庭又都是一个树形结构。

树可以用树形图、嵌套集合、凹入表等方式表示。

其中树形图表示是树结构的主要表示方法:结点用圆圈表示,结点的名字写在圆圈旁边(有时亦可写在圆圈内)。

C语言DFS(深度优先搜索算法)详解

C语言DFS(深度优先搜索算法)详解

C语言DFS(深度优先搜索算法)详解DFS(深度优先)是一种用于遍历或图形或树结构的算法。

它从起点开始,沿着一条路径尽可能远地遍历图形,直到无法继续前进为止,然后返回到上一个节点,探索其他路径。

DFS基本上是一个递归的过程,它使用栈来实现。

DFS的基本思想是递归地遍历图形。

算法通过维护一个visited数组来跟踪已经访问过的节点,以避免无限循环。

首先,我们访问起点节点,并将其标记为已访问。

然后,对于起点的每个未访问的邻居节点,我们递归地调用DFS。

这样,我们沿着一条路径一直走到无法继续为止,然后返回上一个节点继续探索其他未访问的邻居。

我们重复这个过程,直到我们访问了所有的节点。

在实现DFS时,我们需要用到一个栈来存储节点。

首先,将起点节点入栈。

然后,当栈不为空时,我们将栈顶节点出栈,并将其标记为已访问。

接下来,我们将栈顶节点的所有未访问邻居入栈。

重复这个过程,直到栈为空。

需要注意的是,在使用栈时,我们应该按照相反的顺序将邻居节点入栈,这样在出栈时才能按照正确的顺序进行访问。

DFS可以用来解决很多问题,例如图的连通性、寻找路径、生成所有可能的子集等。

对于连通性问题,如果我们可以从起点节点访问到所有的节点,那么该图是连通的。

对于寻找路径问题,我们可以使用DFS来找到从起点到终点的路径。

对于生成所有可能的子集问题,我们可以使用DFS来枚举所有的子集。

下面是一个用C语言实现的DFS的示例代码:```c#include <stdio.h>#define MAX_SIZE 10int graph[MAX_SIZE][MAX_SIZE];int visited[MAX_SIZE];void dfs(int node)visited[node] = 1;printf("%d ", node);for (int i = 0; i < MAX_SIZE; i++) if (graph[node][i] && !visited[i]) dfs(i);}}int mai//初始化图for (int i = 0; i < MAX_SIZE; i++) for (int j = 0; j < MAX_SIZE; j++) graph[i][j] = 0;}}//添加边graph[0][1] = 1;graph[1][0] = 1;graph[1][2] = 1;graph[2][1] = 1;graph[2][3] = 1;graph[3][2] = 1;graph[3][4] = 1;graph[4][3] = 1;// 初始化visited数组for (int i = 0; i < MAX_SIZE; i++) visited[i] = 0;}//从节点0开始进行DFSdfs(0);return 0;```在这个示例代码中,我们使用一个10x10的二维数组表示图形,其中1表示两个节点之间有连接,0表示没有连接。

离散数学试题答案

离散数学试题答案

离散数学试题答案一、选择题1. 命题逻辑中,若命题P为“今天是周末”,命题Q为“我去野餐”,那么复合命题“今天是周末或我去野餐”在逻辑上的表示为:A. P∨QB. P∧QC. ¬P∨QD. ¬P∧Q答案:A2. 在集合论中,集合A和集合B的并集表示为:A. A - BB. B - AC. A ∪ BD. A ∩ B答案:C3. 有限自动机中,确定一个状态为接受状态的条件是:A. 有从该状态出发的ε-转移B. 所有从该状态出发的转移都能到达另一个接受状态C. 该状态不在任何闭包中D. 该状态在至少一个闭包中答案:D4. 哈希表中,解决冲突的常用方法不包括:A. 开放定址法B. 链地址法C. 再散列法D. 树形查找法答案:D5. 图的邻接矩阵表示法中,若顶点u到顶点v有一条边,则矩阵中的元素M[u][v]为:A. 0B. 1C. -1D. ∞答案:B二、填空题1. 在命题逻辑中,德摩根定律表明了________和________的对偶关系,即(¬(P∧Q))等价于________,而(¬(P∨Q))等价于________。

答案:合取;析取;¬P∨¬Q;¬P∧¬Q2. 集合的幂集是指该集合的所有________的集合,记作P(A)。

答案:子集3. 一个有向图G,若对于任意顶点u和v,都存在从u到v以及从v到u的路径,则称图G是________的。

答案:强连通4. 在图的遍历算法中,深度优先搜索(DFS)使用________数据结构进行遍历,而广度优先搜索(BFS)使用________数据结构进行遍历。

答案:栈;队列5. 哈密顿回路是指在一个图中,通过所有顶点恰好一次且最后回到起点的闭合路径,而欧拉回路是指通过图中每条边恰好一次并且回到起点的闭合路径,若一个图存在欧拉回路,则该图必须是________的。

答案:连通三、简答题1. 请简述命题逻辑中的四种标准形式及其真值表。

深度优先搜索算法利用深度优先搜索解决迷宫问题

深度优先搜索算法利用深度优先搜索解决迷宫问题

深度优先搜索算法利用深度优先搜索解决迷宫问题深度优先搜索算法(Depth-First Search, DFS)是一种常用的图遍历算法,它通过优先遍历图中的深层节点来搜索目标节点。

在解决迷宫问题时,深度优先搜索算法可以帮助我们找到从起点到终点的路径。

一、深度优先搜索算法的实现原理深度优先搜索算法的实现原理相当简单直观。

它遵循以下步骤:1. 选择一个起始节点,并标记为已访问。

2. 递归地访问其相邻节点,若相邻节点未被访问,则标记为已访问,并继续访问其相邻节点。

3. 重复步骤2直到无法继续递归访问,则返回上一级节点,查找其他未被访问的相邻节点。

4. 重复步骤2和3,直到找到目标节点或者已经遍历所有节点。

二、利用深度优先搜索算法解决迷宫问题迷宫问题是一个经典的寻找路径问题,在一个二维的迷宫中,我们需要找到从起点到终点的路径。

利用深度优先搜索算法可以很好地解决这个问题。

以下是一种可能的解决方案:```1. 定义一个二维数组作为迷宫地图,其中0代表通路,1代表墙壁。

2. 定义一个和迷宫地图大小相同的二维数组visited,用于记录节点是否已经被访问过。

3. 定义一个存储路径的栈path,用于记录从起点到终点的路径。

4. 定义一个递归函数dfs,参数为当前节点的坐标(x, y)。

5. 在dfs函数中,首先判断当前节点是否为终点,如果是则返回True,表示找到了一条路径。

6. 然后判断当前节点是否越界或者已经访问过,如果是则返回False,表示该路径不可行。

7. 否则,将当前节点标记为已访问,并将其坐标添加到path路径中。

8. 依次递归访问当前节点的上、下、左、右四个相邻节点,如果其中任意一个节点返回True,则返回True。

9. 如果所有相邻节点都返回False,则将当前节点从path路径中删除,并返回False。

10. 最后,在主函数中调用dfs函数,并判断是否找到了一条路径。

```三、示例代码```pythondef dfs(x, y):if maze[x][y] == 1 or visited[x][y] == 1:return Falseif (x, y) == (end_x, end_y):return Truevisited[x][y] = 1path.append((x, y))if dfs(x+1, y) or dfs(x-1, y) or dfs(x, y+1) or dfs(x, y-1): return Truepath.pop()return Falseif __name__ == '__main__':maze = [[0, 1, 1, 0, 0],[0, 0, 0, 1, 0],[1, 1, 0, 0, 0],[1, 1, 1, 1, 0],[0, 0, 0, 1, 0]]visited = [[0] * 5 for _ in range(5)]path = []start_x, start_y = 0, 0end_x, end_y = 4, 4if dfs(start_x, start_y):print("Found path:")for x, y in path:print(f"({x}, {y}) ", end="")print(f"\nStart: ({start_x}, {start_y}), End: ({end_x}, {end_y})") else:print("No path found.")```四、总结深度优先搜索算法是一种有效解决迷宫问题的算法。

dfs和bfs题目整理和分类

dfs和bfs题目整理和分类

DFS和BFS是图论中常用的两种遍历算法,它们在解决各种图论问题和编程竞赛中都有着重要的应用。

以下是对一些经典的DFS和BFS题目进行整理和分类。

一、DFS题目1. 树的遍历(1)给定一棵树,要求按照先序、中序、后序的方式遍历这棵树。

2. 深度优先搜索(1)给定一个有向图,从起点开始进行深度优先搜索,找出所有可达的节点。

(2)给定一个有向图,判断该图中是否存在环。

3. 拓扑排序(1)给定一个有向无环图,对图中的节点进行拓扑排序。

4. 连通分量(1)给定一个无向图,求图中的连通分量个数。

(2)给定一个无向图,求图中的每个连通分量包含的节点个数。

5. 非递归DFS(1)给定一个有向图,使用非递归的方式进行深度优先搜索。

二、BFS题目1. 广度优先搜索(1)给定一个有向图,从起点开始进行广度优先搜索,找出所有可达的节点。

(2)给定一个无向图,从起点开始进行广度优先搜索,找出所有可达的节点。

2. 最短路径(1)给定一个无向图,求从起点到终点的最短路径。

(2)给定一个有向图,求从起点到终点的最短路径。

3. 01矩阵(1)给定一个01矩阵,每个元素是0或1,求从左上角到右下角的最短路径长度。

4. 笛卡尔积(1)给定两个集合A和B,求它们的笛卡尔积。

5. 层次遍历(1)给定一棵树,使用广度优先搜索进行层次遍历。

以上是对一些常见的DFS和BFS题目进行整理和分类。

在解决这些问题时,可以根据具体情况选择合适的算法来进行求解,有效地应用DFS和BFS算法来解决实际问题。

希望以上内容对大家有所帮助。

对于DFS和BFS这两种遍历算法来说,在实际应用中有许多题目是可以通过它们来解决的。

下面继续介绍一些与DFS和BFS相关的经典问题及其解决方法。

6. 单词接龙(1)给定两个单词beginWord和endWord,以及一个字典,找出从beginWord到endWord的最短转换序列的长度。

每次转换只能改变一个字母,并且转换后的单词必须存在于字典中。

dfs的原理与应用

dfs的原理与应用

DFS的原理与应用1. 什么是DFSDFS(Depth-First Search),即深度优先搜索,是一种图遍历算法。

它通过访问一个顶点,然后再递归访问该顶点的所有未访问过的相邻顶点。

DFS的遍历方式类似于树的前序遍历,首先沿着树的深度遍历直到最深处,然后回溯到前一个节点,再继续遍历下一个节点,直到所有节点都被访问完成。

2. DFS的原理DFS基于栈或递归的原理实现。

其基本思想是:从图的某个顶点出发,访问此顶点,并将其标记为已访问。

然后选择该顶点的一个邻接顶点作为下一个要被访问的顶点,并将其入栈或递归调用。

直到栈为空或无法继续访问为止,遍历结束。

3. DFS的应用DFS在图的遍历中具有广泛的应用,它可以解决很多实际问题。

以下是几个常见的DFS应用场景:3.1 连通性问题对于一个无向图,可以使用DFS来判断两个顶点之间是否存在路径。

通过从一个顶点出发进行DFS,如果能访问到目标顶点,则说明两个顶点之间存在路径。

3.2 拓扑排序拓扑排序可以解决有向无环图(DAG)中的节点排序问题。

DFS可以通过寻找有向图中的环来实现拓扑排序。

具体步骤是,首先从一个未访问的顶点开始DFS,当访问完根节点的所有后继节点后,将此节点加入结果集。

然后继续DFS下一个未访问过的顶点,直到所有顶点都被访问。

3.3 迷宫求解在迷宫中,通常需要找到一条从起点到终点的路径。

DFS可以通过遍历迷宫中的所有可能路径来找到解。

具体过程是,从起点开始DFS,尝试每一种可能的行进方向,直到找到终点或者无法继续前进。

如果找到终点,则迷宫有解;如果无法继续前进,则迷宫无解。

3.4 图的连通分量在一个有向图或无向图中,DFS可以用于找出图中的所有连通分量。

具体步骤是,从一个未访问的顶点开始DFS,在DFS过程中遍历所有与其相连的节点,并将其标记为已访问。

然后找到下一个未访问的顶点,继续DFS,直到所有顶点都被访问。

3.5 数独求解DFS可以用于解决数独游戏。

如果无向图g必须进行3次深度优先搜索才能访问其所有顶点,则g一定没有回路(环)

如果无向图g必须进行3次深度优先搜索才能访问其所有顶点,则g一定没有回路(环)

如果无向图g必须进行3次深度优先搜索才能访问其所有顶点,则g一定没有回路(环).
深度优先搜索(DFS)是一种用于确定图中是否有环的常用算法,也可以用于查找图中的路径。

如果一个图必须执行3次DFS才能访问其所有顶点,那么我们可以断定它一定没有
回路。

在图论中,无向图是一个网络顶点的集合,以及每个顶点之间的边的集合。

它具有无序的顶点和边,它表达了一组对象之间的关系。

无向图可以被用于表示一些对象之间的概念关系,如事物之间的父子关系,朋友之间的关系等。

深度优先搜索应用于无向图有多种方法,如识别有向图中的环、确定节点间最小路径和构
建最近邻图等。

深度优先搜索有四个主要步骤:1.访问一个顶点;2.将顶点标记为已访问;
3.对每个相邻的顶点,以这个顶点作为中心,重复上面的步骤直到所有顶点被遍历;
4.当
找不到点和顶点未被访问时,终止搜索。

当前所有顶点都需要三次DFS访问,那么可以假设无向图肯定没有环状结构。

如果图已经有一个环,那么DFS只需要最多两次便可以访问到所有的节点了。

运用深度优先搜索可以完成很多不同的任务,从计算机科学的角度来说,它可以有效地分
析数据。

在给定一个无向图,必须经过三次深度优先搜索才能访问其所有的节点,说明这
个图没有完整的环状结构,因此可以确定这个无向图没有回路。

环路查询算法[001]

环路查询算法[001]

环路查询算法环路查询算法是一种用于解决图数据结构中环路问题的重要算法。

在实际的应用中,环路问题常常会给系统带来很多负面影响,因此解决环路问题具有重要的指导意义。

首先,让我们来了解一下环路查询算法的原理。

环路查询算法通过遍历图中的节点和边,来判断是否存在一个路径可以使得起点与终点重合,即形成一个环路。

该算法主要应用于图数据库、路由算法等领域,对于如何高效地处理环路问题提供了有力的解决方案。

环路查询算法的实现过程中,通常会采用深度优先搜索(DFS)或广度优先搜索(BFS)两种常见的遍历方式。

深度优先搜索算法通过递归地探索每个节点的邻居节点,直到找到终点或发现环路停止。

广度优先搜索算法则采用逐层扩展的方式,通过队列来存储要遍历的节点,并按照先进先出的顺序进行处理,直到找到终点或发现环路。

为了提高环路查询算法的效率,可以对图进行优化。

一种常用的优化方法是使用邻接表或邻接矩阵来表示图的结构,以便更快地查找节点和边的信息。

此外,还可以使用剪枝策略,减少不必要的搜索过程,从而缩短算法的执行时间。

在实际应用中,环路查询算法被广泛用于路由算法中。

网络中的路由器通过环路查询算法,可以确定最佳的路径来传输数据包。

同时,环路查询算法还可以用于图数据库的查询操作中,例如在社交网络中查找两个人之间的关系路径。

除了解决实际问题外,了解环路查询算法的原理对于理解图数据结构中的环路问题也具有重要的指导意义。

通过深入研究环路查询算法,可以帮助我们更好地理解图数据结构的性质和特点,进而优化算法设计和实现。

总而言之,环路查询算法是解决图数据结构中环路问题的一种重要算法。

通过深度优先搜索或广度优先搜索等遍历方式,环路查询算法可以高效地判断图中是否存在环路,并在实际应用中带来许多益处。

同时,了解环路查询算法的原理对于理解图数据结构以及优化算法设计也具有重要的指导意义。

图的连通性检测方法

图的连通性检测方法

图的连通性检测方法图论是数学的一个分支,研究图形结构以及图形之间的关系。

在图论中,连通性是一个重要的概念,用于描述图中的节点或顶点之间是否存在路径相连。

连通性检测方法是用来确定一个图是否是连通图的方法。

本文将介绍几种常用的图的连通性检测方法。

一、深度优先搜索(DFS)深度优先搜索是一种常用的图遍历算法,也可以用来检测图的连通性。

该方法从图中的一个顶点开始,沿着一条路径尽可能深的搜索,直到到达无法继续搜索的节点,然后回溯到上一个节点,继续搜索其他路径。

具体步骤如下:1. 选择一个起始节点作为根节点。

2. 遍历该节点的邻接节点,并标记为已访问。

3. 递归的访问未访问过的邻接节点,直到所有节点都被访问过。

4. 如果所有节点都被访问过,则图是连通的;否则,图是不连通的。

DFS算法的时间复杂度为O(V+E),其中V是节点数,E是边数。

二、广度优先搜索(BFS)广度优先搜索也是一种常用的图遍历算法,同样可以用来检测图的连通性。

该方法从图中的一个顶点开始,先访问其所有邻接节点,然后再依次访问它们的邻接节点。

具体步骤如下:1. 选择一个起始节点作为根节点。

2. 将该节点加入一个队列中。

3. 从队列中取出一个节点,并标记为已访问。

4. 遍历该节点的邻接节点,将未访问过的节点加入队列中。

5. 重复步骤3和步骤4,直到队列为空。

6. 如果所有节点都被访问过,则图是连通的;否则,图是不连通的。

BFS算法的时间复杂度同样为O(V+E)。

三、并查集并查集是一种数据结构,常用于解决图的连通性问题。

它可以高效地合并集合和判断元素是否属于同一个集合。

具体步骤如下:1. 初始化并查集,每个节点都是一个独立的集合。

2. 遍历图中的每条边,将边的两个节点合并到同一个集合中。

3. 判断图是否连通的方法是查找两个节点是否属于同一个集合。

并查集的时间复杂度为O(V+E)。

四、最小生成树最小生成树是指一个连通图的生成树,其所有边的权值之和最小。

数据结构与算法(13):深度优先搜索和广度优先搜索

数据结构与算法(13):深度优先搜索和广度优先搜索
因此访问顺序是:A => C => D => F => B => G => E
2.2.2 有向图的广广度优先搜索
下面面以“有向图”为例例,来对广广度优先搜索进行行行演示。还是以上面面的图G2为例例进行行行说明。
第1步:访问A。 第2步:访问B。 第3步:依次访问C,E,F。 在访问了了B之后,接下来访问B的出边的另一一个顶点,即C,E,F。前 面面已经说过,在本文文实现中,顶点ABCDEFG按照顺序存储的,因此会先访问C,再依次访 问E,F。 第4步:依次访问D,G。 在访问完C,E,F之后,再依次访问它们的出边的另一一个顶点。还是按 照C,E,F的顺序访问,C的已经全部访问过了了,那么就只剩下E,F;先访问E的邻接点D,再访 问F的邻接点G。
if(mVexs[i]==ch)
return i;
return -1;
}
/* * 读取一一个输入入字符
*/
private char readChar() {
char ch='0';
do {
try {
ch = (char)System.in.read();
} catch (IOException e) {
数据结构与算法(13):深度优先搜索和 广广度优先搜索
BFS和DFS是两种十十分重要的搜索算法,BFS适合查找最优解,DFS适合查找是否存在解(或者说 能找到任意一一个可行行行解)。用用这两种算法即可以解决大大部分树和图的问题。
一一、深度优先搜索(DFS)
1.1 介绍
图的深度优先搜索(Depth First Search),和树的先序遍历比比较类似。 它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点V出发,首首先访问该顶点, 然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至至图中所有和V有路路径相通 的顶点都被访问到。若此时尚有其他顶点未被访问到,则另选一一个未被访问的顶点作起始点,重 复上述过程,直至至图中所有顶点都被访问到为止止。 显然,深度优先搜索是一一个递归的过程。

算法导论第十五章习题答案

算法导论第十五章习题答案

算法导论第十五章习题答案算法导论第十五章习题答案算法导论是一本经典的计算机科学教材,其中第十五章涵盖了图算法的内容。

本文将针对该章节中的习题进行解答,并对其中一些问题进行深入探讨。

1. 习题15.1-1题目要求证明:对于任意的有向图G=(V,E),如果图中不存在从节点u到节点v的路径,则在每个强连通分量中,节点u和节点v都在同一个强连通分量中。

证明:假设存在一个强连通分量C,其中节点u在C中,节点v在C'中(C'为除了C之外的其他强连通分量)。

由于不存在从u到v的路径,所以在C中不存在从u到v的路径。

但是根据强连通分量的定义,C中的任意两个节点之间都存在路径。

所以存在一条从v到u的路径。

这与C'中的节点v不在C中矛盾,所以假设不成立,节点u和节点v必定在同一个强连通分量中。

2. 习题15.2-2题目要求证明:在一个有向无环图中,存在一个拓扑排序,使得任意两个非根节点u和v,u在v之前。

证明:假设存在一个有向无环图G=(V,E),不存在上述所要求的拓扑排序。

即对于任意的拓扑排序,存在两个非根节点u和v,u在v之后。

那么我们可以得到一条从u到v的路径。

由于图中不存在环,所以路径上的节点不会重复。

我们可以将路径上的节点按照拓扑排序的顺序排列,得到一个新的拓扑排序,使得u在v之前。

这与假设矛盾,所以原命题成立。

3. 习题15.3-3题目要求证明:在一个有向图G=(V,E)中,如果存在一条从节点u到节点v的路径,那么在图的转置G^T中,存在一条从节点v到节点u的路径。

证明:假设存在一条从节点u到节点v的路径。

那么在图的转置G^T中,边(u,v)变成了边(v,u)。

所以存在一条从节点v到节点u的路径。

因此,原命题成立。

4. 习题15.4-1题目要求:给出一个算法,判断一个有向图G=(V,E)是否是有向无环图。

算法思路:我们可以使用深度优先搜索(DFS)来判断是否存在环。

具体步骤如下:1. 对于图中的每个节点v,设置一个状态标记visited[v]为false。

DFS深度优先搜索(附例题)

DFS深度优先搜索(附例题)

DFS深度优先搜索(附例题)深度优先搜索,简称DFS,算是应⽤最⼴泛的搜索算法,属于图算法的⼀种,dfs按照深度优先的⽅式搜索,通俗说就是“⼀条路⾛到⿊”,dfs 是⼀种穷举,实质是将所有的可⾏⽅案列举出来,不断去试探,知道找到问题的解,其过程是对每⼀个可能的分⽀路径深⼊到不能再深⼊为⽌,且每个顶点只能访问⼀次。

dfs⼀般借助递归来实现例题:⾛迷宫#include <iostream>#include <string.h>using namespace std;int m,n;int sx,sy,ex,ey;//起点终点坐标int mp[20][20];//记录地图int cnt=0;//结果个数int ax[10]={0,0,-1,1};//x的四个⾛向int ay[10]={1,-1,0,0};//y的四个⾛向int vis[20][20];//记录是否来过int dfs(int x,int y){if((x>=0)&&(y>=0)&&(x<n)&&(y<m)&&(mp[x][y]==0)){//坐标合法性if(x==ex&&y==ey){//如果是终点cnt++;return0;}vis[x][y]=1;//将x,y设为已经来过if(vis[x][y]==1){//判断是否相邻顶点可⾛for(int i=0;i<4;i++){int tx=x+ax[i];int ty=y+ay[i];if((tx>=0)&&(ty>=0)&&(tx<n)&&(ty<m)&&(mp[tx][ty]==0)&&vis[tx][ty]==0)//相邻顶点可⾛条件dfs(tx,ty);//递归dfs此点}}vis[x][y]=0;return0;}}int main(){memset(vis,0,sizeof(vis));//将遍历数组全部置0cin>>n>>m;for(int i=0;i<n;i++){for(int j=0;j<m;j++){char c;cin>>c;if(c=='.'){//边输⼊边置mp的0或1,并设置起点坐标和终点坐标mp[i][j]=0;}else if(c=='S'){sx=i;sy=j;mp[i][j]=0;}else if(c=='T'){ex=i;ey=j;mp[i][j]=0;}elsemp[i][j]=1;//'#'为墙壁,⾛不通所以设为1}}dfs(sx,sy);//从起点开始遍历cout<<cnt<<endl;return0;}。

判断一个图是否有环无向图有向图讲解

判断一个图是否有环无向图有向图讲解

一、无向图:方法1:∙如果存在回路,则必存在一个子图,是一个环路。

环路中所有顶点的度>=2。

∙ n算法:第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

如果最后还有未删除顶点,则存在环,否则没有环。

∙ n算法分析:由于有m条边,n个顶点。

i)如果m>=n,则根据图论知识可直接判断存在环路。

(证明:如果没有环路,则该图必然是k棵树k>=1。

根据树的性质,边的数目m = n-k。

k>=1,所以:m<n)ii)如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。

这两种操作的总数不会超过m+n。

由于m<n,所以算法复杂度为O(n)。

∙注:该方法,算法复杂度不止O(V),首先初始时刻统计所有顶点的度的时候,复杂度为(V + E),即使在后来的循环中E>=V,这样算法的复杂度也只能为O(V + E)。

其次,在每次循环时,删除度为1的顶点,那么就必须将与这个顶点相连的点的度减一,并且执行delete node from list[list[node]],这里查找的复杂度为list[list[node]]的长度,只有这样才能保证当degree[i]=1时,list[i]里面只有一个点。

这样最差的复杂度就为O(EV)了。

方法2:DFS搜索图,图中的边只可能是树边或反向边,一旦发现反向边,则表明存在环。

该算法的复杂度为O(V)。

方法3:摘自:/lzrzhao/archive/2008/03/13/2175787.aspx PS:此方法于2011-6-12补充假定:图顶点个数为M,边条数为E遍历一遍,判断图分为几部分(假定为P部分,即图有P 个连通分量)对于每一个连通分量,如果无环则只能是树,即:边数=结点数-1只要有一个满足边数> 结点数-1原图就有环将P个连通分量的不等式相加,就得到:P1:E1=M1-1P2:E2=M2-1...PN:EN>MN-1所有边数(E) > 所有结点数(M) - 连通分量个数(P)即: E + P > M 所以只要判断结果 E + P > M 就表示原图有环,否则无环.实例代码如下:1.#include<iostream>2.#include<malloc.h>ing namespace std;4.#define maxNum 100 //定义邻接举证的最大定点数5.int visited[maxNum];//通过visited数组来标记这个顶点是否被访问过,0表示未被访问,1表示被访问6.int DFS_Count;//连通部件个数,用于测试无向图是否连通,DFS_Count=1表示只有一个连通部件,所以整个无向图是连通的7.int pre[maxNum];8.int post[maxNum];9.int point;//pre和post的值10.11.//图的邻接矩阵表示结构12.typedef struct13.{14.char v[maxNum];//图的顶点信息15.int e[maxNum][maxNum];//图的顶点信息16.int vNum;//顶点个数17.int eNum;//边的个数18.}graph;19.void createGraph(graph *g);//创建图g20.void DFS(graph *g);//深度优先遍历图g21.void dfs(graph *g,int i);//从顶点i开始深度优先遍历与其相邻的点22.void dfs(graph *g,int i)23.{24.//cout<<"顶点"<<g->v[i]<<"已经被访问"<<endl;25. cout<<"顶点"<<i<<"已经被访问"<<endl;26. visited[i]=1;//标记顶点i被访问27. pre[i]=++point;28.for(int j=1;j<=g->vNum;j++)29. {30.if(g->e[i][j]!=0&&visited[j]==0)31. dfs(g,j);32. }33. post[i]=++point;34.}35.36.void DFS(graph *g)37.{38.int i;39.//初始化visited数组,表示一开始所有顶点都未被访问过40.for(i=1;i<=g->vNum;i++)41. {42. visited[i]=0;43. pre[i]=0;44. post[i]=0;45. }46.//初始化pre和post47. point=0;48.//初始化连通部件数为049. DFS_Count=0;50.//深度优先搜索51.for(i=1;i<=g->vNum;i++)52. {53.if(visited[i]==0)//如果这个顶点为被访问过,则从i顶点出发进行深度优先遍历54. {55. DFS_Count++;//统计调用void dfs(graph *g,int i);的次数56. dfs(g,i);57. }58. }59.}60.void createGraph(graph *g)//创建图g61.{62. cout<<"正在创建无向图..."<<endl;63. cout<<"请输入顶点个数vNum:";64. cin>>g->vNum;65. cout<<"请输入边的个数eNum:";66. cin>>g->eNum;67.int i,j;68.//输入顶点信息69.//cout<<"请输入顶点信息:"<<endl;70.//for(i=0;i<g->vNum;i++)71.// cin>>g->v[i];72.//初始画图g73.for(i=1;i<=g->vNum;i++)74.for(j=1;j<=g->vNum;j++)75. g->e[i][j]=0;76.//输入边的情况77. cout<<"请输入边的头和尾"<<endl;78.for(int k=0;k<g->eNum;k++)79. {80. cin>>i>>j;81. g->e[i][j]=1;82. g->e[j][i]=1;//无向图对称83. }84.}85.int main()86.{87. graph *g;88. g=(graph*)malloc(sizeof(graph));89. createGraph(g);//创建图g90. DFS(g);//深度优先遍历91.//连通部件数,用于判断是否连通图92. cout<<"连通部件数量:";93. cout<<DFS_Count<<endl;94.if(DFS_Count==1)95. cout<<"图g是连通图"<<endl;96.else if(DFS_Count>1)97. cout<<"图g不是连通图"<<endl;98.//各顶点的pre和post值99.for(int i=1;i<=g->vNum;i++)100. cout<<"顶点"<<i<<"的pre和post分别为:"<<pre[i]<<" "<<post[i]<<endl;101.//cout<<endl;102.//判断无向图中是否有环103.if(g->eNum+DFS_Count>g->vNum)104. cout<<"图g中存在环"<<endl;105.else106. cout<<"图g中不存在环"<<endl;107.int k;108. cin>>k;109.return 0;110.}111./*112.输入:113.正在创建无向图...114.请输入顶点个数vNum:10115.请输入边的个数eNum:9116.请输入边的头和尾117.1 2118.1 4119.2 5120.2 6121.4 7122.5 9123.6 3124.7 8125.9 10126.*/注意:有向图不能使用此方法。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

常用的图的存储结构主要有以下二种:邻接矩阵和邻接表邻接矩阵与邻接表的对比:1、当图中结点数目较小且边较多时,采用邻接矩阵效率更高。

2、当节点数目远大且边的数目远小于相同结点的完全图的边数时,采用邻接表存储结构更有效率。

有向图稀疏邻接矩阵结构深度优先搜索DFS寻找环路Java实现1.import java.util.*;2.import ng.StringUtils;3.public class DFSSparseCycle {4./** 点数 */5.private int vertexCount;6./** 有向图的稀疏邻接矩阵 */7.private int[][] sparseAdjacencyMatrix;8./** 点访问状态, 0未访问 1已访问 */9.private int[] vertexAccessStatus;10./** 追踪栈 */11.private List<Integer> traceStack = new ArrayList<Integer>();12./** 追踪过的点 */13.private List<Integer> tracedVertexs = new ArrayList<Integer>();14./** 环列表 */15.private List<List<Integer>> cycles = newArrayList<List<Integer>>();16.public DFSSparseCycle(int[][] sparseAdjacencyMatrix) {17.this.sparseAdjacencyMatrix = sparseAdjacencyMatrix;18.this.vertexCount = sparseAdjacencyMatrix.length;19.vertexAccessStatus = new int[vertexCount];20.Arrays.fill(vertexAccessStatus, 0);21.}22.public void findCycle() {23.for (int i = 0; i < vertexCount; i++) {24.if (!tracedVertexs.contains(i)) findCycle(i);25.}26.}27.public void findCycle(int vertex) {28.if (vertexAccessStatus[vertex] == 1) {29.int j = 0;30.if ((j = traceStack.indexOf(vertex)) != -1) {31.List<Integer> cycle = newArrayList<Integer>();32.while (j < traceStack.size()) {33.cycle.add(traceStack.get(j));34.j++;35.}36.cycles.add(cycle);37.return;38.}39.return;40.}41.vertexAccessStatus[vertex] = 1;42.traceStack.add(vertex);43.for (int i = 0; i < vertexCount; i++) {44.if (sparseAdjacencyMatrix[vertex][i] == 1) {45.findCycle(i);46.tracedVertexs.add(i);47.}48.}49.traceStack.remove(traceStack.size() - 1);50.}51.public boolean hasCycle() {52.return cycles.size() > 0;53.}54.public List<List<Integer>> getCycles() {55.return this.cycles;56.}57.public static void main(String[] args) {58.// 有向图的稀疏邻接矩阵59.int[][] adjacencyMatrix = { { 0, 1, 1, 0, 0, 0, 0 },60.{ 0, 0, 0, 1, 0, 0, 0 },61.{ 0, 0, 1, 0, 0, 1, 0 },62.{ 0, 0, 0, 0, 1, 0, 0 },63.{ 0, 0, 1, 0, 0, 0, 0 },64.{ 0, 0, 0, 0, 1, 0, 1 },65.{ 1, 0, 1, 1, 0, 0, 1 }66.};67.DFSSparseCycle dfsCycle = newDFSSparseCycle(adjacencyMatrix);68.dfsCycle.findCycle();69.if (!dfsCycle.hasCycle()) {70.System.out.println("No Cycle.");71.} else {72.List<List<Integer>> cycleList =dfsCycle.getCycles();73.for (int i = 0, len = cycleList.size(); i < len; i++) {System.err.println(StringUtils.join(cycleList.get(i), "#"));74.}75.}76.}77.}有向图稠密邻接表结构深度优先搜索DFS寻找环路Java实现1.import ng.StringUtils;2.import java.util.*;3.public class DFSDenseCycle {4./** 有向图的稠密邻接表 */5.private Map<Integer, Set<Integer>> denseAdjacencyMatrix;6./** 点访问状态 */7.private Set<Integer> vertexAccessStatus = newHashSet<Integer>();8./** 追踪栈 */9.private List<Integer> traceStack = new ArrayList<Integer>();10./** 追踪过的点 */11.private List<Integer> tracedVertexs = new ArrayList<Integer>();12./** 环列表 */13.private List<List<Integer>> cycles = newArrayList<List<Integer>>();14.public DFSDenseCycle(Map<Integer, Set<Integer>>denseAdjacencyMatrix) {15.this.denseAdjacencyMatrix = denseAdjacencyMatrix;16.}17.public void findCycle() {18.for (Map.Entry<Integer, Set<Integer>> entry :denseAdjacencyMatrix.entrySet()) {19.int vertex = entry.getKey();20.if (!tracedVertexs.contains(vertex))findCycle(vertex);21.}22.}23.public void findCycle(int vertex) {24.if (vertexAccessStatus.contains(vertex)) {25.int j = 0;26.if ((j = traceStack.indexOf(vertex)) != -1) {27.List<Integer> cycle = newArrayList<Integer>();28.while (j < traceStack.size()) {29.cycle.add(traceStack.get(j));30.j++;31.}32.cycles.add(cycle);33.return;34.}35.return;36.}37.vertexAccessStatus.add(vertex);38.traceStack.add(vertex);39.Set<Integer> vertexs = denseAdjacencyMatrix.get(vertex);40.for (int v : vertexs) {41.if (denseAdjacencyMatrix.containsKey(v)) {42.findCycle(v);43.tracedVertexs.add(v);44.}45.}46.traceStack.remove(traceStack.size() - 1);47.}48.public boolean hasCycle() {49.return cycles.size() > 0;50.}51.public List<List<Integer>> getCycles() {52.return this.cycles;53.}54.public static void main(String[] args) {55.Map<Integer, Set<Integer>> adjacencyMatrix = newHashMap<Integer, Set<Integer>>();56.adjacencyMatrix.put(0, new HashSet(Arrays.asList(1,2)));57.adjacencyMatrix.put(1, new HashSet(Arrays.asList(2,3)));58.adjacencyMatrix.put(2, new HashSet(Arrays.asList(0,3)));59.DFSDenseCycle dfsCycle = newDFSDenseCycle(adjacencyMatrix);60.dfsCycle.findCycle();61.if (!dfsCycle.hasCycle()) {62.System.out.println("No Cycle.");63.} else {64.List<List<Integer>> cycleList =dfsCycle.getCycles();65.for (int i = 0, len = cycleList.size(); i < len;i++) {System.err.println(StringUtils.join(cycleList.get(i), "#"));66.}67.}68.}69.}。

相关文档
最新文档