資料結構和演算法學習筆記七:圖的搜尋

movin2333發表於2021-07-04

一.簡介

  圖的搜尋是指對圖中的頂點進行搜尋,指定某個頂點,搜尋出這個頂點能訪問到的所有頂點.圖的搜尋分為深度優先和廣度優先兩種,深度優先是指先沿著一條搜尋線進行搜尋,在搜尋到已經搜尋過的頂點時再回退到上一個頂點繼續深入搜尋這個頂點的所有分支...一直回退直到回退到起始頂點,顯然這種搜尋方式是遞迴結構.廣度搜尋是指先搜尋當前頂點,再搜尋這個頂點的所有關聯頂點,再繼續搜尋關聯頂點的關聯頂點...當然,已經搜尋過的頂點不再重複搜尋.

  圖的搜尋實現我寫成了工具類,實現了基於鄰接矩陣和鄰接表結構的圖的兩種搜尋方案.圖的結構實現使用的是上一篇部落格:;資料結構和演算法學習筆記六:圖的相關實現 - 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;
                }
            }
        }
    }
}

 

相關文章