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

来源:互联网 发布:视频制作软件下载 编辑:程序博客网 时间:2024/05/16 19:32

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

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


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

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

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

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

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


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

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

Coordinate.java


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

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

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

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 + "}";      }  }  

并定义了路径数据结构

PathInfo.java

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 style="white-space:pre"></span> /** * 和周围的四个点建立关系 *  * @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 style="white-space:pre"></span>// 无权最短路径计算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 style="white-space:pre"></span>private List<Coordinate> getPath(Coordinate dest, List<Coordinate> cdList) {if (dest.lastPoint != null) {cdList = (getPath(dest.lastPoint, cdList));}cdList.add(dest);return cdList;}


显示最短路径:

<span style="white-space:pre"></span>// 显示一条路径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());}


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

GetDijkstraPath.java

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;}}

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

nearest roads.size(): 49nearest : [{"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}]

输出路径为json格式的,方便取用解析。


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

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





0 0
原创粉丝点击