1. 程式人生 > >圖的遍歷(資料結構)

圖的遍歷(資料結構)

  1. 深度優先遍歷
    1)思路:選出起始頂點v,然後選取與v鄰接的一個頂點u(u未被訪問過),訪問u,讓後重覆上述操作,繼續選取u的一個未訪問過的頂點x,訪問後繼續重複,直至選取的某個點沒有未訪問過的鄰接點了,退回到最近一次訪問過的點, 選取下一個未訪問過的鄰接點,以此類推。
    2)遞迴描述:選取起始頂點v,訪問,選取它的一個鄰接點,若未訪問過,則進行遞迴遍歷,如此可訪問與v連通的所有點。
    3)非連通處理:若訪問完v的所有連通的點後,仍有未訪問過的點,選取下一個為訪問過的點作為起始點,重新進行遞迴遍歷操作。
    4)程式碼實現:
Status DFS(MGraph &G,int v,Status (*Visit)(ElemType))
{
    //遍歷一個連通分量,不限定圖的儲存結構,v為起始點下標(注意,DFS不能遍歷一整個非連通圖,只能遍歷一個連通分量)
Visit(v); visited[v] = true; //w是v的鄰接點,第一次先找到v的第一個鄰接點,進行dfs,在w的 //所有鄰接點都找到了後,返回到v這一層,再找v的第二個鄰接點,以此類推 for(int w = FirstAdjVex(G,v); w >= 0; w = NextAdjVex(G,w)) { if(!visited[w]) DFS(G,w,Visit); } } Status DFSTraverse(MGraph &G,int v,Status (*Visit)(int
v)) { for(v = 0;v < G.vexnum; ++v) { visited[v] = false;//表示所有頂點都為被訪問過 } //因為可能此圖是一個非連通圖,如果要遍歷所有的點,在遍歷完一個連通分量之後,需要再遍歷另一個連通分量 for(v = 0; v < G.vexnum; ++v) { if(!visited[v]) DFS(G,v,Visit);//注意這裡把函式作為引數是怎麼傳遞的 } }

2.廣度優先搜尋
1)思路:選取一個起始點v,逐個遍歷v的鄰接點,直至把v的所有鄰接點都遍歷了一遍,再從v的第一個鄰接點開始,逐個訪問v的第一個鄰接點的所有鄰接點,重複上述操作,直至遍歷完與v連通的所有點。
2)分析:用佇列儲存訪問過的元素,v是起始點,訪問v,v入隊,迴圈判斷條件只要佇列不為空,取出佇列頭元素,訪問其鄰接點並將鄰接點入隊,重複上述操作,直至佇列為空,也就遍歷完了與v連通的所有點。
3)非連通處理:遍歷完v所屬的連通分量,若仍有點未訪問,從從其開始,重新進行廣度優先搜尋。
4)程式碼實現:

Status BFS(MGraph &G,int v,Status (*Visit)(ElemType))
{
        Visit(V);
        visited[v] = true;
        EnQueue(Q,v);

    //佇列不為空
    while(!IsEmpty(Q))
    {
        ElemType u;
        DeQueue(Q,u);
        for(ElemType w = FirstAdjNex(G,u);w >= 0; w = NextAdjVex(G,u,w))//NextAdjVex找除w外的鄰接點
        {
            if(!visited[w])
            {
                Visit(w);
                visited[w] = true;
                EnQueue(Q,w);
            }

        }
    }
}

Status BFSTraverse(MGraph &G,Status (*Visit)(int v))
{
    //不管是dfs,還是bfs,都需要初始化visited陣列為false
    for(v = 0; v < G.vexnum; ++v)
    {
        visited[v] = false;
    }

    for(v = 0; v < G.vexnum; ++v)
    {
        if(!visited[v])
            BFS(G,v,Visit);
    }
}