1. 圖
頂點:圖中的數據元素。V是頂點的有窮非空集合。
弧:<v,w>表示從v到w的一條弧,v為弧尾,w為弧頭。VR是兩個頂點關系的集合。
無向圖:若<v,w>∈VR,必有<w,v>∈VR,則此圖為無向圖。
有向圖:無上述關系的圖。
邊:(v,w)表示無向圖中頂點v和頂點w之間的一條邊。
完全無向圖和完全有向圖
n表示頂點數,e表示弧或邊的數,則對於無向圖,e的取值范圍為0~n(n-1)/2。對於有向圖,e的取值范圍為0~n(n-1)。完全無向圖:有n(n-1)/2條邊的無向圖。完全有向圖:有n(n-1)條弧的有向圖。
稀疏圖:弧或邊較少的圖。(e<nlogn)
稠密圖:弧或邊較多的圖。
權(Weight):與圖的邊和弧相關的數。權可以表示從一個頂點到另一個頂點的距離或耗費。
子圖:若圖G=(V,{E})和G’=(V’,{E’})存在關系:V’ÍV且E’ÍE,則稱G’為G的子圖。
鄰接,度,入度,出度:
對於無向圖G=(V,{E}),若邊(v,v’)∈E,則v和v’互為鄰接點,該邊依附於v和v’,或稱邊與兩點相關聯。頂點v的度TD(v)為和v相關聯的邊的數目。
對於有向圖G=(V,{A}),若弧<v,v’>∈A,則v鄰接到v’,v’鄰接自v,弧與兩點相關聯。以v為頭的弧的數目成為v的入度ID(v),以v為尾的弧的數目成為v的出度OD(v),頂點v的度為入度和出度之和。
弧或邊的數目e和度TD的關系:e=1/2 (TD(v1)+TD(v2)+…+TD(vn))
路徑(Path)、路徑長度、回路(Cycle):
對無向圖G=(V,E),若從頂點vi經過若干條邊能到達vj,稱頂點vi和vj是連通的,又稱頂點vi到vj有路徑。
對有向圖G=(V,A),從頂點vi到vj有有向路徑,指的是從頂點vi經過若干條有向邊(弧)能到達vj。
路徑上邊或弧的數目稱為該路徑的長度。
在一條路徑中,若沒有重復相同的頂點,該路徑稱為簡單路徑;第一個頂點和最后一個頂點相同的路徑稱為回路(環);在一個回路中,若除第一個與最后一個頂點外,其余頂點不重復出現的回路稱為簡單回路(簡單環)。
連通圖、圖的連通分量:
對無向圖G=(V,E),若"vi ,vj ÎV,vi和vj都是連通的,則稱圖G是連通圖,否則稱為非連通圖。若G是非連通圖,則極大的連通子圖稱為G的連通分量。
對有向圖G=(V,A),若"vi ,vj ÎV,都有以vi為起點, vj 為終點以及以vj為起點,vi為終點的有向路徑,稱圖G是強連通圖,否則稱為非強連通圖。若G是非強連通圖,則極大的強連通子圖稱為G的強連通分量。
“極大”的含義:指的是對子圖再增加圖G中的其它頂點,子圖就不再連通。
生成樹、生成森林:
一個連通圖(無向圖)的生成樹是一個極小連通子圖,它含有圖中全部n個頂點和只有足以構成一棵樹的n-1條邊,稱為圖的生成樹。
關於無向圖的生成樹的幾個結論:
a) 一棵有n個頂點的生成樹有且僅有n-1條邊;
b) 如果一個圖有n個頂點和小於n-1條邊,則是非連通圖;
c) 如果多於n-1條邊,則一定有環;
d) 有n-1條邊的圖不一定是生成樹。
有向圖的生成森林是這樣一個子圖,由若干棵有向樹組成,含有圖中全部頂點。有向樹是只有一個頂點的入度為0 ,其余頂點的入度均為1的有向圖。
網:每個邊(或弧)都附加一個權值的圖,稱為帶權圖。帶權的連通圖(包括弱連通的有向圖)稱為網或網絡。
2. 圖的存儲結構
2.1 數組表示法(鄰接矩陣表示法)
基本思想:對於有n個頂點的圖,用一維數組vexs[n]存儲頂點信息,用二維數組A[n][n]存儲頂點之間關系的信息。該二維數組稱為鄰接矩陣。在鄰接矩陣中,以頂點在vexs數組中的下標代表頂點,鄰接矩陣中的元素A[i][j]存放的是頂點i到頂點j之間關系的信息。
數組表示法容易確定兩個頂點之間是否有弧或邊,並容易求得各個頂點的度。
//圖的鄰接矩陣存儲表示 #define INFINITY INT_MAX //最大值∞ #define MAX_VERTEX_NUM 20 //頂點數 typedef enum{DG,DN,UDG,UDN} GraphKind; //{有向圖,有向網,無向圖,無向網} typedef struct ArcCell { VRType adj; //頂點關系類型。對無權圖,用1或0表示相鄰與否;對帶權圖,則為權值類型。 InfoType *info; //該弧相關信息的指針 }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct { VertexType vexs[MAX_VERTEX_NUM]; //頂點向量 AdjMatrix arcs; //鄰接矩陣 int vexnum,arcnum; //圖的當前頂點數和弧數 GraphKind kind; //圖的種類標志 }MGraph;
2.1.1 無向圖的數組表示
(1) 無權圖的鄰接矩陣
無向無權圖G=(V,E)有n(n≧1)個頂點,其鄰接矩陣是n階對稱方陣。其元素的定義如下:
(2) 帶權圖的鄰接矩陣
無向帶權圖G=(V,E)的鄰接矩陣元素的定義如下:
(3) 無向圖鄰接矩陣的特性
a) 鄰接矩陣是對稱方陣;
b) 對於頂點vi,其度數是第i行(或第i列)的非0元素的個數;
c) 無向圖的邊數是上(或下)三角形矩陣中非0元素個數。
2.1.2 有向圖的數組表示
(1) 無權圖的鄰接矩陣
若有向無權圖G=(V,E)有n(n≧1)個頂點,其鄰接矩陣元素定義如下:
(2) 帶權圖的鄰接矩陣
有向帶權圖G=(V,E)的鄰接矩陣元素的定義如下:
(3) 有向圖鄰接矩陣的特性
a) 對於頂點vi,第i行的非0元素的個數是其出度OD(vi);第i列的非0元素的個數是其入度ID(vi)。
b) 鄰接矩陣中非0元素的個數就是圖的弧的數目。
2.2 鄰接表
基本思想:對圖的每個頂點建立一個單鏈表,存儲該頂點所有鄰接頂點及其相關信息。每一個單鏈表設一個表頭結點。第i個單鏈表表示依附於頂點Vi的邊(對有向圖是以頂點Vi為頭或尾的弧)。
2.2.1 結點結構
鏈表中的結點稱為表結點,每個結點由三個域組成,如圖所示。其中鄰接點域(adjvex)指示與頂點Vi鄰接的頂點在圖中的位置(頂點編號),鏈域(nextarc)指向下一個與頂點Vi鄰接的表結點,數據域(info)存儲和邊或弧相關的信息,如權值等。對於無權圖,如果沒有與邊相關的其他信息,可省略此域。
每個鏈表設一個表頭結點(稱為頂點結點),由兩個域組成,如圖所示。鏈域(firstarc)指向鏈表中的第一個結點,數據域(data)存儲頂點名或其他信息。
adjvex |
nextarc |
info |
|
data |
firstarc |
表節點 |
|
頂點節點 |
在圖的鄰接表中,所有頂點結點用一個向量以順序結構形式存儲,可以隨機訪問任意頂點的鏈表,該向量稱為表頭向量,向量的下標指示頂點的序號。
//圖的鄰接表存儲表示 #define MAX_VERTEX_NUM 20 typedef struct ArcNode { int adjvex; //該弧所指向的頂點的位置 struct ArcNode *nextarc; //指向下一條弧 InfoType *info; //該弧相關信息的指針 }ArcNode; typedef struct VNode { VertexType data; //頂點信息 ArcNode *firstarc; //指向依附該頂點的第一條弧 }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct { AdjList vertices; int vexnum,arcnum; //圖的當前頂點數和弧數 int kind; //圖的種類標志 }ALGraph;
2.2.2 示例
用鄰接表存儲圖時,對無向圖,其鄰接表是唯一的,對有向圖,其鄰接表有兩種形式,如圖所示。
2.2.3 鄰接表法的特點
a) 表頭向量中每個分量就是一個單鏈表的頭結點,分量個數就是圖中的頂點數目;
b) 在邊或弧稀疏的條件下,用鄰接表表示比用鄰接矩陣表示節省存儲空間;
c) 在無向圖,頂點Vi的度是第i個鏈表的結點數;
d) 若無向圖中有n個頂點、e條邊,則它的鄰接表需n個頭結點和2e個表結點。
e) 對有向圖可以建立正鄰接表或逆鄰接表。正鄰接表是以頂點Vi為弧尾而建立的鄰接表;逆鄰接表是以頂點Vi為弧頭而建立的鄰接表;
f) 在有向圖的正鄰接表中,第i個鏈表中的結點數是頂點Vi的出度,求入度須遍歷整個鄰接表;在有向圖的逆鄰接表中,第i個鏈表中的結點數是頂點Vi的入度,求出度須遍歷整個鄰接表;
g) 在鄰接表上容易找出任一頂點的第一個鄰接點和下一個鄰接點;
2.3 十字鏈表
有向圖的另外一種鏈式存儲結構。可以看成是將有向圖的正鄰接表和逆鄰接表結合起來得到的一種鏈表。在十字鏈表中,對應於有向圖中每一條弧有一個結點,對應於每個頂點也有一個結點。
2.3.1 結點結構
tailvex |
headvex |
hlink |
tlink |
info |
|
data |
firstin |
firstout |
弧結點 |
|
頂點結點 |
弧結點:
尾域tailvex:指示弧尾頂點在圖中的位置;
頭域headvex:指示弧頭頂點在圖中的位置;
指針域hlink:指向弧頭相同的下一條弧;
指針域tlink:指向弧尾相同的下一條弧;
Info域:指向該弧的相關信息。
弧頭相同的弧在同一鏈表上,弧尾相同的弧在同一鏈表上。它們的頭結點即為頂點結點。
頂點結點:(同鄰接表,頂點結點為順序存儲結構)
data域:存儲和頂點相關的信息;
指針域firstin:指向以該頂點為弧頭的第一條弧結點;
指針域firstout:指向以該頂點為弧尾的第一條弧結點。
//有向圖的十字鏈表存儲表示 #define MAX_VERTEX_NUM 20 typedef struct ArcBox { int tailvex,headvex; //弧尾和弧頭頂點的位置 struct ArcBox *hlink,*tlink; //分別指向弧頭和弧尾相同的弧 InfoType *info; //該弧相關信息的指針 }ArcBox; typedef struct VexNode { VertexType data; //頂點信息 ArcBox *firstin,*firstout; //分別指向該頂點第一條入弧和出弧 }VexNode; typedef struct { VexNode xlist[MAX_VERTEX_NUM]; //表頭向量 int vexnum,arcnum; //有向圖的當前頂點數和弧數 }OLGraph;
2.3.2 示例
從這種存儲結構圖可以看出,從一個頂點結點的firstout出發,沿表結點的tlink指針構成了正鄰接表的鏈表結構,而從一個頂點結點的firstin出發,沿表結點的hlink指針構成了逆鄰接表的鏈表結構。
在十字鏈表中既容易求得以vi為尾的弧,也容易找到以vi為頭的弧。因而容易求得頂點的出度和入度。
2.4 鄰接多重表
鄰接多重表(Adjacency Multilist)是無向圖的另一種鏈式存儲結構。
鄰接表是無向圖的一種有效的存儲結構,在無向圖的鄰接表中,一條邊(v,w)的兩個表結點分別出現在以v和w為頭結點的鏈表中,很容易求得頂點和邊的信息,但在涉及到邊的操作會帶來不便。
鄰接多重表的結構和十字鏈表類似,每條邊用一個結點表示;每個頂點用一個結點表示。
2.4.1 結點結構
mark |
ivex |
ilink |
jvex |
jlink |
info |
|
data |
firstedge |
邊結點 |
|
頂點結點 |
邊結點:
標志域mark:用以標識該條邊是否被訪問過;
ivex和jvex域:該邊所依附的兩個頂點在圖中的位置;
指針域ilink:指向下一條依附於頂點ivex的邊;
指針域jlink:指向下一條依附於頂點jvex的邊;
info域:保存該邊的相關信息。
頂點節點:
Data域:存儲和頂點相關的信息;
指針域firstedge:指向依附於該頂點的第一條邊。
//無向圖的鄰接多重表存儲表示 #define MAX_VERTEX_NUM 20 typedef enum {unvisited,visited} VisitIf; typedef struct EBox { VisitIf mark; //訪問標記 int ivex,jvex; //該邊依附的兩個頂點的位置 struct EBox *ilink,*jlink; //分別指向依附這兩個頂點的下一條邊 InfoType *info; //該邊相關信息的指針 } typedef struct VexBox { VertexType data; EBox *firstedge; //指向第一條依附該頂點的邊 }VexBox; typedef struct { VexBox adjmulist[MAX_VERTEX_NUM]; int vexnum,edgenum; //無向圖的當前頂點數和邊數 }AMLGraph;
2.4.2 示例
在鄰接多重表中,所有依附於同一頂點的邊串聯在同一鏈表中,由於每條邊依附於兩個頂點,則每個邊結點同時鏈接在兩個鏈表中。
鄰接多重表與鄰接表的區別:后者的同一條邊用兩個表結點表示,而前者只用一個表結點表示;除標志域外,鄰接多重表與鄰接表表達的信息是相同的,因此,操作的實現也基本相似。