Java实现的Dijkstra最短路径算法._JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java实现的Dijkstra最短路径算法.

Java实现的Dijkstra最短路径算法.

 2013/8/9 18:20:17  a27574520  程序员俱乐部  我要评论(0)
  • 摘要:首先是核心的Dijkstra类:packagemx.dijkstra;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;importjava.util.Stack;/***基于Dijkstra贪心算法的最短路径寻找先初始化init初始化一次只可以调用一次dijkatra方法
  • 标签:实现 Java 算法

首先是核心的Dijkstra类:

class="java" name="code">package mx.dijkstra;

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

/**
 * 基于 Dijkstra 贪心算法的最短路径寻找 先初始化 init 初始化一次 只可以调用一次 dijkatra方法.再次调用请重新初始化
 * @author Dewey
 */
public class Dijkstra {

	/**
	 * 点的键值集合,标识从起点到每个点的权重总和
	 */
	private Map<Point, Integer> pointKeys = new HashMap<Point, Integer>();
	/**
	 * 边集合,两个点成一条边.用来表示那些点可以连通和所需的权重.
	 */
	private ArrayList<Edge> edges = new ArrayList<Edge>();
	/**
	 * 从起点到每个点的最短路径集合,当算法执行完毕时,里面保存着从起点到各个点的最短路径
	 */
	private Map<Point, Dist> paths = new HashMap<Point, Dist>();
	/**
	 * 表示无穷大的常量
	 */
	private static final int INFINITY = 99999;

	/**
	 * 清空所有集合
	 */
	private void reset() {
		pointKeys.clear();
		edges.clear();
		paths.clear();
	}

	/**
	 * 初始化
	 * 
	 * @param source 点的集合
	 * @param edegs 边的集合
	 * @param start 寻径的起点
	 */
	private void init(ArrayList<Point> source, ArrayList<Edge> edegs, Point start) {
		reset();
		this.edges = edegs;
		for (int i = 0; i < source.size(); i++) {// 取出每个点
			Point v = source.get(i);
			// 把每个点放入键值集合
			if (v.equals(start)) {// 当前点为起点
				// 起点到起点的键值为0
				pointKeys.put(v, 0);
			} else {
				// 到其他点为无穷大
				pointKeys.put(v, INFINITY);
			}
			// 初始化从起点到起点的路径
			Dist dist = new Dist();
			dist.setPoint(start);// 路程点为起点
			dist.setPreDist(null);// 前一个点为null
			dist.setWeight(0);// 路程开销为0
			paths.put(start, dist);// 放入路径集合
		}
	}

	/**
	 * dijkstra 算法实现
	 * @param source 点
	 * @param edegs 边
	 * @param start 寻径的起点
	 * @param end 需要寻的终点
	 * @return
	 */
	public Stack<Point> dijkstra(ArrayList<Point> source, ArrayList<Edge> edegs, Point start, Point end) {
		init(source, edegs, start);
		Integer endPointKey = null;// 从当前点走向下一个点 下一个点原来所需要的开销
		while (pointKeys.size() > 0) {// 键值集合所存在的点大于0
			Point minkeyPoint = getMinKey(pointKeys);// 获得当前键值几个拥有最小键值(开销)的点 称为当前点
			int keyValue = pointKeys.get(minkeyPoint);// 获得拥有最小键值点的键值
			ArrayList<Edge> adjacentEdegs = getEdegs(edges, minkeyPoint);// 寻找与这个点相邻的边
			for (Edge edge : adjacentEdegs) {// 遍历相邻的边
				int currentKey = keyValue + edge.getWeight();// 从起点到当前点的开销 + 通过这条边到下一个点的开销 称为当前开销
				endPointKey = pointKeys.get(edge.getEnd());// 获取从起点到当前边对面点的开销
				if (endPointKey == null) {// 若获取不到 则说明对面的点已经不存在于键值集合 通常是个环路
					continue;// 可能是个环路 或 不可达
				}
				updatePath(endPointKey, edge, currentKey);// 更新路径
			}
			pointKeys.remove(minkeyPoint);
		}
		return getPaths(end);
	}

	/**
	 * 更新路径
	 * @param endPointKey
	 * @param edge
	 * @param currentKey
	 */
	private void updatePath(Integer endPointKey, Edge edge, int currentKey) {
		Dist advance = null;// 每次寻径所走的路线 单步
		if (currentKey < endPointKey) {// 若当前开销 小于 原来从起点到边对面点的开销 则更新对点的键值
			pointKeys.put(edge.getEnd(), currentKey);// 覆盖原来的键值
			advance = new Dist();// 创建新的路程
			advance.setPoint(edge.getEnd());// 起点为 对面边的点
			advance.setPreDist(paths.get(edge.getStart()));// 前一个点为当前点
			advance.setWeight(edge.getWeight());// 路程长度为边的权重
			paths.put(edge.getEnd(), advance);// 放入路径集合
		}
	}

	/**
	 * 算法执行完毕后 寻找重点为参数点的路径 返回路径点的栈 因为终点会被最后找到,所以返回一个栈
	 * 而不是数组,这样遍历比较方便.直接执行初战操作就可以得到正确的从起点到终点所需要的点
	 * @param end
	 * @return
	 */
	private Stack<Point> getPaths(Point end) {
		Stack<Point> stack = null;
		Iterator<Point> iterator = paths.keySet().iterator();
		while (iterator.hasNext()) {
			stack = new Stack<Point>();
			Point c = iterator.next();
			if (!c.equals(end)) {
				continue;
			}
			Dist td = paths.get(c);
			while (td != null) {
				stack.push(td.getPoint());
				td = td.getPreDist();
			}
			break;
		}
		return stack;
	}

	/**
	 * 在集合中寻找值最小的元素
	 * @param pointKeys
	 * @return
	 */
	private Point getMinKey(Map<Point, Integer> pointKeys) {
		Iterator<Point> iterator = pointKeys.keySet().iterator();
		int minValue = INFINITY;
		Point minKeyPoint = null;
		while (iterator.hasNext()) {
			Point point = iterator.next();
			Integer value = pointKeys.get(point);
			if (value < minValue) {
				minValue = value;
				minKeyPoint = point;
			}
		}
		return minKeyPoint;
	}

	/**
	 * 寻找与参数点相邻的边
	 * @param edges
	 * @param point
	 * @return
	 */
	private ArrayList<Edge> getEdegs(ArrayList<Edge> edges, Point point) {
		ArrayList<Edge> tempEdges = new ArrayList<Edge>();
		for (Edge edge : edges) {
			if (edge.getStart().equals(point)) {
				tempEdges.add(edge);
			}
		}
		return tempEdges;
	}

}

最基本的:点的类,只是为了在寻径的时候在内存中标示一个点就可以了,如果需要属性,可以自行添加.在算法中不需要.

package mx.dijkstra;
/**
 * 点
 * @author Dewey
 */
public class Point {
}

?

边的类,两条点组成一条边,并且边有权重(可以是长度),用来标示点与点之间的可连通关系,有向图的连通性就依赖这个类.

package mx.dijkstra;


/**
 * 点与点组成的边
 * @author Dewey
 *
 */
public class Edge {
	/**
	 * 起点
	 */
	private Point start;
	/**
	 * 结束点
	 */
	private Point end;
	/**
	 * 权重
	 */
	private int weight;
	
	public Edge(Point start,Point end,int weight){
		this.start=start;
		this.end=end;
		this.weight=weight;
	}
	public Point getStart() {
		return start;
	}
	public void setStart(Point start) {
		this.start = start;
	}
	public Point getEnd() {
		return end;
	}
	public void setEnd(Point end) {
		this.end = end;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
}

??

路程类,标示算法每一步的前进所需要的两个点.

package mx.dijkstra;

/**
 * 路程
 * @author Dewey
 */
public class Dist{
	/**
	 * 路程的开销 
	 */
	private int weight;
	/**
	 * 路程点 
	 */
	private Point point;
	/**
	 * 前一个点
	 */
	private Dist preDist;
	
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	public Point getPoint() {
		return point;
	}
	public void setPoint(Point point) {
		this.point = point;
	}
	public Dist getPreDist() {
		return preDist;
	}
	public void setPreDist(Dist preDist) {
		this.preDist = preDist;
	}
}

?

一个小例子:

	public void demo1() {
		//声明点
		Point A = new MPoint(1,0,0);//id,x坐标,y坐标
		Point B = new MyPoint(2,0,0);
		Point C = new MyPoint(3,0,0);
		Point D = new MyPoint(4,0,0);
		Point E = new MyPoint(5,0,0);
		//放入点集合
		ArrayList<Point> source = new ArrayList<Point>();
		source.add(A);
		source.add(B);
		source.add(C);
		source.add(D);
		source.add(E);
		//声明边
		ArrayList<Edge> edges = new ArrayList<Edge>();
		edges.add(new Edge(A, B, 10));
		edges.add(new Edge(A, C, 5));
		edges.add(new Edge(B, C, 2));
		edges.add(new Edge(B, D, 1));
		edges.add(new Edge(C, B, 3));
		edges.add(new Edge(C, D, 9));
		edges.add(new Edge(C, E, 2));
		edges.add(new Edge(D, E, 4));
		edges.add(new Edge(E, D, 6));
		edges.add(new Edge(E, A, 7));
		
		Dijkstra d = new Dijkstra();
		Stack<Point> points = d.dijkstra(source, edges, A, D);//提供 点的集合 边的集合 起点 终点 开始寻径
		while (points.size() > 0) {
			Point p = points.pop();
			System.out.print(((MyPoint)p).getId()+">");//打印
		}
	}

?

?

  • Java-Dijkstra-master.zip (1.5 MB)
  • 下载次数: 0
发表评论
用户名: 匿名