1,基本思想: ios
1,用一維數組存儲頂點:描述頂點相關的數據;數組
2,用二維數組存儲邊:描述頂點間的關係和權;安全
2,鄰接矩陣法(二維數組存儲權值表示邊):函數
1,設圖 A = (V, E) 是一個有 n 個頂點的圖,圖的鄰接矩陣爲 Edge[n][n],則:測試
2,解決工程問題時,習慣於對圖中的每一個頂點進行編號,當不須要權值時,取 w 非空表示結點間有鏈接;this
3,無向圖的鄰接矩陣是對稱的,有向圖的鄰接矩陣可能不是對稱的;spa
3,鄰接矩陣設計與實現:設計
1,如何具體表示頂點集數組?指針
2,如何具體表示邊集數組?code
4,實現方式一:直接使用數組表示頂點集和邊集:
1,將鄰接矩陣直接搬到代碼中,這種方法不科學;
2,分析下面代碼的效率:
1,構造效率低下:
1,圖對象初始化時,頻繁調用頂點類型和邊類型的構造函數;
2,空間使用率低下:
1,圖對象佔用大量空間,而大多數空間處於閒置狀態;
3,沒法表示空值:
1,沒法用統一的方式表示邊爲空的情形;
5,實現方式二:使用指針數組表示頂點集和邊集:
1,構造效率:
1,初始化圖對象時,只須要將數組元素賦值爲空,不須要調用頂點類型 和邊類型的構造函數;
2,空間使用率:
1,頂點數據元素和邊數據元素在須要時動態建立;
3,空值的表示:
1,任意的頂點類型和邊類型都是用 NULL 表示空值;
6,圖的鄰接矩陣結構:
1 #ifndef MATRIXGRAPH_H 2 #define MATRIXGRAPH_H 3 4 #include "Graph.h" 5 #include "Exception.h" 6 #include "DynamicArray.h" 7 8 namespace DTLib 9 { 10 11 /* MatirxGraph 沒法動態 添加/刪除 頂點,圖對象空間利用率低。無論頂點是否鏈接,都會佔用空間,使用數組浪費空間,用鏈表替換數組,將鄰接矩陣換爲鄰接鏈表法;適用於內存資源富足場合 */ 12 template < int N, typename V, typename E > // N 是圖中頂點個數,V 是與頂點相關的數據類型,E 是權值的類型; 13 class MatrixGraph : public Graph<V, E> 14 { 15 protected: 16 V* m_vertexes[N]; // 每一個成員都是指向頂點的相關聯的數據元素的指針,這裏的數據是工程須要、工程相關的背景; 17 E* m_edges[N][N]; // 鄰接矩陣 18 int m_eCount; // 當前圖中邊的個數 19 20 public: 21 MatrixGraph() 22 { 23 for(int i=0; i<vCount(); i++) // 指針數組初始化 24 { 25 m_vertexes[i] = NULL; // 沒有一個數據元素和頂點相關聯 26 for(int j=0; j<vCount(); j++) 27 { 28 m_edges[i][j] = NULL; // 一條邊也沒有 29 } 30 } 31 32 m_eCount = 0; 33 } 34 35 /* 獲取和頂點 i 相關聯的元素的值 */ 36 V getVertex(int i) // O(1) 37 { 38 V ret; 39 40 if( !getVertex(i, ret) ) 41 { 42 THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ..."); 43 } 44 45 return ret; 46 } 47 48 /* 獲取頂點 i 所關聯的元素值 value */ 49 bool getVertex(int i, V& value) // O(1) 50 { 51 bool ret = ( (0 <= i) && (i < vCount()) ); // i 的合法性 52 53 if( ret ) 54 { 55 if( m_vertexes[i] != NULL ) // 有具體元素關聯 56 { 57 value = *(m_vertexes[i]); 58 } 59 else 60 { 61 THROW_EXCEPTION(InvalidOperationException, "No value assigned to this vertex ..."); 62 } 63 } 64 return ret; 65 } 66 67 /* 設置和頂點相關聯的元素 */ 68 bool setVertex(int i, const V& value) // O(1) 69 { 70 bool ret = ( (0 <= i) && (i < vCount()) ); 71 72 if( ret ) 73 { 74 V* data = m_vertexes[i]; // 中間數據 data 爲了異常安全 75 76 if( data == NULL ) // 沒有具體元素關聯 77 { 78 data = new V(); 79 } 80 81 if( data != NULL ) // 申請成功 82 { 83 *data = value; // 設置值,單位和要加指針?若是這裏發生異常安全,則下面代碼不執行,圖仍是正常的 84 85 m_vertexes[i] = data; 86 } 87 else 88 { 89 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to store new vertex value ..."); 90 } 91 } 92 93 return ret; 94 } 95 96 /* 獲取從 i 做爲起點的可達的頂點的編號,到數組中 */ 97 SharedPointer< Array<int> > getAdgacent(int i) // O(n) 98 { 99 DynamicArray<int>* ret = NULL; // 定義返回值對象 100 101 if( (0 <= i) && (i < vCount()) ) // i 取值要合法 102 { 103 int n = 0; 104 105 for(int j=0; j<vCount(); j++) // 查找 i 行關聯點 106 { 107 if( m_edges[i][j] != NULL ) // 頂點 i 和 j 相關聯 108 { 109 n++; // n 表示與 i 相關聯的頂點個數 110 } 111 } 112 113 ret = new DynamicArray<int>(n); // 建立返回值對象 114 115 if( ret != NULL ) // 建立成功 116 { 117 for(int j=0, k=0; j<vCount(); j++) // k 做爲輔助變量 118 { 119 if( m_edges[i][j] != NULL ) 120 { 121 ret->set(k++, j); // 記錄對應的頂點編號到數組對象中 122 } 123 } 124 } 125 else 126 { 127 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create ret object ..."); 128 } 129 } 130 else 131 { 132 THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ..."); 133 } 134 135 return ret; 136 } 137 138 /* 判斷 i 到 j 頂點邊是否鏈接,值不爲空就鏈接 */ 139 bool isAdjacent(int i, int j) 140 { 141 return (0 <= i) && (i < vCount()) && (0 <= j) && (j < vCount()) && (m_edges[i][j] != NULL); 142 } 143 144 /* 獲取頂點 i 到頂點 j 邊上面的權值 */ 145 E getEdge(int i, int j) // O(1) 146 { 147 E ret; 148 149 if( !getEdge(i, j, ret) ) // 直接得到值 150 { 151 THROW_EXCEPTION(InvalidParameterException, "Index <i, j> is invalid ..."); 152 } 153 154 return ret; 155 } 156 157 /* 獲取頂點 i 到頂點 j 邊上面的權值 */ 158 bool getEdge(int i, int j, E& value) // O(1) 159 { 160 bool ret = ( (0 <= i) && (i < vCount()) && 161 (0 <= j) && (j < vCount()) ); // i,j 的合法性 162 163 if( ret ) 164 { 165 if( m_edges[i][j] != NULL ) // 權值存在,能夠拿到 166 { 167 value = *(m_edges[i][j]); // 獲取元素,這裏面存儲的是指針,因此要加 * 168 } 169 else 170 { 171 THROW_EXCEPTION(InvalidOperationException, "No value assigened to this edge ..."); 172 } 173 } 174 175 return ret; 176 } 177 178 /* 設置邊上面權值的操做 */ 179 bool setEdge(int i, int j, const E& value) // O(1) 180 { 181 bool ret = ( (0 <= i) && (i < vCount()) && 182 (0 <= j) && (j < vCount()) ); // i,j 的合法性 183 184 if( ret ) 185 { 186 E* ne = m_edges[i][j]; // 使用中間變量 187 188 if( ne == NULL ) // i 到 j 原本不可達 189 { 190 ne = new E(); // 建立可達對象,設置 i 到 j 的鏈接 191 192 if( ne != NULL ) // 建立成功 193 { 194 *ne = value; // 設置權值 195 m_edges[i][j] = ne; // i 到 j 是可達的 196 m_eCount++; // 邊數加 1 197 } 198 else 199 { 200 THROW_EXCEPTION(NoEnoughMemoryException, "No memory to store new edge value ..."); 201 } 202 } 203 else 204 { 205 *ne = value; // 改變權值 206 } 207 } 208 209 return ret; 210 } 211 212 /* 刪除 i 和 j 之間的關聯,即沒有邊了 */ 213 bool removeEdge(int i, int j) // O(1) 214 { 215 bool ret = ( (0 <= i) && (i < vCount()) && 216 (0 <= j) && (j < vCount()) ); // i,j 的合法性 217 218 if( ret ) 219 { 220 E* toDel = m_edges[i][j]; // 定義中間變量指針指向要刪除的權值對象 221 m_edges[i][j] = NULL; // 中間指針指向要刪除的對象了,將鄰接矩陣對應元素賦爲空值 222 223 if( toDel != NULL ) 224 { 225 m_eCount--; // 邊個數減一 226 delete toDel; // 爲了儘可能的達到異常安全目的,釋放 m_edges 所指向的對象; 227 } 228 } 229 230 return ret; 231 } 232 233 /* 獲取當前圖中頂點的數量 */ 234 int vCount() // O(1) 235 { 236 return N; // 頂點的數量爲當前模板參數 N,頂點數量是一個定製; 237 } 238 239 /* 獲取當前圖中邊的數量 */ 240 int eCount() // O(1) 241 { 242 return m_eCount; // 添加邊和刪除邊其都相應的變化 243 } 244 245 /* 頂點 i 的出度,i 行不爲 0 的個數 */ 246 int OD(int i) // O(n) 247 { 248 int ret = 0; 249 if( (0 <= i) && (i < vCount()) ) 250 { 251 for(int j=0; j<vCount(); j++) // 數鄰接矩陣對應的行中有多少個不爲 0 的個數 252 { 253 if( m_edges[i][j] != NULL ) // 第 i 行不爲 0 254 { 255 ret++; 256 } 257 } 258 } 259 else 260 { 261 THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ..."); 262 } 263 264 return ret; 265 } 266 267 /* 頂點 i 的入度,i 列不爲 0 的個數 */ 268 int ID(int i) // O(n) 269 { 270 int ret = 0; 271 272 if( (0 <= i) && (i < vCount()) ) 273 { 274 for(int j=0; j<vCount(); j++) // 數鄰接矩陣對應的列中有多少個不爲 0 的個數 275 { 276 if( m_edges[j][i] != NULL ) // 第 i 列不爲 0 277 { 278 ret++; 279 } 280 } 281 } 282 else 283 { 284 THROW_EXCEPTION(InvalidParameterException, "Index i is invalid ..."); 285 } 286 287 return ret; 288 } 289 290 291 ~MatrixGraph() // O(n*n) 292 { 293 for(int i=0; i<vCount(); i++) // 指針數組初始化 294 { 295 for(int j=0; j<vCount(); j++) 296 { 297 delete m_edges[i][j]; // 銷燬每條邊 298 } 299 300 delete m_vertexes[i] ; // 銷燬和每一個頂點相關聯的數據元素 301 } 302 } 303 }; 304 305 } 306 307 #endif // MATRIXGRAPH_H
7,圖的鄰接矩陣結構實現測試代碼:
1 #include <iostream> 2 #include "MatrixGraph.h" 3 4 using namespace std; 5 using namespace DTLib; 6 7 int main() 8 { 9 MatrixGraph<3, int, int> g; 10 11 g.setEdge(0, 1, 1); 12 g.setEdge(1, 0, 2); 13 g.setEdge(1, 2, 3); 14 15 cout << "vCount: " << g.vCount() << endl; 16 cout << "eCount: " << g.eCoutn() << endl; 17 18 cout << "ID(1): " << g.ID(1) << endl; 19 cout << "OD(1): " << g.OD(1) << endl; 20 cout << "TD(1): " << g.TD(1) << endl; 21 22 cout << "W(0, 1): " << g.getEdge(0, 1) << endl; 23 cout << "W(1, 0): " << g.getEdge(1, 0) << endl; 24 cout << "W(1, 2): " << g.getEdge(1, 2) << endl; 25 26 SharedPointer< Array<int> > aj = g.getAdgacent(2); 27 28 for(int i=0; i<aj->length(); i++) 29 { 30 cout << (*aj)[i] << " "; 31 } 32 33 cout << endl; 34 35 cout << "Delete Edge: " << endl; 36 37 g.removeEdge(0, 1); 38 39 cout << "eCount: " << g.eCoutn() << endl; 40 41 g.setVertex(0, 100); 42 43 cout << "V(0): " << g.getVertex(0) << endl; 44 45 //cout << "W(0, 1): " << g.getEdge(0, 1) << endl; // 非法操做 46 47 return 0; 48 }
8,小結:
1,鄰接矩陣法使用數組對圖相關的數據進行存儲;
2,一維數組存儲頂點相關的數據(空表示無相關的數據);
3,二維數組存儲邊相關的數據(空表示頂點間無鏈接);
4,代碼實現時使用指針數組進行數據的存儲(提升效率);