C++控制台迷宫生成(DFS)和迷宫求解(A*)


前言

提示:VS2019


提示:以下是本篇文章正文内容

一、头文件介绍

1.向量

#include<vector>

遍历方法

非自定义数据类型
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
void print(int val) {
    cout << val << '\t';
}
void test01() {
    vector<int> v;
    v.push_back(10);//尾部插入
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    //方法一:
    for_each(v.begin(), v.end(), print);
    cout << endl;
    //方法二:
    for (vector<int>::iterator it = v.begin(); it < v.end(); it++) {
        cout << *it << '\t';
    }
    cout << endl;
    //方法三:
    vector<int>::iterator pbegin = v.begin();
    vector<int>::iterator pend = v.end();
    while (pbegin != pend) {
        cout << *pbegin << '\t';
        pbegin++;
    }
    cout << endl;
}


int main()
{
    test01();
    return 0;
}

自定义数据类型
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class Person {
public:
	int age;
	string name;
	Person(int age, string name) {
		this->age = age;
		this->name = name;
	}
};
void test01() {
	vector<Person> v;
	Person p1(10, "a");
	Person p2(20, "b");
	Person p3(30, "c");
	v.push_back(p1);
	v.push_back(p2);
	v.push_back(p3);
	for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
		cout << (*it).name << '\t' << (*it).age << endl;
	}
}
void test02() {
	vector<Person*> v;
	Person p1(10, "a");
	Person p2(20, "b");
	Person p3(30, "c");
	v.push_back(&p1);
	v.push_back(&p2);
	v.push_back(&p3);
	for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) {
		cout << (*it)->name << '\t' << (*it)->age << endl;
	}
}
int main() {
	//test01();
	test02();
	return 0;
}
二维向量
#include<iostream>
#include<vector>
using namespace std;
void test01() {
	vector<vector<int>> v;
	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	for (int i = 0; i < 4;i++) {
		v1.push_back(i);
		v2.push_back(i + 4);
		v3.push_back(i + 8);
	}
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);
	for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++) {
		for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) {
			cout << *vit << '\t';
		}
		cout << endl;
	}

}
int main() {
	test01();
	return 0;
}

2.algorithm

#include<algorithm>

find

#include<vector>
#include <iostream>
#include<algorithm>
#include<string>
using namespace std;
class Person {
public:
	string m_Name;
	int m_Age;
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	bool operator==(const Person& p) {
		return (this->m_Age == p.m_Age) && (this->m_Name == p.m_Name);
	}
	
};
//自定义数据类型的一元谓词实现
class FindOlder {
public:
	bool operator()(const Person& p) 
	{
		return p.m_Age > 10;
	}
};
//非自定义数据类型的一元谓词实现
class CountGreater {
public:
	bool operator()(int val) {
		return val > 5;
	}
};
void test01()
{
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	v.push_back(9);
	//使用find查找
	vector<int>::iterator it = find(v.begin(), v.end(), 5);
	if (it == v.end()) 
	{
		cout << "没找着" << endl;
	}
	else 
	{
		cout << "找到了:" << *it << endl;
	}
	vector<int>::iterator it_ = adjacent_find(v.begin(), v.end());
	if (it_ == v.end()) {
		cout << "meiyou" << endl;
	}
	else {
		cout << "you" << ":" << *it_ << endl;
	}
}
void test02() {
	vector<Person> p;
	Person p1("张三", 10);
	Person p2("李四", 11);
	Person p3("二麻子", 12);
	Person p4("张三", 10);
	p.push_back(p1);
	p.push_back(p2);
	p.push_back(p3);
	p.push_back(p4);
	vector<Person>::iterator it_01 = find(p.begin(), p.end(), p1);
	if (it_01 == p.end()) {
		cout << "没找着" << endl;
	}
	else {
		cout << "找到了:" << it_01->m_Name << ":" << it_01->m_Age << endl;
	}
	vector<Person>::iterator it_02 = find_if(p.begin(), p.end(), FindOlder());
	if (it_02 == p.end()) {
		cout << "wu" << endl;
	}
	else {
		cout << "you:" << (*it_02).m_Name << ":" << it_02->m_Age << endl;
	}
}
void test03() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}
	v.push_back(9);
	bool b;
	b = binary_search(v.begin(), v.end(), 5);
	//返回一个布尔类型的数据,只能用于有序数列
	if (b) {
		cout << "you" << endl;
	}
	else {
		cout << "wu" << endl;
	}
	int num = count(v.begin(), v.end(), 9);
	cout << "v有几个9?" << "有" << num << "个" << endl;
	int nums = count_if(v.begin(), v.end(), CountGreater());
	cout << "大于5的数有" << nums << "个" << endl;
}
//_Pred:谓词
int main() {
	//test01();
	//test02();
	test03();
	return 0;
}

transform

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class MyCompare {
public:
	bool operator()(int val1,int val2) {
		return val1 > val2;
	}
};
class MyTransform {
public:
	int operator()(int val) {
		return val + 10;
	}
};
class MyPrint {
public:
	void operator()(int val) {
		cout << val << '\t';
	}
};
void test01() {
	vector<int>v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}
	vector<int>vTarget;
	vTarget.resize(v.size());
	//将前两个参数指定的数据,通过最后一个参数指定的规则,复制到从第三个指定的位置开辟的空间
	transform(v.begin(), v.end(), vTarget.begin(), MyTransform());
	for_each(vTarget.begin(), vTarget.end(), MyPrint());
	cout << endl;
}
int main() {
	test01();
	return 0;
}

交并差

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
void print(int val) {
	cout << val << '\t';
}
void test01() {
	vector<int> v1;
	vector<int> v2;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);
		v2.push_back(i + 3);
	}
	vector<int> vTarget1;
	vTarget1.resize(min(v1.size(), v2.size()));
	cout << "交集:" << endl;
	vector<int>::iterator itEnd1 = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget1.begin());
	for_each(vTarget1.begin(), itEnd1, print);
	cout << endl;
	vector<int> vTarget2;
	vTarget2.resize(v1.size() + v2.size());
	vector<int>::iterator itEnd2 = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget2.begin());
	cout << "并集:" << endl;
	for_each(vTarget2.begin(),itEnd2, print);
	cout << endl;
	vector<int> vTarget3;
	vTarget3.resize(v1.size());
	cout << "v1与v2的差集:" << endl;
	vector<int>::iterator itEnd3 = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget3.begin());
	for_each(vTarget3.begin(), itEnd3, print);
	cout << endl;
	vector<int> vTarget4;
	vTarget4.resize(v2.size());
	cout << "v2与v1的差集:" << endl;
	vector<int>::iterator itEnd4 = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget4.begin());
	for_each(vTarget4.begin(), itEnd4, print);
}
int main() {
	test01();
	return 0;
}

numeric(accumulate、fill)

#include<iostream>
#include<numeric>
#include<vector>
#include<algorithm>
using namespace std;
void print(int val) {
	cout << val << '\t';
}
void test01() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}
	//初始和设为0,包含在numeric中
	int sum = accumulate(v.begin(), v.end(), 0);
	cout << "sum:" << sum << endl;
	v.resize(20);
	//使用一个数据,填满vector
	fill(find(v.begin(), v.end(), 9), v.end(), 13);
	for_each(v.begin(), v.end(), print);
	cout << endl;
}
int main() {
	test01();
	return 0;
}

其他操作(random_shuffle、sort、merge、replace、replace_if、unique、reverse)

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class print {
public:
	void operator()(int val) {
		cout << val << '\t';
	}
};
class Descend {
public:
	bool operator()(int val1,int val2) {
		return val1 > val2;
	}
};
class EnterOne {
public:
	bool operator()(int val) {
		return val > 98;
	}
};
void test01() {
	vector<int> v;
	for (int i = 10; i > 0; i--) {
		v.push_back(i);
	}
	sort(v.begin(), v.end());
	cout << "非降序排列:" << endl;
	for_each(v.begin(), v.end(),print());
	cout << endl;
	cout << "置乱:" << endl;
	random_shuffle(v.begin(), v.end());
	for_each(v.begin(), v.end(), print());
	cout << endl;
	cout << "降序排列:" << endl;
	sort(v.begin(), v.end(), Descend());
	for_each(v.begin(), v.end(), print());
	cout << endl;
	vector<int> v_;
	for (int i = 5; i < 10; i++) {
		v_.push_back(i);
	}
	sort(v.begin(), v.end());
	vector<int>vTarget;
	vTarget.resize(v.size() + v_.size());
	merge(v.begin(), v.end(), v_.begin(), v_.end(), vTarget.begin());
	//_OutIt _Dest:输出目标,merge第五个参数位置
	cout << "合并后的vTarget:" << endl;
	for_each(vTarget.begin(), vTarget.end(), print());
	cout << endl;
	sort(v.begin(), v.end(), Descend());
	sort(v_.begin(), v_.end(), Descend());
	merge(v.begin(), v.end(), v_.begin(), v_.end(), vTarget.begin(), Descend());
	cout << "降序排列:" << endl;
	for_each(vTarget.begin(), vTarget.end(), print());
	cout << endl;
	cout << "去重:" << endl;
	vTarget.erase(unique(vTarget.begin(), vTarget.end()), vTarget.end());
	//unique:将重复元素放置数组尾部,并返回重复值的第一个重复值的迭代器
	for_each(vTarget.begin(), vTarget.end(), print());
	cout << endl;
	cout << "反转后:" << endl;
	reverse(vTarget.begin(), vTarget.end());
	for_each(vTarget.begin(), vTarget.end(), print());
}
void test02() {
	vector<int> v;
	for (int i = 0; i < 6; i++) {
		v.push_back(i);
		v.push_back(i);
	}
	v.push_back(99);
	v.push_back(90);
	v.push_back(99);
	replace(v.begin(), v.end(), 5, 100);
	for_each(v.begin(), v.end(), print());
	cout << endl;
	replace_if(v.begin(), v.end(), EnterOne(), 100);
	for_each(v.begin(), v.end(), print());
}
void test03() {
	vector<int> v1;
	vector<int> v2;
	for (int i = 1; i < 10; i++) {
		v1.push_back(i);
		v2.push_back(i + 100);
	}
	cout << "交换前:" << endl;
	for_each(v1.begin(), v1.end(), print());
	cout << endl;
	for_each(v2.begin(), v2.end(), print());
	cout << endl;
	swap(v1, v2);
	cout << "交换后:" << endl;
	for_each(v1.begin(), v1.end(), print());
	cout << endl;
	for_each(v2.begin(), v2.end(), print());
}
int main() {
	//test01();
	//test02();
	test03();
	return 0;
}

二、动态分配二维数组

#include<iostream>
using namespace std;
int main() {
	int** p;
	int a, b;
	cout << "请输入行列:" << endl;
	cin >> a >> b;

	//全部填充为零,每一维存储一个一级指针,之后为每一个一级指针对应一个数组
	p = new int* [a]{ 0 };
	for (int i = 0; i < a; i++) {
		p[i] = new int[b]{ 0 };
	}
	for (int i = 0; i < a; i++) {
		for (int j = 0; j < b; j++) {
			cout << p[i][j] << " ";
		}
		cout << endl;
	}
	//自己开辟的空间,自己释放
	for (int i = 0; i < a; i++){
		delete[] p[i];
	}
	delete[] p;
	return 0;
}

或者使用智能指针实现(不需要自己释放)
https://blog.csdn.net/zy19940906/article/details/50470087

三、pair

这样pair<int,int> a

#include <iostream>
using namespace std;
int main()
{
    int num;
    string name;
    //初始化
    pair<int, string> a(1, "a");

    //拷贝构造
    pair<int, string> b(a);

    //运算符重载
    pair<int, string> c;
    c = b;

    //通过.firs,.second分别访问第一二个元素
    cout << c.first << " " << c.second << endl;
    return 0;
}

四、思路

1.迷宫生成:

采用深度优先(DFS)生成迷宫
https://blog.csdn.net/jjwwwww/article/details/82872922

2.迷宫求解:

使用简单的A*算法求解迷宫
https://blog.csdn.net/qq_36949278/article/details/109255204

五、代码实现

myMaze.cpp

#include "Maze.h"
/*
	根据深度优先遍历生成迷宫
	并求解
*/

int main()
{
	bool jixu = true;
	int a = 1;
	while (jixu) {
		switch (a) {
		case 1: {
			cout << "请输入迷宫的行和列:" << endl;
			int row, col;
			cin >> row >> col;
			Maze maze(row, col);
			break;
		}
		case 0:
			jixu = false;
		default:
			break;
		}
	}
    return 0;
}

Maze.h

#pragma once
#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
#include<cmath>
using namespace std;
class Maze {
private:
	int** map;
	vector < pair<int, int >> direction = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };//控制方向
	pair<int, int> size;//迷宫的尺寸
	
	void setStartPoint();//开始的点
	bool isInRange(int x, int y);//越界判断
	bool dig(int x, int y);//挖!
	int dist(pair<int, int>);//计算F和
	bool distance(pair<int, int> a,pair<int,int> b);//判断F和大小
	void setPoint(int i, int j,int d);
	int getPoint(int i, int j);
	//冒泡排序
	void bubbleSort(int lo, int hi);
	bool bubble(int lo, int hi);
	//stack<pair<int, int>> path;
	vector<pair<int, int>> open;
	vector<pair<int, int>> close;
	pair<int, int> exit;//迷宫结束的位置
	pair<int, int> start;//迷宫开始的位置
	enum {
		Wall = 0,
		Road = 1,
		Jam = -1,
		Sol = -2
	};
public:
	Maze(int row, int col);//初始化迷宫

	~Maze();
	

	void createMaze();//创建迷宫

	void print();//打印迷宫

	bool solveMaze();//生成路径

	void print_Path();//打印路径
};

Maze.cpp

#include "Maze.h"
Maze::Maze(int row, int col)
{
	//行,列必须是奇数
	if (row % 2 == 0)
	{
		row++;
	}
	if (col % 2 == 0)
	{
		col++;
	}

	//初始化size
	size.first = row;
	size.second = col;
	
	//初始化地图map
	map = new int* [size.first]{ 0 };
	for (int i = 0; i < size.first; i++) {
		map[i] = new int[size.second]{ 0 };
	}
	//做地图
	createMaze();
}
void Maze::createMaze() 
{
	setStartPoint();
	dig(start.first, start.second);
	//设置出口
	exit = { size.first - 1, size.second};
	setPoint(size.first - 1, size.second, 1);
	print();
	solveMaze();
	cout << endl;
	print_Path();
}

//设置入口和起始点
void Maze::setStartPoint() 
{
	//在四周随便选面墙作为起始点
	//只在写入map时,认为计数从0开始,所以这里b,c都只能是偶数
	srand((unsigned)time(NULL));
	int a = rand() % 4 + 1;
	int b = rand() % size.first;
	int c = rand() % size.second;

	if (b < 2) {
		b += 2;
	}
	if (b % 2 == 1) {
		b++;
	}

	if (c < 2){
		c += 2;
	}
	if (c % 2 == 1){
		c++;
	}

	if (a == 1)
	{
		start.first = 2;
		start.second = c;
		map[0][c - 1] = Road;//设置入口后面的墙是路,以下相同
	}
	if (a == 2)
	{
		start.first = size.first - 1;
		start.second = c;
		map[size.first - 1][c - 1] = Road;
	}
	if (a == 3)
	{
		start.first = b;
		start.second = 2;
		map[b - 1][0] = Road;
	}
	if (a == 4)
	{
		start.first = b;
		start.second = size.second - 1;
		map[b - 1][size.second - 1] = Road;
	}
}
//判断节点是否合法
bool Maze::isInRange(int x, int y)
{
	if (x <= 1 || x >= size.first) {
		return false;
	}
	if (y <= 1 || y >= size.second) {
		return false;
	}
	return true;
}

//
bool Maze::dig(int x, int y)
{
	setPoint(x, y, 1);
	//random_shuffle:STL中的函数,用来对一个元素序列进行重新排序(随机的)
	random_shuffle(direction.begin(), direction.end());
	for (int i = 0; i < 4; i++) {
		int temp_X = x + 2 * direction[i].first;
		int temp_Y = y + 2 * direction[i].second;
		if (isInRange(temp_X, temp_Y) && (!getPoint(temp_X, temp_Y)))
		{
			//移动方向后位置合法
			setPoint(x + direction[i].first, y + direction[i].second, Road);
			//print();
			//cout << endl;
			if (!dig(temp_X, temp_Y)) {
				continue;
			}
		}
	}
	//四个方向都没有未标记方块
	if (x == start.first && y == start.second) 
	{
		return true;//栈空返回true,完成迷宫生成
	}
	else 
	{
		return false;//栈非空返回false,返回上一层
	}
}

//打印地图
void Maze::print()
{
	for (int i = 0; i < size.first; i++) {
		for (int j = 0; j < size.second; j++) {
			cout << ((map[i][j] > 0) ? "  " : "■");
		}
		cout << endl;
	}
	cout << endl;
}

//打印路径
void Maze::print_Path() 
{
	for (int i = 1; i <= size.first; i++) {
		for (int j = 1; j <= size.second; j++) {
			switch (getPoint(i, j)) {
			case Wall:
				cout << "■";
				break;
			case Sol:
				cout << "□";
				break;
			case Jam:
			case Road:
			default:
				cout << "  ";
				break;
			}
		}
		cout << endl;
	}
	cout << endl;
}

//计算F和
int Maze::dist(pair<int, int> a) 
{
	return abs(exit.first - a.first + exit.second - a.second) +
		close.size();
}

//采用A*寻找迷宫的解
//计算F和采用升序排列
bool Maze::distance(pair<int, int> a,pair<int, int> b)
{
	int val1 = dist(a);
	int val2 = dist(b);
	return val1 < val2;
}

bool Maze::solveMaze() 
{
	pair<int, int> temp = start;//用于解迷宫
	while(true){
		setPoint(temp.first, temp.second, Sol);
		close.push_back(temp);
		if (abs(exit.first - temp.first + exit.second - temp.second) == 1) 
		{
			break;
		}
		int current_x, current_y;
		current_x = temp.first;
		current_y = temp.second;
		
		for (int i = 0; i < 4; i++) 
		{
			//如若节点周围是路,则入open
			if (isInRange(current_x + direction[i].first, current_y + direction[i].second) 
				&& (getPoint(current_x + direction[i].first, current_y + direction[i].second) == Road)
				//&&((current_x + direction[i].first != start.first)&&(current_y + direction[i].second != start.second))
				) 
			{
				open.push_back({ current_x + direction[i].first, current_y + direction[i].second });
			}
		}
		if (open.empty()) {
			break;
		}
		bubbleSort(0, open.size());
		temp = open.back();
		open.pop_back();
	}
	return true;
}

//冒泡排序,选择路径
void Maze::bubbleSort(int lo, int hi) 
{
	while (!bubble(lo, hi--));
}
bool Maze::bubble(int lo, int hi) 
{
	bool sorted = true;
	while (++lo < hi) 
	{
		if (distance(open[lo - 1], open[lo])) 
		{
			sorted = false;
			swap(open[lo - 1], open[lo]);
		}
	}
	return sorted;
}

//设置地图上某个点
void Maze::setPoint(int i, int j, int d)
{
	map[i - 1][j - 1] = d;
};

//返回地图上某个点
int Maze::getPoint(int i, int j)
{
	return map[i - 1][j - 1];
};

Maze::~Maze() {

	//释放地图
	for (int i = 0; i < size.first; i++)
	{
		delete[] map[i];
	}
	delete[] map;
}

总结

提示:注意pair难以通过STL中自带的sort进行自定义谓词的特殊排序,不要这样做,不如自己重写一个排序方案。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值