Astar算法

A*算法

由于最短路径需要比较每一条可能的路径,所以基本上要遍历所有的节点,由此产生的开销实在是太大。于是我们就有了A* 算法这种在大方向上朝目标前进,在小范围内求最优路径的算法。A* 算法并不是找出最优路径,而是找一个相对来说比较理想的路径。

A* 算法的实现

Astar.h

#pragma once
#include 
#include 
#define COST 10
using namespace std;
struct Point {
	int x;
	int y;
	int G, H, F;
	Point* parent;
};
list Path( Point* start, Point* end);
Point* newPoint(const int x,const int y);//申请新节点
void initAstar(int* maze,const int row,const int col);
void clearAstar();


Astar.cpp

#include 
#include "Astar.h"
static int* Maze;//迷宫对应的二维数组
static int row;//行
static int col;//列
static list openList;//可能要走的路径
static list closeList;//已经走过的路径

static Point* getPath( Point* start,  Point* end);
static Point* isInlist( list& L,  Point* P);//判断坐标是否在列表中
static Point* getLeast();//得到F值最小的点
static vector getSurrondPoint( Point* p);//得到附近可用的坐标
static bool isCanReach(Point* p, Point* target);//节点是否能到达
static int getG(Point* p);
static int getH(Point* p, Point* end);
static int getF(Point* p);

void initAstar(int* maze, const int r, const int l) {
	Maze = maze;
	row = r;
	col = l;
}
Point* newPoint(const int x, const int y) {
	Point* p = new Point;
	memset(p, 0, sizeof(Point));
	p->x = x;
	p->y = y;
	return p;
}
list Path(Point* start, Point* end) {
	list L;
	Point* result = getPath(start, end);
	while (result) {
		L.push_front(result);
		result = result->parent;
	}
	return L;
}
void clearAstar() {
	Maze = NULL;
	row = col = 0;
	list::const_iterator it = openList.begin();
	while (it != openList.end()) {
		delete* it;
		it = openList.erase(it);
	}
	it = closeList.begin();
	while (it != closeList.end()) {
		delete* it;
		it = closeList.erase(it);
	}
}

static Point* getPath( Point* start,  Point* end) {
	openList.push_back(newPoint(start->x, start->y));//首先将起点放入可走的列表,注意内外隔离
	vector surrondPoint;
	Point* leastPoint = NULL;//F值最小的点
	Point* exist = NULL;//是否存在于可行列表中
	vector::iterator it = surrondPoint.begin();
	while (!openList.empty()) {//如果可行列表中还有元素
		leastPoint = getLeast();
		openList.remove(leastPoint);//从可行列表移动到关闭列表
		closeList.push_back(leastPoint);
		surrondPoint = getSurrondPoint(leastPoint);//找到周围的可行坐标
		it = surrondPoint.begin();
		while (it != surrondPoint.end()) {
			exist = isInlist(openList, *it);
			if (exist ==NULL) {//如果不在可行列表中
				(*it)->G = getG(*it);
				(*it)->H = getH(*it,end);
				(*it)->F = getF(*it);
				(*it)->parent = leastPoint;
				openList.push_back(*it);
			}
			else {//在可行列表中
				if (exist->G > getG(*it)) {//原路径开销更大
					exist->G = getG(*it);
					exist->F = getF(exist);
					exist->parent = leastPoint;//更新路径
				}
				delete *it;//没有存在列表的元素要自己负责析构
			}
			++it;
		}
		surrondPoint.clear();
		Point* result = isInlist(openList, end);
		if (result) {
			return result;
		}
	}
	return NULL;//没有找到路径
}

static Point* isInlist( list& L,  Point* p) {
	if (L.empty()) {
		return NULL;
	}
	list::const_iterator it = L.begin();
	while (it != L.end()) {
		if ((*it)->x == p->x && (*it)->y == p->y) {
			return *it;
		}
		++it;
	}
	return NULL;
}
static Point* getLeast() {
	if (openList.empty()) {
		return NULL;
	}
	list::iterator it = openList.begin();
	Point* result = *it;
	while (it != openList.end()) {
		if ((*it)->F < result->F) {
			result = *it;
		}
		++it;
	}
	return result;
}
static vectorgetSurrondPoint( Point* p) {
	vectorv;
	for (int i = p->x - 1; i <= p->x + 1; ++i) {
		for (int j = p->y - 1; j <= p->y + 1; ++j) {
			Point* target = newPoint(i, j);
			if (isCanReach(p, target)) {//可以抵达
				v.push_back(target);
			}
			else {
				delete target;//不可以抵达的坐标要及时析构
			}
		}
	}
	return v;
}
static bool isCanReach(Point* p, Point* target) {
	if (target->x<0 || target->x>row - 1 || target->y<0 || target->y>col - 1
		|| Maze[target->x * col + target->y] == 1 || Maze[target->x * col + target->y] == 2
		|| (target->x == p->x && target->y == p->y)|| isInlist(closeList, target)) {
		return false;
	}
	if (abs(p->x - target->x + p->y - target->y) == 1) {
		return true;
	}
	return false;
}
static int getG( Point* p) {
	return p->parent ? p->parent->G + COST : COST;
}
static int getH(Point* p, Point* end) {
	//直接求那条斜线的长度
	return static_cast(sqrt(static_cast(end->x - p->x * end->x - p->x) +
		static_cast(end->y - p->y * end->y - p->y)))*COST;
}
static int getF(Point* p) {
	return p->G + p->H;
}
main.cpp
 
#include
#include
#include "Astar.h"
using namespace std;
int map[13][13] = {//二维数组在内存顺序存储的
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
{ 0, 1, 0, 1, 0, 1, 2, 1, 0, 1, 0, 1, 0, },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
{ 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, },
{ 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, },
{ 2, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 2, },
{ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, },
{ 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }
};
void AstarTest();
int main(void) {
	AstarTest();
	return 0;
}
void AstarTest() {
	Point* start = newPoint(12, 4);
	Point* end = newPoint(0, 0);
	initAstar(&map[0][0], 13, 13);
	listL = Path(start, end);
	for (auto it = L.begin(); it != L.end(); ++it) {
		printf("(%d,%d)\n", (*it)->x, (*it)->y);
		//Sleep(1000);
	}
	clearAstar();//清理内存
	delete start;
	delete end;
}

总结

我们一定要记住内存的释放,在我们这个算法中,多处程序都可能会造成内存泄漏,如果我们不再使用他,并且并没有将它交给其他接口管理,那我们一定要手动释放它。还有救是要注意内外的隔离,主函数内的内存要由主函数自己来析构,所以接口中应该要为自己分配新的内存。

你可能感兴趣的:(数据结构,算法,c++,开发语言)