原理视频

油管:https://youtu.be/i0x5fj4PqP4
别人的B站翻译:https://www.bilibili.com/video/BV1v44y1h7Dt?spm_id_from=333.999.0.0

基本概念

3个数值

G:起点到当前点步数:会随着路径的改变,例如找到一条更好的路了,A的点G = 原本A的G 和 cur路径到A的G(cur的G + cur到A的G)中的最小值

H:当前点到终点步数,乐观估计,无视障碍物。即实际的H(包含绕开障碍物的整条代价) > 按照无障碍物走的最短H

F:G+H
就是每一步都找最小F的走

每步移动代价


方便计算 * 10

Open表与Close表

var listOpen = new List() { startNode }; //开放集合,可以进行计算(但没有被选中)的节点 ,将初始节点加入到OpenSet当中。所有可能,每走一步都要放入
var listClose = new List();//封闭集合,所有已经计算过而且也被算中的节点 。表示改点已经走过,且是代价最小的点

伪代码

https://blog.csdn.net/a591243801/article/details/80655416

Init
得到StartNode与TargetNode初始化OpenSet与CloseSet将初始节点加入到OpenSet当中Loop (OpenSet.Count > 0)
//找出OpenSet当中fCost最小的点,这个点就是被选中的将要行走的下一个点
currentNode = OpenSet当中fCost最小的点//将这个点从OpenSet当中移除
OpenSet.Remove(currentNode);
//将这个点加入到ClostSet当中
ClosrSet.Add(currentNode);if(currentNode == targetNode)路径已经找到//若路径没有找到,则查找当前选中的节点的邻居节点,
//计算他们的fCost并加入到OpenSet当中方便下一轮计算
foreach neighbour of the currentNode//若这个节点是不可以行走,或者已经被算中过了,则跳过这个节点if (!neighbour.walkable || closeSet.Contains(neighbour))continue;//计算这个这个邻居节点的gCost,若gCost更小则说明//通过currentNode到这个节点的距离更加的短(代价更小)newGCostToNeighbour = currentNode.gCost + GetDistance(currentNode,neighbour);//gCost若更小的话则需要重新计算这个点的fCost和他的父亲节点//若这个节点不在OpenSet的话,则计算这个节点的fCost与设置父亲节点//通过设置父亲节点,那么在之后找到路径之后可以通过父亲节点找到整条路径if(newGCostToNeighbour < neighbour.gCost || !openSet.Contans(neighbour)){neighour.fCost = evaluateFCost(neighour);neighour.parentNode = currentNode;if(!OpenSet.Contains(neighour)){OpenSet.Add(neighbour);}}

核心代码

节点

 public abstract class NodeBase : MonoBehaviour {public List<NodeBase> Neighbors { get; protected set; }//周围的邻居public NodeBase Connection { get; private set; }//上一个节点public float G { get; private set; } //起点到当前:每次找邻居会更新, 取当前到这个邻居,和原本设定中的最小public float H { get; private set; }//当前到达终点:乐观估计,会绕过障碍物,可能比真实到达的要小public float F => G + H; //两者之和

寻路

public static List<NodeBase> FindPath(NodeBase startNode, NodeBase targetNode) {var listOpen = new List<NodeBase>() { startNode }; //开放集合,可以进行计算(但没有被选中)的节点 ,将初始节点加入到OpenSet当中。所有可能,每走一步都要放入var listClose = new List<NodeBase>();//封闭集合,所有已经计算过而且也被算中的节点 。表示改点已经走过,且是代价最小的点while (listOpen.Any()) {//找到最小F todo:优化,每次节点多var current = listOpen[0];//找出OpenSet当中fCost最小的点,这个点就是被选中的将要行走的下一个点,如果F总和相同,找H最小,即到达终点最快(H是乐观估计,不算障碍物估计)foreach (var t in listOpen) if (t.F < current.F || ( t.F == current.F && t.H < current.H)) current = t;//将这个点从OpenSet当中移除listOpen.Remove(current);//将这个点加入到ClostSet当中listClose.Add(current);current.SetColor(ClosedColor);//路径已经到了if (current == targetNode){var currentPathTile = targetNode;var path = new List<NodeBase>();//var count = 100;while (currentPathTile != startNode) {path.Add(currentPathTile);currentPathTile = currentPathTile.Connection; //cur的上一个连接点//count--;//if (count < 0) throw new Exception();//Debug.Log("sdfsdf");}foreach (var tile in path) tile.SetColor(PathColor);startNode.SetColor(PathColor);Debug.Log(path.Count);return path;}//找curNode的邻居,可到达和未在close表(即已经算过的不会再进行计算)foreach (var neighbor in current.Neighbors.Where(t => t.Walkable && !listClose.Contains(t))) {//是否未计算过这个邻居var inSearch = listOpen.Contains(neighbor);//从cur到邻居的G = curG+cur到邻居的G代价var costToNeighbor = current.G + current.GetDistance(neighbor);//路径发生改变,g会变化,例如找到一条更好的路if (!inSearch || costToNeighbor < neighbor.G) {neighbor.SetG(costToNeighbor);neighbor.SetConnection(current);//h是乐观估计,只需要算一遍if (!inSearch) {neighbor.SetH(neighbor.GetDistance(targetNode));listOpen.Add(neighbor);neighbor.SetColor(OpenColor);}}}}return null;}

优化

Open表用二叉堆

二叉堆原理
https://www.cnblogs.com/alimayun/p/12779640.html
父节点就是下标为i/2的节点。
插入节点(按照小堆为例子)

  1. 插入到最后一个位置,元素为a
  2. a跟父节点b比,如果插入的a更小,上浮,ab交换位置
    删除节点
  3. 删除的是头节点
  4. 把最后一个临时a补到堆顶
  5. 跟左b右c比较,如果a比bc中最小的还小,a与其一换位置,为下沉操作
using System;
using System.Collections.Generic;
using System.Text;namespace DataStructure
{public enum HeapType{MinHeap,MaxHeap}public class BinaryHeap<T> where T : IComparable<T>{public List<T> items;public HeapType HType { get; private set; }public T Root{get { return items[0]; }}public BinaryHeap(HeapType type){items = new List<T>();this.HType = type;}public bool Contains(T data){return items.Contains(data);}public void Push(T item){items.Add(item);int i = items.Count - 1;bool flag = HType == HeapType.MinHeap;while (i > 0){if ((items[i].CompareTo(items[(i - 1) / 2]) > 0) ^ flag){T temp = items[i];items[i] = items[(i - 1) / 2];items[(i - 1) / 2] = temp;i = (i - 1) / 2;}elsebreak;}}private void DeleteRoot(){int i = items.Count - 1;items[0] = items[i];items.RemoveAt(i);i = 0;bool flag = HType == HeapType.MinHeap;while (true){int leftInd = 2 * i + 1;int rightInd = 2 * i + 2;int largest = i;if (leftInd < items.Count){if ((items[leftInd].CompareTo(items[largest]) > 0) ^ flag)largest = leftInd;}if (rightInd < items.Count){if ((items[rightInd].CompareTo(items[largest]) > 0) ^ flag)largest = rightInd;}if (largest != i){T temp = items[largest];items[largest] = items[i];items[i] = temp;i = largest;}elsebreak;}}public T PopRoot(){T result = items[0];DeleteRoot();return result;}}}

源码

https://github.com/luoyikun/UnityForTest
AStarDemo场景

unity3d:Astar寻路,A星,A*,二叉堆优化Open表相关推荐

  1. A星寻路与二叉堆优化(2D)

    内容概览 前言 吹水 什么是A星寻路 如何实现A星寻路 节点类 网格类 寻路 优化 使用 使用演示 Hireachy窗口内配置 player配置 GridOwner配置 最终效果 前言 Hi~你好,我 ...

  2. 最短路径——Dijkstra算法以及二叉堆优化(含证明)

    一般最短路径算法习惯性的分为两种:单源最短路径算法和全顶点之间最短路径.前者是计算出从一个点出发,到达所有其余可到达顶点的距离.后者是计算出图中所有点之间的路径距离. 单源最短路径 Dijkstra算 ...

  3. 【贪心】 POJ 1456 Supermarket 详解 (并查集/二叉堆优化)

    题目链接:POJ-1456 题目大意 有n件商品,每件商品的利润为,销售日期的截止时间为(即只能在时间前销售该物品).一天只能销售一件物品.问这n件商品的最大利润为多少 方案一 分析 有两种贪心策略, ...

  4. 在A*寻路中使用二叉堆

    在A*寻路中使用二叉堆 作者:Patrick Lester(2003年4月11日更新) 译者:Panic 2005年3月28日 译者序:     这一篇文章,是"A* Pathfinding ...

  5. 二叉堆及其在A*算法中的应用

    这里讲解的二叉堆,其实是以堆的形式存在的二叉树,这个特殊的结构把A*算法对开启列表的排序需求演绎的出神入化,毫无疑问是A*的最佳拍档. A*算法中最缓慢的部分就是在开启列表中寻找F值最低的节点或者方格 ...

  6. 动画 | 什么是二叉堆?

    点击蓝色"五分钟学算法"关注我哟 加个"星标",天天中午 12:15,一起学算法 来源 | 算法无遗策 二叉堆的解释 (动态选择优先级最高的任务执行) 堆,又称 ...

  7. 大根堆的删除c语言,二叉堆(一)之 C语言详解

    本文介绍二叉堆,二叉堆就是通常我们所说的数据结构"堆"中的一种.和以往一样,本文会先对二叉堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现: ...

  8. 0x17.基础数据结构 - 二叉堆

    目录 一.二叉堆 二.例题 0.AcWing 145. 超市 AcWing 146. 序列(POJ 2442) 三.HuffmanHuffmanHuffman树 1.AcWing 148. 合并果子 ...

  9. 大顶堆删除最大值_算法学习笔记(47): 二叉堆

    堆(Heap)是一类数据结构,它们拥有树状结构,且能够保证父节点比子节点大(或小).当根节点保存堆中最大值时,称为大根堆:反之,则称为小根堆. 二叉堆(Binary Heap)是最简单.常用的堆,是一 ...

最新文章

  1. SQL Server 2008基于策略的管理
  2. MYSQL数据库从A表把数据插入B表
  3. 私有句柄表(内核对象,并非用户对象),全局句柄表
  4. 属性类:Properties
  5. 09. 用两个栈实现队列
  6. 重构我的CMS系统,增加ORM
  7. git 创建和合并分支
  8. java system.gc 作用_JVM源码分析之SystemGC完全解读
  9. 程序员如何做好应聘?简历、面试和Offer
  10. ssm教务系统网站 毕业设计-附源码290915
  11. OC集成Socket.IO时,出现错误: No such module 'Starscream' 的解决办法
  12. qq能上网浏览器不可以
  13. 一定要讲给孩子们的27个小故事
  14. 最强文件搜索神器——Everything
  15. No ‘Access-Control-Allow-Origin‘ header is present on the requested resource Vue配置代理解决跨域问题
  16. PV UV 日活 月活
  17. 贝叶斯分类器做文本分类案例
  18. datagrid全选
  19. Hive SQL 计算指定日期本周的第一天和最后一天
  20. Chrome浏览器运行超图三维场景

热门文章

  1. 云原生第3课:Kubernetes 系统快速入门
  2. MySQL数据库的基本操作流畅版
  3. 怎么给黑白照片上色?这几个软件可以给黑白照片上色
  4. mysql中视图与真实表的区别,数据库表/视图/同义词的区别
  5. 计算机的配置的实验报告怎么写,计算机实验报告范文
  6. ajax点评wnv冠军,[特稿] CS选手wNv.savage的成长之路
  7. 云计算入门了解一些常识-打算参加中国移动云计算项目
  8. Python用tornado的websocket开发聊天室
  9. Code Jam 2017 Qualification Round Problem A. Oversized Pancake Flipper
  10. c语言计时程序 纳秒,前端Tips#4 - 用 process.hrtime 获取纳秒级的计时精度