圖基本算法 圖的表示方法 鄰接矩陣 鄰接表

要表示一個圖G=(V,E),有兩種標準的表示方法,即鄰接表和鄰接矩陣。這兩種表示法既可用於有向圖,也可用於無向圖。通常採用鄰接表表示法,因爲用這種方法表示稀疏圖(圖中邊數遠小於點個數)比較緊湊。但當遇到稠密圖(|E|接近於|V|^2)或必須很快判別兩個給定頂點手否存在連接邊時,通常採用鄰接矩陣表示法,例如求最短路徑算法中,就採用鄰接矩陣表示。

  圖G=<V,E>的鄰接表表示是由一個包含|V|個列表的數組Adj所組成,其中每個列表對應於V中的一個頂點。對於每一個u∈V,鄰接表Adj[u]包含所有滿足條件(u,v)∈E的頂點v。亦即,Adj[u]包含圖G中所有和頂點u相鄰的頂點。每個鄰接表中的頂點一般以任意順序存儲。

  如果G是一個有向圖,則所有鄰接表的長度之和爲|E|,這是因爲一條形如(u,v)的邊是通過讓v出現在Adj[u]中來表示的。如果G是一個無向圖,則所有鄰接表的長度之和爲2|E|,因爲如果(u,v)是一條無向邊,那麼u會出現在v的鄰接表中,反之亦然。鄰接表需要的存儲空間爲O(V+E)。

  鄰接表稍作變動,即可用來表示加權圖,即每條邊都有着相應權值的圖,權值通常由加權函數w:E→R給出。例如,設G=<V,E>是一個加權函數爲w的加權圖。對每一條邊(u,v)∈E,權值w(u,v)和頂點v一起存儲在u的鄰接表中。

鄰接表C++實現:

 

複製代碼

  1 #include <iostream>
  2 #include <cstdio>
  3 using namespace std;
  4 
  5 #define maxn 100  //最大頂點個數
  6 int n, m;       //頂點數,邊數
  7 
  8 struct arcnode  //邊結點
  9 {
 10     int vertex;     //與表頭結點相鄰的頂點編號
 11     int weight = 0;     //連接兩頂點的邊的權值
 12     arcnode * next; //指向下一相鄰接點
 13     arcnode() {}
 14     arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
 15     arcnode(int v):vertex(v),next(NULL) {}
 16 };
 17 
 18 struct vernode      //頂點結點,爲每一條鄰接表的表頭結點
 19 {
 20     int vex;    //當前定點編號
 21     arcnode * firarc;   //與該頂點相連的第一個頂點組成的邊
 22 }Ver[maxn];
 23 
 24 void Init()  //建立圖的鄰接表需要先初始化,建立頂點結點
 25 {
 26     for(int i = 1; i <= n; i++)
 27     {
 28         Ver[i].vex = i;
 29         Ver[i].firarc = NULL;
 30     }
 31 }
 32 
 33 void Insert(int a, int b, int w)  //尾插法,插入以a爲起點,b爲終點,權爲w的邊,效率不如頭插,但是可以去重邊
 34 {
 35     arcnode * q = new arcnode(b, w);
 36     if(Ver[a].firarc == NULL)
 37         Ver[a].firarc = q;
 38     else
 39     {
 40         arcnode * p = Ver[a].firarc;
 41         if(p->vertex == b)  //如果不要去重邊,去掉這一段
 42         {
 43             if(p->weight < w)
 44                 p->weight = w;
 45             return ;
 46         }
 47         while(p->next != NULL)
 48         {
 49             if(p->next->vertex == b)    //如果不要去重邊,去掉這一段
 50             {
 51                 if(p->next->weight < w);
 52                     p->next->weight = w;
 53                 return ;
 54             }
 55             p = p->next;
 56         }
 57         p->next = q;
 58     }
 59 }
 60 void Insert2(int a, int b, int w)   //頭插法,效率更高,但不能去重邊
 61 {
 62     arcnode * q = new arcnode(b, w);
 63     if(Ver[a].firarc == NULL)
 64         Ver[a].firarc = q;
 65     else
 66     {
 67         arcnode * p = Ver[a].firarc;
 68         q->next = p;
 69         Ver[a].firarc = q;
 70     }
 71 }
 72 
 73 void Insert(int a, int b)   //尾插法,插入以a爲起點,b爲終點,無權的邊,效率不如頭插,但是可以去重邊
 74 {
 75     arcnode * q = new arcnode(b);
 76     if(Ver[a].firarc == NULL)
 77         Ver[a].firarc = q;
 78     else
 79     {
 80         arcnode * p = Ver[a].firarc;
 81         if(p->vertex == b) return;      //去重邊,如果不要去重邊,去掉這一句
 82         while(p->next != NULL)
 83         {
 84             if(p->next->vertex == b)    //去重邊,如果不要去重邊,去掉這一句
 85                 return;
 86             p = p->next;
 87         }
 88         p->next = q;
 89     }
 90 }
 91 void Insert2(int a, int b)   //頭插法,效率跟高,但不能去重邊
 92 {
 93     arcnode * q = new arcnode(b);
 94     if(Ver[a].firarc == NULL)
 95         Ver[a].firarc = q;
 96     else
 97     {
 98         arcnode * p = Ver[a].firarc;
 99         q->next = p;
100         Ver[a].firarc = q;
101     }
102 }
103 void Delete(int a, int b)   //刪除以a爲起點,b爲終點的邊
104 {
105     arcnode * p = Ver[a].firarc;
106     if(p->vertex == b)
107     {
108         Ver[a].firarc = p->next;
109         delete p;
110         return ;
111     }
112     while(p->next != NULL)
113         if(p->next->vertex == b)
114         {
115             p->next = p->next->next;
116             delete p->next;
117             return ;
118         }
119 }
120 
121 void Show()     //打印圖的鄰接表(有權值)
122 {
123     for(int i = 1; i <= n; i++)
124     {
125         cout << Ver[i].vex;
126         arcnode * p = Ver[i].firarc;
127         while(p != NULL)
128         {
129             cout << "->(" << p->vertex << "," << p->weight << ")";
130             p = p->next;
131         }
132         cout << "->NULL" << endl;
133     }
134 }
135 
136 void Show2()     //打印圖的鄰接表(無權值)
137 {
138     for(int i = 1; i <= n; i++)
139     {
140         cout << Ver[i].vex;
141         arcnode * p = Ver[i].firarc;
142         while(p != NULL)
143         {
144             cout << "->" << p->vertex;
145             p = p->next;
146         }
147         cout << "->NULL" << endl;
148     }
149 }
150 int main()
151 {
152     int a, b, w;
153     cout << "Enter n and m:";
154     cin >> n >> m;
155     Init();
156     while(m--)
157     {
158         cin >> a >> b >> w;       //輸入起點、終點
159         Insert(a, b, w);        //插入操作
160         Insert(b, a, w);        //如果是無向圖還需要反向插入
161     }
162     Show();
163     return 0;
164 }

複製代碼

 

  

  鄰接表表示法也有潛在的不足之處,即如果要確定圖中邊(u,v)是否存在,只能在頂點u鄰接表Adj[u]中搜索v,除此之外沒有其他更快的辦法。這一不足可通過圖的鄰接矩陣表示法來彌補,但要(在漸進意義下)以佔用更多的存儲空間爲代價。

  在圖G=(V,E)的臨界矩陣表示法中,假定各頂點按某種任意的方式編號爲1,2,···,|V|,那麼G的鄰接矩陣爲一個|V|*|V|的矩陣A=(a[i][j]),它滿足:

  觀察無向圖的鄰接矩陣會發現,它是沿主對角線對稱的。在一個無向圖中,(u,v)和(v,u)表示同一條邊,故無向圖的鄰接矩陣A的轉置矩陣就是它本真。在某些應用中,可以只存儲鄰接矩陣的對角線以及對角線以上的部分,這樣一來,圖所佔用的存儲空間幾乎可以減少一半。

  鄰接矩陣也可以用來表示加權圖。例如,如果G=<V,E>是一個加權圖,其權值函數爲w,對於邊(u,v)∈E,其權值w(u,v)就可以簡單地存儲在鄰接矩陣的第u行第v列的元素中。如果邊不存在,則可以在矩陣的相應元素中存一個NIL值,在很多問題中,對這樣的元素賦0或∞會更爲方便些。

鄰接矩陣C++實現:

複製代碼

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 
 5 #define maxn 100
 6 #define INF 1xffffff    //預定於的最大值
 7 int n, m;   //頂點數、邊數
 8 int g[maxn][maxn];      //鄰接矩陣表示
 9 
10 void Init()
11 {
12     for(int i = 1; i <= n; i++)
13         for(int j = 1; j <= n; j++)
14         g[i][j] = 0;    //講所有頂點度數置零,若爲帶權圖,則置爲INF
15 }
16 void Show() //打印鄰接矩陣
17 {
18     for(int i = 1; i <= n; i++)
19     {
20         for(int j = 1; j <= n; j++)
21             cout << g[i][j] << " ";
22         cout << endl;
23     }
24 }
25 int main()
26 {
27     int a, b;
28     cout << "Enter n and m:";
29     cin >> n >> m;
30     while(m--)
31     {
32         cin >> a >> b;  //輸入爲邊的始點、終點,若有權,還需輸入權w
33         g[a][b] = 1;    //a、b間存在邊,將g[a][b]置1,若有權,則將其置爲權值
34         g[b][a] = 1;    //對於無向圖,還要插入邊(b,a)
35     }
36     Show();
37     return 0;
38 }

複製代碼

(文章以及相關代碼參考算法導論編寫)

https://www.cnblogs.com/dzkang2011/p/graph_1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章