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;
}
}
}
}
感谢您的观看。