1. 程式人生 > >圖的遍歷演算法-深度優先搜尋演算法(dfs)和廣度優先搜尋演算法(bfs)

圖的遍歷演算法-深度優先搜尋演算法(dfs)和廣度優先搜尋演算法(bfs)

一、前提須知

  1. 圖是一種資料結構,一般作為一種模型用來定義物件之間的關係或聯絡。物件:頂點(V)表示;物件之間的關係或者關聯:通過圖的邊(E)來表示。一般oj題中可能就是點與點,也有可能是具體生活中的物體
  2. 圖分為有向圖和無向圖,圖的儲存使用鄰接矩陣(即二維陣列)或者鄰接表。
  3. 圖的最基本操作就是圖的遍歷,深度優先搜尋演算法(dfs)和廣度優先搜尋演算法(bfs)是圖遍歷操作的2種方法。這2鍾方法對於無向圖和有向圖皆適用。

二、深度優先搜尋演算法(dfs)

1.基本思想:

簡單說就是搜到底,重新搜。從v0為起點進行搜尋,如果被訪問過,則做一個標記,直到與v0想連通的點都被訪問一遍,如果這時,仍然有點沒被訪問,可以從中選一個頂點,進行再一次的搜尋,重複上述過程。

2.程式碼思想:

定義一個二維陣列存放點與點之間的關係,可以直接到達即為1,否則為0;

定義一個一維陣列用於記錄某個點是否已經訪問過。初始化全為0,代表都未訪問過。

使用遞迴方法,得出結果。

3.例子:


              ( 網圖)

  1. 以任何一個點為起點,如 頂點 1 。
  2. 從頂點1開始搜尋,為 1->2->3 ,到頂點3後終止。回溯到頂點 2 .
  3.  2->5 到達頂點5 後終止。回溯 到 頂點2,終止於頂點2,回溯到 頂點 1,終止於頂點 1.
  4.  從頂點 4 開始訪問,並終止於頂點 4 。

實現上述圖的遞迴dfs程式碼:

#include <iostream>
using namespace std;
const int maxn=100;

int arr[maxn][maxn];
int vis[maxn + 1] = { 0 };
int n;
void dfs(int start)
{
	vis[start]=1;
	for(int i=1;i<=n;i++)
	{
		if(!vis[i]&&arr[start-1][i-1]==1)
			dfs(i);
		
	}
	cout<<start<<" ";
}
void dfs_traverse(int begin)
{
	dfs(begin);
	for(int i=1;i<=n;i++)//例子中的點是從1開始的,所以是1到n(dfs中同理); 
	{
		if(vis[i]==1)
			continue;
		dfs(i);
	}
}
int main()
{
	int i,j,begin;
	//讀入總的頂點數
	cin>>n; 
	//讀入鄰接矩陣
	for(i=0;i<n;i++) 
		for(j=0;j<n;j++)
			cin>>arr[i][j];
	//輸入深度搜索的起始頂點		
	cin>>begin;
	dfs_traverse(begin);
    return 0;
}

測試資料:

0 1 1 0 0
0 0 1 0 1
0 0 1 0 0
1 1 0 0 1

0 0 1 0 0

結果:


三、廣度優先搜尋演算法(bfs)

1.基本思想:

選擇一個頂點為起始頂點,先搜尋與該點連線的所有的鄰點,依次搜尋所有鄰點的鄰點。

2.程式碼思想:

雙端佇列不為空則迴圈

將未訪問的鄰接點壓入雙端連結串列後面,然後從前面取出並訪問

結合上述2點,使用STL中的queue實現起來可以方便一點

3.例子:


從頂點1開始進行廣度優先搜尋:
  1. 初始狀態,從頂點1開始,佇列={1}
  2. 訪問1的鄰接頂點,1出隊變黑,2,3入隊,佇列={2,3,}
  3. 訪問2的鄰接結點,2出隊,4入隊,佇列={3,4}
  4. 訪問3的鄰接結點,3出隊,佇列={4}
  5. 訪問4的鄰接結點,4出隊,佇列={ 空}
    結點5對於1來說不可達。

實現上述的bfs程式碼:

#include <iostream>
#include<queue>
using namespace std;

const int maxn=100;
int arr[maxn][maxn];
int vis[maxn + 1] = { 0 };
int n;

void bfs(int start)
{
	queue<int>q;
	q.push(start);
	vis[start]=1;
	while(!q.empty())
	{
		int front=q.front();
		cout<<front<<" ";
		q.pop();
		for(int i=1;i<=n;i++)
		{
			if(!vis[i]&&arr[front-1][i-1])
			{
				vis[i]=1;
				q.push(i);
			}
		}	
	}
}
void bfs_traverse(int begin)
{
	bfs(begin);
	for(int i=1;i<=n;i++)//例子中的點是從1開始的,所以是1到n(bfs中同理); 
	{
		if(vis[i]==1)
			continue;
		bfs(i);
	}
}
int main()
{
	int i,j,begin;
	//讀入總的頂點數
	cin>>n; 
	//讀入鄰接矩陣
	for(i=0;i<n;i++) 
		for(j=0;j<n;j++)
			cin>>arr[i][j];
	//輸入深度搜索的起始頂點		
	cin>>begin;
	bfs_traverse(begin);
    return 0;
}

測試資料:

0 1 1 0 0
0 0 1 1 0
0 1 1 1 0
1 0 0 0 0 

0 0 1 1 0

測試結果: