C 資料結構與演算法揭秘13

2021-09-08 16:31:06 字數 3518 閱讀 9233

這節,我們來看看一下什麼了,來看看圖的遍歷吧!

首先,搞清楚,圖的遍歷的基本的含義了。

圖的遍歷是指從圖中的某個頂點出發,按照某種順序訪問圖中的每個頂點,使每個頂點被訪問一次且僅一次。圖的遍歷與樹的遍歷操作功能相似。圖的遍歷是圖的一種基本操作,並且圖的許多其他操作都是建立在遍歷操作的基礎之上的。遍歷示意圖,如圖所示:

然而,圖的遍歷要比樹的遍歷複雜得多。這是因為圖中的頂點之間是多對多的關係,圖中的任何乙個頂點都可能和其它的頂點相鄰接。所以,在訪問了某個頂點之後, 從該頂點出發, 可能沿著某條路徑遍歷之後, 又回到該頂點上。 例如,在下圖中,由於圖中存在迴路,因此在訪問了 a、b、c、d、e之後,沿著邊為圖中頂點的數目。陣列中元素的初始值全為 0,表示頂點都沒有被訪問過,如果頂點vi 被訪問,visited[i-1]為 1。

圖的遍歷有深度優先遍歷和廣度優先遍歷兩種方式,它們對圖和網都適用。 

首先,介紹了一些優先遍歷。

圖的深度優先遍歷(depth_first search)類似於樹的先序遍歷,是樹的先序遍歷的推廣。

我們先回顧一下樹的先序遍歷,如圖所示:

他先序遍歷結果是abdefcfg。

那圖的圖的深度優先遍歷,究竟是那樣的。

假設初始狀態是圖中所有頂點未曾被訪問過, 則深度優先遍歷可從圖中某個頂點v出發,訪問此頂點,然後依次從v的未被訪問的鄰接頂點出發深度優先遍歷圖,直至圖中所有和v路徑相通的頂點都被遍歷過。若此時圖中尚有未被訪問的頂點,則另選圖中乙個未被訪問的頂點作為起始點,重複上述過程,直到圖中所有頂點都被訪問到為止。

下圖(a)所示的無向圖的深度優先遍歷的過程如下圖(b)所示。假設從頂點 v1出發,在訪問了頂點 v1之後,選擇鄰接頂點 v2,因為 v2未被訪問過,所以從 v2出發進行深度優先遍歷。依次類推,接著從 v4、v8、v5出發進行深度優先遍歷。當訪問了 v5之後,由於 v5的鄰接頂點 v2和 v8都已被訪問,所以遍歷退回到 v8。由於同樣的理由,遍歷繼續退回到 v4、v2 直到 v1。由於 v1 的另乙個鄰接頂點 v3未被訪問,所以又從 v3開始進行深度優先遍歷,這樣得到該圖的深度優先遍歷的頂點序列v1→v2→v4→v8→v5→v3→v6→v7。

顯然,這是乙個遞迴的過程。下面以無向圖的鄰接表儲存結構為例來實現圖的深度優先遍歷演算法。在類中增設了乙個整型陣列的成員欄位visited,它的初始值全為 0, 表示圖中所有的頂點都沒有被訪問過。 如果頂點vi被訪問, visited[i-1]為1。並且,把該演算法作為無向圖的鄰接錶類 graphadjlist的成員方法。

由於增設了成員字段 visited,所以在類的構造器中新增以下**。

public graphadjlist(node nodes)

//以下為新增的**

//所有的結點,都沒有訪問過。 都賦值為0

visited = new int[adjlist.length];

for (int i = 0; i < visited.length; ++i) }

由於,他是迴圈遍歷,他的時間的複雜度是o(n).

無向圖的深度優先遍歷演算法的實現如下:   

public void dfs() }

}//從某個頂點出發進行深度優先遍歷

public void dfsal(int i)

p = p.next;

} }

分析上面的演算法,在遍歷圖時,對圖中每個頂點至多呼叫一次dfs方法,因為一旦某個頂點被標記成已被訪問,就不再從它出發進行遍歷。因此,遍歷圖的過程實質上是對每個頂點查詢其鄰接頂點的過程。 其時間複雜度取決於所採用的儲存結構。當圖採用鄰接矩陣作為儲存結構時,查詢每個頂點的鄰接頂點的時間複雜度為o(n2),其中,n為圖的頂點數。而以鄰接表作為圖的儲存結構時,查詢鄰接頂點的時間複雜度為o(e),其中,e為圖中邊或弧的數目。因此,當以鄰接表作為儲存結構時,深度優先遍歷圖的時間複雜度為o(n+e)。具體情況,如圖所示:

下面介紹廣度遍歷。

圖的廣度優先遍歷(breadth_first search)類似於樹的層序遍歷。 我們回顧一下樹的層次遍歷,如圖所示:

樹的層次遍歷結果為abcdefg。

那圖的光序遍歷為

假設從圖中的某個頂點 v 出發,訪問了 v 之後,依次訪問 v 的各個未曾訪問的鄰接頂點。然後分別從這些鄰接頂點出發依次訪問它們的鄰接頂點,並使「先被訪問的頂點的鄰接頂點」先於「後被訪問的頂點的鄰接頂點」被訪問,直至圖中所有已被訪問的頂點的鄰接頂點都被訪問。若此時圖中尚有頂點未被訪問,則另選圖中未被訪問的頂點作為起點,重複上述過程,直到圖中所有的頂點都被訪問為止。換句話說,廣度優先遍歷圖的過程是以某個頂點 v 作為起始點,由近至遠,依次訪問和 v 有路徑相通且路徑長度為 1,2,…的頂點。

圖(a)所示的無向圖的廣度優先遍歷的過程如圖(b)所示。假設從頂點 v1開始進行廣度優先遍歷,首先訪問頂點 v1和它的鄰接頂點 v2和 v3,然後依次訪問 v2 的鄰接頂點 v4 和 v5,以及 v3 的鄰接頂點 v6 和 v7,最後訪問 v4b的鄰接頂點 v8。由於這些頂點的鄰接頂點都已被訪問,並且圖中所有頂點都已被訪問,由此完成了圖的遍歷,得到的頂點訪問序列為:v1→v2→v3→v4→v5→v6→v7→v8,其遍歷過程如下圖(b)所示。

和深度優先遍歷類似,在廣度優先遍歷中也需要乙個訪問標記陣列,我們採用與深度優先遍歷同樣的陣列。並且,為了順序訪問路徑長度為 1,2,…的頂點,需在演算法中附設乙個佇列來儲存已被訪問的路徑長度為 1,2,…的頂點。 以鄰接表作為儲存結構的無向圖的廣度優先遍歷演算法的實現如下, 佇列是迴圈順序佇列。

public void bfs() }

} //從某個頂點出發進行廣度優先遍歷

public void bfsal(int i)

p = p.next;

} }

} 演算法的複雜度是o(n2),具體情況,如圖所示:

分析上面的演算法,每個頂點至多入佇列一次。遍歷圖的過程實質上是通過邊或弧查詢鄰接頂點的過程,因此,廣度優先遍歷演算法的時間複雜度與深度優先遍歷相同,兩者的不同之處在於對頂點的訪問順序不同。

這就是圖的遍歷,極其演算法的實現,下屆,我們討論圖的應用。

C 資料結構與演算法揭秘13

這節,我們來看看一下什麼了,來看看圖的遍歷吧!首先,搞清楚,圖的遍歷的基本的含義了。圖的遍歷是指從圖中的某個頂點出發,按照某種順序訪問圖中的每個頂點,使每個頂點被訪問一次且僅一次。圖的遍歷與樹的遍歷操作功能相似。圖的遍歷是圖的一種基本操作,並且圖的許多其他操作都是建立在遍歷操作的基礎之上的。遍歷示意...

C 資料結構與演算法揭秘13

這節,我們來看看一下什麼了,來看看圖的遍歷吧!首先,搞清楚,圖的遍歷的基本的含義了。圖的遍歷是指從圖中的某個頂點出發,按照某種順序訪問圖中的每個頂點,使每個頂點被訪問一次且僅一次。圖的遍歷與樹的遍歷操作功能相似。圖的遍歷是圖的一種基本操作,並且圖的許多其他操作都是建立在遍歷操作的基礎之上的。遍歷示意...

資料結構與演算法 揭秘

字面意思就是研究資料的一種方法,就是研究資料在程式中組織的一種方法。資料結構就是,元素與元素有一種或者多種關係的集合,在軟體界有一種比較普片的公式就是程式 資料結構 演算法。1 集合 set 和數學的集合一樣,具有唯一性,確定性,無序性。2 線性結構 典型的資料庫二維表,一對一的關係。3 樹形結構 ...