1. 程式人生 > >【資料結構】圖的基本操作——圖的構造(鄰接矩陣,鄰接表),遍歷(DFS,BFS)

【資料結構】圖的基本操作——圖的構造(鄰接矩陣,鄰接表),遍歷(DFS,BFS)

鄰接矩陣實現如下:

/*
主題:用鄰接矩陣實現 DFS(遞迴) 與 BFS(非遞迴)
作者:Laugh
語言:C++

*******************************************
樣例輸出如下:
請選擇圖的型別(a - 無向圖, b - 有向圖):a
請輸入總頂點數,總邊數:8 9
請依次輸入點的資訊:a b c d e f g h
輸入一條邊依附的頂點及權值 (eg: a b 6): 
a b 1
a c 1
b d 1
b e 1
d h 1
e h 1
c f 1
c g 1
f g 1
列印鄰接矩陣:
0 1 1 0 0 0 0 0
1 0 0 1 1 0 0 0
1 0 0 0 0 1 1 0
0 1 0 0 0 0 0 1
0 1 0 0 0 0 0 1
0 0 1 0 0 0 1 0
0 0 1 0 0 1 0 0
0 0 0 1 1 0 0 0
請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):
1
DFS:a b d h e c f g

BFS: a b c d e f g h
*/
#include <iostream>
#include <queue>

using namespace std;

#define OK 1 
typedef int Status; 

/* ————圖的鄰接矩陣儲存表示 ————*/
#define MaxInt 32767                                  // 表示極大值
#define MVNum  100                                    // 最大頂點數
bool visited[MVNum];                                  // 訪問標誌陣列,其初值為 “false”
typedef char VerTexType;                              // 假設頂點的資料型別為字元型
typedef int  ArcType;                                 // 假設邊的權值型別為整型
typedef struct {
	VerTexType vexs[MVNum];                           // 頂點表
	ArcType arcs[MVNum][MVNum];                       // 鄰接矩陣
	int vexnum, arcnum;                               // 圖的當前點數和邊數 
} AMGraph;

int LocateVex(AMGraph G, VerTexType u) {
	/* 存在則返回 u 在頂點表中的下標;否則返回 -1 */
	for (int i = 0; i < G.vexnum; i++)
		if (u == G.vexs[i])
			return i;
			
	return -1;	
} 

/* ————採用鄰接矩陣表示法建立無向網 ————*/
Status CreateUDN(AMGraph &G) {
	int i, j, k;
	char flag;
	ArcType w;
	VerTexType v1, v2;
	
	cout << "請選擇圖的型別(a - 無向圖, b - 有向圖):";
	cin >> flag;
	cout << "請輸入總頂點數,總邊數:";
	cin >> G.vexnum >> G.arcnum;                      // 輸入總頂點數,總邊數
	cout << "請依次輸入點的資訊:"; 
	for (i = 0; i < G.vexnum; i++)                    // 依次輸入點的資訊
		cin >> G.vexs[i];
	for (i = 0; i < G.vexnum; i++)                    // 初始化鄰接矩陣,邊的權值均置為極大值 MaxInt
		for (j = 0; j < G.vexnum; j++)
			G.arcs[i][j] = MaxInt;
			
	cout << "輸入一條邊依附的頂點及權值 (eg: a b 6): " << endl;
	for (k = 0; k < G.arcnum; k++) {                  // 構造鄰接矩陣 
		cin >> v1 >> v2 >> w;                         // 輸入一條邊依附的頂點及權值 
		i = LocateVex(G, v1); j = LocateVex(G, v2);   // 確定 v1 和 v2 在 G 中的位置,即頂點陣列的下標
		G.arcs[i][j] = w;                             // 邊 <v1, v2> 的權值為 w
		if (flag == 'a')
			G.arcs[j][i] = G.arcs[i][j];              // 置 <v1, v2> 的對稱邊 <v2, v1> 的權值為 w 
	}
	return OK; 
} 

/* 返回頂點v的第一個鄰接頂點序號 */
int FirstAdjVex(AMGraph G, int v) {
	for(int i = 0; i < G.vexnum; i++)
		if(G.arcs[v][i] == 1)
			return i;
	return -1;
}
 
/* 返回頂點v的相對於w的下一個鄰接頂點序號 */
int NextAdjVex(AMGraph G, int v, int w) {
	for(int i = w + 1; i < G.vexnum; i++)
		if(G.arcs[v][i] == 1)
			return i;
	return -1;
}


void DFS(AMGraph G, int v) {
	visited[v]=true;
	cout<<G.vexs[v]<<" ";
	for(int w=FirstAdjVex(G, v); w>=0; w=NextAdjVex(G, v, w))
		if(!visited[w])
			DFS(G, w);
}

/* 深搜 */
void DFSTraverse(AMGraph G) {
	for(int i = 0; i < G.vexnum; i++)
		visited[i] = false;
 
	for(int i = 0; i < G.vexnum; i++)
		if(!visited[i])
			DFS(G, i);
}

/* 廣搜,類似於樹的層次遍歷 */
void BFSTraverse(AMGraph G) {
	for(int i = 0; i < G.vexnum; i++)
		visited[i] = false;
 
	queue<int> q;
 
	for(int i = 0; i < G.vexnum; i++) {
		if(!visited[i]) {
			visited[i] = true;
			q.push(i);
			
			while(!q.empty()) {
				int v = q.front();
				q.pop();
				
				cout << G.vexs[v] << " ";
				for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
					if(!visited[w]) {
						visited[w] = true;
						q.push(w);
					}
				}
			}
		}
	}
}

int main() {
	AMGraph G;
	
	CreateUDN(G);
	
	cout << "列印鄰接矩陣:" << endl;
	for (int i = 0; i < G.vexnum; i++) {
		for (int j = 0; j < G.vexnum; j++) {
			if (G.arcs[i][j] != MaxInt)
				cout << G.arcs[i][j] << " ";
			else cout << '0' << " ";
		}
		cout << endl;
	}
	
	int flag;
	cout << "請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):\n"; 
	cin >> flag;
	
	switch(flag) {
		case 1:
			cout << "DFS:";
			DFSTraverse(G);
			cout << endl;
			break;
		case 2:
		 	cout << "BFS:";
			BFSTraverse(G);
			cout << endl;
	}
	
	return 0;
}

鄰接表實現如下:

/*
主題:用鄰接表實現 DFS(遞迴) 與 BFS(非遞迴)
作者:Laugh
語言:C++

*******************************************
樣例輸出如下:
請輸入頂點數和邊數:8 9
請輸入頂點:v1 v2 v3 v4 v5 v6 v7 v8
請輸入邊:
v1 v2
v1 v3
v2 v4
v2 v5
v4 v8
v5 v8
v3 v6
v3 v7
v6 v7
列印鄰接表如下:
v1->v3->v2
v2->v5->v4->v1
v3->v7->v6->v1
v4->v8->v2
v5->v8->v2
v6->v7->v3
v7->v6->v3
v8->v5->v4 
請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):1
DFS:v1 v3 v7 v6 v2 v5 v8 v4 
BFS: v1 v3 v2 v7 v6 v5 v4 v8
*/
#include <iostream>
#include <string>
#include <queue>
using namespace std;
 
bool visited[10];
/* 表結點 */ 
typedef struct ArcNode {
	int adjvex;                 // 該弧所指向的頂點的位置
	ArcNode *nextarc;           // 指向下一條弧的指標
} ArcNode;
 
/* 頭結點 */ 
typedef struct VNode {
	string data;                // 頂點資訊
	ArcNode* firstarc;          // 第一個表結點的地址,指向第一條依附該頂點的弧的指標
} VNode, AdjList[10];
 
typedef struct {
	AdjList vertices;
	int vexnum, arcnum;         // 圖的頂點數和弧數
} ALGraph;
 
/* 返回頂點u在圖中的位置 */ 
int LocateVex(ALGraph G, string u) {
	for(int i = 0; i < G.vexnum; i++)
		if(G.vertices[i].data == u)
			return i;
	return -1;
}
 
/* 構造無向圖 */ 
void CreateUDG(ALGraph &G) {
	string v1, v2;
	int i, j, k;
	
	cout << "請輸入頂點數和邊數:";
	cin >> G.vexnum >> G.arcnum;
 
	cout << "請輸入頂點:";
	for(i = 0; i < G.vexnum; i++) {
		cin >> G.vertices[i].data;
		G.vertices[i].firstarc = NULL;
	}
 
	cout << "請輸入邊:";
	cout << endl;
	for(k = 0; k < G.arcnum; k++) {
		cin >> v1 >> v2;
		i = LocateVex(G, v1);
		j = LocateVex(G, v2);
 
		/* 插入v1的鄰接表,為了提高效率,總在表頭插入結點 */ 
		ArcNode *arc = new ArcNode;
		arc->adjvex = j;
		arc->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = arc;
 
		/* 插入v2的鄰接表,為了提高效率,總在表頭插入結點 */ 
        arc = new ArcNode;
		arc->adjvex = i;
		arc->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = arc;
	}
}
 
/* 列印鄰接表 */ 
void Print(ALGraph G) {
	cout<<"列印鄰接表如下:" << endl;
	
	
	/* 遍歷每個頂點的鄰接表 */ 
	for(int i = 0; i < G.vexnum; i++) {
		cout << G.vertices[i].data;
		ArcNode *p = G.vertices[i].firstarc;
		
		while(p) {
			cout << "->" << G.vertices[p->adjvex].data;
			p = p->nextarc;
		}
		cout<<endl;
	}
}

/* 返回頂點v的第一個鄰接點序號 */ 
int FirstAdjVex(ALGraph G, int v) {
	
	ArcNode *p=G.vertices[v].firstarc;
	if(p)
		return p->adjvex;
	else
		return -1;
}

/* 返回頂點v的相對於w的下一個鄰接點序號 */ 
int NextAdjVex(ALGraph G, int v, int w) {
	ArcNode* p = G.vertices[v].firstarc;
	while(p) {
		if(p->adjvex == w)
			break;
		p = p->nextarc;
	}
 
	if(p->adjvex != w || !p->nextarc)//如果沒找到w或者w是最後一個鄰接點
		return -1;
	return p->nextarc->adjvex;
 
}

void DFS(ALGraph G, int v) {
	visited[v] = true;
	cout << G.vertices[v].data << " ";
	for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
		if(!visited[w])
			DFS(G, w);
}
 
void DFSTraverse(ALGraph G) {
	for(int i = 0; i < G.vexnum; i++)
		visited[i] = false;
 
	for(int i = 0; i < G.vexnum; i++)
		if(!visited[i])
			DFS(G, i);
}
 
void BFSTraverse(ALGraph G) {
	queue<int> q;
	for(int i = 0; i < G.vexnum; i++)
		visited[i] = false;
 
	for(int i = 0; i < G.vexnum; i++) {
		if(!visited[i]) {
			q.push(i);
			visited[i] = true;
			while(!q.empty()) {
				int v = q.front();
				q.pop();
				
				cout << G.vertices[v].data << " ";
				for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
					if (!visited[w]) {
						q.push(w);
						visited[w] = true;
					}
				}
			}
		}
	}
}
 
int main()
{
	ALGraph G;
	CreateUDG(G);
	Print(G);
 
	int flag;
	cout << "請選擇遍歷方式(1.深度優先搜尋; 2.廣度優先搜尋):\n"; 
	cin >> flag;
	
	switch(flag) {
		case 1:
			cout << "DFS:";
			DFSTraverse(G);
			cout << endl;
			break;
		case 2:
		 	cout << "BFS:";
			BFSTraverse(G);
			cout << endl;
	}
	
	return 0;
}