1. 程式人生 > >圖 - 廣度優先遍歷

圖 - 廣度優先遍歷

希望 padding borde i++ arc UC 結點 深度優先 nowrap

圖的遍歷和樹的遍歷類似,我們希望從圖中某一頂點出發訪遍圖中其余頂點,且使每一個頂點僅被訪問一次,這一過程就叫做圖的遍歷(Traverse Graph)。

圖的遍歷方法一般有兩種,第一種是我們在前面講過的《深度優先遍歷(Depth First Search)》,也有稱為深度優先搜索,簡稱為DFS。第二種是廣度優先遍歷(Breadth First Search),也有稱為廣度優先搜索,簡稱為BFS。我們在《隊列與廣度優先搜索》中已經較為詳細地講述了廣度優先搜索的策略,這裏不再贅述。如果說圖的深度優先遍歷類似樹的前序遍歷,那麽圖的廣度優先遍歷就類似於樹的層序遍歷了,我們把圖7-5-3的第一幅圖稍微變形成第二幅圖所示,這樣層次感就更強了,廣度優先遍歷需要用到隊列的操作,可以參考《隊列的順序存儲結構》。

技術分享圖片

下面只給出鄰接矩陣和鄰接表存儲方式時的圖的廣度優先遍歷的算法代碼,沒有給出整體可供測試運行的代碼,其實只需要再寫一個創建圖的函數就可以進行整體測試了,可以參考《鄰接矩陣創建圖》和《鄰接表創建圖》

一、如果我們使用的是鄰接矩陣的方式,則代碼如下:(改編自《大話數據結構》)

C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
typedef char VertexType; /* 頂點類型應由用戶定義 */
typedef int EdgeType; /* 邊上的權值類型應由用戶定義 */

#define MAXSIZE 9 /* 存儲空間初始分配量 */
#define MAXEDGE 15
#define MAXVEX 9

typedef struct
{
VertexType vexs[MAXVEX]; /* 頂點表 */
EdgeType arc[MAXVEX][MAXVEX];/* 鄰接矩陣,可看作邊表 */
int numVertexes, numEdges; /* 圖中當前的頂點數和邊數 */
} MGraph;

/* 鄰接矩陣的廣度遍歷算法 */
void BFSTraverse(MGraph G)
{
int i, j;
Queue Q;
for (i = 0; i < G.numVertexes; i++)
visited[i] = false;
InitQueue(&Q);/* 初始化一輔助用的隊列 */

for (i = 0; i < G.numVertexes; i++)/* 對每一個頂點做循環 */
{
if (!visited[i])/* 若是未訪問過就處理 */
{
visited[i] = true;/* 設置當前頂點訪問過 */
cout << G.vexs[i] << ‘ ‘; /* 打印頂點,也可以其它操作 */
EnQueue(&Q, i);/* 將此頂點入隊列 */
while (!QueueEmpty(Q))/* 若當前隊列不為空 */
{
DeQueue(&Q, &i);/* 將隊對元素出隊列,賦值給i */
for (j = 0 ; j < G.numVertexes; j++)
{
/* 判斷其它頂點若與當前頂點存在邊且未訪問過 */
if (G.arc[i][j] == 1 && !visited[j])
{
visited[j] = true;/* 將找到的此頂點標記為已訪問 */
cout << G.vexs[j] << ‘ ‘; /* 打印頂點 */
EnQueue(&Q, j);/* 將找到的此頂點入隊列 */
}
}
}
}
}
}

遍歷結果為:A B F C G I E D H (上圖所示的圖結構)


一、如果我們使用的是鄰接表的方式,則代碼如下:(改編自《大話數據結構》)

C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
typedef char VertexType; /* 頂點類型應由用戶定義 */
typedef int EdgeType; /* 邊上的權值類型應由用戶定義 */

#define MAXSIZE 9 /* 存儲空間初始分配量 */
#define MAXEDGE 15
#define MAXVEX 9

/* 鄰接表結構****************** */
typedef struct EdgeNode /* 邊表結點 */
{
int adjvex; /* 鄰接點域,存儲該頂點對應的下標 */
int weight; /* 用於存儲權值,對於非網圖可以不需要 */
struct EdgeNode *next; /* 鏈域,指向下一個鄰接點 */
} EdgeNode;

typedef struct VertexNode /* 頂點表結點 */
{
int in; //結點入度
char data; /* 頂點域,存儲頂點信息 */
EdgeNode *firstedge;/* 邊表頭指針 */
} VertexNode, AdjList[MAXVEX];

typedef struct
{
AdjList adjList;
int numVertexes, numEdges; /* 圖中當前頂點數和邊數 */
} graphAdjList, *GraphAdjList;

/* 鄰接表的廣度遍歷算法 */
void BFSTraverse(GraphAdjList GL)
{
int i, j;
EdgeNode *p;
Queue Q;
for (i = 0; i < GL->numVertexes; i++)
visited[i] = false;
InitQueue(&Q);/* 初始化一輔助用的隊列 */

for (i = 0; i < GL->numVertexes; i++)/* 對每一個頂點做循環 */
{
if (!visited[i])/* 若是未訪問過就處理 */
{
visited[i] = true;/* 設置當前頂點訪問過 */
cout << GL->adjList[i].data << ‘ ‘; /* 打印頂點,也可以其它操作 */
EnQueue(&Q, i);/* 將此頂點入隊列 */
while (!QueueEmpty(Q))/* 若當前隊列不為空 */
{
DeQueue(&Q, &i);/* 將隊對元素出隊列,賦值給i */
p = GL->adjList[i].firstedge;/* 找到當前頂點的邊表鏈表頭指針 */

while (p)
{
/* 判斷其它頂點若與當前頂點存在邊且未訪問過 */
if (!visited[p->adjvex])
{
visited[p->adjvex] = true;/* 將找到的此頂點標記為已訪問 */
cout << GL->adjList[p->adjvex].data << ‘ ‘; /* 打印頂點 */
EnQueue(&Q, p->adjvex);/* 將找到的此頂點入隊列 */
}
p = p->next;/* 指針指向下一個鄰接點 */
}
}
}
}
}


遍歷結果為:A F B G E I C H D (上圖所示的圖結構)


由結果可以看出,因為我們采用了不同的存儲方式,即使使用的是同樣的廣度優先搜索,遍歷的結果也是不同的。

圖 - 廣度優先遍歷