圖的遍歷演算法-深度優先搜尋演算法(dfs)和廣度優先搜尋演算法(bfs)
阿新 • • 發佈:2019-01-07
一、前提須知
- 圖是一種資料結構,一般作為一種模型用來定義物件之間的關係或聯絡。物件:頂點(
V
)表示;物件之間的關係或者關聯:通過圖的邊(E
)來表示。一般oj題中可能就是點與點,也有可能是具體生活中的物體 - 圖分為有向圖和無向圖,圖的儲存使用鄰接矩陣(即二維陣列)或者鄰接表。
- 圖的最基本操作就是圖的遍歷,深度優先搜尋演算法(dfs)和廣度優先搜尋演算法(bfs)是圖遍歷操作的2種方法。這2鍾方法對於無向圖和有向圖皆適用。
二、深度優先搜尋演算法(dfs)
1.基本思想:簡單說就是搜到底,重新搜。從v0為起點進行搜尋,如果被訪問過,則做一個標記,直到與v0想連通的點都被訪問一遍,如果這時,仍然有點沒被訪問,可以從中選一個頂點,進行再一次的搜尋,重複上述過程。
2.程式碼思想:
定義一個二維陣列存放點與點之間的關係,可以直接到達即為1,否則為0;
定義一個一維陣列用於記錄某個點是否已經訪問過。初始化全為0,代表都未訪問過。
使用遞迴方法,得出結果。
3.例子:
( 網圖)
- 以任何一個點為起點,如 頂點 1 。
- 從頂點1開始搜尋,為 1->2->3 ,到頂點3後終止。回溯到頂點 2 .
- 2->5 到達頂點5 後終止。回溯 到 頂點2,終止於頂點2,回溯到 頂點 1,終止於頂點 1.
- 從頂點 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,3入隊,佇列={2,3,}
- 訪問2的鄰接結點,2出隊,4入隊,佇列={3,4}
- 訪問3的鄰接結點,3出隊,佇列={4}
- 訪問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
測試結果: