摘要:今天就來看看基于圖的兩種搜索算法,分別是廣度優(yōu)先搜索和深度優(yōu)先搜索算法,這兩個算法都十分的常見,在平常的面試當(dāng)中也可能遇到。
1. 概論
前面說到了圖這種非線性的數(shù)據(jù)結(jié)構(gòu),并且我使用了代碼,簡單演示了圖是如何實現(xiàn)的。今天就來看看基于圖的兩種搜索算法,分別是廣度優(yōu)先搜索和深度優(yōu)先搜索算法,這兩個算法都十分的常見,在平常的面試當(dāng)中也可能遇到。
在圖上面的搜索算法,其實主要的表現(xiàn)形式就是從圖中的一個頂點,找到和另一個頂點之間的路徑,而兩種搜索算法,都是解決這個問題的。
2. 廣度優(yōu)先搜索
廣度優(yōu)先搜索的基本思路就是從一個頂點出發(fā),層層遍歷,直到找到目標(biāo)頂點,其實這樣搜索出來的路徑也就是兩個頂點之間的最短距離。如下圖所示,例如要搜索出頂點 s -> t 的路徑,搜索的方式就是這樣的:
其中黃色的線條表示搜索的節(jié)點,數(shù)字 1、2、3、4 表示搜索的次序,廣度優(yōu)先搜索的原理看起來十分的簡單,但是它的代碼實現(xiàn)還是稍微有點難的,先來看看整體的代碼實現(xiàn),然后再具體講解一下:
public class BFS { /** * 廣度優(yōu)先搜索算法 * @param graph 圖 * @param s 搜索的起點(對應(yīng)圖中的一個頂點) * @param t 搜索的終點 */ public static void bfs(Graph graph, int s, int t){ if (s == t) return; //獲得圖的頂點個數(shù) int vertex = graph.getVertex(); //獲取存儲圖頂點的列表 LinkedList[] list = graph.getList(); //如果某個頂點已經(jīng)被訪問,則設(shè)置為true boolean[] visited = new boolean[vertex]; visited[s] = true; //隊列,存儲的是已經(jīng)被訪問,但是其相連的頂點還沒有被訪問的頂點 Queue queue = new LinkedList<>(); queue.add(s); //記錄搜索的路徑 int[] path = new int[vertex]; for (int i = 0; i < vertex; i++) { path[i] = -1; } while (queue.size() != 0){ int w = queue.poll(); for (int i = 0; i < list[w].size(); i++) { int q = list[w].get(i); if (!visited[q]){ path[q] = w; if (q == t){ print(path, s, t); return; } visited[q] = true; queue.add(q); } } } } //遞歸打印 s-t 的路徑 private static void print(int[] prev, int s, int t){ if (prev[t] != -1 && t != s){ print(prev, s, prev[t]); } System.out.print(t + " "); } }
程序中有三個輔助的變量:
一是 boolean[] visited ,這個數(shù)組表示如果已經(jīng)被訪問,則設(shè)置為 true,例如頂點 s,是最開始被訪問的,直接設(shè)置為 true。
二是有一個隊列 queue,它表示的是,一個頂點已經(jīng)被訪問,但是其相鄰的頂點還沒有被訪問的頂點。例如頂點 s,它自己被訪問了,但是和它相鄰的兩個頂點還沒有被訪問,因此直接被添加到了隊列當(dāng)中。
三是數(shù)組 path,它表示一個頂點是被哪個頂點所訪問的,數(shù)組下標(biāo)表示的是頂點,對應(yīng)存儲的是由誰所訪問。這個邏輯在代碼中的體現(xiàn)便是 path[q] = w 這一行。最后,這個數(shù)組中存儲的便是搜索的路徑,需要遞歸打印出來。
3. 深度優(yōu)先搜索
再來看看深度優(yōu)先搜索,這種搜索的基本思路就是:從起始頂點出發(fā),任意遍歷頂點,如果走不通,則回退一個頂點,然后換一個頂點繼續(xù)遍歷,知道找到目標(biāo)頂點。像下圖這樣:
圖中從頂點 s 出發(fā),藍(lán)色的表示前進(jìn)的頂點,紅色的表示后退一個頂點,直到找到目標(biāo)頂點 t,相信你可以看出來,這樣搜索出來的路徑其實并不是 s 到 t 的最短路徑,而是任意的一條路徑。
深度優(yōu)先的代碼實現(xiàn):
public class DFS { //判斷是否找到了目標(biāo)頂點 private static boolean found = false; public static void dfs(Graph graph, int s, int t){ int vertex = graph.getVertex(); boolean[] visited = new boolean[vertex]; int[] path = new int[vertex]; for (int i = 0; i < vertex; i++) { path[i] = -1; } LinkedList[] list = graph.getList(); recursionDfs(list, s, t, visited, path); print(path, s, t); } //遞歸遍歷 private static void recursionDfs(LinkedList [] list, int w, int t, boolean[] visited, int[] path){ if (found) return; visited[w] = true; if (w == t){ found = true; return; } for (int i = 0; i < list[w].size(); i++) { int q = list[w].get(i); if (!visited[q]){ path[q] = w; recursionDfs(list, q, t, visited, path); } } } private static void print(int[] path, int s, int t){ if (path[t] != -1 && t != s){ print(path, s, path[t]); } System.out.print(t + " "); } }
變量 boolean[] visited 和廣度優(yōu)先搜索一樣,都是表示訪問過的節(jié)點設(shè)置為 true,path 數(shù)組表示訪問的路徑。
最后,總結(jié)一下,廣度和深度優(yōu)先搜索,都是比較暴力的搜索方式,沒有什么優(yōu)化,層層遍歷或者一路遞歸,所以不難看出,這兩個算法的時間復(fù)雜度接近 O(n),空間復(fù)雜度也是 O(n),還是稍微有點高的,所以這兩種搜索算法適用于圖上的頂點數(shù)據(jù)不太多的情況。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73974.html
摘要:深度優(yōu)先搜索上一次已經(jīng)提到,圖的遍歷一般有兩種算法,即廣度優(yōu)先和深度優(yōu)先。用深度優(yōu)先搜索算法對圖中的任務(wù)圖進(jìn)行拓?fù)渑判蜃罱K各頂點的發(fā)現(xiàn)和探索完成時間會保存在中。 深度優(yōu)先搜索(DFS) 上一次已經(jīng)提到,圖的遍歷一般有兩種算法,即廣度優(yōu)先和深度優(yōu)先。其中深度優(yōu)先搜索算法會從第一個指定的頂點開始遍歷圖,沿著路徑直到這條路徑最后一個頂點,接著原路回退并探索下一條路徑。換句話說,它是先深度后廣...
摘要:圖的定義用圖對現(xiàn)實中的系統(tǒng)建??梢杂脠D對現(xiàn)實中的很多系統(tǒng)建模比如對交通流量建模頂點可以表示街道的十字路口邊可以表示街道加權(quán)的邊可以表示限速或者車道的數(shù)量建模人員可以用這個系統(tǒng)來判斷最佳路線及最有可能堵車的街道任何運輸系統(tǒng)都可以用圖來建模比如 圖的定義 用圖對現(xiàn)實中的系統(tǒng)建模 可以用圖對現(xiàn)實中的很多系統(tǒng)建模. 比如對交通流量建模, 頂點可以表示街道的十字路口, 邊可以表示街道. 加權(quán)的邊...
摘要:樹狀結(jié)構(gòu)張飛關(guān)羽劉備荀彧關(guān)平點擊曹操這一項,加載出來劉禪和周倉,點擊周倉,又異步加載項羽和別姬曹操劉禪周倉項羽別姬貂蟬深度優(yōu)先對于入?yún)⒌呐袛?,必須存在且是一個數(shù)組,如果不是,進(jìn)行矯正必須是一個字符串,不能是函數(shù)之類的必須是一個函數(shù)廣度優(yōu)先 1 樹狀結(jié)構(gòu) var result = { id:0, name:張飛, item:[ {id:1,name...
摘要:廣度優(yōu)先搜索上一次已經(jīng)提到,圖的遍歷一般有兩種算法,即廣度優(yōu)先和深度優(yōu)先。其中廣度優(yōu)先搜索算法會從指定的第一個頂點開始遍歷圖,先訪問其所有的相鄰點,就像一次訪問圖的一層。其它最短路徑算法對于加權(quán)圖的最短路徑,廣度優(yōu)先算法可能并不合適。 廣度優(yōu)先搜索(BFS) 上一次已經(jīng)提到,圖的遍歷一般有兩種算法,即廣度優(yōu)先和深度優(yōu)先。其中廣度優(yōu)先搜索算法會從指定的第一個頂點開始遍歷圖,先訪問其所有的...
摘要:不撞南墻不回頭深度優(yōu)先搜索基礎(chǔ)部分對于深度優(yōu)先搜索和廣度優(yōu)先搜索,我很難形象的去表達(dá)它的定義。這就是深度優(yōu)先搜索了,當(dāng)然,這個題目我們還有別的解法,這就到了我們說的廣度優(yōu)先搜索。 不撞南墻不回頭-深度優(yōu)先搜索 基礎(chǔ)部分 對于深度優(yōu)先搜索和廣度優(yōu)先搜索,我很難形象的去表達(dá)它的定義。我們從一個例子來切入。 輸入一個數(shù)字n,輸出1~n的全排列。即n=3時,輸出123,132,213,231,...
閱讀 4604·2021-09-22 14:57
閱讀 565·2019-08-30 15:56
閱讀 2672·2019-08-30 15:53
閱讀 2245·2019-08-29 14:15
閱讀 1692·2019-08-28 17:54
閱讀 564·2019-08-26 13:37
閱讀 3484·2019-08-26 10:57
閱讀 1049·2019-08-26 10:32