DFS:深度优先遍历,深度优先遍历。
两种实现方式:递归和栈。
递归:从顶点v出发深度遍历图G的算法
1 访问v
2 依次从顶点v未被访问的邻接点出发深度遍历。
栈:
1访问v
2将v的邻居节点入栈
3 将栈的顶部元素出栈访问,同时将其邻居元素入栈,重复3直到栈为空
BFS:宽度优先遍历
队列实现:
1访问v
2将v的邻居节点入队
3将队的队头元素出队访问,同时将其相邻元素入队,重复3直到队为空
保存路径:vector<int>&
以vector引用形式记录路径,在元素访问的地方push_back();
DFS应用:单词搜索
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
int a[8][8] = {0};
bool visited[8];//全局数组记录访问过的节点
/*
1 2 3 4 5 6 7 模仿图
1
/ \
2 3
/\ /\
4--5 6--7
*/
void store_graph() //邻接矩阵存储图
{
/*int i, j;
for (i = 1; i <= 10; i++)
for (j = 1; j <= 10; j++)
cin >> a[i][j];
*/
a[1][2] = 1; a[1][3] = 1;
a[2][1] = 1; a[2][4] = 1; a[2][5] = 1;
a[3][1] = 1; a[3][6] = 1; a[3][7] = 1;
a[4][2] = 1; a[4][5] = 1;
a[5][2] = 1; a[5][4] = 1;
a[6][3] = 1; a[6][7] = 1;
a[7][3] = 1; a[7][6] = 1;
}
int Adj(int x) //求邻接点
{
for (int i = 1; i <= 7; i++)
if (a[x][i] == 1 && visited[i] == false)
return i;
return 0;
}
void dfs(int v,vector<int>&path) //深度遍历顶点
{
cout << v << " "; //访问顶点v
path.push_back(v);
visited[v] = true;
int adj = Adj(v);
while (adj != 0)
{
if (visited[adj] == false)//先递归第一个邻接点,在递归第二个邻接点。。。
dfs(adj,path); //递归调用是实现深度遍历的关键所在
adj = Adj(v);//v的上一个邻接点访问到已经访问的,则找下一个邻接点
}
}
//将顶部节点所有未被访问的“邻居”(即“一层邻居节点”)踹入栈中“待用”
//然后围绕顶部节点猛攻,每个节点被访问后被踹出
void dfs_stack(int v,vector<int>&path)
{
stack<int>s;
cout << v << " ";
path.push_back(v);
visited[v] = true;
int temp = Adj(v);
while (temp != 0)
{
s.push(temp);
visited[temp] = true;
temp = Adj(v);
}//保存与头一个点相连接的所有点
while (!s.empty())
{
int top = s.top();
visited[top] = true;
cout << top << " ";
path.push_back(top);
s.pop();
int adj = Adj(top);//将刚弹出栈顶的元素的所有邻接点入栈
while(adj!=0)//刚弹出来的节点邻接点在入栈在上方,先访问,深度优先
{
s.push(adj);
visited[adj] = true;
adj = Adj(top);
}
}
}
void bfs(int v,vector<int>&path)//宽度遍历顶点
{
cout << v << " ";//访问初始节点
path.push_back(v);
visited[v] = true;
int adj;
queue<int>q;
q.push(v);
int temp;
while (!q.empty())
{
temp = q.front();
q.pop();
adj = Adj(temp);//将队头节点入队
while (adj != 0)
{
if (visited[adj] == false)
{
cout << adj << " ";
path.push_back(adj);
visited[adj] = true;
q.push(adj);
}
adj = Adj(temp);
}
}
}
void print_path(vector<int>path)
{
for (auto v : path)
cout << v << " ";
cout << endl;
}
int main()
{
cout << "初始化图:" << endl;
store_graph();
memset(visited, false, sizeof(visited));
cout << "dfs递归遍历结果:" << endl;
vector<int>path1;
dfs(1, path1);
cout << endl;
print_path(path1);
memset(visited, false, sizeof(visited));
cout << "dfs栈结构遍历结果:" << endl;
vector<int>path2;
dfs_stack(1, path2);
cout << endl;
print_path(path2);
memset(visited, false, sizeof(visited));
cout << endl;
cout << "bfs队列结构遍历结果:" << endl;
vector<int>path3;
bfs(1,path3);
cout << endl;
print_path(path3);
return 0;
}
运行结果:
力扣79:单词搜索
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
vector<vector<bool>> is_visited(board.size(), vector<bool>(board[0].size(),false));
for(int i = 0;i<board.size();++i)
{
for(int j = 0;j<board[0].size();++j)
{
if(dfs_exist(board,word,is_visited,0,i,j))
return true;
}
}
return false;
}
bool dfs_exist(vector<vector<char>>& board,string&word,vector<vector<bool> >&is_visited,int start_index,int x,int y)
{
if(start_index == word.size())
return true;
if(x<0||x>=board.size()||y<0||y>=board[0].size()||board[x][y]!=word[start_index]||is_visited[x][y])
return false;
is_visited[x][y] = true;
bool ret = (dfs_exist(board,word,is_visited,start_index+1,x+1,y)||
dfs_exist(board,word,is_visited,start_index+1,x-1,y)||
dfs_exist(board,word,is_visited,start_index+1,x,y+1)||
dfs_exist(board,word,is_visited,start_index+1,x,y-1));
//当我们把ij位置的所有都找完之后,会到这一步,不管成功与否,我们都需要
//把ij这个位置的可走信息变成false(可走),因为这一步之后,会回溯至上一个位置的
//另一种路线,而另一种路线是可以走ij这个位置的。
is_visited[x][y] = false;//回溯,当前节点未访问
return ret;
}
};