圖——圖的鄰接矩陣存儲結構

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,代碼實現時使用指針數組進行數據的存儲(提升效率);

相關文章
相關標籤/搜索