C語言—鄰接矩陣和鄰接表的理解
阿新 • • 發佈:2018-11-20
要談鄰接表,那我們先談談鄰接矩陣,因為鄰接表就是因為鄰接矩陣對於稀疏圖造成記憶體的很大浪費。那麼它是如何浪費的哪? 別急慢慢來!
- 什麼叫做鄰接矩陣?
它就是儲存頂點是否存在連線關係的二維陣列如下(右),關係圖(左)
解釋圖:如果a1->a2有線連線的話,用1表示反之用0表示。
程式碼如下:
#define MAX_VERTEX_NUM 20 /*最多頂點數目*/ #define INFINITY 32768 /*表示最大值*/ #include <stdio.h> #include <stdlib.h> /*圖的種類: DG表示有向圖 DN表示有向網 UDG表示無向圖 UDN表示無向網*/ typedef enum {DG,DN,UDG,UDN} GraphKind; typedef int VertexData;//假設頂點資料為字元型 typedef struct ArcNode//儲存鄰接結點的資訊 { int adj; //對於無權圖,用1或0表示是否相鄰;對帶權圖,則為表示權值型別 int info; //暫時不知道儲存什麼。 }ArcNode; typedef struct { VertexData vertex[MAX_VERTEX_NUM]; ArcNode arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//鄰接矩陣 int vexnum, arcnum;//圖放入頂點數和弧數 GraphKind kind;//圖的種類標誌 }AdjMatrix;//鄰接矩陣資訊 int locateVertex(AdjMatrix *G, VertexData v)//找頂點函式 { int j = 0, k; for (k = 0; k < G->vexnum; k++) { if (G->vertex[k] == v) { j = k; break; } } return (j); } int main() { AdjMatrix *G; G = (AdjMatrix *)malloc(sizeof(AdjMatrix));//定義物件 int i, j, k, weight; VertexData v1=0, v2=0;//兩頂點。 printf("請輸入圖的頂點數和弧數\n"); scanf_s("%d,%d", &G->vexnum, &G->arcnum); getchar(); for (i = 0; i < G->vexnum; i++)//初始化鄰接矩陣 { for (j = 0; j < G->vexnum; j++) { G->arcs[i][j].adj = 0;//權值最大 } } printf("請輸入頂點的資料\n"); for (i = 0; i < G->vexnum; i++) { scanf_s("%d", &G->vertex[i]); } printf("請輸入兩個頂點和權值\n"); for (k = 0; k < G->arcnum; k++)//兩個頂點建立聯絡 { scanf_s("%d,%d,%d", &v1, &v2, &weight);//讀入資料 i = locateVertex(G, v1); j = locateVertex(G, v2); G->arcs[i][j].adj = weight;//賦權值 }//建弧完成 printf("打印出帶權圖結構如下\n"); for (i = 0; i < G->vexnum; i++) { for (j = 0; j < G->vexnum; j++) { printf("%d ", G->arcs[i][j].adj); } printf("\n"); } system("pause"); return 0; }
執行結果如下:
從圖中我們發現存了不少0,表示它們不是鄰接關係,但是我們並不需要記住它們不相鄰,所以這就大大浪費了記憶體。所以就有了鄰接表法儲存。
- 鄰接法
優點:只儲存關聯的資訊,對於圖中存在的邊資訊,則儲存,而不相鄰的頂點則不保留資訊。
圖奉上如下:
後面的結點我只分了兩份,實際還要給權值給開個空間儲存資訊。(我給省略了)。
程式碼如下:
//鄰接表儲存結構的形式 #include <stdio.h> #include<stdlib.h> #define MAX_VERTEX_NUM 20 #define VertexData int #define max 100 #define size 4//儲存數字的大小 #define bian 4//儲存邊的大小 int edge[1000][2] = { 0 }; typedef enum{DG,DN,UDG,UDN} GraphKind;//圖的種類 typedef struct ArcNode { int data; struct ArcNode *nextarc; //指向下一條弧的指標 //int weight;//權值 先不考慮 }ArcNode; typedef struct VertexNode { VertexData data;//頂點資料 ArcNode *firstarc;//指向該頂點第一條弧的指標 }VertexNode; typedef struct { VertexNode vertex[MAX_VERTEX_NUM];//一維頂點陣列 int vexnum, arcnum;//頂點個數和弧數 }AdjList;//鄰接目錄 int find_insert(ArcNode *edge, ArcNode *temp) { ArcNode *p; p = edge; while (p->nextarc != NULL)//迴圈找到一維頂點陣列中的每一個頂點之後的鄰接點 { p = p->nextarc; } p->nextarc = temp;//插入找到的邊 return 0; } AdjList* CreGraph()//建立圖 { int i,c1,c2; ArcNode *Arc; Arc = (ArcNode*)malloc(sizeof(ArcNode)); AdjList *picture; picture = (AdjList*)malloc(sizeof(AdjList)); picture->vexnum = size; picture->arcnum = bian; printf("請輸入頂點\n"); for (i = 1; i <= picture->vexnum; i++) { scanf_s("%d", &picture->vertex[i].data); picture->vertex[i].firstarc = NULL;//剛開始把一維陣列建立起來 } //再確定哪兩個頂點連線需要存邊0代表出度連線1代表入度 for (int i = 1; i <= picture->arcnum; i++)//建立聯絡 { c1 = edge[i][0]; c2 = edge[i][1]; Arc = (ArcNode*)malloc(sizeof(ArcNode));//新申請的結點 Arc->data = edge[i][1];//獲取頂點數 Arc->nextarc = NULL; //從輸入的弧中將入度相同的結點連線起來 if (picture->vertex[c1].firstarc == NULL) { picture->vertex[c1].firstarc = Arc; } else { find_insert(picture->vertex[c1].firstarc, Arc); } } return picture; } int main() { int i = 0; AdjList* picture; printf("請輸入要連線的序號邊\n"); for (i = 1; i <= bian ; i++) { scanf("%d",&edge[i][0]);//代表號,不是放權值 scanf("%d", &edge[i][1]); } picture = CreGraph(); printf("鄰接表如下\n"); for (int i = 1; i <= picture->vexnum; i++) { ArcNode *p; p = (ArcNode*)malloc(sizeof(ArcNode)); if (picture->vertex[i].firstarc == NULL) { printf("error"); } else { p = picture->vertex[i].firstarc; printf("%d ", picture->vertex[i].data); while (p != NULL) { printf("%d ", p->data); p = p->nextarc; } } printf("\n"); } system("pause"); return 0; }
程式碼有點長,但對於IT專業的我們來說,耐的住心慢慢理解,到最終get it,是非常重要的,加油!