图的BFS和DFS原理及实例分析(java)
https://blog.csdn.net/feilong_csdn/article/details/69386527
图的深度优先遍历(DFS)和广度优先遍历(BFS),DFS利用递归来实现比较易懂,DFS非递归就是将需要的递归的元素利用一个栈Stack来实现,以达到递归时候的顺序,而BFS则是利用一个队列Queue来实现。
package DataStructure;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class Graph {
private int number = 9;
private boolean[] flag;
private String[] vertexs = { "A", "B", "C", "D", "E", "F", "G", "H", "I" };
private int[][] edges = {
{ 0, 1, 0, 0, 0, 1, 1, 0, 0 },
{ 1, 0, 1, 0, 0, 0, 1, 0, 1 },
{ 0, 1, 0, 1, 0, 0, 0, 0, 1 },
{ 0, 0, 1, 0, 1, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 1, 0, 1, 0 },
{ 1, 0, 0, 0, 1, 0, 1, 0, 0 },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0 },
{ 0, 0, 0, 1, 1, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0, 0, 0, 0, 0 }
};
void DFSTraverse() {
flag = new boolean[number];
for (int i = 0; i < number; i++) {
if (flag[i] == false) {// 当前顶点没有被访问
DFS(i);
}
}
}
void DFS(int i) {
flag[i] = true;// 第i个顶点被访问
System.out.print(vertexs[i] + " ");
for (int j = 0; j < number; j++) {
if (flag[j] == false && edges[i][j] == 1) {
DFS(j);
}
}
}
void DFS_Map(){
flag = new boolean[number];
Stack<Integer> stack =new Stack<Integer>();
for(int i=0;i<number;i++){
if(flag[i]==false){
flag[i]=true;
System.out.print(vertexs[i]+" ");
stack.push(i);
}
while(!stack.isEmpty()){
int k = stack.pop();
for(int j=0;j<number;j++){
if(edges[k][j]==1&&flag[j]==false){
flag[j]=true;
System.out.print(vertexs[j]+" ");
stack.push(j);
break;
}
}
}
}
}
void BFS_Map(){
flag = new boolean[number];
Queue<Integer> queue = new LinkedList<Integer>();
for(int i=0;i<number;i++){
if(flag[i]==false){
flag[i]=true;
System.out.print(vertexs[i]+" ");
queue.add(i);
while(!queue.isEmpty()){
int k=queue.poll();
for(int j=0;j<number;j++){
if(edges[k][j]==1&&flag[j]==false){
flag[j] = true;
System.out.print(vertexs[j]+" ");
queue.add(j);
}
}
}
}
}
}
public static void main(String[] args) {
Graph graph = new Graph();
System.out.println("DFS递归:");
graph.DFSTraverse();
System.out.println();
System.out.println("DFS非递归:");
graph.DFS_Map();
System.out.println();
System.out.println("BFS非递归:");
graph.BFS_Map();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
程序运行结果:
前言
图的DFS和BFS算法
https://blog.csdn.net/qq_24486393/article/details/50270481
文章主要介绍数据结构知识板块中图的两种不同存储结构下(邻接表和邻接矩阵)BFS和DFS遍历算法。BFS和DFS应用领域不再说明,深搜和广搜的遍历算法十分重要。
DFS
原理:深度优先搜索,顾名思义即为一条道走到黑的搜索策略,行不通退回来换另外一条道再走到黑,依次直到搜索完成。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。可以通过图示清晰的说明。
图解遍历下图的全部节点:
基于邻接矩阵的DFS算法代码实现
void DFS(GraphAMatrix G,int i,int *visited)
{
int j;
if(visited[i])
return ;//若结点被遍历过 返回
else
{
cout<<i<<endl;
visited[i]=1;
//遍历与该结点相邻的结点 (从第一个开始)
for(j=0;j<G.numVertexs;j++)
{
if(!visited[i]&&G.Edge[i][j])
DFS(G,j,visited);//从相邻结点的第一个进行递归式深搜遍历
}
}
}
void DFS_GreahDG(GreapAMstrix G)
{
int i,j,e;
int *visited;//为每一个结点设置一个初始标志为未遍历
visited=(int *)malloc(sizeof(int)*G.numVertexs);
memset(visited,0,sizeof(int)*G.numVertexs);
//对每一个未被遍历结点进行DFS深度搜索
for(i=0;i<G.numVertexs;i++)
{
if(!visited[i])
DFS(G,i,visited);//调用深搜算法
}
free(visited);//释放指针
printf("\n");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
基于邻接表的DFS算法实现(全)
#include<iostream>
#include<stdlib.h>
#define maxvn 10
using namespace std;
typedef char VertexType;
//定义图的存储数据类型
typedef struct ArcNode{
int adjvesx;
struct ArcNode *nextarc;
int info;
}ArcNode;
typedef struct VNode{
VertexType data;
ArcNode *firstarc;
}VNode,AdjList[maxvn];
typedef struct{
AdjList vertices;
int Vnum,Anum;
}AdjGraph;
//定义一个全局标识数组
int visited[maxvn];
int LocateVex(char u,AdjGraph G)
{
int i;
for(i=0;i<G.Vnum;i++)
{
if(u==G.vertices[i].data)
return i;
}
if(i==G.Vnum)
{
cout<<"ERROR!"<<endl;
exit(1);
}
return 0;
}
//创建图
void CreatAdjGraph_adjList(AdjGraph &G)
{
ArcNode *p;
cout<<"Please input Vnum and Anum:"<<endl;
cin>>G.Vnum>>G.Anum;
cout<<"Please input Vertices:"<<endl;//创建表头
for(int i=0;i<G.Vnum;i++)
{
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
cout<<"Please input Arc[i][j]:"<<endl;//创建链表
for(int k=0;k<G.Anum;k++)
{
p=(ArcNode*)malloc(sizeof(ArcNode));
char v1,v2;
cin>>v1>>v2;
int i=LocateVex(v1,G);
int j=LocateVex(v2,G);
int w;
cin>>w;
p->adjvesx=j;
p->info=w;
p->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p;
}
}
//深搜算法
void DFS(AdjGraph G,int i)
{
ArcNode*p;
visited[i]=1;
p=G.vertices[i].firstarc;
while(p)
{
if(!visited[p->adjvesx])
{
visited[p->adjvesx]=1;
cout<<p->adjvesx<<endl;
}
p=p->nextarc;
}
return;
}
//调用深搜算法
void DFSTraverse(AdjGraph G)
{
for(int i=0;i<G.Vnum;i++)
visited[i]=0;
for(int i=0;i<G.Vnum;i++)
{
if(!visited[i])
DFS(G,i);
}
}
//主函数
int main()
{
AdjGraph G;
CreatAdjGraph_adjList(G);
DFSTraverse(G);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
BFS
宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。
我们可以图示清楚的了解算法的具体实施过程:
基于邻接矩阵的BFS:
void BFS_Graph(GraphAMatrix G){
//图的广度优先遍历
int i,j,e;//i j 为循环控制变量 e为取队列元素变量
CQueue Q;
int *visited = (int *)malloc(sizeof(int)*G.numVertexes);//标记数组
InitCQueue(&Q);
for(int i=0;i<G.numVertexes;i++){
//遍历所有顶点 非连通图的情况化 要遍历全部加上循环
if(!visited[i]){
printf("%d",i);
visited[i] = 1;
EnCQueue(&Q,i);//起点入队列
while(!CQueue(Q)){//循环操作
DeQueue(&Q,&e);//出队列
for(int j=0;j<G.numVertexes;j++){
//遍历顶点集合
if(!visited[j]&&G.edges[e][j]){
//判断当前结点是否被访问过 且与出队结点是否相连
printf("%d",j);
visited[j] = 1;
EnCQueue(&Q,j);
}
}
}
}
}
free(visited);
printf("\n");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
基于邻接表的BFS
void BFS_GraphADJList(GraphADJList G){
//图的广度优先遍历
int i,j,e;//i j 为循环控制变量 e为取队列元素变量
CQueue Q;
EdgeNode *p;
int *visited = (int *)malloc(sizeof(int)*G.numVertexes);//标记数组
InitCQueue(&Q);
for(int i=0;i<G.numVertexes;i++){
//遍历所有顶点 非连通图的情况化 要遍历全部加上循环
if(!visited[i]){
printf("%d",i);
visited[i] = 1;
EnCQueue(&Q,i);//起点入队列
while(!CQueue(Q)){//循环操作
DeQueue(&Q,&e);//出队列
p = G.adjList[e].firstedge;//从顶点的链表的第一个边结点开始
while(p){
j = p->adjvex;//记录当前边的终点序号
if(!visited[j]){
printf("%d",j);
visited[j] = 1;
EnCQueue(&Q,j);
}
p = p->next;//移动到下一条边
}
}
}
}
free(visited);
printf("\n");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
DFS与BFS比较
DFS深度优先搜索,空间需求较低,不需要BFS需要一个队列保存搜索过程中搜索记录;其次,深搜在搜索过程中要考虑回溯,在搜索HTML链接,爬取数据方面适用颇多;多用于解决连通性问题。
BFS广度优先搜索,空间需求较高,根据其搜索模式,便于求解最短路径问题,上文提到的Dijkstral和prim算法均基于其思想,因为是按层进行搜索,所以很容易求得最短路径。