圖的遍歷與簡(jiǎn)單應(yīng)用

-DFS(Depth First Search):深度優(yōu)先搜索

訪問(wèn)完一個(gè)頂點(diǎn)的所有鄰接點(diǎn)之后,會(huì)按原路返回,對(duì)應(yīng)著堆棧、出棧
void DFS ( Vertex V )
{ visited [ V ] = true ;
for ( V的每個(gè)鄰接點(diǎn)W )
if ( !visited [ W ] )
DFS ( W ) ;
}

深度優(yōu)先搜索相當(dāng)于樹(shù)的先序遍歷
若有N個(gè)頂點(diǎn)、E條邊,時(shí)間復(fù)雜度為:
用鄰接表存儲(chǔ)圖,有 O ( N + E )
用鄰接矩陣存儲(chǔ)圖,有 O ( N的平方 )

-BFS(Breadth First Search):廣度優(yōu)先搜索(相當(dāng)于樹(shù)的層序遍歷)

樹(shù)是一種特殊的圖,類(lèi)似于樹(shù)的層序遍歷(隊(duì)列),圖的遍歷是先選取一個(gè)頂點(diǎn),將它移出隊(duì)列時(shí)把它所有鄰接點(diǎn)入隊(duì),重復(fù)該操作
void BFS ( Vertex V )
{ visited [ V ] = true ; // 標(biāo)記為已訪問(wèn)
Enqueue ( V , Q ) ; // 壓入隊(duì)列中
while ( ! IsEmpty ( Q ) ) {
V = Dequeue ( Q ) ;
for ( V的每個(gè)鄰接點(diǎn) W )
if ( ! visited [ W ] ){
visited [ W ] = true ;
Enqueue ( W , Q ) ;
}
}
}
若有N個(gè)頂點(diǎn)、E條邊,時(shí)間復(fù)雜度是:
用鄰接表存儲(chǔ)圖,有 O ( N + E )
用鄰接矩陣存儲(chǔ)圖,有 O ( N的平方 )

為什么需要兩種遍歷??jī)煞N遍歷有不同特點(diǎn)
BFS:對(duì)于解決最短或最少問(wèn)題特別有效,而且尋找深度小,但缺點(diǎn)是內(nèi)存耗費(fèi)量大(需要開(kāi)大量的數(shù)組單元用來(lái)存儲(chǔ)狀態(tài))。DFS:對(duì)于解決遍歷和求所有問(wèn)題有效,對(duì)于問(wèn)題搜索深度小的時(shí)候處理速度迅速,然而在深度很大的情況下效率不高

圖不連通,怎么遍歷?深度遍歷和廣度遍歷都會(huì)丟棄孤立結(jié)點(diǎn)
連通:如果從V到W存在一條(無(wú)向)路徑,則稱(chēng)V和W是連通的
路徑:V到W的路徑是一系列頂點(diǎn){V,v1,v2,…,vn,W}集合,其中任一對(duì)相鄰的頂點(diǎn)間都有圖中的邊。路徑的長(zhǎng)度是路徑中的邊數(shù)(如果帶權(quán),則是所有邊的權(quán)重和)。如果V到W之間的所有頂點(diǎn)都不同,則稱(chēng)簡(jiǎn)單路徑。
回路:起點(diǎn)等于終點(diǎn)的路徑,帶有回路的就不是簡(jiǎn)單路徑
連通圖:圖中任意兩頂點(diǎn)均連通
連通分量:無(wú)向圖的極大連通子圖
極大頂點(diǎn)數(shù):再加1個(gè)頂點(diǎn)就不連通了
極大邊數(shù):包含子圖中所有頂點(diǎn)相連的所有邊
對(duì)于有向圖,有強(qiáng)連通和弱連通之分
強(qiáng)連通:有向圖中頂點(diǎn)V和W之間存在雙向路徑,則稱(chēng)V和W是強(qiáng)連通
弱連通:有向圖不是強(qiáng)連通圖,但是將該圖的路徑方向去掉后其變?yōu)檫B通圖,則稱(chēng)之為若連通
強(qiáng)連通圖:有向圖中任意兩頂點(diǎn)均強(qiáng)連通

每調(diào)用一次DFS(V),就把V所在的連通分量都遍歷了一遍。BFS也是一樣
void ListComponents ( Graph G ) // 所有分量列出來(lái)
{ for ( each V in G )
if ( ! visited [ V ] ) {
DFS ( V ) ; // or BFS ( V )
}
}

圖的簡(jiǎn)單應(yīng)用

-驗(yàn)證六度空間:

算法思路:
對(duì)每個(gè)節(jié)點(diǎn),進(jìn)行廣度優(yōu)先搜索
搜索過(guò)程中累計(jì)訪問(wèn)的節(jié)點(diǎn)數(shù)
需要記錄“層數(shù)”,僅僅計(jì)算6層以?xún)?nèi)的節(jié)點(diǎn)數(shù)

void SDS ( )
{
for ( each V in G ) {
count = BFS ( V ) ;
Output ( count / N ) ;
}
}

void BFS ( Vertex V )
{
visited [ V ] = true ; count = 1 ; // count 記錄訪問(wèn)的結(jié)點(diǎn)數(shù)量
level = 0 ; last = V ; // level指訪問(wèn)的層數(shù),last為訪問(wèn)該層的最后那個(gè)節(jié)點(diǎn)
Enqueue ( V , Q ) ;
while ( ! IsEmpty ( Q ) ) {
V = Dequeue ( Q ) ;
for ( V的每個(gè)鄰接點(diǎn) W )
if ( !visited [ W ] ) { //每一個(gè)V的鄰接點(diǎn)W進(jìn)隊(duì)列的時(shí)候,讓tail指向W
visited [ W ] = true ;
Enqueue ( W , Q ) ; count++ ;
tail = W ;
}
if ( V == last ) {
level ++ ; last = tail ; // 當(dāng)V是最后一個(gè)結(jié)點(diǎn)時(shí),層數(shù)加一
}
if ( level == 6 ) break ; // 層數(shù)為6 跳出
} return count ; // 輸出訪問(wèn)的總節(jié)點(diǎn)數(shù)
}

-最短路徑問(wèn)題

在網(wǎng)絡(luò)中,求兩個(gè)不同頂點(diǎn)之間的所有路徑中,邊的權(quán)值之和最小的那一條路徑,這條路徑就是兩點(diǎn)之間的最短路徑(Shortest Path)第一個(gè)頂點(diǎn)為源點(diǎn)(Source)最后一個(gè)頂點(diǎn)為終點(diǎn)(Destination)
問(wèn)題分類(lèi):
單源最短路徑問(wèn)題:從某固定源點(diǎn)出發(fā),求其到所有其他頂點(diǎn)的最短路徑
(有向)無(wú)權(quán)圖
(有向)有權(quán)圖
多源最短路徑問(wèn)題:求任意兩頂點(diǎn)間的最短路徑

無(wú)權(quán)圖的單源最短路徑算法
按照遞增(非遞減)的順序找出到各個(gè)頂點(diǎn)的最短路。BFS
初始化以下數(shù)組:
dist [ W ] = S到W的最短距離
dist [ S ] = 0
path [ W ] = S到W的路上經(jīng)過(guò)的某頂點(diǎn)
void Unweighted ( Vertex S )
{
Enqueue ( S , Q ) ; // 源點(diǎn)入隊(duì)
while ( ! IsEmpty ( Q ) ) {
V = Dequeue ( Q ) ;
for ( V的每個(gè)鄰接點(diǎn) W )
if ( list [ W ] == -1 ) {
dist [ W ] = dist [ V ] + 1 ;
path [ W ] = V ;
Enqueue ( W , Q ) ;
}
}
}
V個(gè)頂點(diǎn)E條邊,時(shí)間復(fù)雜度
T = O ( | V | + | E | )

有權(quán)圖的單源最短路算法(不一定是經(jīng)過(guò)頂點(diǎn)最少的路徑)圖中沒(méi)有負(fù)值圈

按照遞增(非遞減)的順序找出到各個(gè)頂點(diǎn)的最短路。Dijkstra算法
Dijkstra算法:令S={ 源點(diǎn) s+已經(jīng)確定了最短路徑的頂點(diǎn)Vi },對(duì)任一未收錄的頂點(diǎn)V,定義 dist [ V ]為S到V的最短路徑長(zhǎng)度,但該路徑僅經(jīng)過(guò)S中的頂點(diǎn)。即路徑 { S -> ( Vi 屬于 S ) -> V } 的最小長(zhǎng)度
若路徑是按照遞增(非遞減)的順序生成的,則:真正的最短路必須只經(jīng)過(guò)S中的頂點(diǎn),每次從未收錄的頂點(diǎn)中選一個(gè)dist最小的收錄,增加一個(gè)V進(jìn)入S,可能影響另一個(gè)W的dist值(此時(shí)V一定在路徑上且V有一條直接到W的邊)
void Dijkstra ( Vertex s )
{
while ( 1 ) {
V = 未收錄頂點(diǎn)中dist的最小值
if ( 這樣的V不存在 )
break ;
collected [ V ] = true ;
for ( V的每個(gè)鄰接點(diǎn)W )
if ( collected [ W ] == false )
if ( dist [ V ] + E小于 dist [ W ] ) {
dist [ W ] = dist [ V ] + E ;
path [ W ] = V ;
}
}
}
//不能解決有負(fù)邊的情況
如何得到未收錄頂點(diǎn)中dist的最小值并完成 dist [ W ] = dist [ V ] + E 操作
方法1:直接掃描所有未收錄頂點(diǎn)-O( | V | ),T = O ( | V | 的平方 + | E | );
方法2:將dist存在最小堆中-O( | E | log| V | ),更新 dist [ W ] 的值-O ( log| V | ),
T = O ( | V | log| V | + | E | log| V | ) = O( | E | log| V | )

多源最短路算法:

方法1:直接將單源最短路算法調(diào)用|V|遍,T = O ( |V|的立方 + | E | * | V | ),對(duì)于稀疏圖較優(yōu)
方法2:Floyd算法,T = O ( | V |的立方 ),對(duì)于稠密圖較優(yōu)
void Floyd ( )
{
for ( i = 0 ; i < N ; i ++ )
for ( j = 0 ; j < N ; j ++ ){
D[ i ][ j ] = G[ i ][ j ] ;
path[ i ][ j ] = -1 ;
}
for ( k = 0 ; k < N ; k ++ )
for ( i = 0 ; i < N ; i ++ )
for ( j = 0 ; j < N ; j ++ )
if ( D[ i ][ k ] + D[ k ][ j ] < D[ i ][ j ] ) {
D[ i ][ j ] = D[ i ][ k ] + D[ k ][ j ] ;
path[ i ][ j ] = k ;
}
}
T = O ( | V |的立方 )

-最小生成樹(shù)問(wèn)題

連通圖邊最少
什么是最小生成樹(shù):
首先是樹(shù),樹(shù)是一種特殊的圖,樹(shù)沒(méi)有回路,[ V ]個(gè)頂點(diǎn)一定有[ V ]-1條邊
生成樹(shù):包含全部頂點(diǎn),[ V ]-1條邊都在圖里,生成樹(shù)任意加一條邊都會(huì)生成回路
邊的權(quán)重和最小

貪心算法約束:只能用圖里有的邊,只能正好用掉 [ V ]-1條邊,不能有回路
Prime算法:讓一顆小樹(shù)長(zhǎng)大:從一頂點(diǎn)開(kāi)始,尋找一條與該樹(shù)相連的最小邊,在以連結(jié)的兩個(gè)頂點(diǎn)的樹(shù)為基礎(chǔ),再找與之相關(guān)的最小邊,加入的邊不能形成回路,依此類(lèi)推。有點(diǎn)像Dijkstra算法

void Prime ( )
{
MST = { s } ; // 初始化一棵最小生成樹(shù) 選擇根結(jié)點(diǎn)s
while ( 1 ) {
V = 未收錄頂點(diǎn)中 dist 的最小者;// dist定義為一個(gè)頂點(diǎn)到這棵生成樹(shù)的最小距離,dist [ V ] = E( v, w )或正無(wú)窮
if ( 這樣的V不存在 )
break ;
將V收錄進(jìn)MST;dist [ V ] = 0 ;
for ( V 的每個(gè)鄰接點(diǎn) W )
if ( dist [ W ] != 0 ) // W未被收錄
if ( E( v, w ) < dist [ W ] ) {
dist [ W ] = E( v, w ) ;
parent [ W ] = V ;
}
}
if ( MST中收錄的頂點(diǎn)不到 [ V ] 個(gè) ) // 有為連通的頂點(diǎn)
Error (“生成樹(shù)不存在”) ;
}
該算法適用于稠密圖

Kruskal算法-將森林合并成樹(shù),按照權(quán)重從小到大把邊收錄進(jìn)來(lái),注意不能構(gòu)成回路
void Kruskal ( graph G )
{
MST = { } ; // MST中收集的是邊,所以一開(kāi)始時(shí)空集
while ( MST 中不到 [ V ]-1條邊&& E中還有邊 ) {
從 E 中取一條權(quán)重最小的邊 E( v, w ) ; // 用最小堆存放邊
將 E( v, w )從 E 中刪除;
if ( E( v, w )不在 MST 中構(gòu)成回路 )
// 用并查集檢查是否構(gòu)成回路,每一個(gè)頂點(diǎn)是一個(gè)集合,收錄邊時(shí)兩棵樹(shù)變成一棵樹(shù),判斷新加入的邊與原來(lái)的是否屬于同一棵樹(shù)
將 E( v, w ) 加入MST;
else
徹底無(wú)視 E( v, w );
)
if ( MST 中不到 [ V ]-1條邊 )
Error ( “生成樹(shù)不存在” );
}

連通圖的最小生成樹(shù)不是唯一的,思考:
當(dāng)用Kruskal算法的思想加邊的時(shí)候出現(xiàn)(兩條權(quán)重相同并連接的兩棵樹(shù)相同的邊)的時(shí)候最小生成樹(shù)路徑不唯一
反之當(dāng)用Kruskal算法的思想加邊的時(shí)候沒(méi)出現(xiàn)(兩條權(quán)重相同并連接的兩棵樹(shù)相同的邊)的時(shí)候最小生成樹(shù)路徑唯一
或者說(shuō)決定路徑是否唯一的因素是使兩棵樹(shù)距離最小的邊是否只有一條,若有多條則不唯一

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,362評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,577評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,486評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,852評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,600評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,944評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,944評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,108評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,652評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,385評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,616評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,111評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,798評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,205評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,537評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,334評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,570評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容

  • https://zh.visualgo.net/graphds 淺談圖形結(jié)構(gòu)https://zh.visualgo...
    狼之獨(dú)步閱讀 4,186評(píng)論 0 0
  • 圖是一種比線性表和樹(shù)更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),在圖中,結(jié)點(diǎn)之間的關(guān)系是任意的,任意兩個(gè)數(shù)據(jù)元素之間都可能相關(guān)。圖是一種多對(duì)...
    Alent閱讀 2,330評(píng)論 1 22
  • 第一章 緒論 什么是數(shù)據(jù)結(jié)構(gòu)? 數(shù)據(jù)結(jié)構(gòu)的定義:數(shù)據(jù)結(jié)構(gòu)是相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。 第二章...
    SeanCheney閱讀 5,807評(píng)論 0 19
  • 現(xiàn)實(shí)生活中有很大一類(lèi)問(wèn)題可以用簡(jiǎn)潔明了的圖論語(yǔ)言來(lái)描述,可以轉(zhuǎn)化為圖論問(wèn)題。 相關(guān)定義 圖可以表示為G=(V, E...
    芥丶未央閱讀 1,742評(píng)論 0 7
  • 今天我說(shuō),這個(gè)是我送給自己的六一禮物,我媽說(shuō),咋還過(guò)六一呢你,都多大了,額,,我沒(méi)孩子之前應(yīng)該都是可以過(guò)六一的,哈哈
    Esther米爾米兒閱讀 310評(píng)論 0 0