圖的基本概念http://hi.baidu.com/%C8%ED%BC%FE%B8%D6%C7%D9%CA%A6/blog/item/f7b50c07791b8ec57a8947ec.html 圖,無向圖G = (V, E)有向圖 G = <V, E> V是點集vertex, E是邊集edge 圖通常有兩種儲存方法。
- 鄰接矩陣, 多用於稠密圖,記錄每兩個頂點之間邊的資訊。空間複雜度是O(|V|2);通常實際問題稠密圖情況很少。
- 鄰接表, 是表示圖的標準方法,尤其對於稀疏圖節省很多儲存空間,空間複雜度是O(|E|+|V|). 對於每個頂點,使用一個表存放所有鄰接的頂點。
鄰接矩陣容易理解就不介紹了,鄰接表實現方法: (1)使用vector或list (2)使用map,將key設為頂點,值設為鄰接表。 (3)使用Vertex類,頂點即為Vertex的執行個體,將鄰接表作為Vertex的成員函數。 下面一步一步介紹如何用代碼實現鄰接表結構來儲存圖,主要體會為什麼需要這些資訊。 首先,從鄰接表的定義中直觀的看出需要有頂點資訊,對於每個頂點一定儲存了資料資訊,鄰接頂點資訊。而對於鄰接頂點結構,一定儲存了next鄰接頂點資訊。即:struct adjVertexNode
{
adjVertexNode* next;
}
struct VertexNode
{
char* data;//以結點儲存的資訊為字元為例。
adjVertexNode* list; //鄰接點鏈表。
}
一個圖結構便可以由結點數組組成。考慮到數組不能用變數聲明大小。所以預先給定一個足夠大的數組。當然也可以用vector,List實現,那是後話了。同時圖必須要包含頂點數量資訊。#define MAX_VERTEX_NUM 20
struct Graph
{
VertexNode VertexNode[MAX_VERTEX_NUM];
int vertexNum;
}
以上,是我們嘗試構建一個圖的儲存結構必須,也是一定應該會想到的資訊。 接下來,對於adjVertexNode結構體, 由於它明顯是個鏈表,很容易會考慮裡面是不是應該有資料資訊呢?否則只有一個鏈沒有意義。 於是很容易想到寫成存鄰接頂點資料資訊:struct adjVertexNode
{
char* data;
adjVertexNode* next;
}
而恰恰這是最容易出現的錯誤寫法!!!事實上這個資料資訊已在頂點VertexNode結構體中體現了,完全沒有必要這樣重複寫出來。 回過頭仔細看一下定義:對於每個頂點,使用一個表存放所有鄰接的頂點。也就是說,存放的資料一定是標識鄰接頂點的資訊。但又不能重複存放定點資料資訊。 因為一個圖鄰接表標記法需要一個儲存頂點的數組,所以這裡應該存放頂點位置資訊,也就是每個頂點在頂點數組中的位置資訊。即:struct adjVertexNode
{
int adjVertexPosition;
adjVertexNode* next;
} 務必要理解這一點,如果還是有點暈,那先記住他,到後面實現拓撲排序時,會看到為什麼要儲存位置資訊。 另外,對於拓撲排序,起始點是從一個入度為0的頂點開始,所以入度資訊必須包含在頂點結構體中。於是:struct VertexNode
{
char* data;//以結點儲存的資訊為字元為例。
adjVertexNode* list; //鄰接點鏈表。
int indegree;
} 至此,得到了一組圖需要的較為完整的結構體資訊,至少完成拓撲排序所需要的資訊足夠了。#define MAX_VERTEX_NUM 20
struct adjVertexNode
{
int adjVertexPosition;
adjVertexNode* next;
}
struct VertexNode
{
char* data;//以結點儲存的資訊為字元為例。
adjVertexNode* list; //鄰接點鏈表。
int indegree;
}
struct Graph
{
VertexNode VertexNode[MAX_VERTEX_NUM];
int vertexNum;
}
還有一些其他資訊,比如邊上的權值(可以儲存在adjVertexNode中),圖的邊數,類型(可以儲存在Graph中),這裡沒有添加,主要是避免混淆。當真正理解每個元素資訊為什麼需要時再做擴充。在下一篇拓撲排序的實現中,能看到如何應用上面的結構體實際儲存一個圖。