数据结构课程设计相关代码(实验二)

实验二 隐式图的搜索问题
实验二代码如下:

#include <vector>
#include <list> 
#include <math.h>
#include <iostream>
using namespace std;
const int N = 3;		//数组边长大小
struct node {           //状态类
	int data[N][N];     //九宫数据
	int G, H, F;        //3个估价函数值
	node* parent;       //前继指针
	node() :G(0), H(0), F(0), parent(NULL) {}				//默认构造函数
};
class Astar {
public:
	Astar(int startmaze[N][N], int endmaze[N][N]);			//初始化Astatr
	list<node*> GetPath();									//获取全部路径
	void Print();											//显示最佳路径的每一步状态
private:
	bool isok();                                         //判断是否有解
	node* findPath();                                    //获取最佳路径
	vector<node*> getSurroundPoints(node* Sudoku) const; //获取0周围的可以移动获得的状态表
	bool isInList(list<node*>& list, node point);        //判断开启列表中是否包含某点
	bool isSame(node* p, node point);                    //判断两个9宫内数据是否相同
	node* getLeastFpoint();                              //从开启列表中返回 F 值最小的状态指针
	node* finallyload();                                 //在开启列表中寻找结束状态并返回,否则返回空
	node* upSudoku(node*, int, int) const;				 //返回给定状态0上移的状态指针
	node* downSudoku(node*, int, int) const;             //返回给定状态0下移的状态指针
	node* leftSudoku(node*, int, int) const;             //返回给定状态0左移的状态指针
	node* rightSudoku(node*, int, int) const;            //返回给定状态0右移的状态指针
	int GetG(node* Sudoku) { return Sudoku->parent == NULL ? 1 : Sudoku->parent->G + 1; }  //从初始状态到指定状态的移动代价(如果是初始节点,则其父节点是空)
	int GetH(node* Sudoku);								//从指定状态到目标状态的估算成本
	int GetF(node* Sudoku) { return GetH(Sudoku) + GetG(Sudoku); }      //G,H之和
private:
	node startSudoku;				//初始九宫
	node endSudoku;					//目标九宫
	list<node*> openList;			//开启列表
	list<node*> closeList;			//关闭列表
	list<node*> path;				//最佳路径
};
Astar::Astar(int startmaze[N][N], int endmaze[N][N]) {      //初始化初始九宫和目标九宫
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			startSudoku.data[i][j] = startmaze[i][j];
			endSudoku.data[i][j] = endmaze[i][j];
		}
	}
}
bool Astar::isok() {    //求出逆序对,判断是否有解
	int a[9], k = 0;
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++)
			a[k++] = startSudoku.data[i][j];
	int sum = 0;
	for (int i = 0; i < 9; i++)
		for (int j = i + 1; j < 9; j++)
			if (a[j] && a[i] && a[i] > a[j])
				sum++;
	return !(sum & 1);					//由于目标解为偶数,所以状态的逆序数为偶数才可行,交换空格,逆序数增幅为偶数,故初始节点和目标的节点的逆序数奇偶性相同
}
list<node*> Astar::GetPath() {          //根据路径链的头指针获取全部路径列表
	node* result = findPath();			//路径链的头指针
	while (result) {
		path.push_front(result);		//插入头部
		result = result->parent;
	}
			// 清空临时开闭列表,防止重复执行 GetPath 导致结果异常
	openList.clear();
	closeList.clear();
	return path;
}
void Astar::Print() {					//显示最佳路径的每一步状态
	GetPath();							//获取最佳路径
	if (isok()) {
		cout << "最优路径为:" << endl;
		for (auto i : path) {
			for (int j = 0; j < N; j++) {
				for (int k = 0; k < N; k++) {
					cout << i->data[j][k] << " ";
				}
				cout << endl;
			}
			cout << endl;
		}
	}
	else cout << "无解!\n";
}
node* Astar::finallyload() {					//在开启列表中寻找结束状态并返回,否则返回空
	for (auto p : openList)
		if (isSame(p, endSudoku))
			return p;
	return NULL;
}
node* Astar::findPath() {						//获取最佳路径
	node* p = &startSudoku;
	openList.push_back(p);						//置入初始状态,内外隔离
	while (!openList.empty()) {
		auto curPoint = getLeastFpoint();		//找到 F 值最小的点
		openList.remove(curPoint);				//从开启列表中删除
		closeList.push_back(curPoint);			//放到关闭列表
				//1,找到当前周围4个格中可以移动的格子
		auto surroundPoints = getSurroundPoints(curPoint);
		for (auto& target : surroundPoints)    //2,对某一个状态,如果它不在列表中,加入到开启列表,设置当状态为其父状态,计算 F 
			if (!isInList(openList, *target) && !isInList(closeList, *target)) {
				target->parent = curPoint;
				target->G = GetG(target);		//从父结点按规则移动的距离
				target->H = GetH(target);
				target->F = GetF(target);
				openList.push_back(target);
			}
			else {
				int tempG = GetG(target);
				if (tempG < target->G) {		//判断是否有更优秀的到达该结点的路线
					target->parent = curPoint;
					target->G = tempG;
					target->F = GetF(target);
				}
			}
		if (isInList(openList, endSudoku))						//如果目标状态在开启列表中,结束搜索
			return finallyload();
	}
	return NULL;
}
vector<node*> Astar::getSurroundPoints(node* Sudoku) const {	//获取0周围的可以移动获得的状态表
	vector<node*> test;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (Sudoku->data[i][j] == 0) {
				if (i != 0)test.push_back(upSudoku(Sudoku, i, j));
				if (i != N - 1)test.push_back(downSudoku(Sudoku, i, j));
				if (j != 0)test.push_back(leftSudoku(Sudoku, i, j));
				if (j != N - 1)test.push_back(rightSudoku(Sudoku, i, j));
				return test;
			}
		}
	}
	return test;
}
bool Astar::isSame(node* p, node point) {					//判断两个9宫内数据是否相同
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			if (p->data[i][j] != point.data[i][j])
				return false;
	return true;
}
bool Astar::isInList(list<node*>& list, node point) {		//判断开启列表中是否包含某点
	for (auto p : list)
		if (isSame(p, point))
			return true;
	return false;
}
node* Astar::getLeastFpoint() {								//从开启列表中返回 F 值最小的状态指针
	if (!openList.empty()) {
		auto resPoint = openList.front();
		for (auto& point : openList)
			if (point->F < resPoint->F)
				resPoint = point;
		return resPoint;
	}
	return NULL;
}
node* Astar::upSudoku(node* Sudoku, int a, int b) const {   //返回给定状态0上移的状态指针
	node* p = new(node);
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			p->data[i][j] = Sudoku->data[i][j];				//将给定状态复制
	p->data[a][b] = p->data[a - 1][b];						//交换0和0上面的数据
	p->data[a - 1][b] = 0;
	return p;
}
node* Astar::downSudoku(node* Sudoku, int a, int b) const {  //返回给定状态0下移的状态指针
	node* p = new(node);
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			p->data[i][j] = Sudoku->data[i][j];				//将给定状态复制
	p->data[a][b] = p->data[a + 1][b];						//交换0和0下面的数据
	p->data[a + 1][b] = 0;
	return p;
}
node* Astar::leftSudoku(node* Sudoku, int a, int b) const {  //返回给定状态0左移的状态指针
	node* p = new(node);
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			p->data[i][j] = Sudoku->data[i][j];				//将给定状态复制
	p->data[a][b] = p->data[a][b - 1];						//交换0和0左面的数据
	p->data[a][b - 1] = 0;
	return p;
}
node* Astar::rightSudoku(node* Sudoku, int a, int b) const { //返回给定状态0左移的状态指针
	node* p = new(node);
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			p->data[i][j] = Sudoku->data[i][j];				//将给定状态复制
	p->data[a][b] = p->data[a][b + 1];						//交换0和0右面的数据
	p->data[a][b + 1] = 0;
	return p;
}
int Astar::GetH(node* Sudoku) {				//从指定状态到目标状态的估算成本
	int h = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (Sudoku->data[i][j] != 0)
				h += abs(Sudoku->data[i][j] / N - i) + abs(Sudoku->data[i][j] % N - j);
		}
	}
	return h;								//返回所有数字距离它目标位置的最短距离之和
}
int main() {
	int startmaze[N][N] = { {1,2,3},{4,5,6},{7,8,0} };  //初始九宫数据
	int endmaze[N][N] = { {0,1,2},{3,4,5},{6,7,8} };    //目标九宫数据
	Astar astar(startmaze, endmaze);
	astar.Print();										//输出最佳路径
	system("pause");
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值