1. 程式人生 > >資料結構與演算法17-圖的十字連結串列

資料結構與演算法17-圖的十字連結串列

對於有向圖來說,鄰接表是有缺陷的,關心了出度問題,想了解入度就必須要遍歷整個圖才能知道,反之,逆鄰接表解決了入度的情況。

把鄰接表與逆鄰接表結合起來,即有向圖的一種儲存方法十字連結串列(Orthogonal   List)。

我們重新定義頂點表結構

firstin表示入邊表頭指標,指向該頂點的入邊表中第一個結點;

firstout表示出邊表頭指標,指向該頂點的出邊表中第一個結點;

重新定義了邊表結點結構

其中

tailvex是指弧起點在頂點的下標,

headvex是指弧終點在頂點表中的下標,

headlink是指入邊表指標域,指向終點相同的一下條邊

taillink是指出邊表指標域,指向起點相同的下一條邊。

如果是網,還可以再增加一個weight域來儲存權值。

 

如圖

頂點依然是存入一個一維陣列{v0,v1,v2,v3},實線箭頭指標的圖示完全與前面提到的鄰接表相同。就以頂點v0來說,firstout指向的是出邊表中的第一個結點v3。所以v0邊表結點的headvex=3,而tailvex其實就是當前頂點v0的下標0,由於v0只有一個出邊頂點,所以headlink和taillink都是空的。

我們重點需要來解釋虛線箭頭的含義,它其實就是此圖的逆鄰接表的表示。對於v0來說,它有兩個頂點v1和v2的入邊。因此v0的firstin指向頂點v1的邊表結點中headvex為0的結點①。接著由入邊結點的headlink指向下一個入邊頂點v2,如圖②

對於頂點v1,它有一個入邊頂點v2,所以它的firstin指向頂點v2的邊表結點中headvex為1的結點,如圖中的③。

firstin 指向headvex相同的,用的是headlink

firstout指向tailvex相同的,用的是taillink

十字連結串列的好處就是因為把鄰接表和逆鄰接表整合在一起,這樣既容易找到vi為尾的弧,也容易打到以vi為頭的弧,因而容易求得頂點的出度和入度。而且它除了結構複雜一點燃上,其實建立圖的演算法的時間複雜度與鄰接表相同,因此,在有向圖的應用中,十字連結串列是非常好的資料結構模型。

鄰接多重表

對於無向圖的邊操作,如下圖要刪除(v0,v2)這條邊要做

需要對鄰接表結構中右邊表的陰影兩個結點進行刪除操作,顯然比較煩瑣

因此,我們也仿照十字連結串列的方式對邊表結構進行一些改造,也許就可避免剛才的問題。

重新定義邊表結構:

其中ivex和jvex是與某條邊依附的兩個頂點在頂點表中的下標。ilink指向依附頂點ivex的下條邊,jlink指向依附頂點的下一條邊。這就是鄰接多重表結構

我們來看結構示意圖的繪製過程,理解了它是如何連線的,也就是理解鄰接多重表構造原理了。如下圖,左圖告訴我們它有4個頂點和5條邊,顯然我們就應該先將4個頂點和5條邊的邊表結點畫出來。由是無向圖,所以ivex是0、jvex是1還是反過來都是無所謂的,不過為了繪圖方便,都將ivex值設定得與一旁的頂點下標相同

首先連線①②③④就是將頂點的firstedge指向一條邊,頂點下標要與ivex的值相同,這很好理解,接著,由於頂點v0的(v0,v1)的鄰邊有(v0,v3)和(v0,v2)。因此⑤⑥的連線就是滿足指向下一條依附於頂點v0的邊的目標,注意ilink指向的結點的jvex一定要和它本身的ivex值相同。同樣道理

連線⑦就是指(v1,v0)這條邊,它是相當於頂點v1指向(v1,v2)邊後的下一條。v2有三條邊依附,所以在v3之後就有⑧⑨。連線⑩的就是頂點v3在連線④之後的下條邊。

鄰接多重表與鄰接表的差別,僅僅是在於同一條邊在鄰接表中用兩個結點表示,而在鄰接多重表中只有一個結點。這樣對邊的操作就方便多了,若要刪除左圖的(v0,v2)這條邊,只要右圖的⑥⑨的連結指向改為^即可。

邊集陣列

邊集陣列是由兩個一維陣列構成。一個是儲存頂點的資訊;另一個是儲存邊資訊,這個邊陣列每個資料元素由一條邊的起點下標(begin)、終點下標(end)和權(weight)組成。

在邊集陣列中要查詢一個頂點的度需要掃描整個陣列,效率並不高。因此它更適合對邊依次時行處理的操作,而不適合對頂點相關的操作。回會學習一種克魯斯卡爾演算法。

 

資料結構如下