【1】圖的基本概念
(1)圖是由頂點集合以及頂點間的關系集合組成的一種數據結構。
Graph = (V,E) V是頂點的又窮非空集合;E是頂點之間關系的有窮集合,也叫邊集合。
(2)有向圖:頂點對<x,y>是有序的;無向圖:頂點對<x,y>是無序的。
(3)無向邊:若頂點Vi到Vj之間的邊沒有方向,則稱這條邊為無向邊,用無序偶對(Vi,Vj)來表示。
如果圖中任意兩個頂點時間的邊都是無向邊,則稱該圖為無向圖:
由於是無向圖,所以連接頂點A與D的邊,可以表示為無序對(A,D),也可以寫成(D,A)
對於如上無向圖來說,G=(V,{E}) 其中頂點集合V={A,B,C,D};邊集合E={(A,B),(B,C),(C,D),(D,A),(A,C)}
有向邊:若從頂點Vi到Vj的邊有方向,則稱這條邊為有向邊,也稱為弧。
用有序偶<Vi,Vj>來表示,Vi稱為弧尾,Vj稱為弧頭。
如果圖中任意兩個頂點之間的邊都是有向邊,則稱該圖為有向圖:
連接頂點A到D的有向邊就是弧,A是弧尾,D是弧頭,<A,D>表示弧。注意不能寫成<D,A>。
對於如上有向圖來說,G=(V,{E})其中頂點集合V={A,B,C,D};弧集合E={<A,D>,<B,A>,<C,A>,<B,C>}
(4)完全無向圖:若有n個頂點的無向圖有n(n-1)/2 條邊, 則此圖為完全無向圖。
完全有向圖:有n個頂點的有向圖有n(n-1)條邊, 則此圖為完全有向圖。
(5)樹中根節點到任意節點的路徑是唯一的,但是圖中頂點與頂點之間的路徑卻不是唯一的。
路徑的長度是路徑上的邊或弧的數目。
(6)如果對於圖中任意兩個頂點都是連通的,則成G是連通圖。
(7)圖按照邊或弧的多少分稀疏圖和稠密圖。 如果任意兩個頂點之間都存在邊叫完全圖,有向的叫有向圖。
若無重復的邊或頂點到自身的邊則叫簡單圖。
(8)圖中頂點之間有鄰接點。無向圖頂點的邊數叫做度。有向圖頂點分為入度和出度。
(9)圖上的邊和弧上帶權則稱為網。
(10)有向的連通圖稱為強連通圖。
【2】圖的存儲結構
關於圖的存儲結構,可以分為以下五種:
(1) 鄰接矩陣
圖的鄰接矩陣存儲方式是用兩個數組來表示圖:
一個一維數組存儲圖中頂點信息;
一個二維數組(稱為鄰接矩陣)存儲圖中邊或弧的信息
(2) 鄰接表
鄰接矩陣是一種不錯的圖存儲結構。 但是:對於邊樹相對頂點較少的圖,這種結構是存在存儲空間的極大浪費的。
因此我們考慮先進一步,使用鄰接表存儲,關於鄰接表的處理辦法是這樣:
下圖是一個無向圖的鄰接表結構:
對於有向圖而言,為了更便於確定頂點的入度(或以頂點為弧頭的弧)。
我們可以建立一個有向圖的逆鄰接表。如下圖所示:
而對於有權值的網圖,可以在邊表節點定義中再增加一個weight的數據域,存儲權值信息即可。 如下圖所示:
那么,有了這些結構的圖,下面定義代碼如下:
(3) 十字鏈表
對於有向圖而言,鄰接表也是有缺陷的。
試想想哈,關心了出度問題,想了解入度問題就必須把整個圖遍歷才能知道。
反之,逆鄰接表解決了入度問題卻不了解出度的情況。
那是否可以將鄰接表和逆鄰接表結合起來呢?答案是肯定的。
這就是所謂的存儲結構:十字鏈表。其詳解如下圖:
(4) 鄰接多重表
有向圖的優化存儲結構為十字鏈表。
對於無向圖的鄰接表,有沒有問題呢?如果我們要刪除無向圖中的某一條邊時?
那也就意味着必須找到這條邊的兩個邊節點並進行操作。其實還是比較麻煩的。比如下圖:
欲刪除上圖中的(V0,V2)這條邊,需要對鄰接表結構中右邊表的陰影兩個節點進行刪除。
仿照十字鏈表的方式,對邊表節點的結構進行改造如下:
(5)邊集數組
邊集數組側重於對邊依次進行處理的操作,而不適合對頂點相關的操作。
關於邊集數組詳解如下:
【3】圖的遍歷
圖的遍歷圖和樹的遍歷類似,那就是從圖中某一頂點出發訪遍圖中其余頂點,且使每一個頂點僅被訪問一次,這個過程就叫做圖的遍歷。
對於圖的遍歷來說,如何避免因回路陷入死循環,就需要科學地設計遍歷方案,通過有兩種遍歷次序方案:深度優先遍歷和廣度優先遍歷。
(1) 深度優先遍歷
深度優先遍歷(Depth_First_Search),也稱為深度優先搜索,簡稱DFS。
為了更好的理解深度優先遍歷。請看下面的圖解:
其實根據遍歷過程轉換為右圖后,可以看到其實相當於一棵樹的前序遍歷。
(2)廣度優先遍歷
廣度優先遍歷(Breadth_First_Search),又稱為廣度優先搜索,簡稱BFS。
深度遍歷類似樹的前序遍歷,廣度優先遍歷類似於樹的層序遍歷。
【5】圖的鄰接矩陣和鄰接表實現
Good Good Study, Day Day Up.
順序 選擇 循環 總結