算法和数据结构(12)最短路径1

最短路径问题

最短路径

在上篇007的问题中,若想求得可行路径中,路径最短的一条路是什么呢?

无权图的单源最短路径

复习:无权图。权:在图的边和弧相关的数,权可以表示从一个顶点到另一个顶点的耗费/距离等;

算法思想:

通过bfs算法,当每一层的结点都遍历,判断当前层的结点的属性;判断这层结点是否符合你的end要求(例如 007是否跳至岸边);因为bfs算法是每层的扫描,当前层入符合end要求,必然是最短路径;

故我们需要在bfs循环中,去保存当前的层的distance(距离)或者path(路径),可以采取数组/map等数据结构,同时也可以自己创建类;

前篇007:https://editor.csdn.net/md/?articleId=104146261

007问题深化:求007的最短路径需要跳多少次,或者求007的路径

下列为解决代码,若需要路径,遍历下述的path的HashMap 即可拿到;

注意:path中存的为每个结点的最短路径中的父类结点对象;拿到具体路径,直接遍历达到终止时即可;

 public int shortestWay(Node node) {
        HashMap<String, Integer> dist = new HashMap<>();
        HashMap<Node, Node> path = new HashMap<>();
        Queue<Node> queue = new Queue<>();
        queue.add(node);
        dist.put(node.name, 0);
        path.put(node, null);
        Node endNode = null;
        while (queue.isEmpty()) {
            Node node1 = queue.peek();
            for (Node nearNode : node1.nearNode()) {
                if (!dist.containsKey(nearNode.name)) {
                    dist.put(nearNode.name, dist.get(node1.name) + 1);
                    path.put(nearNode, node1);
                    queue.add(nearNode);
                    if ((Math.abs(nearNode.x) - xEdge) < 1 || (Math.abs(nearNode.y) - yEdge) < 1) {
                        endNode = nearNode;
                        break;
                    }
                }
            }
        }
        if (endNode == null) throw new RuntimeException("can't jump to edge");
        return dist.get(endNode.name);
    }

###有权图的单源最短路径算法

Dijkstra算法

核心思想:在无权最短路径算法的基础,增加当前收录源点s 和 到达该目的地的v的 的最短路径的权值/路径,当权值/路径大于了当前权值,说明非权重最小的情况,不断的让该权重递减,退出循环时,即是最小权值;在此过程中,不断收录最短路径的顶点v;

换言之:A->…->B->…->C是A到C的一条最短路径,那么这条路径中经过B点,在这条路径中A到B的路径也是A到B的最短路径,即:一条最短路径中包含路过的所有节点的最短路径

令s = {源点s + 已经确定了最短路径的顶点vi}

对任一路径v,定义dist[v]为s到v的最短路径长度,但该路径仅经历s中收录的顶点。

若路径按递增顺序生成,则:

  1. 真正的最短路径必须只经过s中收录过的顶点
  2. 每次未收录的顶点中选一个dist最小的收录

需要基于邻接矩阵 / 邻接表 进行实现:

复习:https://blog.csdn.net/qq_32193775/article/details/104133695

//伪代码如下
public void dijkstra(int v){
	while(true){
		
	}

}

代码如下:

public int[] dijkstra(int v) {
		if (v < 0 || v >= numOfVexs)
			throw new ArrayIndexOutOfBoundsException();
		boolean[] st = new boolean[numOfVexs];// 默认初始为false
		int[] distance = new int[numOfVexs];// 存放源点到其他点的矩离
		
		for (int i = 0; i < numOfVexs; i++)
			for (int j = i + 1; j < numOfVexs; j++) {
				if (edges[i][j] == 0) {
					edges[i][j] = Integer.MAX_VALUE;
					edges[j][i] = Integer.MAX_VALUE;
				}
			}
		for (int i = 0; i < numOfVexs; i++) {
			distance[i] = edges[v][i];
		}
		st[v] = true;
		// 处理从源点到其余顶点的最短路径
		for (int i = 0; i < numOfVexs; ++i) {
			int min = Integer.MAX_VALUE;
			int index=-1;
			// 比较从源点到其余顶点的路径长度
			for (int j = 0; j < numOfVexs; ++j) {
				// 从源点到j顶点的最短路径还没有找到
				if (st[j]==false) {
					// 从源点到j顶点的路径长度最小
					if (distance[j] < min) {
						index = j;
						min = distance[j];
					}
				}
			}
			//找到源点到索引为index顶点的最短路径长度
			if(index!=-1)
			st[index] = true;
			// 更新当前最短路径及距离
			for (int w = 0; w < numOfVexs; w++)
				if (st[w] == false) {
					if (edges[index][w] != Integer.MAX_VALUE
							&& (min + edges[index][w] < distance[w]))
						distance[w] = min + edges[index][w];
				}
		}
		return distance;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值