数据结构重读 - 单源最短路径(Dijkstra)

单源最短路径:给定带权有向图和源点v,求从v到G中其余各点的最短路径。

Dijkstra算法非常类似于最小生成树算法(的Prim)。

算法

0、假设源为v0,设置辅助变量dist和pre,优先队列pq,按照dist[x]从小到达排序(小顶堆)。

1、如果v0->i连通,初始化dist[i]为w[v0][i]。放(dist[i], i)入pq。

2、循环,直到pq为空。

2.1、取出pq中最小的,设其下标为x,

2.2、遍历图matrix[x][i], i 0->nvexs。如果dist[x]+matrix[x][i] < dist[i],更新dist[i]=dist[x]+matrix[x][i],并且放(dist[i], i)入pq,并且pre[i] = x。

3、如果dist[i]<INFINTE,输出dist[i],并倒序输出pre[?]直到为-1。

上述这么搞,时间复杂度应该为O(nlogn)

好了,代码如下:

图及输入

import java.util.Arrays;
import java.util.Scanner;

public class Graph {

	public Graph() {
		scan = new Scanner(System.in);
	}

	public void input() {
		intput_vexs();
		input_arcs();
	}

	private void intput_vexs() {
		// Input vexs
		int nvexs = 0;
		System.out.println("Please enter n for vexs:");
		if (scan.hasNextInt()) {
			nvexs = scan.nextInt();
		}
		vexs = new int[nvexs];
		for (int i = 0; i < nvexs; i++) {
			System.out.println("Please enter a integer for vex(" + i + "):");
			if (scan.hasNextInt()) {
				vexs[i] = scan.nextInt();
			}
		}
	}

	private void input_arcs() {
		// Input weight between vexs
		int nvexs = vexs.length;
		matrix = new int[nvexs][];
		for (int i = 0; i < nvexs; i++) {
			matrix[i] = new int[nvexs];
			Arrays.fill(matrix[i], Integer.MAX_VALUE);
		}
		int narcs = 0;
		int x = 0, y = 0, w = 0;
		System.out.println("Please enter n for arcs:");
		if (scan.hasNextInt()) {
			narcs = scan.nextInt();
		}
		for (int i = 0; i < narcs; i++) {
			System.out.println("Please enter x, y, w for arc(" + i + "):");
			if (scan.hasNextInt()) {
				x = scan.nextInt();
				x = vex2i(x);
			}
			if (scan.hasNextInt()) {
				y = scan.nextInt();
				y = vex2i(y);
			}
			if (scan.hasNextInt()) {
				w = scan.nextInt();
			}
			if (x == -1 || y == -1 || w <= 0) {
				System.out.println("x or y or w invalid, please enter again:");
				i--;
			} else {
				matrix[x][y] = w;
			}
		}
	}

	public int vex2i(int v) {
		for (int i = 0; i < vexs.length; i++) {
			if (v == vexs[i]) {
				return i;
			}
		}
		return -1;
	}

	public int[][] matrix = null;
	public int[] vexs = null;
	private Scanner scan = null;

	public static void main(String[] args) {
		Graph g = new Graph();
		g.input();
		System.out.println("vexs:");
		for (int i = 0; i < g.vexs.length; i++) {
			System.out.print(g.vexs[i] + " ");
		}
		System.out.println();
		System.out.println("matrix:");
		for (int i = 0; i < g.matrix.length; i++) {
			for (int j = 0; j < g.matrix[i].length; j++) {
				System.out.format("%11d ", g.matrix[i][j]);
			}
			System.out.println();
		}
	}
}

Dijkstra算法

import java.util.Comparator;
import java.util.PriorityQueue;

class DijPair {

	public DijPair(int i, int w) {
		this.i = i;
		this.w = w;
	}

	public int i;
	public int w;
}

public class Dijkstra {

	public void SetGraph(Graph g) {
		this.g = g;
	}

	public void ShortPath(int start) {
		// Convert start to position
		int v = g.vex2i(start);
		if (v == -1) {
			System.out.println("start vex " + start + " invalid");
		}
		// PriorityQueue
		PriorityQueue<DijPair> pq = new PriorityQueue<DijPair>(10,
				new Comparator<DijPair>() {
					@Override
					public int compare(DijPair a, DijPair b) {
						return a.w - b.w;
					}
				});
		// Init dist & pre
		int dist[] = new int[g.vexs.length];
		int pre[] = new int[g.vexs.length];
		for (int i = 0; i < g.matrix[v].length; i++) {
			pre[i] = -1;
			dist[i] = g.matrix[v][i];
			if (dist[i] != Integer.MAX_VALUE) {
				pre[i] = v;
				pq.add(new DijPair(i, dist[i]));
			}
		}
		// While not empty
		while (!pq.isEmpty()) {
			// Pool the smallest w and it's i
			DijPair cur = pq.poll();
			if (cur == null) {
				break;
			}
			// Update dist if smaller
			for (int i = 0; i < g.matrix[cur.i].length; i++) {
				if (g.matrix[cur.i][i] != Integer.MAX_VALUE
						&& dist[cur.i] + g.matrix[cur.i][i] < dist[i]) {
					dist[i] = dist[cur.i] + g.matrix[cur.i][i];
					pre[i] = cur.i;
					pq.add(new DijPair(i, dist[i]));
				}
			}
		}
		// End
		for (int i = 0; i < dist.length; i++) {
			if (dist[i] != Integer.MAX_VALUE) {
				System.out.format("short_dist %d to %d is %d ", start,
						g.vexs[i], dist[i]);
				System.out.print(", path is ");
				System.out.format("%d ", g.vexs[i]);
				int tmp = pre[i];
				while (tmp != -1) {
					System.out.format("<- %d ", g.vexs[tmp]);
					tmp = pre[tmp];
				}
				System.out.println();
			}
		}
	}

	private Graph g = null;;

	public static void main(String[] args) {
		Graph g = new Graph();
		g.input();
		Dijkstra dij = new Dijkstra();
		dij.SetGraph(g);
		dij.ShortPath(0);
	}
}

测试图:

测试数据:

6
0
1
2
3
4
5
8
0 5 100
0 2 10
0 4 30
1 2 5
2 3 50
4 3 20
3 5 10
4 5 60

测试输出:

short_dist 0 to 2 is 10 , path is 2 <- 0
short_dist 0 to 3 is 50 , path is 3 <- 4 <- 0
short_dist 0 to 4 is 30 , path is 4 <- 0
short_dist 0 to 5 is 60 , path is 5 <- 3 <- 4 <- 0

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *