迪杰斯特拉算法求最短路径


一、什么是迪杰斯特拉算法?

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法策略,广度优先思想,一步一步算出距离起始点最近且未访问过的顶点,直至所有顶点都被访问最终可得出起始点到所有顶点的最短路径。

二、实现步骤

本代码使用永久和临时标号方式来实现。
1、初始化起始点到其他顶点的路径及权值,不存在边的权值为0。
2、选出当前距离起始点权值最小的顶点,总权值为0和永久顶点除外,标记当前选中的顶点为永久顶点。
3、根据步骤2⃣️选出的顶点,遍历它的直接临界点,如果起始点到当前遍历顶点的总权值比之前统计的总权值小,则更新起始点到该顶点的路径及权值。
4、重复步骤2⃣️3⃣️,直至所有顶点全部遍历完成。

三、实现代码

代码如下(示例):

public class Test {

	/**
	 * 所有端点名称
	 */
	private static final String[] ENDPOINT_NAMES;
	/**
	 * 端点矩阵  图
	 */
	private static final int[][] GRAPH;

	/**
	 * 起点 下标
	 */
	private static final int START_ENDPOINT_INDEX;


	static {
		ENDPOINT_NAMES = new String[]{"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8"};
		GRAPH = new int[9][9];
		for (int i = 0; i < GRAPH.length; i++) {
			for (int j = 0; j < GRAPH[i].length; j++) {
				if (i == j) {
					GRAPH[i][j] = 0;
				} else {
					GRAPH[i][j] = -1;
				}

			}
		}
		GRAPH[0][1] = 1;
		GRAPH[1][0] = 1;

		GRAPH[0][2] = 5;
		GRAPH[2][0] = 5;

		GRAPH[1][2] = 3;
		GRAPH[2][1] = 3;

		GRAPH[1][3] = 7;
		GRAPH[3][1] = 7;

		GRAPH[1][4] = 5;
		GRAPH[4][1] = 5;

		GRAPH[2][4] = 1;
		GRAPH[4][2] = 1;

		GRAPH[2][5] = 7;
		GRAPH[5][2] = 7;

		GRAPH[4][3] = 2;
		GRAPH[3][4] = 2;

		GRAPH[6][3] = 3;
		GRAPH[3][6] = 3;

		GRAPH[4][6] = 6;
		GRAPH[6][4] = 6;

		GRAPH[4][7] = 9;
		GRAPH[7][4] = 9;

		GRAPH[4][5] = 3;
		GRAPH[5][4] = 3;

		GRAPH[5][7] = 5;
		GRAPH[7][5] = 5;

		GRAPH[6][7] = 2;
		GRAPH[7][6] = 2;

		GRAPH[6][8] = 7;
		GRAPH[8][6] = 7;

		GRAPH[7][8] = 4;
		GRAPH[8][7] = 4;

		//随机选择起点、终点
		Random random = new Random();
		START_ENDPOINT_INDEX = random.nextInt(ENDPOINT_NAMES.length - 1);

	}


	public static void main(String[] args) {

		ShortestPath[] shortestPaths = init(GRAPH[START_ENDPOINT_INDEX]);

		List<Integer> visitedEndPointIndexList = new ArrayList<>(shortestPaths.length);
		visitedEndPointIndexList.add(START_ENDPOINT_INDEX);

		selectAndUpdateShortestPath(shortestPaths, visitedEndPointIndexList);

		for (int i = 0; i < shortestPaths.length; i++) {
			if (i == START_ENDPOINT_INDEX) {
				continue;
			}
			ShortestPath temp = shortestPaths[i];
			System.out.print(ENDPOINT_NAMES[START_ENDPOINT_INDEX] + "到" + ENDPOINT_NAMES[i] + "最短权值为:" + temp.getTotalWeight() + "  ");
			List<EndPoint> pathList = temp.getLinkedList();
			for (EndPoint endPoint : pathList) {
				System.out.print(endPoint.getName() + "->");
			}
			System.out.println();
		}
	}

	/**
	 * 筛选当前离源点最近的端点并且更新原点到其他端点的最短路径
	 * 时间复杂度 n的平方,n为端点数
	 *
	 * @param shortestPaths
	 * @param visitedEndPointIndexList
	 */
	private static void selectAndUpdateShortestPath(ShortestPath[] shortestPaths, List<Integer> visitedEndPointIndexList) {

		int minWeight = Integer.MAX_VALUE;
		ShortestPath minShortestPath = null;
		int nextIndex = -1;

		for (int i = 0; i < shortestPaths.length; i++) {

			ShortestPath temp = shortestPaths[i];
			int weight = temp.getTotalWeight();
			if (weight == 0) {
				continue;
			}
			if (visitedEndPointIndexList.contains(i)) {
				continue;
			}
			if (weight < minWeight) {
				nextIndex = i;
				minWeight = weight;
				minShortestPath = temp;
			}
		}
		if (nextIndex == -1) {
			return;
		}
		visitedEndPointIndexList.add(nextIndex);
		int[] nextSearch = GRAPH[nextIndex];
		for (int i = 0; i < nextSearch.length; i++) {
			int weight = nextSearch[i];
			if (weight == -1 || nextIndex == i || visitedEndPointIndexList.contains(i)) {
				continue;
			}
			int totalWeight = minShortestPath.getTotalWeight() + weight;
			ShortestPath currentPath = shortestPaths[i];
			int currentTotalWeight = currentPath.getTotalWeight();
			// 更新最短路径
			if (currentTotalWeight > totalWeight || currentTotalWeight == 0) {
				LinkedList<EndPoint> linkedList = new LinkedList<>();
				linkedList.addAll(minShortestPath.getLinkedList());
				linkedList.add(new EndPoint(ENDPOINT_NAMES[i], weight));
				shortestPaths[i] = new ShortestPath(totalWeight, linkedList);
			}
		}
		selectAndUpdateShortestPath(shortestPaths, visitedEndPointIndexList);

	}


	/**
	 * 初始化 源点到其他端点的路径
	 *
	 * @param array
	 * @return
	 */
	private static ShortestPath[] init(int[] array) {
		ShortestPath[] shortestPaths = new ShortestPath[array.length];
		ShortestPath currentPointPath;
		List<EndPoint> linkedList;
		EndPoint endPoint;
		for (int i = 0; i < array.length; i++) {

			int weight = array[i];
			linkedList = new LinkedList();
			endPoint = new EndPoint(ENDPOINT_NAMES[START_ENDPOINT_INDEX], 0);
			linkedList.add(endPoint);
			currentPointPath = new ShortestPath(0, linkedList);
			shortestPaths[i] = currentPointPath;
			// 说明没边
			if (weight == -1) {

				continue;
			}
			endPoint = new EndPoint(ENDPOINT_NAMES[i], weight);
			linkedList.add(endPoint);
			currentPointPath.setTotalWeight(currentPointPath.getTotalWeight() + weight);

		}
		return shortestPaths;

	}


}

@Data
@AllArgsConstructor
class EndPoint {
	/**
	 * 端点名称
	 */
	private String name;
	/**
	 * 权值
	 */
	private Integer weight;
}

@Data
@AllArgsConstructor
class ShortestPath {
	/**
	 * 路径总权值
	 */
	private Integer totalWeight;
	/**
	 * 路径
	 */
	private List<EndPoint> linkedList;
}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了狄迪斯特拉的算法的原理及实现.由于它遍历计算的节点很多,所以效率低,可以自行根据其他数据结构进行优化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值