近段時間又回顧了下數據結構中的圖,我之前的有一篇博文介紹了圖與線性表和樹的區別與聯系。 並且就圖的存儲和圖的創建也做了一些簡單的說明,
這一篇我將着重說說圖的兩種基本的遍歷方法,深度遍歷和廣度遍歷。 深度遍歷: 深度遍歷類似於樹的先根遍歷,是樹的先根遍歷的推廣。假設初始狀態是圖中所有頂點未曾被訪問,則深度遍歷可從圖中 某個頂點v出發,訪問此頂點,然后依次從v的未被訪問的鄰接點出發深度優先遍歷圖,直至圖中所有與v有路徑的頂點都被訪問到,若此時 圖中尚有頂點未被訪問,則另選圖中一個未被訪問的頂點作為起始點,重復上述過程,直至圖中所有頂點都被訪問到為止。 其具體的代碼實現如下:
int DFSTraverse(MGraph G)
{
int v;
printf("\n深度遍歷輸出 : \n");
for(v = 0; v < G.vexnum; v++)
{
visited[v] = 0;
}
for(v = 0; v < G.vexnum; v++)
{
if(visited[v] == 0)
{
DFS(G, v);
printf("\n");
}
}
return true;
}
int DFS(MGraph G, int v)
{
int w;
visited[v] = 1;
printf("%s ", G.vexs[v]);
for(w = 0; w < G.vexnum; w++)
{
if(G.arcs[v][w].adj ==1 && visited[w] == 0)
{
DFS(G,w);
}
}
return true;
}
其實質是運用了遞歸思想,在遍歷圖中時,對圖中的每個頂點之多調用一次DNS函數,因為一旦某個頂點唄標志城已被訪問, 就不再從它出發進行搜索了,因此遍歷圖的實質上是對每個頂點查找器鄰接點的過程。
廣度遍歷:
廣度優先搜索遍歷類似於樹的按層次遍歷的過程。假設從圖中某個頂點v出發,在訪問了v之后依次訪問v的各個未曾訪問過的鄰接點,然后分別 從這些鄰接點出發依次訪問它們的鄰接點,並使“先被訪問的頂點的鄰接點”先與“后被訪問的鄰接點”被訪問,直至圖中所有已被訪問的鄰接點都被訪問到, 若此時圖中尚有頂點未被訪問到,則另選圖中一個未被訪問的頂點作為起始點,重復上述操作,直至圖中所有頂點都被訪問到為止。 其具體代碼實現如下:
int QueueInit(Queue *sq)
{
if(sq)
{
sq->front = 0;
sq->rear = 0;
}
else
return false;
return true;
}
int QueueIsEmpty(Queue sq)
{
if(sq.front == sq.rear)
return true;
else
return false;
}
int EnQueue(Queue *sq, int x)
{
if(sq->front == (sq->rear+1)%MAX_VERTEX_NUM)
{
printf("Queue is full!\n");
return false;
} else
{
sq->data[sq->rear] = x;
sq->rear = (sq->rear+1)%MAX_VERTEX_NUM;
}
}
int OutQueue(Queue *sq)
{
if(QueueIsEmpty(*sq))
{
printf("Queue is Empty!\n");
return false;
} else
{
sq->front = (sq->front+1)%MAX_VERTEX_NUM;
}
}
int QueueFront(Queue sq, int *e)
{
if(QueueIsEmpty(sq))
{
printf("Queue is full!\n");
return false;
} else
{
*e = sq.data[sq.front];
return true;
}
}
int BFSTraverse(MGraph G)
{
int v;
printf("廣度遍歷 : \n");
for(v = 0; v < G.vexnum; v++)
{
visited[v] = 0;
}
for(v = 0; v < G.vexnum; v++)
{
if(visited[v] == 0)
{
BFS(G, v);
printf("\n");
}
}
return true;
}
int BFS(MGraph G, int v)
{
int v1, v2;
Queue sq;
QueueInit(&sq);
EnQueue(&sq, v);
visited[v] = 1;
printf("%s ", G.vexs[v]);
while(QueueIsEmpty(sq) == false)
{
QueueFront(sq, &v1);
OutQueue(&sq);
for(v2 = 0; v2 < G.vexnum; v2++)
{
if(G.arcs[v1][v2].adj != 0 && visited[v2] == 0)
{
EnQueue(&sq, v2);
visited[v2] = 1;
printf("%s ", G.vexs[v2]);
}
}
}
return true;
}
對於圖的廣度優先遍歷的試下來說,運用了隊列的特點,每一個頂點之多進一次隊列,便利圖的實質上是通過邊或者弧 找鄰接點的過程。
從上可以看出,其實廣度遍歷和深度遍歷它們兩者的時間復雜度是一樣的,兩者的不同之處僅僅在於對頂點訪問的順序不同而已。