1. 程式人生 > >圖的搜尋演算法javascript

圖的搜尋演算法javascript

搜尋就是從一個指定的點開始找到其他節點。圖的搜尋基本上分為深度優先搜尋和廣度優先搜尋。先來說說深度優先搜尋。

        深度優先搜尋包括從一條路徑的起始頂點開始追溯,直到到達最後一個頂點,然後回溯,繼續追溯下一條路徑,直到到達最後的頂點,如此往復,直到沒有路徑為止。如下圖所示:


演算法的思路就是訪問一個沒有訪問過的點,將它標記為已訪問,再遞迴去訪問在初始頂點的鄰接表中其他沒有訪問過的點。

程式碼如下:

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>