1. 程式人生 > >看資料結構寫程式碼(35) 圖的鄰接矩陣表示法

看資料結構寫程式碼(35) 圖的鄰接矩陣表示法

雜談:最近清明小長假,好好的放鬆了一下。節前 和 節後 都有點 鬆懈。不好,不好。貴在堅持。加油。

圖的鄰接矩陣表示法是用 兩個陣列 來表示 圖的資料結構。一個是頂點陣列,另一個是鄰接矩陣陣列。鄰接矩陣 裡存放著 頂點的關係。

用鄰接矩陣表示圖,在 看 頂點之間 是否有邊,或者 求頂點的度等操作時比較簡單。但空間浪費巨大,在插入,刪除 頂點 和邊 操作時 需要 移動大量資料,造成不便。所以在插入刪除比較多,節點數比較多的時候 不宜 使用這種結構。

下面上程式碼:

// MGraph2.cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <climits>
#include <cstring>

#define INFINITY INT_MAX
#define MAX_VERTEX_NUM 20
enum E_State
{
	E_State_Error = 0,
	E_State_Ok = 1,
};
enum E_Graph_Kind
{
	DG = 0,//有向圖
	DN,//有向網
	UDG,//無向圖
	UDN,//無向網
};
//邊(弧)單元
typedef struct ArcCell
{
	int adj;//表示頂點的關係型別,對於無權圖,0,1表示是否相鄰,對於有權圖,表示權值型別
	char * info;//邊,弧其餘資訊.
}AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
//定義圖
struct MGraph
{
	char  vexs[MAX_VERTEX_NUM];//頂點集
	AdjMatrix arcs;//圖的鄰接矩陣
	int vexNum,arcNum;
	E_Graph_Kind kind;
};

int graphLocation(MGraph graph,char  vex);
void createDG(MGraph * graph);
void createDN(MGraph * graph);
void createUDG(MGraph * graph);
void createUDN(MGraph * graph);

void graphCreate(MGraph * graph){
	E_Graph_Kind kind;
	printf("請輸入要建立的圖的型別(有向圖:0,有向網:1,無向圖:2,無向網:3)\n");
	scanf("%d",&kind);
	switch (kind){
	case DG:
		createDG(graph);
		break;
	case DN:
		createDN(graph);
		break;
	case UDG:
		createUDG(graph);
		break;
	case UDN:
		createUDN(graph);
		break;
	default:
		break;
	}
}
//返回頂點vex的第一個鄰接點
char  firstAdjVex(MGraph graph,char vex){
	int location = graphLocation(graph,vex);
	int i = 0;
	for (; i < graph.vexNum; i++){
		if ((graph.kind == DG || graph.kind == UDG) && graph.arcs[location][i].adj == 1){
			return graph.vexs[i];
		}
		else if((graph.kind == DN || graph.kind == UDN) && graph.arcs[location][i].adj != INFINITY){
			return graph.vexs[i];
		}
	}
	return ' ';
}
//返回頂點vex1 相對於 vex2的下一個鄰接點.
char  nextAdjVex(MGraph graph,char  vex1,char  vex2){
	int location1 = graphLocation(graph,vex1);
	int location2 = graphLocation(graph,vex2);
	int i = location2+1;
	for (; i < graph.vexNum; i++){
		if ((graph.kind == DG || graph.kind == UDG) && graph.arcs[location1][i].adj == 1){
			return graph.vexs[i];
		}
		else if((graph.kind == DN || graph.kind == UDN) && graph.arcs[location1][i].adj != INFINITY){
			return graph.vexs[i];
		}
	}
	return ' ';
}


//查詢頂點的位置
int graphLocation(MGraph graph,char  vex){
	for (int i = 0; i < graph.vexNum; i++){
		if (graph.vexs[i] == vex){
			return i;
		}
	}
	return -1;
}
//建立圖 子函式
//有向圖
void createDG(MGraph * graph){
	graph->kind = DG;
	printf("請輸入頂點數,邊(弧)數\n");
	scanf("%d%d%*c",&graph->vexNum,&graph->arcNum);
	//初始化鄰接矩陣
	for (int i = 0; i < MAX_VERTEX_NUM; i++){
		for (int j = 0; j < MAX_VERTEX_NUM; j++){
			graph->arcs[i][j].adj = 0;
			graph->arcs[i][j].info = NULL;
		}
	}
	//構造頂點集
	printf("請輸入頂點集\n");
	for (int i = 0; i < graph->vexNum; i++){
		scanf("%c",&graph->vexs[i]);
	}
	//構造頂點關係
	fflush(stdin);
	printf("請輸入頂點的關係\n");
	for (int i = 0; i < graph->arcNum; i++){
		char vex1,vex2;
		scanf("%c%c%*c",&vex1,&vex2);
		int location1 = graphLocation(*graph,vex1);
		int location2 = graphLocation(*graph,vex2);
		graph->arcs[location1][location2].adj = 1;
	}
}
//有向網
void createDN(MGraph * graph){
	graph->kind = DN;
	printf("請輸入頂點數,邊(弧)數\n");
	scanf("%d%d%*c",&graph->vexNum,&graph->arcNum);
	//初始化鄰接矩陣
	for (int i = 0; i < MAX_VERTEX_NUM; i++){
		for (int j = 0; j < MAX_VERTEX_NUM; j++){
			graph->arcs[i][j].adj = INFINITY;
			graph->arcs[i][j].info = NULL;
		}
	}
	//構造頂點集
	printf("請輸入頂點集\n");
	for (int i = 0; i < graph->vexNum; i++){
		scanf("%c",&graph->vexs[i]);
	}
	//構造頂點關係
	fflush(stdin);
	printf("請輸入頂點的關係\n");
	for (int i = 0; i < graph->arcNum; i++){
		char vex1,vex2;
		int weight;
		scanf("%c%c%d%*c",&vex1,&vex2,&weight);
		int location1 = graphLocation(*graph,vex1);
		int location2 = graphLocation(*graph,vex2);
		graph->arcs[location1][location2].adj = weight;
	}
}
//無向圖
void createUDG(MGraph * graph){
	graph->kind = UDG;
	printf("請輸入頂點數,邊(弧)數\n");
	scanf("%d%d%*c",&graph->vexNum,&graph->arcNum);
	//初始化鄰接矩陣
	for (int i = 0; i < MAX_VERTEX_NUM; i++){
		for (int j = 0; j < MAX_VERTEX_NUM; j++){
			graph->arcs[i][j].adj = 0;
			graph->arcs[i][j].info = NULL;
		}
	}
	//構造頂點集
	printf("請輸入頂點集\n");
	for (int i = 0; i < graph->vexNum; i++){
		scanf("%c",&graph->vexs[i]);
	}
	fflush(stdin);
	//構造頂點關係
	printf("請輸入頂點的關係\n");
	for (int i = 0; i < graph->arcNum; i++){
		char vex1,vex2;
		scanf("%c%c%*c",&vex1,&vex2);
		int location1 = graphLocation(*graph,vex1);
		int location2 = graphLocation(*graph,vex2);
		graph->arcs[location1][location2].adj = graph->arcs[location2][location1].adj = 1;
	}
}
//無向網
void createUDN(MGraph * graph){
	graph->kind = UDN;
	printf("請輸入頂點數,邊(弧)數\n");
	scanf("%d%d%*c",&graph->vexNum,&graph->arcNum);
	//初始化鄰接矩陣
	for (int i = 0; i < MAX_VERTEX_NUM; i++){
		for (int j = 0; j < MAX_VERTEX_NUM; j++){
			graph->arcs[i][j].adj = INFINITY;
			graph->arcs[i][j].info = NULL;
		}
	}
	//構造頂點集
	printf("請輸入頂點集\n");
	for (int i = 0; i < graph->vexNum; i++){
		scanf("%c",&graph->vexs[i]);
	}
	//構造頂點關係
	fflush(stdin);
	printf("請輸入頂點的關係\n");
	for (int i = 0; i < graph->arcNum; i++){
		char vex1,vex2;
		int weight;
		scanf("%c%c%d%*c",&vex1,&vex2,&weight);
		int location1 = graphLocation(*graph,vex1);
		int location2 = graphLocation(*graph,vex2);
		graph->arcs[location1][location2].adj =graph->arcs[location2][location1].adj = weight;
	}
}

//檢視頂點資料之間是否相鄰
bool graphIsAdj(MGraph graph,char vex1,char vex2){
	E_Graph_Kind kind = graph.kind;
	int weight = (kind == DG || kind == UDG) ? 0 : INFINITY;
	int location1 = graphLocation(graph,vex1);
	int location2 = graphLocation(graph,vex2);
	return graph.arcs[location1][location2].adj != weight ? true : false;
}

int graphDegree(MGraph graph,char vex){
	int location = graphLocation(graph,vex);
	E_Graph_Kind kind = graph.kind;
	int weight = (kind == DG || kind == UDG) ? 0 : INFINITY;
	int degree = 0;
	for (int i = 0; i < graph.vexNum; i++){//計算行
		if (graph.arcs[location][i].adj != weight){
			degree++;
		}
	}
	for (int i = 0; i < graph.vexNum; i++){//計算列
		if (graph.arcs[i][location].adj != weight){
			degree++;
		}
	}
	if (kind == UDG || kind == UDN){
		degree /= 2;
	}
	return degree;
}

//當有以下操作時,不適合 用鄰接矩陣的方式來處理。
void insertVex(MGraph * graph,char  vex){
	graph->vexs[graph->vexNum++] = vex;
}
//需要移動很多元素.
void deleteVex(MGraph * graph,char  vex){
	int location = graphLocation(*graph,vex);
	//刪除頂點集
	for (int i = location+1; i < graph->vexNum; i++){
		graph->vexs[i-1] = graph->vexs[i];
	}
	//計算刪除的邊(弧)數
	graph->arcNum -= graphDegree(*graph,vex);
	//刪除邊(弧)
	//vex下面的上移
	for (int i = location+1; i < graph->vexNum; i++){
		for (int j = 0; j < graph->vexNum; j++){
			graph->arcs[i-1][j] = graph->arcs[i][j];
		}
	}
	//vex右邊的左移
	for (int i = location + 1; i < graph->vexNum; i++){
		for (int j = 0; j < graph->vexNum; j++){
			graph->arcs[j][i-1] = graph->arcs[j][i];
		}
	}
	//清理垃圾資料(第vexNum行 和 第vexNum列)
	int maxVexNum = graph->vexNum;
	E_Graph_Kind kind = graph->kind;
	int weight = (kind == DG || kind == UDG) ? 0 : INFINITY;
	for (int i = 0; i < maxVexNum; i++){
		graph->arcs[maxVexNum-1][i].adj = weight;
		graph->arcs[i][maxVexNum-1].adj = weight;
	}
	graph->vexNum--;
}
//插入邊(弧)
void insertArc(MGraph * graph,char  vex1,char  vex2,int weight){
	int location1 = graphLocation(*graph,vex1);
	int location2 = graphLocation(*graph,vex2);
	E_Graph_Kind kind = graph->kind;
	if (kind == DG || kind == UDG){
		graph->arcs[location1][location2].adj = 1;
	}
	else{
		graph->arcs[location1][location2].adj = weight;
	}
	if (kind == UDG || kind == UDN)
	{
		graph->arcs[location2][location1].adj = graph->arcs[location1][location2].adj;
	}
}
//刪除邊(弧)
void deleteArc(MGraph * graph,char  vex1,char  vex2){
	int location1 = graphLocation(*graph,vex1);
	int location2 = graphLocation(*graph,vex2);
	E_Graph_Kind kind = graph->kind;
	if (kind == DG || kind == UDG){
		graph->arcs[location1][location2].adj = 0;
	}
	else{
		graph->arcs[location1][location2].adj = INFINITY;
	}
	if (kind == UDG || kind == UDN)
	{
		graph->arcs[location2][location1].adj = graph->arcs[location1][location2].adj;
	}
}

void printAdjMatrix(MGraph graph){
	for (int i = 0; i < graph.vexNum; i++){
		for (int j = 0; j < graph.vexNum; j++){
			printf("%d\t",graph.arcs[i][j]);
		}
		printf("\n");
	}
}




int _tmain(int argc, _TCHAR* argv[])
{
	MGraph graph;
	graphCreate(&graph);
	printAdjMatrix(graph);
	printf("圖 有 %d個頂點,%d個邊(弧)\n",graph.vexNum,graph.arcNum);
	char * isAdj = graphIsAdj(graph,'a','d')? "相鄰":"不相鄰";
	int degree = graphDegree(graph,'c');
	printf("a 和 d %s,c的度數是:%d\n",isAdj,degree);
	char vexFirst = firstAdjVex(graph,'c');
	char vexNext = nextAdjVex(graph,'c','a');
	printf("c的第一個鄰接點是%c\nc的相對於a的下一個鄰接點是%c\n",vexFirst,vexNext);
	insertVex(&graph,'e');
	printf("插入節點e之後:\n");
	printAdjMatrix(graph);
	printf("插入邊(e,d)之後:\n");
	insertArc(&graph,'e','d',1);
	printAdjMatrix(graph);
	printf("刪除頂點c之後:\n");
	deleteVex(&graph,'c');
	printAdjMatrix(graph);
	deleteArc(&graph,'a','b');
	printf("刪除弧(a,b)之後:\n");
	printAdjMatrix(graph);
	return 0;
}
執行截圖: