圖的鄰接矩陣和鄰接表
許多人到這一塊會比較混亂,特別是鄰接表,定義的東西很多,同時也為自己做一個總結。
打算以圖的深度優先搜索為例,分別表示鄰接矩陣和鄰接表。
開始前,為了方便大家對命名的記憶,列出了以下常用單詞:
- vertex/vertices:頂點
- arc:弧
- matrix:矩陣
- adjacency matrix:鄰接矩陣
- graph:圖
- depth-first search:深度優先搜索
鄰接矩陣
輸出固定為:
5 6 //頂點數,邊數
A B C D E //五個頂點的名字
A C 12 //頂點A到頂點E的權值
A E 8
B C 6
C D 5
D E 8
E B 6
先上定義
//鄰接矩陣存儲
typedef struct {
char vex[10]; //頂點表
int arcs[10][10]; //鄰接矩陣
int vexnum, arcnum; //圖的信息,頂點總數和邊總數
};
鄰接矩陣較為簡單,將一個二維數組和其他信息打包即可
因為輸入數據的時候不一定按順序來,所以需要一個頂點表記錄頂點編號。
C 
/*
輸入格式:
5 6 //頂點數,邊數
A B C D E //五個頂點的名字
A C 12 //頂點A到頂點E的權值
A E 8
B C 6
C D 5
D E 8
E B 6
*/
#include <iostream>
using namespace std;
//鄰接矩陣存儲
typedef struct {
char vex[10]; //頂點表
int arcs[10][10]; //鄰接矩陣
int vexnum, arcnum; //圖的信息,頂點總數和邊總數
}AMGraph;
//函數聲明
void Create(AMGraph &G);
int Locate(AMGraph G, char v);
void DFS(AMGraph G, int v);
bool visited[10] = { false };
int main() {
AMGraph graph;
Create(graph);
DFS(graph, 0);
//輸出鄰接矩陣
//cout << endl;
//for (int i = 0; i < graph.vexnum; i++) {
// for (int j = 0; j < graph.vexnum; j++) {
// cout << graph.arcs[i][j] << " ";
// }
// cout << endl;
//}
return 0;
}
//創建無向圖
void Create(AMGraph &G) {
char v1, v2; //接收輸入的頂點
int x = 0, y = 0, w = 0; //輸入的邊的權w,對應行標x,列表y
cin >> G.vexnum >> G.arcnum; //總頂點、邊數
for (int i = 0; i < G.vexnum; i++) { //依次輸入節點信息
cin >> G.vex[i];
}
//初始化鄰接矩陣,邊均為0
for (int i = 0; i < G.vexnum; i++) {
for (int j = 0; j < G.vexnum; j++) {
G.arcs[i][j] = 0;
}
}
//根據輸入的圖的邊構造矩陣
for (int i = 0; i < G.arcnum; i++) {
cin >> v1 >> v2 >> w;
x = Locate(G, v1);
y = Locate(G, v2);
G.arcs[x][y] = w;
G.arcs[y][x] = w;
}
cout << "創建成功" << endl;
}
//根據頂點名獲得其編號下標
int Locate(AMGraph G, char v) {
int result = -1;
for (int i = 0; i < G.vexnum; i++) {
if (G.vex[i] == v) {
result = i;
break;
}
}
return result;
}
//從編號為v的節點開始深度優先搜索並輸出節點名
void DFS(AMGraph G, int v) {
cout << G.vex[v] << endl;
visited[v] = true;
for (int i = 0; i < G.vexnum; i++) {
if ((G.arcs[v][i] != 0) && (visited[i] == false)) {
DFS(G, i);
}
}
}
鄰接表
輸出固定為:
5 6 //頂點數,邊數
A B C D E //五個頂點的名字
A C
A E
B C
C D
D E
E B
這里的三個定義比較復雜,相互嵌套繞的有點暈...
//定義邊
typedef struct ArcNode{
int adjvex; //邊另一頭的節點
struct ArcNode *nextarc; //邊
}ArcNode;
//定義頂點
typedef struct VexNode {
char data; //頂點信息
ArcNode *firstarc; //邊
}VexNode, AdjList[10];
//定義鄰接表
typedef struct {
AdjList vertices; //表本體
int vexnum, arcnum; //額外信息,頂點、邊總數
}ALGraph;
三個定義的關系如下

/*
輸入格式:
5 6 //頂點數,邊數
A B C D E //五個頂點的名字
A C
A E
B C
C D
D E
E B
*/
#include <iostream>
using namespace std;
//定義邊
typedef struct ArcNode{
int adjvex; //邊另一頭的節點
struct ArcNode *nextarc; //邊
}ArcNode;
//定義頂點
typedef struct VexNode {
char data; //頂點信息
struct ArcNode *firstarc; //邊
}VexNode, AdjList[10];
//定義鄰接表
typedef struct {
AdjList vertices; //表本體
int vexnum, arcnum; //額外信息,頂點、邊總數
}ALGraph;
//函數聲明
void Create(ALGraph &G);
int Locate(ALGraph G, char v);
void DFS(ALGraph G, int v);
bool visited[10] = { false }; //已經被搜索到的頂點變為true,避免重復搜索
int main() {
ALGraph graph;
Create(graph);
DFS(graph, 0);
return 0;
}
//創建
void Create(ALGraph &G) {
char v1, v2; //存輸入的兩個邊
int x = 0, y = 0; //存輸入的兩個邊的編號下標
ArcNode *p1, *p2;
cin >> G.vexnum >> G.arcnum;
for (int i = 0; i < G.vexnum; i++) {
cin >> G.vertices[i].data;
G.vertices[i].firstarc = NULL; //初始化為空,避免野指針
}
//讀入兩點構建邊
for (int i = 0; i < G.arcnum; i++) {
p1 = new ArcNode;
p1->nextarc = NULL;
p2 = new ArcNode;
p2->nextarc = NULL;
cin >> v1 >> v2;
x = Locate(G, v1);
y = Locate(G, v2);
p1->adjvex = y;
p2->adjvex = x;
p1->nextarc = G.vertices[x].firstarc;
G.vertices[x].firstarc = p1;
p2->nextarc = G.vertices[y].firstarc;
G.vertices[y].firstarc = p2;
}
cout << "創建完成" << endl;
}
//根據頂點名得到其對應的編號下標
int Locate(ALGraph G, char v) {
int result = -1;
for (int i = 0; i < G.vexnum; i++) {
if (G.vertices[i].data == v) {
result = i;
break;
}
}
return result;
}
//從編號為v的頂點開始深度優先搜索並輸出頂點名
void DFS(ALGraph G, int v) {
ArcNode *p = new ArcNode; //編號為v的頂點的指針
int w = 0; //后一個指針的編號
cout << G.vertices[v].data << endl;
visited[v] = true;
p = G.vertices[v].firstarc;
while (p != NULL) {
w = p->adjvex;
if (visited[w] == false) {
DFS(G, w);
}
p = p->nextarc;
}
}
