C++深度优先和广度优先的实现

前言

本文主要讲的深度优先算法和广度优先算法的区别,其中深度优先有两种实现方式,一种是递归法,另一种是非递归(栈实现),而广度优先就是队列的实现;
后面还会以图形表述栈实现和队列实现;且用到了图形库easyx;

源码如下:

main.cpp

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
#include <iostream>
#include<vector>
#include<windows.h>
#include"Draw.h"
#include"DFS.h"
#include"BFS.h"
#include"Search.h"
using namespace std;
vector<vector<int>> map =
{
{0,0,1,0,1,0,1},
{1,0,0,0,0,0,1},
{1,0,1,1,1,0,0},
{1,0,0,0,1,1,1},
{0,0,1,0,0,0,1},
{1,0,1,0,1,0,0},
{1,0,1,1,1,0,1},
};
//检查数据的合法性
bool check(int x, int y)
{
//所走的路径不能越界,也不能走到地图为1的地方。
if ((y < 0 || x<0) || y >= map.size() ||x>=map[y].size() || map[y][x] == 1)
{
return false;
}
return true;
}
//测试图形库是否能正常运行
void test()
{
Draw draw(600, map);
draw.updata();
}
//深度优先算法
void test1()
{
DFS dfs(check);
Draw draw(600, map);
Pos start{ 0,0 };
Pos end{ 1,6 };
draw.level[end.y][end.x] = Draw::end;//设置终点位置
draw.updata();
const auto& path = dfs.recursive(start,end);//开始寻路,路径找完后用vector保存了
for (const auto& e : path)
{
draw.level[e.y][e.x] = Draw::visit;//路径设置为visit。注意x,y不要写反了
draw.updata();
Sleep(500);
}
}
//广度优先算法
void test2()
{
BFS bfs(check);
Draw draw(600, map);
Pos start{ 1,1 };
Pos end{ 3,0 };
draw.level[end.y][end.x] = Draw::end;
draw.updata();
const auto& path = bfs.queue(start, end);
for (const auto& e : path)
{
draw.level[e.y][e.x] = Draw::visit;
draw.updata();
Sleep(500);
}

}
int main()
{
//test();
//test1();
//test2();
system("pause");
return 0;
}

Draw.h

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
110
111
112
113
114
115
116
117
118
119
120
#pragma once
#include<vector>
#include<easyx.h>
#include<string>
#include<iostream>

//区别名
using vec2 = std::vector<std::vector<int>>;
//绘制地图的类
class Draw
{
public:
Draw(int&& length, vec2& map) :length(length)
{
this->level = map;
this->size = length / level.size();
initgraph(length, length, EW_SHOWCONSOLE);
}
~Draw()
{
closegraph();
}
enum {
road=0,//空地
wall,//墙
visit,//走过的路
end,//终点
};
//绘制的地图。
vec2 level;
//游戏更新
void updata()
{
draw();
test();
}
private:
int length; //宽度和高度
int size; //每个瓦片的大小
//绘制地图
void draw()
{
BeginBatchDraw();//开始批量画图
cleardevice();//把之前的先清除
for (size_t i = 0; i < level.size(); i++)
{
for (size_t j = 0; j < level[i].size(); j++)
{
if (level[i][j] == road)
{
setfillcolor(RGB(0xdd, 0xdd, 0xdd));//设置路的颜色
}
else if (level[i][j] == wall)
{
setfillcolor(RGB(0x33, 0x33, 0xcc));
}
else if (level[i][j] == visit)
{
setfillcolor(RGB(0x33, 0xcc, 0x33));
}
else if (level[i][j] == end)
{
setfillcolor(RGB(0xff, 0x33, 0x33));
}
rect(j, i);//绘制瓦片,j代表x,i代表y。
/*(0,0)----------▷ x的正方向
|
|
|
|
▽ y的正方向
图形库窗口的坐标*/
}
}
EndBatchDraw();
}
//绘制文本
void test()
{
system("cls");//清屏
std::string str="";
for (size_t i = 0; i < level.size(); i++)
{
for (size_t j = 0; j < level[i].size(); j++)
{
if (level[i][j] == road)
{
str += " ";//设置路的标识符
}
else if (level[i][j] == wall)
{
str += "+ ";//墙
}
else if (level[i][j] == visit)
{
str += ". ";//走过的路
}
else if (level[i][j] == end)
{
str += "= ";//终点
}
}
str += '\n';
}
std::cout << str << std::endl;
}
//绘制瓦片
void rect(int x, int y)
{
fillrectangle(x * size, y * size, (x + 1) * size, (y + 1) * size);
/* void fillrectangle(
int left,
int top,
int right,
int bottom
); */

}
};

Search.h

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
#pragma once
#include<functional>
#include<vector>
struct Pos
{
int x;
int y;
Pos(int x=0, int y=0) :x(x), y(y) {}
};
class Search
{
protected:
using Function = std::function<bool(int, int)>;
public:
Search(Function fn) :fn(fn) {}
protected:

//通过函数适配器调用外部规则,对数据进行判断;
Function fn;
//创建一个vector保存路径
std::vector<Pos> path;
//判断这条路是否走过
bool isVisited(Pos pos)
{
for (const auto& e : path)
{
if (pos.x == e.x && pos.y == e.y)
{
return true;
}
}
return false;
}
//判断下次移动是否合法
bool isValid(Pos pos)
{
return fn(pos.x, pos.y) && !isVisited(pos);//fn调用外部规则check
}
};

DFS.h

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
#pragma once
#include "Search.h"
//深度优先算法
class DFS : public Search
{
public:
DFS(std::function<bool(int, int)> fn):Search(fn)//构造子类的时候,需要初始化父类。
{

}
/*start 起点坐标
end 终点坐标*/
//递归法
std::vector<Pos> recursive(Pos start, Pos end)
{
this->end = end;
path.push_back(start);
_recursive(start);
return path;
}
//非递归法(栈实现)
std::vector<Pos> stack(Pos start, Pos end)
{
static Pos dir[4] = {
{0,1},//y+1向下
{1,0},//x+1向右
{-1,0},//x-1向左
{0,-1},//y-1向上
};
std::stack<Pos> st;
st.push(start);
while (!st.empty())
{
auto now = st.top();
st.pop();
for (size_t i = 0; i < 4; i++)
{
//准备移动的路径
Pos move(now.x + dir[i].x, now.y + dir[i].y);
//判断是否能移动
if (isValid(move))
{
st.push(move);
path.push_back(move);
//判断是否到达终点
if (move.x == end.x && move.y == end.y)
{
return path;
}
}
}
}
return path;
}
private:
bool is_end=false;//递归需要的标志位,默认位false
Pos end; //保存终点坐标
void _recursive(Pos now)
{
static Pos dir[4] = {
{0,1},//y+1向下
{1,0},//x+1向右
{-1,0},//x-1向左
{0,-1},//y-1向上
};
//判断是否到达终点
if (now.x == end.x && now.y == end.y)
{
is_end = true;//找到终点标志位置1
return;
}
//循环遍历下右左上4个方向
for (int i = 0; i < 4; i++)
{
//准备移动的路径
Pos move(now.x + dir[i].x, now.y + dir[i].y);
//判断能否移动
if (!is_end && isValid(move))
{
path.push_back(move);//保存走过的路径
_recursive(move);
}
}
}
};

BFS.h

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
#pragma once
#include "Search.h"
class BFS :public Search
{
public:
BFS(Function fn):Search(fn)
{
}
std::vector<Pos> queue(Pos start, Pos end)
{
static Pos dir[4] = {
{0,1},//y+1向下
{1,0},//x+1向右
{-1,0},//x-1向左
{0,-1},//y-1向上
};
std::queue<Pos> qu;
qu.push(start);
while (!qu.empty())
{
auto now = qu.front();
qu.pop();
for (size_t i = 0; i < 4; i++)
{
Pos move(now.x + dir[i].x, now.y + dir[i].y);
if (isValid(move))
{
qu.push(move);
path.push_back(move);
if (move.x == end.x && move.y == end.y)
{
return path;
}
}
}
}
return path;
}
};

测试结果

递归实现:
在这里插入图片描述

深度优先(栈实现):
在这里插入图片描述

广度优先(队列实现)
在这里插入图片描述

深度优先(栈实现)和广度优先(队列实现)图解

深度优先:
在这里插入图片描述

广度优先:
在这里插入图片描述


C++深度优先和广度优先的实现
https://howl144.github.io/2021/01/27/00001. C++深度优先和广度优先的实现/
Author
Deng Ye
Posted on
January 27, 2021
Licensed under