看資料結構寫程式碼(35) 圖的鄰接矩陣表示法
阿新 • • 發佈:2019-01-10
雜談:最近清明小長假,好好的放鬆了一下。節前 和 節後 都有點 鬆懈。不好,不好。貴在堅持。加油。
圖的鄰接矩陣表示法是用 兩個陣列 來表示 圖的資料結構。一個是頂點陣列,另一個是鄰接矩陣陣列。鄰接矩陣 裡存放著 頂點的關係。
用鄰接矩陣表示圖,在 看 頂點之間 是否有邊,或者 求頂點的度等操作時比較簡單。但空間浪費巨大,在插入,刪除 頂點 和邊 操作時 需要 移動大量資料,造成不便。所以在插入刪除比較多,節點數比較多的時候 不宜 使用這種結構。
下面上程式碼:
執行截圖:// 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; }