圖的搜尋演算法javascript
阿新 • • 發佈:2019-01-04
搜尋就是從一個指定的點開始找到其他節點。圖的搜尋基本上分為深度優先搜尋和廣度優先搜尋。先來說說深度優先搜尋。
深度優先搜尋包括從一條路徑的起始頂點開始追溯,直到到達最後一個頂點,然後回溯,繼續追溯下一條路徑,直到到達最後的頂點,如此往復,直到沒有路徑為止。如下圖所示:
演算法的思路就是訪問一個沒有訪問過的點,將它標記為已訪問,再遞迴去訪問在初始頂點的鄰接表中其他沒有訪問過的點。
程式碼如下:
function dfs(v){//深度優先搜尋 this.marked[v]=true;//將標識位設為已訪問 if(this.adj[v]!=null){//如果有相鄰節點 document.write('訪問節點:'+v+'<br>'); } var len=this.adj[v].length; for(var i=0;i<len;i++){ var w=this.adj[v];//將所選節點對應路徑一條條搜尋下去 for(var j=0;j<w.length;j++) if(!this.marked[w[j]]){//對應一個路徑一次搜尋到底 this.dfs(w[j]); } } }
實驗程式碼如下:
//實驗
g=new Graph(5);
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,3);
g.addEdge(2,4);
g.showGraph();
g.dfs(1);
實驗結果為:
// 0-> 1 2
// 1-> 0 3
// 2-> 0 4
// 3-> 1
// 4-> 2
// 訪問節點:1
// 訪問節點:0
// 訪問節點:2
// 訪問節點:4
// 訪問節點:3
深度優先搜尋的時間複雜度為O(n+e)
再來說說廣度優先搜尋,就是從第一個頂點開始,嘗試訪問儘可能靠近它的頂點。先把同層的搜尋完再逐漸向下搜尋。過程如下圖:
演算法的思想如下:
首先找到與當前頂點相鄰的未訪問頂點,將其新增到已訪問頂點列表及佇列中;
從圖中取出下一個頂點v,新增到已訪問的頂點列表中;
將所有和v相鄰的未訪問頂點新增到佇列。
程式碼如下:
function bfs(s){//廣度優先搜尋 for(var i=0;i<this.vertices;i++){//由於先進行深度優先搜尋,所以這裡要將標識位重置 this.marked[i]=false; } var queue=[]; this.marked[s]=true; queue.push(s); while(queue.length>0){ var v=queue.shift(); if(v!=undefined){ document.write("訪問節點:"+v+'<br>'); } for(var i=0;i<this.adj[v].length;i++){ var w=this.adj[v];//找到所選節點的相鄰子列表 for(var j=0;j<w.length;j++){ if(!this.marked[w[j]]){ this.marked[w[j]]=true;//依次訪問其相鄰子列表 queue.push(w[j]);//將子列表推送入佇列 } } } } }
實驗程式碼如下:
//實驗
g=new Graph(5);
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,3);
g.addEdge(2,4);
g.showGraph();
g.dfs(1);
g.bfs(1);
//結果
// 0-> 1 2
// 1-> 0 3
// 2-> 0 4
// 3-> 1
// 4-> 2
// 訪問節點:1
// 訪問節點:0
// 訪問節點:2
// 訪問節點:4
// 訪問節點:3
// 訪問節點:1
// 訪問節點:0
// 訪問節點:3
// 訪問節點:2
// 訪問節點:4
廣度優先搜尋的時間複雜度和深度優先搜尋一樣,都是O(n+e),兩者不同之處僅僅在於對頂點訪問的順序不同。
圖的表示和搜尋的完整程式碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
// function Vertex(label){
// this.label=label;
// }
function Graph(v){//圖類
this.vertices=v;//結點數
this.edges=0;//邊數
this.adj=[];//陣列存放頂點數量
for(var i=0;i<this.vertices;i++){
this.adj[i]=[];//子陣列儲存相鄰頂點
}
this.addEdge=addEdge;//新增邊
this.showGraph=showGraph;//顯示圖
this.dfs=dfs;//深度優先搜尋
this.bfs=bfs;//廣度優先搜尋
this.marked=[];//標識位陣列
for(var i=0;i<this.vertices;i++){//給所有結點新增未訪問過的標識位
this.marked[i]=false;
}
}
function addEdge(v,w){//新增邊
this.adj[v].push(w);//將w新增到v的相鄰頂點列表
this.adj[w].push(v);//將v新增到w的相鄰頂點列表
this.edges++;//邊數加一
}
function showGraph(){//顯示圖
for(var i=0;i<this.vertices;i++){
document.write(i+"->");
for(var j=0;j<this.vertices;j++){
if(this.adj[i][j]!=undefined){//顯示和該結點相鄰的結點
document.write(this.adj[i][j]+" ");
}
}
document.write("<br>");
}
}
function dfs(v){//深度優先搜尋
this.marked[v]=true;//將標識位設為已訪問
if(this.adj[v]!=null){//如果有相鄰節點
document.write('訪問節點:'+v+'<br>');
}
var len=this.adj[v].length;
for(var i=0;i<len;i++){
var w=this.adj[v];//將所選節點對應路徑一條條搜尋下去
for(var j=0;j<w.length;j++)
if(!this.marked[w[j]]){//對應一個路徑一次搜尋到底
this.dfs(w[j]);
}
}
}
function bfs(s){//廣度優先搜尋
for(var i=0;i<this.vertices;i++){//由於先進行深度優先搜尋,所以這裡要將標識位重置
this.marked[i]=false;
}
var queue=[];
this.marked[s]=true;
queue.push(s);
while(queue.length>0){
var v=queue.shift();
if(v!=undefined){
document.write("訪問節點:"+v+'<br>');
}
for(var i=0;i<this.adj[v].length;i++){
var w=this.adj[v];//找到所選節點的相鄰子列表
for(var j=0;j<w.length;j++){
if(!this.marked[w[j]]){
this.marked[w[j]]=true;//依次訪問其相鄰子列表
queue.push(w[j]);//將子列表推送入佇列
}
}
}
}
}
//實驗
g=new Graph(5);
g.addEdge(0,1);
g.addEdge(0,2);
g.addEdge(1,3);
g.addEdge(2,4);
g.showGraph();
g.dfs(1);
g.bfs(1);
//結果
// 0-> 1 2
// 1-> 0 3
// 2-> 0 4
// 3-> 1
// 4-> 2
// 訪問節點:1
// 訪問節點:0
// 訪問節點:2
// 訪問節點:4
// 訪問節點:3
// 訪問節點:1
// 訪問節點:0
// 訪問節點:3
// 訪問節點:2
// 訪問節點:4
</script>
</body>
</html>