码迷,mamicode.com
首页 > 编程语言 > 详细

基于无向图且权重单一的最短路径Dijkstra算法——JAVA实现

时间:2015-02-09 11:01:59      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:android   java   dijkstra   最短路径   

做一个无向图的权重单一的最短路径算法。

模拟停车场最近车位的选择。


首先参考了博友JavaMan_chen的博文
http://blog.csdn.net/javaman_chen/article/details/8254309

但是这个算法是有问题的。

算法中,如果A点是当前点,是选取距离A点权重最小的那一点作为下一个路径点的。

这就带来了一个问题,即,距离A点的2个点如果权重相同,那就会随机选取其中一条。

于是,在数据量稍微大点的时候,就出错了。


在这里使用Dijkstra算法使用的是用OPEN, CLOSE表的方式。

首先,定义了坐标点的数据结构

Coordinate.java


Coordinate中包含相邻坐标的List,以及距离起始点的距离。

在算法中,一开始要进行所有路径点的关联。

之后,通过从起始点进行扩散,将所有点的step计算出来。

<span style="font-size:18px;">package com.harlan.dijkstra;

import java.util.LinkedList;


/**
 * 坐标点的数据结构
 * 
 * @author Harlan
 * 
 */
public class Coordinate {
	//x坐标
	public int x;
	//y坐标
	public int y;
	//相邻坐标
	public LinkedList<Coordinate> adj;
	//距离
	public int steps;
	// 最短路径中的前一个顶点
	public Coordinate lastPoint;
;

	public Coordinate(){
		
	}
	
	public Coordinate(int newX, int newY) {
		x = newX;
		y = newY;
		adj=new LinkedList<Coordinate>();
		reset();
	}
	
	public void reset(){
		steps=Integer.MAX_VALUE;
		lastPoint=null;
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Coordinate))
			return false;

		Coordinate other = (Coordinate) obj;
		if (x == other.x && y == other.y) {
			return true;
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return x*10000+y;
	}

	/**
	 * 以JSON格式展示坐标
	 */
	@Override
	public String toString() {
		return "{\"x\":" + x + ",\"y\":" + y + "}";
	}
}
</span>

并定义了路径数据结构

PathInfo.java

<span style="font-size:18px;">package com.harlan.dijkstra;

import java.util.List;

/**
 * 路径信息
 * @author Harlan
 *
 */
public class PathInfo {

	//目标点的坐标
	private Coordinate targetCd;
	
	//去往目标点的最佳路径
	private List<Coordinate> cdList;

	public Coordinate getTargetCd() {
		return targetCd;
	}

	public void setTargetCd(Coordinate targetCd) {
		this.targetCd = targetCd;
	}

	public List<Coordinate> getCdList() {
		return cdList;
	}

	public void setCdList(List<Coordinate> cdList) {
		this.cdList = cdList;
	}
	
	
}
</span>


在算法中,对于路径点的关联方法:

<span style="font-size:18px;">/**
	 * 和周围的四个点建立关系
	 * 
	 * @param node
	 */
	private void getContactWithF(Coordinate node) {
		Coordinate coordinate = getCoordinate(node);
		Coordinate EAST = new Coordinate(node.x + 1, node.y);
		Coordinate SOUTH = new Coordinate(node.x, node.y + 1);
		Coordinate WEST = new Coordinate(node.x - 1, node.y);
		Coordinate NORTH = new Coordinate(node.x, node.y - 1);
		if (isCellSafe(EAST, mRoads)) {
			EAST = getCoordinate(EAST);
			coordinate.adj.add(EAST);
		}
		if (isCellSafe(SOUTH, mRoads)) {
			SOUTH = getCoordinate(SOUTH);
			coordinate.adj.add(SOUTH);
		}
		if (isCellSafe(WEST, mRoads)) {
			WEST = getCoordinate(WEST);
			coordinate.adj.add(WEST);
		}
		if (isCellSafe(NORTH, mRoads)) {
			NORTH = getCoordinate(NORTH);
			coordinate.adj.add(NORTH);
		}
	}

/**
	 * 判断周围的位子是不是道路
	 * 
	 * @param head
	 * @return
	 */
	public boolean isCellSafe(Coordinate park, Set<Coordinate> roads) {
		boolean isSafe = false;
		// 在道路集合里面,就是安全的,否则,不安全
		for (Coordinate info : roads) {
			if (info.equals(park)) {
				isSafe = true;
			}
		}
		return isSafe;
	}</span>

无权最短路径的算法如下:

<span style="font-size:18px;">// 无权最短路径计算
	public void unweighted(Coordinate enter) {

		if (enter == null)
			throw new NoSuchElementException("Start vertex not found!");

		LinkedList<Coordinate> q = new LinkedList<Coordinate>();
		
		clearAll();
		enter = vertexMap.get(enter.toString());

		System.out.println("unweighted Harlan:" + enter.adj.toString());

		q.addLast(enter);

		enter.steps = 0;

		while (!q.isEmpty()) {
			Coordinate v = q.removeFirst();
			for (Iterator<Coordinate> itr = v.adj.iterator(); itr.hasNext();) {
				Coordinate w = itr.next();
				if (w.steps == Integer.MAX_VALUE) {
					w.steps = v.steps + 1;
					w.lastPoint = v;
					q.addLast(w);
				}
			}
		}
	}
</span>

遍历获取实际最短路径
<span style="font-size:18px;">	private List<Coordinate> getPath(Coordinate dest, List<Coordinate> cdList) {
		if (dest.lastPoint != null) {
			cdList = (getPath(dest.lastPoint, cdList));
		}
		cdList.add(dest);
		return cdList;
	}</span>

显示最短路径:

<span style="font-size:18px;">	// 显示一条路径
	public void printPath(String coodrStr) throws NoSuchElementException {
		Coordinate coord = vertexMap.get(coodrStr);
		if (coord == null)
			throw new Exception(No path  found!");
		else if (coord.steps == Integer.MAX_VALUE)
			System.out.println(coord.toString() + "is unreachable!");
		else {
			printPath(coord);
			System.out.println();
		}
	}

	// 显示实际最短路径
	private void printPath(Coordinate dest) {

		if (dest.lastPoint != null) {
			printPath(dest.lastPoint);
			System.out.print(",");
		}
		System.out.print(dest.toString());
	}</span>

最后,写一个对外的使用类,便可以在Android或者其他地方使用了

GetDijkstraPath.java

<span style="font-size:18px;">package com.harlan.dijkstra;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class GetDijkstraPath {

	private static final String TAG = GetDijkstraPath.class.getSimpleName();
	
	/**
	 * 主函数,测试类
	 * @param args
	 */
	 public static void main(String[] args) {  
	    	Coordinate enter = new Coordinate(2, 0);
		
	    	Set<Coordinate> roads = new HashSet<Coordinate>();
	    	roads.add(new Coordinate(3, 10));
	    	roads.add(new Coordinate(3,11));
	    	roads.add(new Coordinate(3, 8));
	    	roads.add(new Coordinate(3, 9));
	    	roads.add(new Coordinate(3, 6));
	    	roads.add(new Coordinate(3, 7));
	    	roads.add(new Coordinate(3, 4));
	    	roads.add(new Coordinate(3, 5));
	    	roads.add(new Coordinate(3, 2));
	       	roads.add(new Coordinate(3, 3));
	    	roads.add(new Coordinate(3, 1));
	    	roads.add(new Coordinate(6, 1));
	    	roads.add(new Coordinate(1, 9));
	    	roads.add(new Coordinate(1, 8));
		roads.add(new Coordinate(1, 11));
		roads.add(new Coordinate(1, 10));
		roads.add(new Coordinate(1, 5));
		roads.add(new Coordinate(1, 4));
		roads.add(new Coordinate(1, 7));
		roads.add(new Coordinate(1, 6));
		roads.add(new Coordinate(1, 1));
		roads.add(new Coordinate(1, 3));
		roads.add(new Coordinate(1, 2));
		roads.add(new Coordinate(4, 1));
		roads.add(new Coordinate(4, 11));
		roads.add(new Coordinate(7, 5));
		roads.add(new Coordinate(7, 4));
		roads.add(new Coordinate(2, 11));
	    	roads.add(new Coordinate(7, 7));
	    	roads.add(new Coordinate(7,6));
	    	roads.add(new Coordinate(7, 1));
	    	roads.add(new Coordinate(7, 3));
	    	roads.add(new Coordinate(7,2));
	    	roads.add(new Coordinate(2, 1));
	    	roads.add(new Coordinate(7, 9));
	    	roads.add(new Coordinate(7,8));
	    	roads.add(new Coordinate(7, 11));
	    	roads.add(new Coordinate(7, 10));
	    	roads.add(new Coordinate(5,11));
	    	roads.add(new Coordinate(5, 10));
	    	roads.add(new Coordinate(5, 9));
	    	roads.add(new Coordinate(5,8));
	    	roads.add(new Coordinate(5,7));
	    	roads.add(new Coordinate(5,6));
	    	roads.add(new Coordinate(5,5));
	    	roads.add(new Coordinate(5,4));
	    	roads.add(new Coordinate(5,3));
	    	roads.add(new Coordinate(5,2));
	    	roads.add(new Coordinate(5,1));
	    	System.out.println("nearest roads.size(): "+roads.size());
	    	
	    	
	    	Set<Coordinate> trags = new HashSet<Coordinate>();
	    	trags.add(new Coordinate(5, 4));
	    	trags.add(new Coordinate(5, 5));
	    	PathInfo nearest = getNearestPathInfo(roads,trags,enter);
	    	System.out.println("nearest : "+nearest.getCdList());
	    }  
	
	 
	 /**
	  * 对外的接口(如果计算多入口的最短路径的时候使用)
	  * 获取多入口的最佳路径
	  * @param roads
	  * @param trags
	  * @param enters
	  * @return
	  */
	 public static PathInfo getNearestPathInfoFromDiffEnter(Set<Coordinate> roads,
				Set<Coordinate> trags, Set<Coordinate> enters){
		 List<PathInfo> list = new ArrayList<>();
		 for(Coordinate enter:enters){
			 list.add(getNearestPathInfo(roads,trags,enter));
		 }
		 //每条路径的步长
		 int steps = Integer.MAX_VALUE;
		 PathInfo nearste = new PathInfo();
		 for(PathInfo pathInfo:list){
			 if(pathInfo.getCdList().size()<steps){
				 steps = pathInfo.getCdList().size();
				 nearste = pathInfo;
			 }
		 }
		 return nearste;
		 
	 }
	 
	 
	 /**
	  * 对外的接口(如果计算单一入口的最短路径时候使用)
	  * 获取单一入口的最佳路径
	  * 
	  * @param roads
	  * @param trags
	  * @param enter
	  * @return
	  */
	 public static PathInfo getNearestPathInfo(Set<Coordinate> roads,
				Set<Coordinate> trags, Coordinate enter){
		 List<PathInfo> list = getAllAvailablePathInfo(roads,trags,enter);
//		 for(PathInfo info:list){
//	    		System.out.println("getNearestPathInfo targ:"+info.getTargetCd());
//	    		System.out.println("getNearestPathInfo route:"+info.getCdList());
//	    		System.out.println("getNearestPathInfo *********************");
//	    	}
//		 
		 //每条路径的步长
		 int steps = Integer.MAX_VALUE;
		 PathInfo nearste = new PathInfo();
		 for(PathInfo pathInfo:list){
			 if(pathInfo.getCdList().size()<steps){
				 steps = pathInfo.getCdList().size();
				 nearste = pathInfo;
			 }
		 }
		 return nearste;
	 }
	 
	
	/**
	 * 获取到达所有目标点的所有可用路径
	 * 
	 * @param roads
	 * @param trags
	 * @param enter
	 * @return
	 */
	private static List<PathInfo> getAllAvailablePathInfo(Set<Coordinate> roads,
			Set<Coordinate> trags, Coordinate enter) {
		Set<Coordinate> availableRoadTar = getAllRoadNearTarg(roads,trags);
		
    	//计算出起始点到各个可达点的距离
		HarlanDijkstra test=new HarlanDijkstra(roads,enter);  
	    test.unweighted(enter);
		
		//得出到停车位的可达点的最短路径
		List<PathInfo> availableList = new ArrayList<>();
		for(Coordinate info:availableRoadTar){
			PathInfo pathInfo = test.getPathInfo(info.toString());
			availableList.add(pathInfo);
			
		}
		return availableList;
	}

	
	/**
	 * 获取通往所有目标的有效道路点(一个目标的临近道路点的集合)
	 * @param roads
	 * @param tragSet
	 * @return
	 */
	private static Set<Coordinate> getAllRoadNearTarg(Set<Coordinate> roads,
			Set<Coordinate> tragSet) {
		Set<Coordinate> allOfNearList = new HashSet<>();
		for (Coordinate targ : tragSet) {
//			System.out.println("getAllRoadNearTarg targ:"+targ);
			Set<Coordinate> childSet = getRoadNearTarg(roads,targ);
			allOfNearList.addAll(childSet);
		}
		return allOfNearList;
	}
	
	/**
	 * 获取通往一个目标的临近道路点
	 * 
	 * @param roads
	 * @param targ
	 * @return
	 */
	private static Set<Coordinate> getRoadNearTarg(Set<Coordinate> roads,
			Coordinate targ) {
		Set<Coordinate> nearList = new HashSet<>();
		Coordinate EAST = new Coordinate(targ.x + 1, targ.y);
		Coordinate SOUTH = new Coordinate(targ.x, targ.y + 1);
		Coordinate WEST = new Coordinate(targ.x - 1, targ.y);
		Coordinate NORTH = new Coordinate(targ.x, targ.y - 1);
		for (Coordinate info : roads) {
			if (EAST.equals(info)) {
				nearList.add(EAST);
			}
			if (SOUTH.equals(info)) {
				nearList.add(SOUTH);
			}
			if (WEST.equals(info)) {
				nearList.add(WEST);
			}
			if (NORTH.equals(info)) {
				nearList.add(NORTH);
			}
		}
		return nearList;
	}

}</span>


在Main方法中,距离可达目标点(5, 4)或(5, 5)输出如下:

<span style="font-size:18px;">nearest roads.size(): 49
nearest : [{"x":2,"y":0}, {"x":2,"y":1}, {"x":3,"y":1}, {"x":4,"y":1}, {"x":5,"y":1}, {"x":5,"y":2}, {"x":5,"y":3}]</span>
输出路径为json格式的,方便取用解析。




在Android中,改编贪食蛇的源码进行相关"地图"的随机生成。

经过各种检验,算法无误。






基于无向图且权重单一的最短路径Dijkstra算法——JAVA实现

标签:android   java   dijkstra   最短路径   

原文地址:http://blog.csdn.net/singleton1900/article/details/43667267

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!