導航:首頁 > 源碼編譯 > 圖的遍歷演算法的原理

圖的遍歷演算法的原理

發布時間:2024-07-01 07:03:42

『壹』 鍥炬繁搴︿紭鍏堥亶鍘嗙畻娉曟槸鎬庝箞瀹炵幇鐨勶紵

浣跨敤鏍堟潵瀹炵幇綆楁硶銆

鐢ㄩ偦鎺ヨ〃琛ㄧず鍥捐繘琛屾繁搴︿紭鍏堥亶鍘嗘椂錛岄氬父閲囩敤鏍堟潵瀹炵幇綆楁硶錛屽箍搴﹂亶鍘嗕嬌鐢ㄩ槦鍒椼

鎵╁睍鏉愭枡錛

娣卞害浼樺厛閬嶅巻錛氱被浼間笌鏍戠殑鍓嶅簭閬嶅巻銆備粠鍥句腑鐨勬煇涓欏剁偣v鍑哄彂錛岃塊棶姝ら《鐐癸紝鐒跺悗浠巚鐨勬湭琚璁塊棶鍒扮殑閭繪帴鐐硅繘琛岄亶鍘嗭紝鐩村埌鍥句腑鎵鏈夊拰v鏈夎礬寰勭浉閫氱殑欏剁偣閮借璁塊棶鍒

娉錛氫紭鍏堣塊棶澶栧眰鑺傜偣錛岃塊棶鍒版棤鏂伴《鐐規椂錛屼細榪涜屽洖閫錛岃塊棶鏈琚璁塊棶榪囩殑鍒嗘敮欏剁偣銆

騫垮害浼樺厛閬嶅巻錛氱被浼間簬鏍戠殑灞傚簭閬嶅巻銆備粠鍥句腑鐨勬煇涓欏剁偣w鍑哄彂錛岃╅《鐐箇鍏ラ槦錛岀劧鍚庨《鐐箇鍐嶅嚭闃燂紝騫惰╂墍鏈夊拰欏剁偣w鐩歌繛鐨勯《鐐瑰叆闃燂紝鐒跺悗鍐嶅嚭闃熶竴涓欏剁偣t錛屽苟璁╂墍鏈夊拰t鐩歌繛浣嗘湭琚璁塊棶榪囩殑欏剁偣鍏ラ槦鈥︹︾敱姝ゅ驚鐜錛屾寚瀹氬浘涓鎵鏈夊厓緔犻兘鍑洪槦銆


鍙傝冭祫鏂欐潵婧愶細

鐭ョ綉璁烘枃-鏁版嵁緇撴瀯涓鍥劇殑閬嶅巻綆楁硶鐮旂┒

『貳』 數據結構中出圖的二種遍歷,寫出演算法與思想,謝謝

BFS,廣度優先搜索
先遍歷離起點近的,再到遠的,直至全圖。先遍歷所有與起點距離為1的點,再到所有距離為2的點……
具體實現,需要一個隊列進行輔助存儲。
舉個例,S為起點,S到A,B,C3個點相鄰。A又與A1,A2相鄰,B與B1,B2相鄰,C沒有與其他點相鄰。對於遍歷A發生的事情,就是「發現」了A1,A2。但是,這是不能立即遍歷A1,A2,這與BFS宗旨違背,必須先遍歷B,C。而又由於B,C肯定是比A1,A2先「發現」,這就體現了一種「先進先出」的性質,因而需要隊列對為擴展的結點進行暫存
BFS()
{
queue q;
q.push(s);//一開始的s點
while(q非空)
{
從q中取一元素
將該元素「發現」,而又未被進過q的結點入隊
}
}

DFS,深度優先搜索
先選定一條路徑,對路徑上的點進行遍歷。然後,從路徑的盡頭開始,逐步回退,在每個分支再遍歷其他路徑及其上面的點。
具體實現,常寫作遞歸,故可理解為通過棧輔助存儲。
還是上面的距離,DFS出來的其中一種序列是S,A,A1,A2,B,B1,B2,C。路徑S,A,A1為第一選取的路徑,然後回退,逐步選取其他分支,在A選取了A2作為第二路徑,以此類推。由於這樣對每個點所做的操作就是「發現」,「遍歷」與「回退」,操作種類相同,故常寫作遞歸。。。
DFS(int target)
{
for(target的每個發現點)
{
DFS(該發現點)
}
//結束函數實際上就是回退的過程
}

『叄』 圖的矩陣深度和廣度遍歷演算法

圖的遍歷是指從圖中任一給定頂點出發,依次訪問圖中的其餘頂點。如果給定的圖是連通圖,則從圖中的任意一點出發,按照一個指定的順序就可以訪問到圖中的所有頂點,且每個頂點只訪問一次。這個過程稱為圖的遍歷。
圖的遍歷比樹的遍歷復雜的多。樹是一種特殊類型的圖,即無圈(無迴路)連通圖。樹中的任意兩個頂點間都有唯一的路徑相通。在一個頂點被訪問過之後,不可能又沿著另外一條路徑訪問到已被訪問過的結點。而圖中的頂點可能有邊與其他任意頂點相連
。因此在訪問了某個頂點之後,可能沿著另一條邊訪問已被訪問過的頂點。例如圖(a)中的G1,在訪問了V1,V2和V3之後,有可能沿著邊(V3,V1)訪問到V1。為了避免一頂點被多次訪問,可以設立一個集合Visited,用來記錄已被訪問過的頂點。它的初值為空
集。一旦V1被訪問過,即把V1加到集合Visited中。圖的遍厲通常有兩種:圖的深度優先
搜索和圖的廣度優先搜索。
1)圖的深度優先搜索
從圖G=(V,E)的一個頂點V0出發,在訪問了任意一個與V0相鄰且未被訪問過的頂點W1之後,再從W1出發,訪問和W1相鄰且未被訪問過的頂點W2,然後再從W2出發進行如上所述訪問,直到找到一個它相鄰的結點,都被訪問過的結點為止。然後退回到尚有相
鄰結點未被訪問過的頂點,再從該頂點出發,重復上述搜索過程,直到所有被訪問過的頂點的鄰接點都被訪問過為止。圖的這種遍歷過程就稱為圖的深度優先搜索。例如從頂點V1出發對圖3.3.5進行深度優先搜索,遍歷的順序為 V1,V2,V5,V10,V6,V7,V3,V12,V1
1,V8,V4,V9。(與鄰接表中的鄰接點排列順序有關,即p->next.vertex=v2 or v3對遍歷
順序有影響 )
例25.(p194.c)圖的深度優先搜索。從圖G的頂點V0
發進行深度優先搜索,列印出各個頂點的遍歷順序。
解:圖的深度優先搜索法為:
(1)首先訪問V0並把V0加到集合visited中;
(2)找到與V0相鄰的頂點W,若W未進入
visited中,則以深度優先方法從W開始搜索。
(3)重復過程(2)直到所有於V0相鄰的頂點
都被訪問過為止。

下面是對用鄰接表表示的圖G進行深度優先搜索的程序
int rear=0; /*Visit和rear都為全局變數*/
int visit[500];
depth_first_search(g,v0) /*從V0開始對圖G進行深度
優先搜索*/
graphptr g[ ]; /*指針數組,為鄰接表表頭頂點指針
g[vi]...g[vn]*/
int v0; /*這里V0和W都是頂點標號,如V0=0或1*/
{ /*g[v0]是頂點V0的表頭指針*/
int w;
graphptr p; /*鏈表的結點指針*/
visit [++rear]=v0;
printf("%d\n",v0);
p=g[v0];/*指定一個頂點,通過鄰接表表頭指針
,訪問v0的鄰接頂點*/
while (p!=NULL)
{
w=p->vertex ;/*這里W是與V0相鄰的一個頂點*/
if (!visited(w))/*當V0的相鄰結點,W未被訪問時,從W開始遍厲*/
depth_first_search(g,w);
p=p->next;/*接著訪問另一個相鄰頂點*/
}
}
int visited(w) /*檢查頂點w是否進入visited(w)*/
int w ;
{
int i;
for (i=1;i<=rear;i++)
if (visit [ i ] == w) return(1);/*W在visit[]中,說明被訪問過*/
return(0); /*W不在visit[]中,說明未被訪問過,返回0*/
}
2)圖的廣度優先搜索
從圖G的一個頂點V0出發,依次訪問V0的鄰接點K1,K2...Kn。然後再順序訪問K1,K2...Kn的所有尚未被訪問過的鄰接點。如此重復,直到圖中的頂點都被訪問過為止。圖的這種搜索稱為圖的廣度優先搜索。例如:從V1出發按廣度優先搜索方法遍歷圖3.3.5,頂
點的訪問順序為V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12。
圖的廣度優先搜索類似樹的按層次遍歷,需要有一個隊列來存放還沒
有來得及處理的頂點。圖的廣度優先搜索演算法為:
(1)首先把V0放入隊列;
(2)若隊列為空則結束,否則取出隊列的頭V;
(3)訪問V並把所有與V相鄰且未被訪問的頂點插入隊列;
(4)重復(2)-(3)直到隊列為空。
上述演算法中所有已被訪問過的頂點都放在隊列中,因此只要檢查某個頂點是否在隊列中就可以判斷出該頂點是否已被訪問過。
廣度搜索法的程序如下:
broad_first_search(g,v0) /*從V0開始對圖g進行廣度優先搜索*/
graphptr g[ ]; /*為鄰接表,表頭頂點指針*/
int v0;
{
int queue[500],front =1, tail=1,v;
graphptr p;
queue [tail]=v0; /*把V0插入隊列queue*/
while (front <=tail)/*當隊列不為空*/
{
v=queue[front++]; /*取出隊列中的頂點*/
printf("%d\n",v); /*訪問該頂點*/
p=g[v]; /*從頂點V的鏈表來考慮與V相鄰的頂點*/
while (p!=NULL)
{
v=p->vertex; /*從第一個結點(即邊)中找出相鄰的頂點*/
if (!visited(queue,tail,v))/*判斷頂點是否進入隊列,如進入隊列
說明已被訪問或將要訪問*/
queue[++tail]=v;/*如果該頂點未被訪問過,將此相鄰頂點插入隊列*/
p=p-->next;/*再考慮該結點的下一個相鄰頂點*/
}
}
}
visited (q,tail,v)/*判斷頂點是否被訪問過,訪問過時,返回1,否則返回0*/
int q[ ],tail,v;/*進入隊列的頂點,在front之前的頂點已被訪問過列印輸出,
在front和tail之間的頂點是即將要訪問頂點*/
{
int i;
for(i=1;i<=tail;i++)/*掃描隊列,確定v是否在隊列中,在隊列中返回1,否則返回0*
/
if (q[i]==v)return(1);/*隊列中的頂點都認為已被訪問過*/
return(0);
}

深度優先的非遞歸演算法

/*設當前圖(或圖的某個連通分枝)的起始訪問點為p*/
NodeType stackMain,stackSec
visit(p)
p->mark=true;
do
{
for(all v isTheConnectNode of (G,p))//將當前點的鄰接點中的所有結點壓入副棧中
if(v.marked==false)
statckSec.push(v)
//將副棧中的點依次彈出,壓入主棧中,這與非遞歸演算法中使用隊列的意圖類似
while(!stackSec.isEmpty())
stackMain.push(statckSec.pop());
do//找出下一個未訪問的結點或者沒找到,直到棧為空
{
if(!stackMain.isEmpty())

{
p=stackMain.pop();

}
}while(p.marked==true&&!stackMain.isEmpty())
if(p.marked==false)//訪問未訪問結點.

{

visit(p);

p.marked=true;

}

}while(!stackMain.isEmpty())

『肆』 圖遍歷的演算法

圖的遍歷方法目前有深度優先搜索法和廣度(寬度)優先搜索法兩種演算法。 深度優先搜索法是樹的先根遍歷的推廣,它的基本思想是:從圖G的某個頂點v0出發,訪問v0,然後選擇一個與v0相鄰且沒被訪問過的頂點vi訪問,再從vi出發選擇一個與vi相鄰且未被訪問的頂點vj進行訪問,依次繼續。如果當前被訪問過的頂點的所有鄰接頂點都已被訪問,則退回到已被訪問的頂點序列中最後一個擁有未被訪問的相鄰頂點的頂點w,從w出發按同樣的方法向前遍歷,直到圖中所有頂點都被訪問。其遞歸演算法如下:
Boolean visited[MAX_VERTEX_NUM]; //訪問標志數組
Status (*VisitFunc)(int v); //VisitFunc是訪問函數,對圖的每個頂點調用該函數
void DFSTraverse (Graph G, Status(*Visit)(int v)){
VisitFunc = Visit;
for(v=0; v<G.vexnum; ++v)
visited[v] = FALSE; //訪問標志數組初始化
for(v=0; v<G.vexnum; ++v)
if(!visited[v])
DFS(G, v); //對尚未訪問的頂點調用DFS
}
void DFS(Graph G, int v){ //從第v個頂點出發遞歸地深度優先遍歷圖G
visited[v]=TRUE; VisitFunc(v); //訪問第v個頂點
for(w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G,v,w))
//FirstAdjVex返回v的第一個鄰接頂點,若頂點在G中沒有鄰接頂點,則返回空(0)。
//若w是v的鄰接頂點,NextAdjVex返回v的(相對於w的)下一個鄰接頂點。
//若w是v的最後一個鄰接點,則返回空(0)。
if(!visited[w])
DFS(G, w); //對v的尚未訪問的鄰接頂點w調用DFS
} 圖的廣度優先搜索是樹的按層次遍歷的推廣,它的基本思想是:首先訪問初始點vi,並將其標記為已訪問過,接著訪問vi的所有未被訪問過的鄰接點vi1,vi2,…, vi t,並均標記已訪問過,然後再按照vi1,vi2,…, vi t的次序,訪問每一個頂點的所有未被訪問過的鄰接點,並均標記為已訪問過,依次類推,直到圖中所有和初始點vi有路徑相通的頂點都被訪問過為止。其非遞歸演算法如下:
Boolean visited[MAX_VERTEX_NUM]; //訪問標志數組
Status (*VisitFunc)(int v); //VisitFunc是訪問函數,對圖的每個頂點調用該函數
void BFSTraverse (Graph G, Status(*Visit)(int v)){
VisitFunc = Visit;
for(v=0; v<G.vexnum, ++v)
visited[v] = FALSE;
initQueue(Q); //置空輔助隊列Q
for(v=0; v<G.vexnum; ++v)
if(!visited[v]){
visited[v]=TRUE; VisitFunc(v);
EnQueue(Q, v); //v入隊列
while(!QueueEmpty(Q)){
DeQueue(Q, u); //隊頭元素出隊並置為u
for(w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w))
if(!Visited[w]){ //w為u的尚未訪問的鄰接頂點
Visited[w]=TRUE; VisitFunc(w);
EnQueue(Q, w);
}
}
}
}

『伍』 圖遍歷演算法之DFS/BFS

在計算機科學, 圖遍歷(Tree Traversal,也稱圖搜索)是一系列圖搜索的演算法, 是單次訪問樹結構類型數據(tree data structure)中每個節點以便檢查或更新的一系列機制。圖遍歷演算法可以按照節點訪問順序進行分類,根據訪問目的或使用場景的不同,演算法大致可分為28種:

圖遍歷即以特定方式訪問圖中所有節點,給定節點下有多種可能的搜索路徑。假定以順序方式進行(非並行),還未訪問的節點就需通過堆棧(LIFO)或隊列(FIFO)規則來確定訪問先後。由於樹結構是一種遞歸的數據結構,在清晰的定義下,未訪問節點可存儲在調用堆棧中。本文介紹了圖遍歷領域最流行的廣度優先搜索演算法BFS和深度優先搜索演算法DFS,對其原理、應用及實現進行了闡述。通常意義上而言,深度優先搜索(DFS)通過遞歸調用堆棧比較容易實現,廣義優先搜索通過隊列實現。

深度優先搜索(DFS)是用於遍歷或搜索圖數據結構的演算法,該演算法從根節點開始(圖搜索時可選擇任意節點作為根節點)沿著每個分支進行搜索,分支搜索結束後在進行回溯。在進入下一節點之前,樹的搜索盡可能的加深。
DFS的搜索演算法如下(以二叉樹為例):假定根節點(圖的任意節點可作為根節點)標記為 ,
(L) : 遞歸遍歷左子樹,並在節點 結束。
(R): 遞歸遍歷右子樹,並在節點 結束。
(N): 訪問節點 。
這些步驟可以以任意次序排列。如果(L)在(R)之前,則該過程稱為從左到右的遍歷;反之,則稱為從右到左的遍歷。根據訪問次序的不同,深度優先搜索可分為 pre-order、in-order、out-order以及post-order遍歷方式。

(a)檢查當前節點是否為空;
(b)展示根節點或當前節點數據;
(c)遞歸調用pre-order函數遍歷左子樹;
(d)遞歸調用pre-order函數遍歷右子樹。
pre-order遍歷屬於拓撲排序後的遍歷,父節點總是在任何子節點之前被訪問。該遍歷方式的圖示如下:

遍歷次序依次為:F -B -A-D- C-E-G- I-H.

(a)檢查當前節點是否為空;
(b)遞歸調用in-order函數遍歷左子樹;
(c)展示根節點或當前節點數據;
(d)遞歸調用in-order函數遍歷右子樹。
在二叉樹搜索中,in-order遍歷以排序順序訪問節點數據。該遍歷方式的圖示如下:

遍歷次序依次為:A -B - C - D - E - F - G -H-I

(a)檢查當前節點是否為空;
(b)遞歸調用out-order函數遍歷右子樹;
(c)展示根節點或當前節點數據;
(d)遞歸調用out-order函數遍歷左子樹。
該遍歷方式與LNR類似,但先遍歷右子樹後遍歷左子樹。仍然以圖2為例,遍歷次序依次為:H- I-G- F- B- E- D- C- A.

(a)檢查當前節點是否為空;
(b)遞歸調用post-order函數遍歷左子樹;
(c)遞歸調用post-order函數遍歷右子樹;
(d)展示根節點或當前節點數據。
post-order遍歷圖示如下:

遍歷次序依次為:A-C-E-D-B-H-I-G-F.

pre-order遍歷方式使用場景:用於創建樹或圖的副本;
in-order遍歷使用場景:二叉樹遍歷;
post-order遍歷使用場景:刪除樹

遍歷追蹤也稱樹的序列化,是所訪問根節點列表。無論是pre-order,in-order或是post-order都無法完整的描述樹特性。給定含有不同元素的樹結構,pre-order或post-order與in-order遍歷方式結合起來使用才可以描述樹的獨特性。

樹或圖形的訪問也可以按照節點所處的級別進行遍歷。在每次訪問下一層級節點之前,遍歷所在高層級的所有節點。BFS從根節點(圖的任意節點可作為根節點)出發,在移動到下一節點之前訪問所有相同深度水平的相鄰節點。

BFS的遍歷方法圖示如下:

遍歷次序依次為: F-B-G-A-D-I-C-E-H.

圖演算法相關的R包為igraph,主要包括圖的生成、圖計算等一系列演算法的實現。

使用方法:

參數說明:

示例:

結果展示:

DFS R輸出節點排序:

使用方法:

參數含義同dfs
示例:

結果展示:

BFS R輸出節點排序:

以尋找兩點之間的路徑為例,分別展示BFS及DFS的實現。圖示例如下:

示例:

輸出結果:

示例:

輸出結果:

[1] 維基網路: https://en.wikipedia.org/wiki/Tree_traversal
[2] GeeksforGeeks: https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/
[3] http://webdocs.cs.ualberta.ca/~holte/T26/tree-traversal.html
[4]Martin Broadhurst, Graph Algorithm: http://www.martinbroadhurst.com/Graph-algorithms.html#section_1_1
[5]igraph: https://igraph.org/r/doc/dfs.html
[6]igraph: https://igraph.org/r/doc/bfs.html
[7] Depth-First Search and Breadth-First Search in python: https://eddmann.com/posts/depth-first-search-and-breadth-first-search-in-python/

『陸』 圖遍歷演算法之最短路徑Dijkstra演算法

最短路徑問題是圖論研究中一個經典演算法問題,旨在尋找圖中兩節點或單個節點到其他節點之間的最短路徑。根據問題的不同,演算法的具體形式包括:

常用的最短路徑演算法包括:Dijkstra演算法,A 演算法,Bellman-Ford演算法,SPFA演算法(Bellman-Ford演算法的改進版本),Floyd-Warshall演算法,Johnson演算法以及Bi-direction BFS演算法。本文將重點介紹Dijkstra演算法的原理以及實現。

Dijkstra演算法,翻譯作戴克斯特拉演算法或迪傑斯特拉演算法,於1956年由荷蘭計算機科學家艾茲赫爾.戴克斯特拉提出,用於解決賦權有向圖的 單源最短路徑問題 。所謂單源最短路徑問題是指確定起點,尋找該節點到圖中任意節點的最短路徑,演算法可用於尋找兩個城市中的最短路徑或是解決著名的旅行商問題。

問題描述 :在無向圖 中, 為圖節點的集合, 為節點之間連線邊的集合。假設每條邊 的權重為 ,找到由頂點 到其餘各個節點的最短路徑(單源最短路徑)。

為帶權無向圖,圖中頂點 分為兩組,第一組為已求出最短路徑的頂點集合(用 表示)。初始時 只有源點,當求得一條最短路徑時,便將新增頂點添加進 ,直到所有頂點加入 中,演算法結束。第二組為未確定最短路徑頂點集合(用 表示),隨著 中頂點增加, 中頂點逐漸減少。

以下圖為例,對Dijkstra演算法的工作流程進行演示(以頂點 為起點):

註:
01) 是已計算出最短路徑的頂點集合;
02) 是未計算出最短路徑的頂點集合;
03) 表示頂點 到頂點 的最短距離為3
第1步 :選取頂點 添加進


第2步 :選取頂點 添加進 ,更新 中頂點最短距離




第3步 :選取頂點 添加進 ,更新 中頂點最短距離




第4步 :選取頂點 添加進 ,更新 中頂點最短距離





第5步 :選取頂點 添加進 ,更新 中頂點最短距離



第6步 :選取頂點 添加進 ,更新 中頂點最短距離



第7步 :選取頂點 添加進 ,更新 中頂點最短距離

示例:node編號1-7分別代表A,B,C,D,E,F,G

(s.paths <- shortest.paths(g, algorithm = "dijkstra"))輸出結果:

(s.paths <- shortest.paths(g,4, algorithm = "dijkstra"))輸出結果:

示例:

找到D(4)到G(7)的最短路徑:

[1] 維基網路,最短路徑問題: https://zh.wikipedia.org/wiki/%E6%9C%80%E7%9F%AD%E8%B7%AF%E9%97%AE%E9%A2%98 ;
[2]CSDN,Dijkstra演算法原理: https://blog.csdn.net/yalishadaa/article/details/55827681 ;
[3]RDocumentation: https://www.rdocumentation.org/packages/RNeo4j/versions/1.6.4/topics/dijkstra ;
[4]RDocumentation: https://www.rdocumentation.org/packages/igraph/versions/0.1.1/topics/shortest.paths ;
[5]Pypi: https://pypi.org/project/Dijkstar/

閱讀全文

與圖的遍歷演算法的原理相關的資料

熱點內容
數控g71編程時應注意什麼 瀏覽:411
捷聯慣導演算法心得 瀏覽:144
c4d命令的理解 瀏覽:568
pdf文檔水印 瀏覽:917
高斯模糊演算法java 瀏覽:354
小學樂高機器人編程作品 瀏覽:522
小猿搜題app怎麼使用 瀏覽:420
內孔左螺紋編程 瀏覽:893
怎麼查找程序員信息 瀏覽:538
adb日誌導出到本地的命令 瀏覽:717
手機微信壓縮包 瀏覽:263
坐高鐵應下什麼app 瀏覽:529
命令行查找文件夾 瀏覽:389
快遞加密個人信息 瀏覽:828
怎麼開對應用的加密 瀏覽:201
備用安卓手機怎麼用 瀏覽:585
數據分析與應用黑馬程序員 瀏覽:485
單片機觸摸屏屏編程 瀏覽:403
java實現base64 瀏覽:906
小傻瓜怎麼連接伺服器 瀏覽:650