A星算法

    之前做的一个项目,现在才把它记录下来,项目中有一个这样功能,用户在地图上面选择起点、终点,需要在地图上面寻找一条最短的路径并显示到地图上。

在寻路中有两个比较常用的算法,一个迪杰斯特(Dijkstra)算法,迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径。 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。因为它是一个广度优先的算法,所以它的效率会比较低。另外一个是A星算法,它是基于启发式代价函数,启发式函数在应用和游戏中非常有用。在速度和精确度之间取得折中将会让你的程序运行得更快。

下面是我实现的代码:

package com.heng.test.map;

import java.util.*;

/**
 * A*算法
 * @author 黎荣恒
 *
 */
public class AStar {
	
	private int[][] map;// 地图(0可通过 1不可通过)
	private List<Node> openList;// 开启列表
	private List<Node> closeList;// 关闭列表
	private final int COST_STRAIGHT = 10;// 垂直方向或水平方向移动的路径评分
	private final int COST_DIAGONAL = 14;// 斜方向移动的路径评分
	private int row;// 行
	private int column;// 列
	
	public AStar(int[][] map, int row, int column) {
		this.map = map;
		this.row = row;//行
		this.column = column;//列
		openList = new ArrayList<Node>();//初始化开启列表
		closeList = new ArrayList<Node>();//初始化关闭列表
	}

	/**
	 *  查找坐标
	 * @param x1	起点x轴坐标
	 * @param y1	起点y轴坐标
	 * @param x2	终点x轴坐标
	 * @param y2	终点y轴坐标
	 * @return (-1:错误,0:没找到,1:找到了)
	 */
	public int search(int x1, int y1, int x2, int y2) {
		// 输入有错误
		if (x1 < 0 || x1 >= row || x2 < 0 || x2 >= row || y1 < 0
				|| y1 >= column || y2 < 0 || y2 >= column) {
			return -1;
		}
		// 输入有错误
		if (map[x1][y1] == 1 || map[x2][y2] == 1) {
			return -1;
		}

		Node sNode = new Node(x1, y1, null);//起点
		Node eNode = new Node(x2, y2, null);//终点
		openList.add(sNode);
		List<Node> resultList = search(sNode, eNode);
		if (resultList.size() == 0) {
			return 0;
		}
		for (Node node : resultList) {
			map[node.getX()][node.getY()] = 2;
		}
		return 1;
	}

	/**
	 * 查找核心算法
	 * @param sNode  起点
	 * @param eNode  终点
	 * @return       可走路径做点队列
	 */
	private List<Node> search(Node sNode, Node eNode) {
		List<Node> resultList = new ArrayList<Node>();
		boolean isFind = false;
		Node node = null;
		while (openList.size() > 0) {
			// System.out.println(openList);
			// 取出开启列表中最低F值,即第一个存储的值的F为最低的
			node = openList.get(0);
			// 判断是否找到目标点
			if (node.getX() == eNode.getX() && node.getY() == eNode.getY()) {
				isFind = true;
				System.out.println("------找到目标------");
				break;
			}
			// 上
			if ((node.getY() - 1) >= 0) {
				checkPath(node.getX(), node.getY() - 1, node, eNode,
						COST_STRAIGHT);
			}
			// 下
			if ((node.getY() + 1) < column) {
				checkPath(node.getX(), node.getY() + 1, node, eNode,
						COST_STRAIGHT);
			}
			// 左
			if ((node.getX() - 1) >= 0) {
				checkPath(node.getX() - 1, node.getY(), node, eNode,
						COST_STRAIGHT);
			}
			// 右
			if ((node.getX() + 1) < row) {
				checkPath(node.getX() + 1, node.getY(), node, eNode,
						COST_STRAIGHT);
			}
			// 左上
			if ((node.getX() - 1) >= 0 && (node.getY() - 1) >= 0) {
				checkPath(node.getX() - 1, node.getY() - 1, node, eNode,
						COST_DIAGONAL);
			}
			// 左下
			if ((node.getX() - 1) >= 0 && (node.getY() + 1) < column) {
				checkPath(node.getX() - 1, node.getY() + 1, node, eNode,
						COST_DIAGONAL);
			}
			// 右上
			if ((node.getX() + 1) < row && (node.getY() - 1) >= 0) {
				checkPath(node.getX() + 1, node.getY() - 1, node, eNode,
						COST_DIAGONAL);
			}
			// 右下
			if ((node.getX() + 1) < row && (node.getY() + 1) < column) {
				checkPath(node.getX() + 1, node.getY() + 1, node, eNode,
						COST_DIAGONAL);
			}
			// 从开启列表中删除
			// 添加到关闭列表中
			closeList.add(openList.remove(0));
			// 开启列表中排序,把F值最低的放到最底端
			Collections.sort(openList, new NodeFComparator());
			// System.out.println(openList);
		}
		if (isFind) {
			System.out.println("node = "+node.getParentNode());
			getPath(resultList, node);
		}
		return resultList;
	}

	/**
	 * 查询此路是否能走通
	 * @param x
	 * @param y
	 * @param parentNode
	 * @param eNode
	 * @param cost
	 * @return
	 */
	private boolean checkPath(int x, int y, Node parentNode, Node eNode,
			int cost) {
		//System.out.println("--------checkPath-------");
		Node node = new Node(x, y, parentNode);
		// 查找地图中是否能通过,不能通过则把该点加入到关闭列表
		if (map[x][y] == 1) {
			closeList.add(node);
			return false;
		}
		// 查找关闭列表中是否存在
		if (isListContains(closeList, x, y) != -1) {
			return false;
		}
		// 查找开启列表中是否存在
		int index = -1;
		if ((index = isListContains(openList, x, y)) != -1) {
			// G值是否更小,即是否更新G,F值
			if ((parentNode.getG() + cost) < openList.get(index).getG()) {
				node.setParentNode(parentNode);
				countG(node, eNode, cost);
				countF(node);
				openList.set(index, node);
			}
		} else {
			// 添加到开启列表中
			node.setParentNode(parentNode);
			count(node, eNode, cost);
			openList.add(node);
		}
		return true;
	}

	// 集合中是否包含某个元素(-1:没有找到,否则返回所在的索引)
	private int isListContains(List<Node> list, int x, int y) {
		//System.out.println("----------寻路中-------");
		for (int i = 0; i < list.size(); i++) {
			Node node = list.get(i);
			if (node.getX() == x && node.getY() == y) {
				return i;
			}
		}
		return -1;
	}

	// 从终点往返回到起点
	private void getPath(List<Node> resultList, Node node) {
		System.out.println("node = "+node);
		if (node.getParentNode() != null) {
			getPath(resultList, node.getParentNode());
		}
		resultList.add(node);
	}
	
	// 计算G,H,F值
	private void count(Node node, Node eNode, int cost) {
		countG(node, eNode, cost);
		countH(node, eNode);
		countF(node);
	}

	// 计算G值
	private void countG(Node node, Node eNode, int cost) {
		if (node.getParentNode() == null) {
			node.setG(cost);
		} else {
			node.setG(node.getParentNode().getG() + cost);
		}
	}

	// 计算H值
	private void countH(Node node, Node eNode) {
		node.setF((Math.abs(node.getX() - eNode.getX()) + Math.abs(node.getY()
				- eNode.getY())) * 10);
	}

	// 计算F值
	private void countF(Node node) {
		node.setF(node.getG() + node.getH());
	}
}

// 节点比较类
class NodeFComparator implements Comparator<Node> {
	@Override
	public int compare(Node o1, Node o2) {
		return o1.getF() - o2.getF();
	}

}


案例代码下载:http://download.csdn.net/detail/u013043346/9327155

你可能感兴趣的:(算法,寻路,寻路算法,A星算法,Java实现A星算法)