圖的遍歷
圖的遍歷為從圖中某一頂點出發訪遍圖中其余頂點,且使每一個頂點僅被訪問一次的過程。
對于圖的遍歷,不想樹那么簡單,需要在遍歷的過程中把訪問過的頂點打上標記,以避免訪問多次。具體辦法是設置一個訪問數組visited[n]
,n
是圖中頂點的個數,初始值為0,訪問后設置為1。
對于圖的遍歷來說,通常有兩種遍歷方案:深度優先遍歷和廣度優先遍歷。
深度優先遍歷
深度優先遍歷(Depth_First_Search),也稱為深度優先搜索,簡稱DFS。
遍歷方式:
( 對于連通圖)從圖中某個頂點
v
出發,訪問此頂點,然后從v的未被訪問的鄰接點出發深度優先遍歷圖,直到圖中所有和v
有路徑相通的頂點都被訪問到。對于非連通圖,只需要對它的連通分量分別進行深度優先遍歷,即在先前一個頂點進行一次深度優先遍歷后,若圖中尚有頂點未被訪問,則另選圖中一個未曾被訪問的頂點作起始點,重復上述過程,直到圖中所有的頂點都被訪問過為止。
-
DFS其實就是一個遞歸的過程,就像一棵樹的前序遍歷。
深度優先遍歷
鄰接矩陣的DFS代碼實現
/**
* 鄰接矩陣的DFS遞歸算法
*/
void DFS(MGraph G, int i){
int j;
visited[i] = TRUE;
printf("%c", G.vexs[i]); // 打印頂點(可以變成其他操作)
for (j = 0; j < G.numVertexes; j++)
if (G.arc[i][j] == 1 && !visited[j])
DFS(G,j);
}
/**
* 鄰接矩陣的DFS遍歷操作
*/
void DFSTraverse(MGraph G){
int i;
for (i = 0; i < G.numVertexes; i++) {
visited[i] = FALSE;
}
for (i = 0; i < G.numVertexes; i++) {
if (!visited[i]) {
DFS(G, i);
}
}
}
附上鄰接矩陣存儲結構、圖的創建和測試代碼:
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define MAXSIZE 9 // 存儲空間初始分配量
#define MASEDGE 15
#define MAXVEX 9
#define INIFINITY 65535
typedef int Status;
typedef int Boolean; // 布爾類型,值是TRUE或者FALSE
typedef char VertexType; // 頂點類型
typedef int EdgeType; // 邊上的權值類型
typedef struct {
VertexType vexs[MAXVEX]; // 頂點表
EdgeType arc[MAXVEX][MAXVEX]; // 鄰接矩陣
int numVertexes, numEdges; // 圖中當前的頂點數和邊數
}MGraph;
/**
* 創建圖
*/
void CreateMGRraph(MGraph * G){
int i, j;
G->numVertexes = 9; // 9個頂點
G->numEdges = 15; // 15條邊
//讀入頂點信息,建立頂點表
G->vexs[0] = 'A';
G->vexs[1] = 'B';
G->vexs[2] = 'C';
G->vexs[3] = 'D';
G->vexs[4] = 'E';
G->vexs[5] = 'F';
G->vexs[6] = 'G';
G->vexs[7] = 'H';
G->vexs[8] = 'I';
for (i = 0; i < G->numVertexes; i++) // 初始化圖
for (j = 0; j < G->numVertexes; j++)
G->arc[i][j] = 0;
G->arc[0][1] = 1;
G->arc[0][5] = 1;
G->arc[1][2] = 1;
G->arc[1][8] = 1;
G->arc[1][6] = 1;
G->arc[2][3] = 1;
G->arc[2][8] = 1;
G->arc[3][4] = 1;
G->arc[3][7] = 1;
G->arc[3][6] = 1;
G->arc[3][8] = 1;
G->arc[4][5] = 1;
G->arc[4][7] = 1;
G->arc[5][6] = 1;
G->arc[6][7] = 1;
for (i = 0; i < G->numVertexes; i++)
for (j = 0; j < G->numVertexes; j++)
G->arc[j][i] = G->arc[i][j];
}
Boolean visited[MAXVEX]; // 訪問標志數組
/**
* 鄰接矩陣的DFS遞歸算法
*/
void DFS(MGraph G, int i){
int j;
visited[i] = TRUE;
printf("%c", G.vexs[i]); // 打印頂點(可以變成其他操作)
for (j = 0; j < G.numVertexes; j++)
if (G.arc[i][j] == 1 && !visited[j])
DFS(G,j);
}
/**
* 鄰接矩陣的DFS遍歷操作
*/
void DFSTraverse(MGraph G){
int i;
for (i = 0; i < G.numVertexes; i++) {
visited[i] = FALSE;
}
for (i = 0; i < G.numVertexes; i++) {
if (!visited[i]) {
DFS(G, i);
}
}
}
int main(int argc, const char * argv[]) {
MGraph G;
CreateMGRraph(&G);
printf("\n鄰接矩陣的深度優先遍歷:\n");
DFSTraverse(G);
printf("\n");
return 0;
}
鄰接矩陣的DFS運行結果
鄰接表的DFS代碼實現
對于鄰接表的DFS,和鄰接矩陣差不多,只不過在遞歸函數中將數組換成了鏈表。
核心代碼:
/**
* 鄰接表的深度優先遞歸算法
*/
void DFS(GraphAdjList GL, int i){
EdgeNode *p;
visited[i] = TRUE;
printf("%c", GL->adjList[i].data); // 打印結點
p = GL->adjList[i].firstedge;
while (p) {
if (!visited[p->adjvex]) {
DFS(GL, p->adjvex);
}
p = p->next;
}
}
/**
* 鄰接表的深度優先遍歷操作
*/
void DFSTraverse(GraphAdjList GL){
int i;
for (i = 0; i < GL->numVertexes; i++)
visited[i] = FALSE; // 初始化所有頂點狀態都是未訪問過狀態
for (i = 0; i < GL->numVertexes; i++) {
if (!visited[i]) {
DFS(GL, i);
}
}
}
附上隊列操作和測試代碼:
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define MAXSIZE 9 // 存儲空間初始分配量
#define MASEDGE 15
#define MAXVEX 9
#define INIFINITY 65535
typedef int Status;
typedef int Boolean; // 布爾類型,值是TRUE或者FALSE
typedef char VertexType; // 頂點類型
typedef int EdgeType; // 邊上的權值類型
typedef struct {//鄰接矩陣結構
VertexType vexs[MAXVEX]; // 頂點表
EdgeType arc[MAXVEX][MAXVEX]; // 鄰接矩陣
int numVertexes, numEdges; // 圖中當前的頂點數和邊數
}MGraph;
#pragma - 鄰接表結構
typedef struct EdgeNode{ // 邊表結點
int adjvex; // 鄰接點域,存儲該頂點對應的下標
int weight;
struct EdgeNode * next; // 鏈域,指向下一個鄰接點
}EdgeNode;
typedef struct VertexNode{ // 頂點表結點
int in; // 頂點入度
char data; // 頂點域
EdgeNode * firstedge; // 邊表頭指針
}VertexNode, AdjList[MAXSIZE];
typedef struct {
AdjList adjList;
int numVertexes, numEdges; // 圖中當前的頂點數和邊數
}graphAdjList, *GraphAdjList;
#pragma DFS
/**
* 創建圖
*/
void CreateMGRraph(MGraph * G){
int i, j;
G->numVertexes = 9; // 9個頂點
G->numEdges = 15; // 15條邊
//讀入頂點信息,建立頂點表
G->vexs[0] = 'A';
G->vexs[1] = 'B';
G->vexs[2] = 'C';
G->vexs[3] = 'D';
G->vexs[4] = 'E';
G->vexs[5] = 'F';
G->vexs[6] = 'G';
G->vexs[7] = 'H';
G->vexs[8] = 'I';
for (i = 0; i < G->numVertexes; i++) // 初始化圖
for (j = 0; j < G->numVertexes; j++)
G->arc[i][j] = 0;
G->arc[0][1] = 1;
G->arc[0][5] = 1;
G->arc[1][2] = 1;
G->arc[1][8] = 1;
G->arc[1][6] = 1;
G->arc[2][3] = 1;
G->arc[2][8] = 1;
G->arc[3][4] = 1;
G->arc[3][7] = 1;
G->arc[3][6] = 1;
G->arc[3][8] = 1;
G->arc[4][5] = 1;
G->arc[4][7] = 1;
G->arc[5][6] = 1;
G->arc[6][7] = 1;
for (i = 0; i < G->numVertexes; i++)
for (j = 0; j < G->numVertexes; j++)
G->arc[j][i] = G->arc[i][j];
}
/**
* 利用鄰接矩陣構建鄰接表
*/
void CreatALGraph(MGraph G, GraphAdjList * GL){
int i, j;
EdgeNode * e;
*GL = (GraphAdjList)malloc(sizeof(graphAdjList));
(*GL)->numVertexes = G.numVertexes;
(*GL)->numEdges = G.numEdges;
for (i = 0; i < G.numVertexes; i++) { // 讀入頂點信息,建立頂點表
(*GL)->adjList[i].in = 0;
(*GL)->adjList[i].data = G.vexs[i];
(*GL)->adjList[i].firstedge = NULL; // 將邊表置為空
}
for (i = 0; i < G.numVertexes; i++) { // 建立邊表
for (j = 0; j < G.numVertexes; j++) {
if (G.arc[i][j] == 1) {
e = (EdgeNode *)malloc(sizeof(EdgeNode));
e->adjvex = j; // 鄰接序號為j
e->next = (*GL)->adjList[i].firstedge; // 將當前頂點上的指向的結點指針賦值給e
(*GL)->adjList[i].firstedge = e; // 將當前頂點的指針指向e
(*GL)->adjList[j].in++;
}
}
}
}
Boolean visited[MAXSIZE]; // 訪問標志數組
/**
* 鄰接表的深度優先遞歸算法
*/
void DFS(GraphAdjList GL, int i){
EdgeNode *p;
visited[i] = TRUE;
printf("%c", GL->adjList[i].data); // 打印結點
p = GL->adjList[i].firstedge;
while (p) {
if (!visited[p->adjvex]) {
DFS(GL, p->adjvex);
}
p = p->next;
}
}
/**
* 鄰接表的深度優先遍歷操作
*/
void DFSTraverse(GraphAdjList GL){
int i;
for (i = 0; i < GL->numVertexes; i++)
visited[i] = FALSE; // 初始化所有頂點狀態都是未訪問過狀態
for (i = 0; i < GL->numVertexes; i++) {
if (!visited[i]) {
DFS(GL, i);
}
}
}
int main(int argc, const char * argv[]) {
MGraph G;
GraphAdjList GL;
CreateMGRraph(&G);
CreatALGraph(G, &GL);
printf("\n深度優先遍歷:");
DFSTraverse(GL);
printf("\n");
return 0;
}
鄰接表的DFS結果