一文搞懂深度優先搜索、廣度優先搜索(dfs,bfs)

@公衆號閱讀連接java

前言

在有向圖和無向圖中,若是節點之間無權值或者權值相等,那麼dfs和bfs時常出如今平常算法中。不只如此,dfs,bfs不只僅可以解決圖論的問題,在其餘問題的搜索上也是最基礎(可是策略不一樣)的兩種經典算法面試

在這裏插入圖片描述
而且五大經典算法的 回溯算法其實也是 dfs的一種。dfs,bfs基礎可以解決搜索類問題的大部分狀況,只不過搜索隨着數據增大而呈非線性的增加,因此兩種算法在數據較多的狀況是不太適用的。

鄰接矩陣和鄰接表

鄰接矩陣: 鄰接矩陣就是用數組(二維)表示圖。具體能夠看下面例子。固然,這種狀況很容易形成空間浪費,因此不少人進行空間優化,甚至是鄰接表的方式。 算法

在這裏插入圖片描述
鄰接表: 而鄰接表則是數組套鏈表。這樣能夠比起鄰接矩陣節省很多空間,可是若是無向圖 依然會重複浪費一半空間,就有十字鏈表,多重連接表等等出現。同時,對於有權圖來講, 只需對節點加一個屬性weight便可!
在這裏插入圖片描述

深度優先搜索(dfs)

概念數組

深度優先搜索屬於圖算法的一種,英文縮寫爲DFS即Depth First Search.其過程簡要來講是對每個可能的分支路徑深刻到不能再深刻爲止,並且每一個節點只能訪問一次.數據結構

簡單的說,要完成dfs要有前提條件.就是有聯通點。單個節點dfs就斷掉了,他要找打和它聯繫的節點。dfs入手可能比bfs簡單的緣由是dfs大部分之間利用遞歸的走向完成dfs,而不多須要標記學習

咱們一般使用鄰接表(一維數組套鏈表a[List])或者鄰接矩陣(二維數組a[][])儲存圖的信息。有時爲了優化空間會選擇十字鏈表或者鄰接多重表進行存儲節省空間,可是操做每每是很複雜的。而且通常來講圖的更大須要設計算法的優化,因此這裏例子使用鄰接矩陣完成!優化

對於dfs的流程來講,大體能夠認爲是這樣:網站

  • 從初始點開始按照一個方向遍歷,這個方向到盡頭中止後到另外一個方向,,,直到全部操做完成退出!
  • 深度優先搜索執行過程像是一個棧的操做。喜新厭舊。老是處理最新加入的節點,這點遞歸剛好知足其性質,而且遞歸代碼寫起來也更簡潔
  • dfs的流程能夠參考二叉樹的前序遍歷,它實質就是一個dfs。

對於上圖的dfs。能夠用一下代碼來表示:spa

package 圖論;
public class dfs {
	static boolean isVisit[];
	public static void main(String[] args) {
		int map[][]=new int[7][7];
		isVisit=new boolean[7];
		map[0][1]=map[1][0]=1;
		map[0][2]=map[2][0]=1;
		map[0][3]=map[3][0]=1;
		
		map[1][4]=map[4][1]=1;
		map[1][5]=map[5][1]=1;
		map[2][6]=map[6][2]=1;
		map[3][6]=map[6][3]=1;
	
		isVisit[0]=true;
		dfs(0,map);//從0開始遍歷
	}
	private static void dfs(int index,int map[][]) {
		// TODO Auto-generated method stub
		System.out.println("訪問"+(index+1)+" ");
		for(int i=0;i<map[index].length;i++)//查找聯通節點
		{
			if(map[index][i]>0&&isVisit[i]==false)
			{
				isVisit[i]=true;
				dfs(i,map);
			}
		}
		System.out.println((index+1)+"訪問結束 ");
	}
}
複製代碼

大體順序訪問爲 設計

在這裏插入圖片描述

寬度(廣度)優先搜索(bfs)

概念

BFS,其英文全稱是Breadth First Search。 BFS並不使用經驗法則算法。從算法的觀點,全部由於展開節點而獲得的子節點都會被加進一個先進先出的隊列中。通常的實驗裏,其鄰居節點還沒有被檢驗過的節點會被放置在一個被稱爲 open 的容器中(例如隊列或是鏈表),而被檢驗過的節點則被放置在被稱爲 closed 的容器中。(open-closed表)

簡單來講,bfs就是先進先出的隊列遍歷,然而這樣在分佈的狀況就是按層遍歷,能夠參考二叉樹遍歷的層序遍歷

若是從路徑上走來看,dfs就是一條跑的很快的瘋狗,處處亂咬。沒路了就轉頭,再沒路了再跑回來去其餘地方,而bfs就像是一團毒氣,慢慢延申!

就拿上述的圖來講,咱們使用鄰接表來實現遍歷。

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

public class bfs {
	public static void main(String[] args) {
		List<Integer> map[]=new ArrayList[7];
		boolean isVisit[]=new boolean[7];
		for(int i=0;i<map.length;i++)//初始化
		{
			map[i]=new ArrayList<Integer>();
		}
		map[0].add(1);map[0].add(2);map[0].add(3);
		map[1].add(0);map[1].add(4);map[1].add(5);
		map[2].add(0);map[2].add(6);
		map[3].add(0);map[3].add(6);
		map[4].add(1);
		map[5].add(1);
		map[6].add(2);map[6].add(3);
		
		Queue<Integer>q1=new ArrayDeque<Integer>();
		q1.add(0);isVisit[0]=true;
		while (!q1.isEmpty()) {
			int va=q1.poll();
			System.out.println("訪問"+(va+1));
			for(int i=0;i<map[va].size();i++)
			{
				int index=map[va].get(i);
				if(!isVisit[index])
				{
					q1.add(index);
					isVisit[index]=true;
				}
			}
		}
	}
}
複製代碼

在這裏插入圖片描述

總結與比較

上面說到dfs和bfs每每是在尋路上的兩個極端的表現!固然在不一樣場景使用可能也有些不一樣。

  • dfs能夠運用在查找和爬蟲中,若是爬蟲的話那麼更可能是優先找到不一樣連接,可用於統計等。而在查找中好比迷宮類能夠利用dfs判斷是否存在路徑,出路等等。
  • bfs也能夠運用在算法和爬蟲之中。而bfs優先處理本身周圍的資源。因此在爬蟲能夠用於遍歷網站,搜尋整個網站的價值信息等等,筆者之前用爬蟲+bfs實現過下載網站的模板(17素材的網頁模板)。而在算法中,在迷宮或者無權圖中bfs能夠找到最短路徑
    在這裏插入圖片描述

在上面能夠看得出在鄰接矩陣實現儲存上浪費不少空間,但有些狀況使用二維數組很合適——迷宮類問題。咱們在面試學習,會常常遇到迷宮類須要bfs找最短路徑,或者dfs查詢是否存在。或者雙bfs又或者dfs+bfs等等解決具體問題。

最後,但願你們能關注我公衆號(bigsai),咱們一塊兒學習數據結構與算法!感受還行,能夠動動小手,點個贊!

相關文章
相關標籤/搜索