文字描述
鄰接多重表是無向圖的另一種鏈式存儲結構. 雖然鄰接表是無向圖的一種很有效的存儲結構,在鄰接表中容易求得頂點和邊的各種信息. 但是,在鄰接表中每一條邊(vi,vj)有兩個結點,分別在第i個和第j個鏈表中,這給某些圖的操作帶來不便。如對已被搜索過的邊作記號或刪除一條邊等,此時需要找到表示同一條邊的兩個結點。因此,在進行這類操作的無向圖的問題中采用鄰接多重表更合適。
鄰接多重表的結構和十字鏈表類型。邊結點和頂點結點如下示:
邊結點由6個域組成:mark為標志域,可標記這條邊是否被搜索過; ivex和jvex為該邊依附的兩個頂點在圖中的位置;ilink指向下一條依附於頂點ivex的邊;jlink指向下一條依附於頂點jvex的邊,info為指向和邊相關的各種信息的指針域。
頂點結點由2個域組成:data存儲和該頂點相關的信息如頂點名稱;firstedge域指示第一條依附於該頂點的邊。
示意圖
算法分析
建立鄰接多重鏈表的時間復雜度和建立鄰接表是相同的. 另外鄰接多重表幾乎只針對無向圖或無向網。
代碼實現

1 /* 2 以鄰接多重表作為圖的存儲結構創建無向圖。 3 */ 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #define MAX_VERTEX_NUM 20 9 typedef enum {DG, DN, UDG, UDN} GraphKind; 10 typedef enum {unvisited, visited} VisitIf; 11 typedef char InfoType; 12 typedef char VertexType; 13 //頂點結點 14 typedef struct EBox{ 15 VisitIf mark;//訪問標記 16 int ivex, jvex;//該邊依附的兩個頂點的位置 17 struct EBox *ilink, *jlink;//分別指向依附這兩個頂點的下一條邊 18 InfoType *info;//該邊信息指針 19 }EBox; 20 //邊結點 21 typedef struct VexBox{ 22 VertexType data;//存儲頂點名稱 23 EBox *firstedge;//指向第一條依附該頂點的邊 24 }VexBox; 25 //圖結點 26 typedef struct{ 27 VexBox adjmulist[MAX_VERTEX_NUM]; 28 int vexnum,edgenum; //無向圖的當前頂點數和邊數 29 GraphKind kind; 30 }AMLGraph; 31 32 /* 33 若G中存在頂點u,則返回該頂點在圖中位置;否則返回-1。 34 */ 35 int LocateVex(AMLGraph G, VertexType v) 36 { 37 int i = 0; 38 for(i=0; i<G.vexnum; i++){ 39 if(v == G.adjmulist[i].data) 40 return i; 41 } 42 return -1; 43 } 44 45 /* 46 若G中存在頂點位置loc存在,則返回其頂點名稱 47 */ 48 VertexType LocateVInfo(AMLGraph G, int loc){ 49 return G.adjmulist[loc].data; 50 } 51 52 /* 53 采用鄰接多重表的存儲結構,構造無向圖 54 */ 55 int CreateUDG(AMLGraph *G) 56 { 57 int i = 0, j = 0, k = 0, IncInfo = 0; 58 int vi = 0, vj = 0; 59 char tmp[10] = {0}; 60 EBox *p = NULL; 61 62 printf("輸入頂點數,邊數,其他信息標志位: "); 63 scanf("%d,%d,%d", &G->vexnum, &G->edgenum, &IncInfo); 64 65 for(i=0; i<G->vexnum; i++){ 66 //輸入頂點值 67 printf("輸入第%d個頂點: ", i+1); 68 memset(tmp, 0, sizeof(tmp)); 69 scanf("%s", tmp); 70 G->adjmulist[i].data = tmp[0]; 71 G->adjmulist[i].firstedge = NULL; 72 } 73 for(k=0; k<G->edgenum; k++){ 74 printf("輸入第%d條邊(頂點1, 頂點2): ", k+1); 75 memset(tmp, 0, sizeof(tmp)); 76 scanf("%s", tmp); 77 sscanf(tmp, "%c,%c", &vi, &vj); 78 i = LocateVex(*G, vi); 79 j = LocateVex(*G, vj); 80 p = (EBox*)malloc(sizeof(EBox)); 81 p->ivex = i; 82 p->jvex = j; 83 p->mark = unvisited; 84 p->ilink = G->adjmulist[i].firstedge; 85 p->jlink = G->adjmulist[j].firstedge; 86 G->adjmulist[i].firstedge = p; 87 G->adjmulist[j].firstedge = p; 88 if(IncInfo){ 89 //Input(p->info); 90 } 91 } 92 return 0; 93 } 94 95 /* 96 采用鄰接多重表的存儲結構,構造圖 97 */ 98 int CreateGrap(AMLGraph *G) 99 { 100 printf("輸入圖類型: -有向圖(0), -有向網(1), +無向圖(2), -無向網(3): "); 101 scanf("%d", &G->kind); 102 switch(G->kind){ 103 case DG: 104 case DN: 105 default: 106 printf("還不支持!\n"); 107 return -1; 108 case UDG: 109 return CreateUDG(G); 110 } 111 return 0; 112 } 113 114 /* 115 輸出圖的信息 116 */ 117 void printG(AMLGraph G) 118 { 119 if(G.kind == DG){ 120 printf("類型:有向圖;頂點數 %d, 邊數 %d\n", G.vexnum, G.edgenum); 121 }else if(G.kind == DN){ 122 printf("類型:有向網;頂點數 %d, 邊數 %d\n", G.vexnum, G.edgenum); 123 }else if(G.kind == UDG){ 124 printf("類型:無向圖;頂點數 %d, 邊數 %d\n", G.vexnum, G.edgenum); 125 }else if(G.kind == UDN){ 126 printf("類型:無向網;頂點數 %d, 邊數 %d\n", G.vexnum, G.edgenum); 127 } 128 int i = 0; 129 EBox *vi = NULL; 130 EBox *vj = NULL; 131 EBox *vf = NULL; 132 for(i=0; i<G.vexnum; i++){ 133 printf("%c(%d): ", G.adjmulist[i].data, i); 134 vf = G.adjmulist[i].firstedge; 135 vi = vf->ilink; 136 vj = vf->jlink; 137 printf("fistedge:%c(%d)->%c(%d); ", LocateVInfo(G, vf->ivex), vf->ivex, LocateVInfo(G, vf->jvex), vf->jvex); 138 printf(" || ilink:"); 139 while(vi){ 140 printf("%c(%d)->%c(%d);", LocateVInfo(G, vi->ivex), vi->ivex, LocateVInfo(G, vi->jvex), vi->jvex); 141 vi = vi->ilink; 142 } 143 printf(" || jlink:"); 144 while(vj){ 145 printf("%c(%d)->%c(%d);", LocateVInfo(G, vj->ivex), vj->ivex, LocateVInfo(G, vj->jvex), vj->jvex); 146 vj = vj->jlink; 147 } 148 printf("\n"); 149 } 150 return ; 151 } 152 153 int main(int argc, char *argv[]) 154 { 155 AMLGraph G; 156 if(CreateGrap(&G) > -1){ 157 printG(G); 158 } 159 return 0; 160 }
代碼運行