Java — A*算法(三) 完结

接Java — A*算法(二)

把思路和方法整理一遍后就开始码代码了(搬砖的都懂~~~)

Data.java

public class Data 
{
	
	Point point;
	double g;
	double h;
	Data parent;
	
	public Data(Point p, double g, double h, Data parent)
	{
		this.point = p;
		this.g = g;
		this.h = h;
		this.parent = parent;
		
	}
	
	double f()
	{
		return g + h;
	}

}

Point.java

public class Point 
{
	int x, y;
	Point(int x, int y)
	{
		this.x = x;
		this.y = y;
	}

	public boolean equals(Object o)
	{
		return o != null && o instanceof Point && ((Point)o).x == x && ((Point)o).y == y;
	}
}

MinHeep.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;


public class MinHeep 
{
	private final ArrayList<Data> queue = new ArrayList<>();
	private int endPnt = 0;
	private final Map<String, Data> index = new HashMap<>();

	public Data getAndRemoveMin()
	{
		if (isEmpty())
		{
			return null;
		}

		Data head = queue.get(0);
		Data last = queue.get(endPnt - 1);
		queue.set(0, last);
		endPnt--;
		index.remove(getKey(head.point));
		topDown();
		return head;
	}

	public Data find(Point pnt)
	{
		return index.get(getKey(pnt));
	}
	public void add(Data data)
	{
		if (queue.size() > endPnt)
		{
			queue.set(endPnt, data);
		}
		else
		{
			queue.add(data);
		}
		endPnt++;		
		index.put(getKey(data.point), data);
		bottomUp();
	}

	public boolean isEmpty()
	{
		return endPnt <= 0;
	}

	private String getKey(Point pnt)
	{
		return String.format("%d-%d", pnt.x, pnt.y);
	}

	private void topDown()
	{
		for (int cur = 0; cur < endPnt; )
		{
			int left  = 2 * cur + 1;
			int right = 2 * cur + 2;
			
			Data dc = queue.get(cur);
			Data dl = left < endPnt ? queue.get(left) : null;
			Data dr = right < endPnt ? queue.get(right) : null;

			int next = -1;
			Data dn = dc;
			if (dl != null && dl.f() < dn.f())
			{
				next = left;
				dn = dl;
			}
			if (dr != null && dr.f() < dn.f())
			{
				next = right;
				dn = dr;
			}
			
			if (next >= 0 && next < endPnt)
			{
				queue.set(next, dc);
				queue.set(cur, dn);
				cur = next;
			}
			else
			{
				break;
			}
		}
	}

	private void bottomUp()
	{
		for (int cur = endPnt - 1; cur >= 0; )
		{
			int parent = (cur - 1) / 2;
			if (parent < 0)
			{
				break;
			}

			Data dc = queue.get(cur);
			Data dp = queue.get(parent);
			
			if (dc.f() < dp.f())
			{
				queue.set(parent, dc);
				queue.set(cur, dp);
				cur = parent;
			}
			else
			{
				break;
			}
		}
	}
}

Main.java

public class Main 
{
	// 地图元素
	static final char START   = 'S';  // 起点
	static final char END     = 'E';  // 终点
	static final char SPACE   = '.';  // 空地
	static final char WALL    = 'W';  // 墙
	static final char VISITED = '-';  // 被访问过
	static final char ON_PATH = '@';  // 在结果路径上
	
	// 地图字符串
	static final String[] S_MAP = {
		". . . . . . . . w . . . . . . . . E . .",
		". . . W W W W . . w . . . . . . . . . .",
		". . . . . . W . . . w . . . . . . . . .",
		". . S . . . W . . . . w . . . . . . w .",
		". . . . . . W . . . . . w . . . . . . .",
		". . . . . . W . . . . . . w . . . . . .",
		". . . . . . W . . . . . . . w . . w . .",
		". . . . . . W . . . . . . . . w . . . .",
		". . . W W W W . . . . . . . . . w . . .",
		". . . . . . . . . . . . . . . . . . . .",
	};
	
	// 地图
	static char[][] MAP    = new char[S_MAP[0].replace(" ", " ").length()][S_MAP.length];
	// 地图的最大尺寸
	static Point MAX_PNT   = new Point(MAP.length, MAP[0].length );
	// 起点
	static Point START_PNT = null;
	// 终点
	static Point END_PNT   = null;
	
	public static void main(String[] args)
	{
		genMap();
		printMap();
		
		search();
		
		printMap();
	}
	
	/**
	 *  用地图字符串产生地图数据
	 */
	static void genMap()
	{
		int idx = 0;
		for(String s : S_MAP){
			char[] cs = s.replace(" ", "").toCharArray();
			for(int i = 0; i < cs.length; i++){
				MAP[i][idx] = cs[i];
				switch(cs[i]){
				case START:
					START_PNT = new Point(i, idx);
					break;
				case END:
					END_PNT = new Point(i, idx);
					break;
				}
			}
			idx++;
		}
	}
	
	/**
	 *  打印地图
	 */
	static void printMap(){
		for(int j = 0; j < MAX_PNT.y; j++){
			for(int i = 0; i < MAX_PNT.x; i++){
				System.out.printf("%c", MAP[i][j]);
			}
			System.out.printf("\n");
		}
		System.out.printf("\n");
	}
	
	/**
	 *  搜索算法
	 */
	static void search()
	{
		final MinHeep heap = new MinHeep();  // 用最小堆来记录扩展的点
		final int[][] directs = {{1, 0}, {0 ,1}, {-1, 0}, {0, -1}};  // 可以扩展的四个方向
		
		heap.add(new Data(START_PNT, 0, 0, null));  // 把起始点放入堆
		Data lastData = null;  // 找到的最后一个点的数据,用来反推路径
		
		for(boolean finish = false; !finish && !heap.isEmpty();)
		{
			final Data data = heap.getAndRemoveMin();  // 取出f值最小的点
			final Point point = data.point;
			if(MAP[point.x][point.y] == SPACE)  // 将取出的点标识为已访问点
			{  
				MAP[point.x][point.y] = VISITED; 
			}
			
			for(int[] d : directs)  // 遍历四个方向的点
			{
				final Point newPnt = new Point(point.x + d[0], point.y + d[1]);
				if(newPnt.x >= 0 && newPnt.x < MAX_PNT.x && newPnt.y >= 0 && newPnt.y < MAX_PNT.y)
				{
					char e = MAP[newPnt.x][newPnt.y];
					if(e == END)  // 如果是终点,则跳出循环,不用再找
					{
						lastData = data;
						finish = true;
						break;
					}
					if(e != SPACE)  //如果不是空地就不需要再扩展
					{
						continue;
					}
					
					final Data inQueueData = heap.find(newPnt);
					if(inQueueData != null)  // 如果在堆里,则更新g值
					{
						if(inQueueData.g > data.g + 1)
						{
							inQueueData.g = data.g + 1;
							inQueueData.parent = data;
						}
					}
					else  //  如果不在堆里,则放入堆中
					{
						double h = h(newPnt);
						Data newData = new Data(newPnt, data.g + 1, h, data);
						heap.add(newData);
					}
				}
			}
		}
		
		//反方向找路径
		for(Data pathData = lastData; pathData != null;)
		{
			Point pnt = pathData.point;
			if(MAP[pnt.x][pnt.y] == VISITED)
			{
				MAP[pnt.x][pnt.y] = ON_PATH;
			}
			pathData = pathData.parent;
		}
	}
	
	/**
	 *  h函数
	 */
	static double h(Point pnt){
		//return hBFS(pnt);
		return hEuclidianDistance(pnt);
		//return hBFS(pnt);
		//return hBFS(pnt);
	}
	
	/**
	 *  曼哈顿距离,小于等于实际值
	 */
	static double hManhattanDistance(Point pnt)
	{
		return Math.abs(pnt.x - END_PNT.x) + Math.abs(pnt.x - END_PNT.y);
	}
	
	/**
	 *  欧式距离,小于等于实际值
	 */
	static double hEuclidianDistance(Point pnt)
	{
		return Math.sqrt(Math.pow(pnt.x - END_PNT.x, 2) + Math.pow(pnt.x - END_PNT.y, 2));
	}
	
	/**
	 *  欧式距离平方,大于等于实际值
	 */
	static double hPowEuclidianDistance(Point pnt)
	{
		return Math.pow(pnt.x - END_PNT.x, 2) + Math.pow(pnt.x - END_PNT.y, 2);
	}
	
	/**
	 *  BFS的h值,恒为0
	 */
	static double hBFS(Point pnt)
	{
		return 0;
	}
}

=============================== 完结 ==================================

转载于:https://my.oschina.net/quantou/blog/738649

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值