圖的遍歷,首先說下定義:

而在這里,就給大家敘述下深度優先遍歷。本來是要用自己的話來給大家講解的,但是搜了下網上的定義,覺得還是網上的定義更可靠和嚴謹,所以就摘取了百度百科的說明:
假設給定圖G的初態是所有頂點均未曾訪問過。在G中任選一頂點v為初始出發點(源點),則深度優先遍歷可定義如下:首先訪問出發點v,並將其標記為已訪問過;然后依次從v出發搜索v的每個鄰接點w。若w未曾訪問過,則以w為新的出發點繼續進行深度優先遍歷,直至圖中所有和源點v有路徑相通的頂點(亦稱為從源點可達的頂點)均已被訪問為止。若此時圖中仍有未訪問的頂點,則另選一個尚未訪問的頂點作為新的源點重復上述過程,直至圖中所有頂點均已被訪問為止。
圖的深度優先遍歷類似於樹的前序遍歷。采用的搜索方法的特點是盡可能先對縱深方向進行搜索。這種搜索方法稱為深度優先搜索(Depth-First Search)。相應地,用此方法遍歷圖就很自然地稱之為圖的深度優先遍歷。
如圖:

然后看下算法思想,其實在上述定義中也說過,現在來總結下:

首先發下用鄰接鏈表法實現的深度優先遍歷代碼(如果不理解鄰接鏈表法,請在本博客數據結構系列中查找,里面有詳細介紹),代碼是基於本博客數據結構系列講解鄰接鏈表法實現圖寫的,大家可以把這段代碼加在那些代碼中就可以運行:
- static void recursive_dfs(TLGraph* graph, int v, int visited[], LGraph_Printf* pFunc)
- {
- int i = 0;
-
- pFunc(graph->v[v]);
-
- visited[v] = 1;
-
- printf(", ");
-
- for(i=0; i<LinkList_Length(graph->la[v]); i++)
- {
- TListNode* node = (TListNode*)LinkList_Get(graph->la[v], i);
-
- if( !visited[node->v] )
- {
- recursive_dfs(graph, node->v, visited, pFunc);
- }
- }
- }
-
- void LGraph_DFS(LGraph* graph, int v, LGraph_Printf* pFunc)
- {
- TLGraph* tGraph = (TLGraph*)graph;
- int* visited = NULL;
- int condition = (tGraph != NULL);
-
- condition = condition && (0 <= v) && (v < tGraph->count);
- condition = condition && (pFunc != NULL);
- condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);
-
- if( condition )
- {
- int i = 0;
-
- recursive_dfs(tGraph, v, visited, pFunc);
-
- for(i=0; i<tGraph->count; i++)
- {
- if( !visited[i] )
- {
- recursive_dfs(tGraph, i, visited, pFunc);
- }
- }
-
- printf("\n");
- }
-
- free(visited);
- }
最后發下用鄰接矩陣法實現的深度優先遍歷代碼(如果不理解鄰接矩陣法,請在本博客數據結構系列中查找,里面有詳細介紹),代碼是基於本博客數據結構系列講解鄰接矩陣法實現圖寫的,大家可以把這段代碼加在那些代碼中就可以運行:
- static void recursive_dfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc)
- {
- int i = 0;
-
- pFunc(graph->v[v]);
-
- visited[v] = 1;
-
- printf(", ");
-
- for(i=0; i<graph->count; i++)
- {
- if( (graph->matrix[v][i] != 0) && !visited[i] )
- {
- recursive_dfs(graph, i, visited, pFunc);
- }
- }
- }
-
- void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc)
- {
- TMGraph* tGraph = (TMGraph*)graph;
- int* visited = NULL;
- int condition = (tGraph != NULL);
-
- condition = condition && (0 <= v) && (v < tGraph->count);
- condition = condition && (pFunc != NULL);
- condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);
-
- if( condition )
- {
- int i = 0;
-
- recursive_dfs(tGraph, v, visited, pFunc);
-
- for(i=0; i<tGraph->count; i++)
- {
- if( !visited[i] )
- {
- recursive_dfs(tGraph, i, visited, pFunc);
- }
- }
-
- printf("\n");
- }
-
- free(visited);
- }
圖的廣度優先遍歷(BFS):
圖的廣度優先搜索是樹的按層次遍歷的推廣,它的基本思想是:首先訪問初始點vi,並將其標記為已訪問過,接着訪問vi的所有未被訪問過的鄰接點 vi1,vi2, …, vi t,並均標記已訪問過,然后再按照vi1,vi2, …, vi t的次序,訪問每一個頂點的所有未被訪問過的鄰接點,並均標記為已訪問過,依次類推,直到圖中所有和初始點vi有路徑相通的頂點都被訪問過為止。
如圖:


首先發下用鄰接鏈表法實現的廣度優先遍歷代碼(如果不理解鄰接鏈表法,請在本博客數據結構系列中查找,里面有詳細介紹),代碼是基於本博客數據結構系列講解鄰接鏈表法實現圖寫的,大家可以把這段代碼加在那些代碼中就可以運行::
- static void recursive_bfs(TLGraph* tGraph, int v, int visited[], LGraph_Printf* pFunc)
- {
- LinkQueue* queue = LinkList_Create();
-
- if(NULL != queue)
- {
- LinkQueue_Append(queue, tGraph->v + v);
-
- while(0 < LinkQueue_Length(queue))
- {
- int i = 0;
-
- v = (LVertex**)LinkQueue_Retrieve(queue) - tGraph->v;
-
- pFunc(tGraph->v[v]);
-
- printf(", ");
-
- for(i=0; i<tGraph->la[v]; i++)
- {
- TListNode* node = (TListNode*)LinkList_Get(tGraph->la[v], i);
-
- if(!visited[node->v])
- {
- LinkQueue_Append(queue, tGraph->v + node->v);
-
- visited[node->v] = 1;
- }
- }
- }
- }
-
- LinkQueue_Destroy(queue);
- }
-
- void LGraph_BFS(LGraph* graph, int v, LGraph_Printf* pFunc)
- {
- TLGraph* tGraph = (TLGraph*)graph;
-
- int* visited = NULL;
-
- int condition = (NULL != tGraph);
- condition = condition && (0 <= v) && (v < tGraph->count);
- condition = condition && (NULL != pFunc);
- condition = condition && (NULL != (visited = (int*)calloc(tGraph->count, sizeof(int))));
-
- if(condition)
- {
- int i = 0;
-
- recursive_bfs(tGraph, v, visited, pFunc);
-
- for(i=0; i<tGraph->count; i++)
- {
- if(!visited[i])
- {
- recursive_bfs(tGraph, i, visited, pFunc);
- }
- }
-
- printf("\n");
- }
-
- free(visited);
- }
最后發下用鄰接矩陣法實現的廣度優先遍歷代碼(如果不理解鄰接矩陣法,請在本博客數據結構系列中查找,里面有詳細介紹),代碼是基於本博客數據結構系列講解鄰接矩陣法實現圖寫的,大家可以把這段代碼加在那些代碼中就可以運行:
- static void recursive_bfs(TMGraph* tGraph, int v, int visited[], MGraph_Printf* pFunc)
- {
- LinkQueue* queue = LinkQueue_Create();
-
- if(NULL != queue)
- {
- LinkQueue_Append(queue, tGraph->v + v);
-
- visited[v] = 1;
-
- while(0 < LinkQueue_Length(queue))
- {
- int i = 0;
-
- v = (MVertex**)LinkQueue_Retrieve(queue) - tGraph->v;
-
- pFunc(tGraph->v[v]);
-
- printf(", ");
-
- for(i=0; i<tGraph->count; i++)
- {
- if((0 != tGraph->matrix[v][i]) && (!visited[i]))
- {
- LinkQueue_Append(queue, tGraph->v + i);
-
- visited[i] = 1;
- }
- }
- }
- }
-
- LinkQueue_Destroy(queue);
- }
-
- void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc)
- {
- TMGraph* tGraph = (TMGraph*)graph;
-
- int* visited = NULL;
-
- int condition = (NULL != tGraph);
- condition = condition && (0 <= v) && (v < tGraph->count);
- condition = condition && (NULL != pFunc);
- condition = condition && (NULL != (visited = (int*)calloc(tGraph->count, sizeof(int))));
-
- if(condition)
- {
- int i = 0;
-
- recursive_bfs(tGraph, v, visited, pFunc);
-
- for(i=0; i<tGraph->count; i++)
- {
- if(!visited[i])
- {
- recursive_bfs(tGraph, i, visited, pFunc);
- }
- }
-
- printf("\n");
- }
-
- free(visited);
- }
前面已經說了圖的深度優先遍歷算法,是用遞歸實現的,而在這里就講一下用非遞歸實現,需要借助棧:
算法思想:
1. 棧初始化
2. 輸出起始頂點,起始頂點改為“已訪問”標志,將起始頂點進棧
3. 重復下列操作直到棧為空:
3.1 取棧頂元素頂點
3.2 棧頂元素頂點存在未被訪問過的鄰接點w,則:
3.2.1 輸出頂點w
3.2.2 將頂點w改為“已訪問”標志
3.2.3 將頂點w進棧
3.3 否則,當前頂點出棧
非遞歸實現深度優先遍歷(鄰接鏈表法)
- static void orther_dfs(TLGraph* tGraph, int v, int visited[], LGraph_Printf* pFunc)
- {
- LinkStack* stack = LinkStack_Create();
-
- LinkStack_Push(stack, tGraph->v + v);
-
- while(!LinkStack_Empty(stack))
- {
- int w = (LVertex**)LinkStack_Top(stack) - tGraph->v;
-
- LinkStack_Pop(stack);
-
- if(!visited[w])
- {
- int i = 0;
-
- pFunc(tGraph->v[w]);
-
- visited[w] = 1;
-
- for(i=0; i<LinkList_Length(tGraph->la[v]); i++)
- {
- if(!visited[i])
- {
- LinkStack_Push(stack, tGraph->v + i);
- }
- }
- }
- }
-
- LinkStack_Destroy(stack);
- }
-
- void LGraph_DFS_Orther(LGraph* graph, int v, LGraph_Printf* pFunc)
- {
- TLGraph* tGraph = (TLGraph*)graph;
-
- int* visited = NULL;
-
- int condition = (NULL != tGraph);
- condition = condition && (0 <= v) && (v < tGraph->count);
- condition = condition && (NULL != pFunc);
- condition = condition && (NULL != (visited = (int*)calloc(tGraph->count, sizeof(int))));
-
- if(condition)
- {
- int i = 0;
-
- orther_dfs(tGraph, v, visited, pFunc);
-
- for(i=0; i<tGraph->count; i++)
- {
- if(!visited[i])
- {
- orther_dfs(tGraph, i, visited, pFunc);
- }
- }
-
- printf("\n");
- }
-
- free(visited);
- }
非遞歸實現深度優先遍歷(鄰接矩陣法)
- static void orther_dfs(TMGraph* tGraph, int v, int visited[], MGraph_Printf* pFunc)
- {
- LinkStack* stack = LinkStack_Create();
-
- LinkStack_Push(stack, tGraph->v + v);
-
- while(!LinkStack_Empty(stack))
- {
- int w = (MVertex**)LinkStack_Top(stack) - tGraph->v;
-
- LinkStack_Pop(stack);
-
- if(!visited[w])
- {
- int i = 0;
-
- pFunc(tGraph->v[w]);
-
- visited[w] = 1;
-
- for(i=0; i<LinkList_Length(tGraph->count); i++)
- {
- if((0!=tGraph->matrix[v][i]) && (!visited[i]))
- {
- LinkStack_Push(stack, tGraph->v + i);
- }
- }
- }
- }
-
- LinkStack_Destroy(stack);
- }
-
- void MGraph_DFS_Orther(MGraph* graph, int v, MGraph_Printf* pFunc)
- {
- TMGraph* tGraph = (TMGraph*)graph;
-
- int* visited = NULL;
-
- int condition = (NULL != tGraph);
- condition = condition && (0 <= v) && (v < tGraph->count);
- condition = condition && (NULL != pFunc);
- condition = condition && (NULL != (visited = (int*)calloc(tGraph->count, sizeof(int))));
-
- if(condition)
- {
- int i = 0;
-
- orther_dfs(tGraph, v, visited, pFunc);
-
- for(i=0; i<tGraph->count; i++)
- {
- if(!visited[i])
- {
- orther_dfs(tGraph, i, visited, pFunc);
- }
- }
-
- printf("\n");
- }
-
- free(visited);
- }