數據結構之圖(1)【鄰接矩陣、鄰接表】


鄰接矩陣創建無向網:

圖的鄰接矩陣(Adjacency Matrix)存儲方式是用兩個數組來表示圖。一個一維的數組存儲圖中頂點信息,一個二維數組(稱為鄰接矩陣)存儲圖中的邊或弧的信息。

設圖G有n個頂點,則鄰接矩陣是一個n*n的方陣,定義為:

我們來看一個實例,圖7-4-2的左圖就是一個無向圖。

我們再來看一個有向圖樣例,如圖7-4-3所示的左圖。

圖的術語中,我們提到了網的概念,也就是每條邊上都帶有權的圖叫做網。那些這些權值就需要保存下來。

設圖G是網圖,有n個頂點,則鄰接矩陣是一個n*n的方陣,定義為:

如圖7-4-4左圖就是一個有向網圖。

下面示例無向網圖的創建代碼:

 1 #include "stdafx.h"
 2 #include<iostream>
 3 #define MaxInt 10000                   //表示權值的無窮
 4 #define MVNum 100                      //最大頂點數,應由用戶定義
 5 typedef char VerTexType;               //假設頂點數據類型為字符型
 6 typedef int ArcType;                   //假設邊的權值類型為整形
 7 using namespace std;
 8 typedef struct
 9 {
10     VerTexType vexs[MVNum];            //頂點表
11     ArcType arcs[MVNum][MVNum];        //鄰接矩陣
12     int vexnum, arcnum;                //圖的當前點數和邊數
13 }AMGraph;
14 
15 void CreateUDN(AMGraph &G)             //采用鄰接矩陣表示法,創建無向網&G
16 {
17     int i, j, w;
18     cout << "請輸入總頂點數、總邊數(空格隔開):" << endl;
19     cin >> G.vexnum >> G.arcnum;       //輸入總頂點數、總邊數
20     cout << "請輸入頂點信息(空格隔開):" << endl;
21     for (i = 0; i < G.vexnum; i++)     //依次輸入點的信息
22     {
23         cin >> G.vexs[i];
24     }
25     for (i = 0; i < G.vexnum; i++)     //初始化鄰接矩陣,編的權值均為極大值MaxInt
26         for (j = 0; j < G.vexnum; j++)
27             G.arcs[i][j] = MaxInt;
28 
29     for (int k = 0; k < G.arcnum; k++) //構造鄰接矩陣
30     {
31         cout << "請輸入第" << k + 1 << "條邊的信息(輸入順序:連接點1編號,連接點2編號,邊的權值):" << endl;
32         cin >> i >> j >> w;            //輸入一條邊依附的頂點及權值
33         G.arcs[i - 1][j - 1] = w;      
34         G.arcs[j - 1][i - 1] = G.arcs[i - 1][j - 1];
35     }
36 }
37 
38 void coutAMGraph(AMGraph &G)           //無向網的輸出
39 {
40     int i, j;
41     cout << "該圖的鄰接矩陣為:" << endl;
42     cout << "\t";
43     for (i = 0; i < G.vexnum; i++)
44         cout << G.vexs[i] << "\t";
45     cout << endl;
46     for (i = 0; i < G.vexnum; i++)
47     {
48         cout << G.vexs[i] << "\t";
49         for (j = 0; j < G.vexnum; j++)
50         {
51             cout << G.arcs[i][j] << "\t";
52         }
53         cout << endl;
54     }
55 }
56 int main()
57 {
58     AMGraph MG;
59     CreateUDN(MG);
60     coutAMGraph(MG);
61     return 0;
62 }

輸出結果:

鄰接表創建無向網:

鄰接表(Adjacency List) 是圖的一種鏈式存儲結構,在鄰接表中,對圖中每個頂點建立一個單鏈表,第i個單鏈表中的節點表示依附於頂點Vi的邊(對有向圖是以頂點Vi為尾的弧)。每個節點由3個域組成,其中鄰接點域(adjvex)指示與頂點vi鄰接的點在圖中的位置,鏈域(nextarc)指示下一條邊或弧的節點;數據域(info)存儲和邊或弧相關的信息,如權值等。每個鏈表上附設一個表頭節點。在表頭節點中,除了設有鏈域(firstarc)指向鏈表中的第一個節點之外,還設有存儲頂點Vi的名或者其他有關信息的數據域(data)。
如圖:
頭節點(存儲頂點信息)
表(邊)節點(存儲兩個頂點之間邊的信息)
這些表頭節點(可以鏈相接)通常以順序結構的形式存儲,以便隨機訪問任一個頂點的鏈表。
 
上面這一段是嚴蔚敏版數據結構那本書中對用鄰接表法構建圖的介紹,說的過於理論化,我第一次看的時候也是不知所雲,但是仔細閱讀,並且閱讀了書中的偽代碼,便明白了作者的意思。現在做出簡要總結:
在構建圖時,需要兩個結構體,一個存儲圖中節點的信息,便是上面介紹的頭節點,一個是兩個節點之間邊的信息,便是上面的表(邊)節點。 采用一個一維數組存儲頭結點信息,然后為每個頭結點建立一個鏈表,讓頭結點作為這個鏈表的表頭節點(具體實現方法便是讓頭結點內的指針firstarc 指向鏈表的首地址),鏈表中存儲的正是和這個頭結點相關聯的表節點(邊的信息),這些邊都是尾部和頭結點相連。表節點中的adjvex存儲的是與這條邊關聯的另一個頭結點在數組中的索引(邊的箭頭所關聯的頭節點),表節點中的nextarc則是存儲的該鏈表表頭相關聯的另一條邊的信息。
下圖是上圖的鄰接表:
圖2
以第一行為例:V1是圖中的頭結點,V1后面的鏈表是所有與V1相連的邊
此處需要普及一個概念:我們平時口語所說的邊,例如上面的圖1中V1 指向 V2的那條邊,在圖論里面成為“弧”,對於弧來說V1叫“弧尾”,V2是該弧的“弧頭”。(雖然不知道名字的來源故事,但是至少人家是專業術語,說出去,讓人一聽,感覺好高大上的樣子,裝逼必備利器)。
下面是代碼:
 1 #include "stdafx.h"
 2 #include<iostream>
 3 #include<string>
 4 using namespace std;
 5 #define MVNum 100                      //最大頂點值
 6 #define ERROR 1 
 7 typedef char VerTexType;
 8 typedef struct ArcNode                 //邊結點
 9 {
10     int adjvex;                        //改變所指向的頂點的位置
11     struct ArcNode *nextarc;           //指向下一條邊的指針
12     string info;                       //和邊相關的信息
13 }ArcNode;
14 typedef struct VNode                   //頂點信息
15 {                 
16     VerTexType data;                   
17     ArcNode *firstarc;                 //指向第一條依附該頂點的邊的指針
18 }VNode, AdjList[MVNum];                //AdList表示鄰接表類型
19 typedef struct                         //鄰接表
20 {
21     AdjList vertices; 
22     int vexnum, arcnum;                //圖的當前頂點數和邊數
23 }ALGraph;
24 
25 int LocateVex(ALGraph &G, char &v1)    //定位函數   
26 {
27     int i;
28     for (i = 0; i < G.vexnum; i++)
29     {
30         if (G.vertices[i].data == v1)
31             return i;
32     }
33     if (i >= G.vexnum)
34         return ERROR;
35     else
36         return 0;
37 }
38 void CreateUDG(ALGraph &G)             //創建無向圖
39 {
40     ArcNode *p1, *p2;
41     int i, j, k;
42     char v1, v2;
43     cout << "請輸入圖的頂點數、弧數:" << endl;
44     cin >> G.vexnum >> G.arcnum;       //輸入總頂點數,總邊數
45     cout << "請輸入頂點:" << endl; 
46     for (i = 0; i < G.vexnum; i++)
47     {
48         cin >> G.vertices[i].data;     //輸入頂點值
49         G.vertices[i].firstarc = NULL; //初始化表頭結點的指針域為NULL
50     }
51     for (k = 0; k < G.arcnum; k++)     
52     {
53         cout << "請輸入弧尾和弧頭:";
54         cin >> v1 >> v2;               //輸入各邊,構造鄰接表
55         i = LocateVex(G, v1);
56         j = LocateVex(G, v2);
57         p1 = new ArcNode;              //生成一個新結點*p1
58         p1->adjvex = j;                //鄰接點序號為j
59         p1->nextarc = G.vertices[i].firstarc;
60         G.vertices[i].firstarc = p1;
61         p2 = new ArcNode;
62         p2->adjvex = i;
63         p2->nextarc = G.vertices[j].firstarc;
64         G.vertices[j].firstarc = p2;
65     }
66     cout << "圖構建成功!" << endl;
67 }
68 
69 void coutUDG(ALGraph G)                //輸出函數
70 {
71     int i, j;
72     cout << "輸出為:" << endl;
73     for (i = 0; i<G.vexnum; i++)
74     {
75         cout << i;
76         ArcNode *p;
77         p = G.vertices[i].firstarc;
78         while (p != NULL)
79         {
80             cout << "-> " << p->adjvex;
81             p = p->nextarc;
82         }
83         cout << endl;
84     }
85 }
86 int main()
87 {
88     ALGraph MG;
89     CreateUDG(MG);
90     coutUDG(MG);
91     return 0;
92 }

 

輸出結果:

 

今天就先到這里啦,下一篇再寫十字鏈表和鄰接多重表哈!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM