圖的鄰接矩陣和鄰接表及深度優先搜索


圖的鄰接矩陣和鄰接表

許多人到這一塊會比較混亂,特別是鄰接表,定義的東西很多,同時也為自己做一個總結。
打算以圖的深度優先搜索為例,分別表示鄰接矩陣和鄰接表。
開始前,為了方便大家對命名的記憶,列出了以下常用單詞:

  1. vertex/vertices:頂點
  2. arc:弧
  3. matrix:矩陣
  4. adjacency matrix:鄰接矩陣
  5. graph:圖
  6. 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;
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM