图论-有向带权图的最短路径(Dijkstra)算法

寻找两个顶点之间的最短路径



规则,总是派遣一个代理人到下一个城市,代理人的工作是记录源点到其它城市费用最小信息。
计算费用,构造一个数组,保持从源点到其他顶点的最短距离。在算法执行的过程中这个距离是变化的。直到最后,它存储了从源点开始的真正最短距离。


package com.mapbar.structure;
/**  

 * Class Graph_Dijkstra.java 

 * Description Dijkstra 最短路径算法,用数组替代优先级队列来存储最短距离

 * Company mapbar 

 * author Chenll E-mail: Chenll@mapbar.com

 * Version 1.0 

 * Date 2012-8-30 下午03:46:15

 */

//保存从起始点到当前点的距离以及父节点
class DistPar{
	
	public int distance;
	
	public int parVert;
	
	public DistPar(int pv, int dis){
		this.distance = dis;
		
		this.parVert = pv;
	}
}	

//定义顶点
class Vertex{
	
	public char label;
	
	public boolean isInTree;
	
	public Vertex(char label){
		this.label = label;
		isInTree = false;
	}
}

class Graph{
	
	private final int MAX_VERTX = 20; //节点数
	
	private final int INFINITY = 1000000; //最远距离

	private Vertex vertexList[];

	private int adjMat[][]; //邻接矩阵

	private int nVerts; //记录顶点的个数

	private int nTree; //记录树中顶点的个数

	private int currentVert; //当前顶点
	
	private DistPar sPath[];//最短路径数组,存储源点到其它顶点距离情况。
	
	private int startToCurrent;

	//构造方法
	public Graph() {
		vertexList = new Vertex[MAX_VERTX];
		adjMat = new int[MAX_VERTX][MAX_VERTX];
		nVerts = 0;
		// 初始化矩阵
		for (int i = 0; i < MAX_VERTX; i++) {
			for (int j = 0; j < MAX_VERTX; j++) {
				adjMat[i][j] = INFINITY;
			}
		}
		sPath = new DistPar[MAX_VERTX];
	}

	// 添加顶点
	public void addVertex(char label) {
		vertexList[nVerts++] = new Vertex(label);
	}

	// 添加边
	public void addEdge(int sv, int dv, int dis) {
		adjMat[sv][dv] = dis;
	}
	
	//路径规划
	public void path(){
		int startTree = 0;
		vertexList[0].isInTree = true;
		nTree = 1;
		
		for(int i = 0; i<nVerts; i++){
			int tempDis = adjMat[startTree][i];
			sPath[i] = new DistPar(startTree,tempDis);
		}
		
		while(nTree  < nVerts){
			//(1)找到sPath数组中最小的距离
			int indexMin= getMin();
			int minDis = sPath[indexMin].distance;
			if(minDis == INFINITY){
				break;
			} else {
				//(2) 设置当前顶点
				currentVert = indexMin;
				//源点到当前顶点的最短距离
				startToCurrent = sPath[indexMin].distance;
			}
			vertexList[currentVert].isInTree = true;
			nTree ++;
			//(3)根据当前顶点变化,调整数组
			adjust_sPath();
		}
		displayPath();
		//重置
		nTree = 0;
		for(int j = 0; j<nVerts; j++){
			vertexList[j].isInTree = false;
		}
	}
	
	//找到sPath[i]数组中未在树中并且距离最小的顶点
	public int getMin(){
		int minDis = INFINITY;
		int indexMin = 0;
		for(int i = 1; i<nVerts; i++){
			if(!vertexList[i].isInTree && sPath[i].distance < minDis){
				minDis =  sPath[i].distance;
				indexMin = i;
			}
		}
		return indexMin;
	}
	
	//根据当前顶点调整距离数组的值
	public void adjust_sPath(){
		//循环计数器,依次指向每个顶点
		int column = 1;
		while (column < nVerts){
			if(vertexList[column].isInTree){
				column ++;
				continue;
			}
			int currentToFringe = adjMat[currentVert][column];
			int startToFring =  currentToFringe + startToCurrent;
			int sPathDis= sPath[column].distance; 
			if(startToFring < sPathDis){
				//替换当前项,让数组总是存储从源点到所有已知顶点最短路径
				sPath[column].parVert = currentVert;
				sPath[column].distance = startToFring;
			}
			column ++;
		}
	}
	
	//显示数组就是源点到各个顶点的最短距离括号里面是父节点
	public void displayPath(){
		for(int j = 0; j<nVerts; j++){
			System.out.print(vertexList[j].label+"=");
			if(sPath[j].distance == INFINITY){
				System.out.print("INF");
			} else {
				System.out.print(sPath[j].distance);
			}
			char parent = vertexList[sPath[j].parVert].label;
			System.out.print("("+parent+") ");
		}
	}
}

public class Graph_Dijkstra {
	public static void main(String[] args){
		Graph g = new Graph();
		g.addVertex('A');
		g.addVertex('B');
		g.addVertex('C');
		g.addVertex('D');
		g.addVertex('E');
		
		g.addEdge(0, 1, 50);
		g.addEdge(0, 3, 80);
		g.addEdge(1, 2, 60);
		g.addEdge(1, 3, 90);
		g.addEdge(2, 4, 40);
		g.addEdge(3, 2, 20);
		g.addEdge(3, 4, 70);
		g.addEdge(4, 1, 50);
		g.path();
	}
}
输出结果:A=INF(A)  B=50(A)  C=100(D)  D=80(A)  E=140(C) 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值