数据结构和算法学习笔记七:图的搜索
一.简介
图的搜索是指对图中的顶点进行搜索,指定某个顶点,搜索出这个顶点能访问到的所有顶点.图的搜索分为深度优先和广度优先两种,深度优先是指先沿着一条搜索线进行搜索,在搜索到已经搜索过的顶点时再回退到上一个顶点继续深入搜索这个顶点的所有分支...一直回退直到回退到起始顶点,显然这种搜索方式是递归结构.广度搜索是指先搜索当前顶点,再搜索这个顶点的所有关联顶点,再继续搜索关联顶点的关联顶点...当然,已经搜索过的顶点不再重复搜索.
图的搜索实现我写成了工具类,实现了基于邻接矩阵和邻接表结构的图的两种搜索方案.图的结构实现使用的是上一篇博客:;数据结构和算法学习笔记六:图的相关实现 - movin2333 - 博客园 (cnblogs.com)中的图的实现.
二.深度优先搜索:
/************************************ * 创建人:movin * 创建时间:2021/7/4 8:41:02 * 版权所有:个人 ***********************************/ using System; using System.Collections.Generic; using System.Text; namespace GraphCore { /// <summary> /// 深度优先遍历算法工具 /// </summary> public class DepthFirstSearchUtil { /// <summary> /// 邻接矩阵的深度优先遍历 /// 访问与给定下标顶点相连通的所有顶点 /// 无向图 /// </summary> /// <param name="graph">邻接矩阵形式存储的图</param> /// <param name="whenVisited">当遍历到顶点后的回调</param> /// <param name="whenVisited">记录顶点是否访问过的数组</param> /// <param name="index">当前遍历的顶点下标,默认0</param> public static void DFS(AdjacencyMatrixGraph graph,Action<AdjacencyMatrixVertex> whenVisited,bool[] visited = null,int index = 0) { if(visited == null) { visited = new bool[graph.Count]; } if(index >= graph.Count || index < 0) { return; } visited[index] = true; if(whenVisited != null) { whenVisited(graph.vertices[index]); } for(int i = 0;i < graph.adjacencyMatrix.GetLength(1); i++) { //在满足条件时才会进入递归,否则终止递归 if(graph.adjacencyMatrix[index,i] != 0 && !visited[i]) { DFS(graph, whenVisited, visited, i); } } } /// <summary> /// 邻接表的深度优先遍历 /// 访问与给定下标顶点相连通的所有顶点 /// 无向图 /// </summary> /// <param name="graph">邻接表形式存储的图</param> /// <param name="whenVisited">当遍历到顶点后的回调</param> /// <param name="visited">记录顶点是否访问过的数组</param> /// <param name="index">当前遍历的顶点下标,默认0</param> public static void DFS(AdjacencyListGraph graph, Action<AdjacencyListVertex> whenVisited, bool[] visited = null, int index = 0) { if (visited == null) { visited = new bool[graph.Count]; } if (index >= graph.Count || index < 0) { return; } //递归终止条件 if (visited[index]) { return; } visited[index] = true; if (whenVisited != null) { whenVisited(graph.vertices[index]); } AdjacencyListEdgeNode node = graph.vertices[index].firstEdge; //遍历链表的所有结点并递归 while(node != null) { DFS(graph, whenVisited, visited, node.vertexIndex); node = node.next; } } } }
三.广度优先搜索:
/************************************ * 创建人:movin * 创建时间:2021/7/4 15:23:35 * 版权所有:个人 ***********************************/ using System; using System.Collections.Generic; using System.Text; namespace GraphCore { /// <summary> /// 广度优先遍历算法工具 /// </summary> public class BreadthFirstSearchUtil { /// <summary> /// 邻接矩阵的广度优先遍历 /// 访问与给定下标顶点相连通的所有顶点 /// 无向图 /// </summary> /// <param name="graph">图</param> /// <param name="whenVisited">访问到顶点后的回调</param> /// <param name="startIndex">开始访问的顶点下标</param> public static void BFS(AdjacencyMatrixGraph graph, Action<AdjacencyMatrixVertex> whenVisited, int startIndex = 0) { if(startIndex >= graph.Count || startIndex < 0) { return; } //顶点是否访问的标识 bool[] visited = new bool[graph.Count]; //是否遍历顶点的关联顶点的标识 bool[] searched = new bool[graph.Count]; //存储所有访问到的顶点的栈 Queue<AdjacencyMatrixVertex> vertexQueue = new Queue<AdjacencyMatrixVertex>(); //辅助栈,存储之前访问到的所有顶点的对应下标,和存储顶点的栈同存同取 Queue<int> indexQueue = new Queue<int>(); //开始结点入栈 vertexQueue.Enqueue(graph.vertices[startIndex]); indexQueue.Enqueue(startIndex); visited[startIndex] = true; //所有顶点出栈 while (vertexQueue.Count > 0) { AdjacencyMatrixVertex vertex = vertexQueue.Dequeue(); int currentIndex = indexQueue.Dequeue(); //访问顶点 if (whenVisited != null) { whenVisited(vertex); } //没有遍历过的情况下 if (!searched[currentIndex]) { //遍历此下标顶点的所有关联顶点,没有访问过的入栈 for (int i = 0; i < graph.adjacencyMatrix.GetLength(1); i++) { if (graph.adjacencyMatrix[currentIndex, i] != 0 && !visited[i]) { vertexQueue.Enqueue(graph.vertices[i]); indexQueue.Enqueue(i); visited[i] = true; } } searched[currentIndex] = true; } } } /// <summary> /// 邻接矩阵的广度优先遍历 /// 访问与给定下标顶点相连通的所有顶点 /// 无向图 /// </summary> /// <param name="graph">图</param> /// <param name="whenVisited">访问到顶点之后的回调</param> /// <param name="startIndex">开始访问的顶点下标</param> public static void BFS(AdjacencyListGraph graph, Action<AdjacencyListVertex> whenVisited, int startIndex = 0) { if (startIndex >= graph.Count || startIndex < 0) { return; } //顶点是否访问的标识 bool[] visited = new bool[graph.Count]; //是否遍历顶点的关联顶点的标识 bool[] searched = new bool[graph.Count]; //存储所有访问到的顶点的栈 Queue<AdjacencyListVertex> vertexQueue = new Queue<AdjacencyListVertex>(); //辅助栈,存储之前访问到的所有顶点的对应下标,和存储顶点的栈同存同取 Queue<int> indexQueue = new Queue<int>(); //开始结点入栈 vertexQueue.Enqueue(graph.vertices[startIndex]); indexQueue.Enqueue(startIndex); visited[startIndex] = true; while(vertexQueue.Count > 0) { AdjacencyListVertex vertex = vertexQueue.Dequeue(); int currentIndex = indexQueue.Dequeue(); if(whenVisited != null) { whenVisited(vertex); } if (!searched[currentIndex]) { //访问边表,将没有访问过的顶点加入队列 AdjacencyListEdgeNode node = vertex.firstEdge; do { int vertexIndex = node.vertexIndex; if (!visited[vertexIndex]) { vertexQueue.Enqueue(graph.vertices[vertexIndex]); indexQueue.Enqueue(vertexIndex); visited[vertexIndex] = true; } node = node.next; } while (node != null); searched[currentIndex] = true; } } } } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步