資料結構基礎 之 圖 的 鄰接矩陣實現與鄰接表實現
【鄰接矩陣】
鄰接矩陣,就是一個反應邊與邊之間聯絡的二維陣列。這個二維陣列我們用matrix[numV][numV]表示,其中numV是頂點數。
對於無權圖
若頂點Vi和Vj之間有邊,則matrix[Vi][Vj]=1;否則matrix[Vi][Vj]=0。
對於有權圖
若頂點Vi和Vj之間有邊,且權值為weight,則matrix[Vi][Vj]=weight;否則matrix[Vi][Vj]=0或MAXWEIGHT(取最小權值或最大權值)。
【鄰接表】
當圖中的邊數較少時,用鄰接矩陣來實現圖結構,則會浪費很多記憶體空間。因此,考慮另一種實現圖結構的方法:鄰接表。在鄰接表中主要有兩種節點結構體:
頂點節點((vertex)表示節點資料,也可以是節點下標;以及下一節點地址(next))
邊節點((vertex)表示節點資料,也可以是節點下標;(adjvex)通俗理解就是(vertex)節點出度表;以及出度表中下一出度節點地址(next))
【原始碼示例】
- 鄰接矩陣建圖
void Graph::createGraph() { cout << "輸入邊數 "; while (cin >> numE && numE < 0) cout << "輸入有誤!,重新輸入 "; int i, j, w; if (!isWeighted) //無權圖 { if (!isDirected) //無向圖 { cout << "輸入每條邊的起點和終點:\n"; for (int k = 0; k < numE; k++) { cin >> i >> j; while (!check(i, j)) { cout << "輸入的邊不對!重新輸入\n"; cin >> i >> j; } matrix[i][j] = matrix[j][i] = 1; } } else //有向圖 { cout << "輸入每條邊的起點和終點:\n"; for (int k = 0; k < numE; k++) { cin >> i >> j; while (!check(i, j)) { cout << "輸入的邊不對!重新輸入\n"; cin >> i >> j; } matrix[i][j] = 1; } } } else //有權圖 { if (!isDirected) //無向圖 { cout << "輸入每條邊的起點、終點和權值:\n"; for (int k = 0; k < numE; k++) { cin >> i >> j >> w; while (!check(i, j, w)) { cout << "輸入的邊不對!重新輸入\n"; cin >> i >> j >> w; } matrix[i][j] = matrix[j][i] = w; } } else //有向圖 { cout << "輸入每條邊的起點、終點和權值:\n"; for (int k = 0; k < numE; k++) { cin >> i >> j >> w; while (!check(i, j, w)) { cout << "輸入的邊不對!重新輸入\n"; cin >> i >> j >> w; } matrix[i][j] = w; } } } }
- 鄰接表建圖
void Graph::createGraph() { //用一個新的變量表示邊數,numE的修改則留到insertedge()中 int numEdge = 0; cout << "輸入邊數 "; while (cin >> numEdge && numEdge < 0) cout << "輸入有誤!,重新輸入 "; int i, j, w; if (!isWeighted) //無權圖 { cout << "輸入每條邊的起點和終點:\n"; for (int k = 0; k < numEdge; k++) { cin >> i >> j; while (!check(i, j)) { cout << "輸入的邊不對!重新輸入\n"; cin >> i >> j; } insertEdge(i, j); } } else //有權圖 { cout << "輸入每條邊的起點、終點和權值:\n"; for (int k = 0; k < numEdge; k++) { cin >> i >> j >> w; while (!check(i, j, w)) { cout << "輸入的邊不對!重新輸入\n"; cin >> i >> j >> w; } insertEdge(i, j, w); } } } void Graph::insertEdge(int vertex, int adjvex, int weight) { insertedge(vertex, adjvex, weight); if (!isDirected) //無向圖 insertedge(adjvex, vertex, weight); } void Graph::insertedge(int vertex, int adjvex, int weight) { EdgeNode *p, *q, *r; p = q = r = NULL; if (adjList[vertex].next) //非第一個節點 { p = adjList[vertex].next; //移動p到合適位置 while (p && (p->adjvex < adjvex)) { q = p; p = p->next; } if (p && (p->adjvex == adjvex)) //修改已有邊權值 p->weight = weight; else { r = new EdgeNode; r->adjvex = adjvex; r->weight = weight; r->next = p; //當加入的新節點位於表的第一個位置 if (adjList[vertex].next == p) adjList[vertex].next = r; else q->next = r; numE++; } } else { p = new EdgeNode; p->adjvex = adjvex; p->weight = weight; p->next = NULL; adjList[vertex].next = p; numE++; } }
【詳細原始碼詳址】
http://blog.csdn.net/zhangxiangdavaid/article/details/38321327
http://blog.csdn.net/zhangxiangdavaid/article/details/38323593
【最後的話】
很明顯的發現,鄰接矩陣和鄰接表一個是以矩陣陣列的形式記錄了圖中邊的關係,一個是以連結串列陣列的形式記錄邊的關係。無它,連結串列肯定比資料更節省空間,但是,查詢運算元組往往比連結串列更快捷。如果,還有興趣可以用STL的 list 實現,這樣將盡收二者之長,鑑於實現非常簡單,此處程式碼就不再給出。
【注】
list,vector是push_back,queue和stack是push 。