A*寻路算法

C++实现:

#include <iostream>
#include <stack>
#include <set>
#include <queue>
#include <string>
#include <vector>
#include<algorithm>
using namespace std;

typedef struct wayPoint
{
    int x;//起始点x
    int y;//起始点y
    double value;//记录下来的总距离
    double dis;//距离它中心那个点的距离。
    //double
    wayPoint* father = nullptr;
    wayPoint(int x,int y, double dis,double val)
    {
        this->x = x;
        this->y = y;
        this->dis = dis;
        value = val;
        father = nullptr;
    }
}wp;

class Compare//比较器
{
public:
    bool operator()(const wayPoint& p1, const wayPoint& p2) const
    {
        return p1.value > p2.value;
    }
};

priority_queue<wayPoint,vector<wayPoint>,Compare> insertQueue;//插入所有点的第一个容器
stack<wayPoint> resQueue;//结果容器
vector<string> map = {"10000",
                      "11110",
                      "00000" };//用来测试的地图
pair<int, int> start = { 0,1 };//起始点坐标
pair<int, int> End = { 2,2 };//终止点坐标
vector<vector<int>> seq = { {-1,-1},{-1,0},{-1,1},{0,-1},{0,+1},{1,-1},{1,0},{1,1} };//分别对应八个位置,第一个位置代表行,第二个位置代表列
wayPoint Father = *new wayPoint(start.first,start.second,0,0);
int Map[15] = { false };//把所有出现的点全部标记为false.


bool operator==(const pair<int, int>& p1, const pair<int, int>& p2)
{
    if (p1.first == p2.first && p1.second == p2.second)
    {
        return true;
    }
    return false;
}

//MergeSort() O(NlogN) master公式
//T(N) = a * T(N/b) + f(n);//O(N^d) d = 1,a = 1,b = 1 logba < d O(n^d);
void FindWay(vector<string> map,pair<int,int> start,pair<int,int> end,wayPoint* lastFather)
{
    if (start == end) return;
    //if (resQueue.empty()) return;
    if (!Map[lastFather->x * map[0].size() + lastFather->y] &&
        map[lastFather->x][lastFather->y] != '1')
    {
        resQueue.push(*lastFather);
        Map[lastFather->x * map[0].size() + lastFather->y] = true;//置为真。
    }
    for (int i = 0; i < seq.size(); ++i)
    {
        if (start.first + seq[i][0] >= 0 && start.second + seq[i][1] >= 0 
            && start.first + seq[i][0] < map.size() && start.second + seq[i][1] < map[0].size())//地图范围限制
        {

            //计算这个点距离起点的位置
            int x = seq[i][0];
            int y = seq[i][1];

            //计算这个点目前的位置
            int curPosX = x + start.first;
            int curPosY = y + start.second;

            //如果已经访问过这个点了或者是这个点是墙,那么就不再访问它了,打断当次循环。
            if (Map[curPosX * map[0].size() + curPosY] || map[curPosX][curPosY] == '1')//因为有前面的for循环保证,所以不会有负数。
            {
                continue;
            }

            //如果没有访问,这次访问,然后置为true.
            Map[curPosX * map[0].size() + curPosY] = true;

            //距离终点的x长度和y的长度
            int disAboutEndX = abs(end.first - curPosX);
            int disAboutEndY = abs(end.second - curPosY);

            wayPoint temp = *new wayPoint(curPosX, curPosY, pow(pow(x, 2) + pow(y, 2), 0.5),
                pow(pow(x,2) + pow(y,2),0.5) + lastFather->dis + disAboutEndX + disAboutEndY);
            //temp要继承父类的距离

            temp.father = lastFather;
            insertQueue.push(temp);//所有的周围的点全部加进来,如果有这个点就不加,没有就加
        }
    }
    if (insertQueue.empty()) {
        cout << "无路可走!!!" << endl;
        return;//如果最后连入队队列这个容器都是空的,那么就说明没有路存在
    }
    if (!insertQueue.empty())//如果入队队列里面有数字的话就执行。
    {
        wayPoint popBox = insertQueue.top();
        resQueue.push(popBox);//把弹出来的这个数字加到resQueue中。
        insertQueue.pop();//然后从入队队列中弹出来。
        FindWay(map, { popBox.x,popBox.y }, end, &popBox);
    }
}

int main()
{
    FindWay(map, start, End, &Father);

    return 0;
}

C#版本:

using System;
using System.Runtime.Serialization;
using System.Collections.Generic;
namespace HelloWorldApplication
{
    struct pair
    {
        public int first = 0;
        public int second = 0;
        public pair(int first, int second)
        {
            this.first = first;
            this.second = second;
        }

        public static bool operator ==(pair p1, pair p2)
        {
            if (p1.first == p2.first && p1.second == p2.second)
            {
                return true;
            }
            return false;
        }

        public static bool operator !=(pair p1, pair p2)
        {
            if (p1.first != p2.first || p1.second != p2.second)
            {
                return false;
            }
            return true;
        }

        public override int GetHashCode()
        {
            return 0;
        }

#pragma warning disable CS8765 // 参数类型的为 Null 性与重写成员不匹配(可能是由于为 Null 性特性)。
        public override bool Equals(object obj)
#pragma warning restore CS8765 // 参数类型的为 Null 性与重写成员不匹配(可能是由于为 Null 性特性)。
        {
            throw new NotImplementedException();
        }
    };

    //只有class才可以,struct不行。
    public class wayPoint
    {
        public int x;//起始点x
        public int y;//起始点y
        public double value;//记录下来的总距离
        public double dis;//距离它中心那个点的距离。
        public wayPoint? father = null;
        
        public wayPoint(int x, int y, double dis, double val)
        {
            this.x = x;
            this.y = y;
            this.dis = dis;
            value = val;
            father = null;
        }

}

class FindPath
    {

        static void Main(string[] args)
        {
            FindWay(map, start, end, Father);
        }

        static int[,] seq = new int[,] { { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { 0, 1 }, { 1, -1 }, { 1, 0 }, { 1, 1 } };
        static pair start = new pair(0,1);
        static pair end = new pair(2,2);
        static wayPoint Father = new wayPoint(start.first, start.second, 0, 0);
        static int[] Map = new int[15];//把所有出现的点全部标记为false.
        static string[] map = {"10000",
                               "11111",
                               "00000" };
        static List<wayPoint> insertQueue = new List<wayPoint>();//插入所有点的第一个容器
        static Stack<wayPoint> resQueue = new Stack<wayPoint>();//结果容器
        static int index = 0;

        static void FindWay(string[] map, pair start, pair end, wayPoint lastFather)
        {
            if (start == end) return;
            //if (resQueue.empty()) return;
            if ((Map[lastFather.x * map[0].Length + lastFather.y] == 0) &&
                map[lastFather.x][lastFather.y] != '1')
            {
                resQueue.Append<wayPoint>(lastFather);
                Map[lastFather.x * map[0].Length + lastFather.y] = 1;//置为真。
            }
            for (int i = 0; i < seq.GetLength(0); ++i)
            {
                if (start.first + seq[i,0] >= 0 && start.second + seq[i,1] >= 0
                    && start.first + seq[i,0] < map.Length && start.second + seq[i,1] < map[0].Length)
                {

                    //计算这个点距离起点的位置
                    int x = seq[i,0];
                    int y = seq[i,1];

                    //计算这个点目前的位置
                    int curPosX = x + start.first;
                    int curPosY = y + start.second;

                    //如果已经访问过这个点了或者是这个点是墙,那么就不再访问它了,打断当次循环。
                    if (Map[curPosX * map[0].Length + curPosY] == 1 || map[curPosX][curPosY] == '1')//因为有前面的for循环保证,所以不会有负数。
                    {
                        continue;
                    }

                    //如果没有访问,这次访问,然后置为true.
                    Map[curPosX * map[0].Length + curPosY] = 1;

                    //距离终点的x长度和y的长度
                    int disAboutEndX = Math.Abs(end.first - curPosX);
                    int disAboutEndY = Math.Abs(end.second - curPosY);

                    wayPoint temp = new wayPoint(curPosX, curPosY, Math.Pow(Math.Pow(x, 2) + Math.Pow(y, 2), 0.5),
                        Math.Pow(Math.Pow(x, 2) + Math.Pow(y, 2), 0.5) + lastFather.dis + disAboutEndX + disAboutEndY);
                    //temp要继承父类的距离

                    temp.father = lastFather;
                    insertQueue.Add(temp);
                    HeapInsert(ref insertQueue, index++);
                    //insertQueue.Add(temp);//所有的周围的点全部加进来,如果有这个点就不加,没有就加
                }
            }
            if (insertQueue.Count == 0)
            {
                Console.WriteLine("无路可逃!!!");
                return;//如果最后连入队队列这个容器都是空的,那么就说明没有路存在
            }
            if (insertQueue != null && insertQueue.Count > 0)//如果入队队列里面有数字的话就执行。
            {
                wayPoint popBox = insertQueue[0];
                resQueue.Push(popBox);//把弹出来的这个数字加到resQueue中。
                insertQueue.RemoveAt(0);//然后从入队队列中弹出来。(弹出来需要重新调整堆结构)
                HeapIfy(ref insertQueue, 0, --index);//弹出来的话就执行一次HeapIfy过程
                FindWay(map, new pair(popBox.x,popBox.y),end, popBox);
            }
        }

        //手写堆结构,保证每次弹出一个最小值。
        //如果对这一块并不是太熟悉的兄弟们可以在重新回去重温一下。
        //这块堆排序的算法我是跟着左神学习的,我觉得他讲的非常好。
        //兄弟们也可以去看一下。
        static void HeapInsert(ref List<wayPoint> test, int index)
        {
            while (index > 0)
            {
                if ((index - 1) / 2 >= 0 && test[(index - 1) / 2].value > test[index].value)
                {
                    //swap函数
                    swap(ref test, (index - 1) / 2, index);
                }
                index = (index - 1) / 2;
            }
        }

        static void swap(ref List<wayPoint> test,int L,int R)
        {
            wayPoint temp = test[R];
            test[L] = test[R];
            test[L] = temp;
        }

        //HeapIfy过程
        static void HeapIfy(ref List<wayPoint> test,int index,int heapSize)
        {
            int left = index * 2 + 1;
            while (left < heapSize)
            {
                int smallest = left + 1 < heapSize && test[left + 1].value < test[left].value ? left + 1 : left;
                smallest = test[smallest].value < test[index].value ? smallest : index;
                if (smallest == index)
                {
                    return;
                }
                swap(ref test, index, smallest);
                index = smallest;
                left = index * 2 + 1;
            }
        }
    }
}

感谢您的观看。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值