一个小笔记(5):A*算法
A-Star算法是一种静态路网中求解最短路径最有效的直接搜索方法
其实百科有
咳咳,直接上代码。各种注释也算是有助理解了,毕竟这还是抄的~
// A*寻路算法.cpp : 定义控制台应用程序的入口点。
// Win32控制台程序
#include
<math.h>
#include
<list>
using
namespace
std;
/*
把地图当成一个个的格子
公式:F=G+H
F:相对路径长度
G:从起点沿着产生的路径,移动到指定点的耗费(路径长度)
H:预估值,从指定的格子移动到终点格子的预计耗费
使用两个表来保存相关数据
启动列表:有可能将要经过的点存到启动列表
关闭列表:不会再被遍历的点
步骤
1、将起点格子加入启动列表中
2、在启动列表中查找权值(F值)最小的格子
3、查找它周围的能走的格子
4、把这些格子加入启动列表中,已经在启动或关闭列表中的格子不用加入
5、把这些加入启动列表的格子的"父格子"设为当前格子
6、再把当前格子从启动列表中删除,加入关闭列表中
7、如果终点在启动列表中,则找到路径,退出流程,不进行第9步
8、如果启动列表中没有格子了,说明没有找到路径,退出流程,不进行第9步
9、跳转第2步
*/
// 0:可行走的点
// 1:阻挡点
// 2:路径
// 3:起点
// 4:终点
int
g_PathLattice[10][10] =
{
{ 0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,1,0,0,0,0,0 },
{ 0,0,3,0,1,0,4,0,0,0 },
{ 0,0,0,0,1,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0 },
{ 0,0,0,0,0,0,0,0,0,0 },
};
struct
Node
{
int
row; // 行
int
rank; // 列
int
f;
int
g;
int
h;
Node * pParent; // 当前结点路径的前一个结点(父格子)
};
#define
LatticeLen 10 // 格子边长
// 函数前向声明
int
Distance(int
row1, int
rank1, int
row2, int
rank2);
bool
IsNodeInList(Node * pNode, list<Node *> list);
Node * GetNearestNode(list<Node *> list, Node * Rec);
void
GetNearNodeList(Node * pNode, list<Node *> & listNear,
list<Node *> listStart, list<Node *> listEnd, Node * pEndNode);
void
EraseFromList(Node * pNode, list<Node *> & listStart);
void
ClearList(list<Node *> nodeList);
int
main()
{
// 起点
int
rowStart;
int
rankStart;
// 终点
int
rowEnd;
int
rankEnd;
// 查找起点和终点的位置
for (int
i = 0; i < 10; i++)
{
for (int
j = 0; j < 10; j++)
{
if (g_PathLattice[i][j] == 3)
{
rowStart = i;
rankStart = j;
}
if (g_PathLattice[i][j] == 4)
{
rowEnd = i;
rankEnd = j;
}
}
}
// 起点
Node * nodeStart = new
Node;
nodeStart->row = rowStart;
nodeStart->rank = rankStart;
nodeStart->g = 0;
nodeStart->h = Distance(rowStart, rankStart, rowEnd, rankEnd);
nodeStart->f = nodeStart->h;
nodeStart->pParent = nullptr;
// 终点
Node * nodeEnd = new
Node;
nodeEnd->row = rowEnd;
nodeEnd->rank = rankEnd;
// 定义启动列表和关闭列表
list<Node *> listStart;
list<Node *> listEnd;
// 把起点加入启动列表
listStart.push_back(nodeStart);
// 当前结点
Node * pNowNode = nullptr;
// 如果终点在启动列表中,则已经找到路径,退出循环
while (!IsNodeInList(nodeEnd, listStart))
{
Node * Rec = nullptr;
// 查找权值最小的格子作为当前点
pNowNode = GetNearestNode(listStart, Rec);
// 如果没有找到,则说明没有路径
if (pNowNode == nullptr)
{
break;
}
// 存放当前格子周围能加入启动列表的格子
list<Node *> listNear;
GetNearNodeList(pNowNode, listNear, listStart, listEnd, nodeEnd);
// 将当前结点加入关闭列表中
listEnd.push_back(pNowNode);
// 将当前结点从启动列表中删除
EraseFromList(pNowNode, listStart);
// 将周围点加入启动列表中
for (list<Node *>::iterator
it = listNear.begin();
it
!=
listNear.end(); it++)
{
listStart.push_back(*it);
}
}
if (pNowNode == nullptr)
{
printf("路径不存在\n");
ClearList(listStart);
ClearList(listEnd);
delete
nodeEnd;
return 0;
}
// 在启动列表中找到终点
Node * pNodeFind = nullptr;
for (list<Node *>::iterator
it = listStart.begin();
it
!=
listStart.end(); it++)
{
if ((*it)->row == nodeEnd->row &&
(*it)->rank == nodeEnd->rank)
{
pNodeFind = (*it);
break;
}
}
while (pNodeFind)
{
g_PathLattice[pNodeFind->row][pNodeFind->rank] = 2;
pNodeFind = pNodeFind->pParent;
}
for (int
i = 0; i < 10; i++)
{
for (int
j = 0; j < 10; j++)
{
if (g_PathLattice[i][j] == 0)
{
printf("^ ");
}
else
if (g_PathLattice[i][j] == 1)
{
printf("* ");
}
else
if (g_PathLattice[i][j] == 2)
{
printf("# ");
}
}
printf("\n");
}
ClearList(listStart);
ClearList(listEnd);
delete
nodeEnd;
return 0;
}
int
Distance(int
row1, int
rank1, int
row2, int
rank2)
{
// 格子的中点坐标
int
x1 = rank1 * LatticeLen + LatticeLen / 2;
int
y1 = row1 * LatticeLen + LatticeLen / 2;
int
x2 = rank2 * LatticeLen + LatticeLen / 2;
int
y2 = row2 * LatticeLen + LatticeLen / 2;
return (int)sqrt((double)((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}
bool
IsNodeInList(Node * pNode, list<Node *> NodeList)
{
for (list<Node *>::iterator
it = NodeList.begin();
it
!=
NodeList.end(); it++)
{
if (pNode->row == (*it)->row && pNode->rank == (*it)->rank)
{
return
true;
}
}
return
false;
}
Node * GetNearestNode(list<Node *> NodeList, Node * Rec)
{
int
tempF = 1000000;
for (list<Node *>::iterator
it = NodeList.begin();
it
!=
NodeList.end(); it++)
{
if ((*it)->f < tempF)
{
Rec = *it;
tempF = (*it)->f;
}
}
return
Rec;
}
void
GetNearNodeList(Node * pNode, list<Node *> & listNear,
list<Node *> listStart, list<Node *> listEnd, Node * pEndNode)
{
// 将结点旁边的8个点加入到listNear中
// 在启动或关闭列表中的点不能加入listNear
// 阻挡点不能加入listNear
for (int
i = -1; i <= 1; i++)
{
for (int
j = -1; j <= 1; j++)
{
if (i == 0 && j == 0)
{
// 自己格子
continue;
}
int
rowTemp = pNode->row + i;
int
rankTemp = pNode->rank + j;
if (rowTemp < 0 || rankTemp < 0 || rowTemp > 9 || rankTemp > 9)
{
// 越界
continue;
}
if (g_PathLattice[rowTemp][rankTemp] == 1)
{
// 阻挡点
continue;
}
Node
node;
node.row = rowTemp;
node.rank = rankTemp;
if (IsNodeInList(&node, listStart))
{
// 在启动列表中
continue;
}
if (IsNodeInList(&node, listEnd))
{
// 在关闭列表中
continue;
}
Node * pNearNode = new
Node;
pNearNode->g = pNode->g + Distance(pNode->row, pNode->rank, rowTemp, rankTemp);
pNearNode->h = Distance(rowTemp, rankTemp, pEndNode->row, pEndNode->rank);
pNearNode->f = pNearNode->g + pNearNode->h;
pNearNode->row = rowTemp;
pNearNode->rank = rankTemp;
pNearNode->pParent = pNode;
listNear.push_back(pNearNode);
}
}
}
void
EraseFromList(Node * pNode, list<Node *> & listStart)
{
for (list<Node *>::iterator
it = listStart.begin();
it
!=
listStart.end(); it++)
{
if (pNode->row == (*it)->row && pNode->rank == (*it)->rank)
{
listStart.erase(it);
return;
}
}
}
void
ClearList(list<Node *> nodeList)
{
for (list<Node *>::iterator
it = nodeList.begin();
it
!=
nodeList.end(); it++)
{
delete
*it;
}
}
一个小笔记(5):A*算法的更多相关文章
- 一个小笔记(2):Socket网络编程
网络通信的流程: 服务器端申请套接字 -> 绑定套接字到本地,打开端口 -> 监听端口 -> 等待接受消息 -> 有消息之后,读取消息 客户端申请套接字 -> 向服务端发 ...
- 学习完nio的一个小笔记吧
这是一个nio网络通信服务端的demo,主要就学习了selector的一些用法,以及它里面的事件类型 selector是对nio的一个优化,它能保证既能高效处理线程中的事件,又能保证线程不会一直占用c ...
- 一个小笔记(8):EN_2
Why is programming fun? What delights may its practitioner expect as his reward? First is the sheer ...
- 一个小笔记(7):EN_1
For nearly ten years, the Unified Modeling Language(UML) has been the industry standard for visualiz ...
- JavaScript关于返回数据类型一个小小的笔记
Javascript关于返回数据类型的一个小笔记 javascript数据类型有两种. 一种是基本数据类型:String.Number.Boolean.Symbol.Underfine.Null 一种 ...
- c++学习笔记---04---从另一个小程序接着说
从另一个小程序接着说 文件I/O 前边我们已经给大家简单介绍和演示过C和C++在终端I/O处理上的异同点. 现在我们接着来研究文件I/O. 编程任务:编写一个文件复制程序,功能实现将一个文件复制到另一 ...
- c++学习笔记---03---从一个小程序说起2
从一个小程序说起2 要求:编写一个程序,要求用户输入一串整数和任意数目的空格,这些整数必须位于同一行中,但允许出现在该行中的任何位置.当用户按下键盘上的"Enter"键时,数据输入 ...
- c++学习笔记---02---从一个小程序说起
从一个小程序说起 这一讲的主要目的是帮助大家在C语言的背景知识上与C++建立联系. 问题探索 问题:对一个整型数组求和. 要求:定义一个存储着 n 个元素的数组,要求用C语言完成这个任务. 赶紧的:大 ...
- python笔记_查看函数调用栈的一个小技巧
一.背景 最近在看一个开源框架的源码,涉及到的内容非常杂乱,有的函数不知道是在什么时候被谁给调用了?调用的时候传入了什么参数?为了解决这个问题,写了一个小的装饰器. 二.实现 这个装饰器函数主要参考了 ...
随机推荐
- tableView刷新指定的cell 或section和滚动到指定的位置
转自:http://blog.csdn.net/tianyou_code/article/details/54426494 //一个section刷新 NSIndexSet *indexSet=[[N ...
- uoj#269. 【清华集训2016】如何优雅地求和(数论)
传送门 首先,如果\(f(x)=1\),那么根据二项式定理,有\(Q(f,n,k)=1\) 当\(f(x)=x\)的时候,有\[Q=\sum_{i=0}^ni\times \frac{n!}{i!(n ...
- bzoj2502清理雪道
传送门 好题啊,由于每个点既可以进,也可以出,就可以新建一个源点和汇点,对于每个点都连边,然后就是最小流板子了. 代码: #include<cstdio> #include<iost ...
- Java - 安装jdk并设置环境变量
前言 双十一买了台新的笔记本,需要重新安装下Java,这里记录下安装的过程,毕竟万事开头难,就算是老手也不一定能一次就把Java安装成功. 安装jdk 作为一名Java开发,当然是要安装jdk了,如果 ...
- vue 生命周期钩子函数
实例中的生命周期钩子可以分为以下8种情况: beforeCreate: 实例刚被创建,vue所有属性都还不存在 created: 实例创建完成,但$el还不存在 beforeMount:挂载之前 mo ...
- java数据结构----数组篇
1.数组作为java常用的数据结构之一,使用相对简单,下图展示了数组常用操作在允许和不允许重复值的情况下的比较次数 2.进行封装后的代码: package com.cn.higharray; /** ...
- 洛谷 P2376 [USACO09OCT]津贴Allowance
https://www.luogu.org/problemnew/show/P2376 看了题解做的,根本不会贪心.. #include<cstdio> #include<algor ...
- 洛谷 P1463 [HAOI2007]反素数
https://www.luogu.org/problemnew/show/P1463 注意到答案就是要求1-n中约数最多的那个数(约数个数相同的取较小的) 根据约数个数的公式,在约数个数相同的情况下 ...
- python之模块random,time,os,sys,序列化模块(json,pickle),collection
引入:什么是模块: 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类型. 1.使用python编写的代码(.py ...
- 098 Validate Binary Search Tree 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树.一个二叉搜索树有如下定义: 左子树只包含小于当前节点的数. 右子树只包含大于当前节点的数. 所有子树自身必须也是二叉搜索树.示例 1 ...