Direxla のアルゴリズム
簡単に言うと、有向グラフでは、グラフ内の特定の開始点が与えられた場合、この点から到達できるすべての点と各点の間の最短距離はどれくらいになりますか。到達できない点の場合、距離は正の無限大になります。有向、負の重みなし、リングを持つことができます。
したがって、Direxla のアルゴリズムは、ソース ポイントから各ポイントまでの最小距離テーブルを生成することです。
例: 図に示すような有向グラフ
与えられた開始点 a から出発して、最終的に取得する必要があるのは、a と b、c、d、e の各点の間の最短距離です。デフォルトでは、 a からそれ自体までの距離は 0 で、まだ到達していない他の点からの距離は正の無限大です。決定された答えは変更されず、未決定のレコードの中から最小のものが見つかります。
ある | b | c | d | e |
---|---|---|---|---|
0 | 正の無限大 | 正の無限大 | 正の無限大 | 正の無限大 |
したがって、点aから始まる1、2、6の3つの面から始めます。重み 1 のエッジを見つけます。ad の距離は 1 で、前の正の無限大よりも小さい (前の距離よりも小さい) ため、a と d の間の距離を更新します。同じことが bcd にも当てはまります。アップデート後の距離は以下の通りです。
ある | b | c | d | e |
---|---|---|---|---|
0 | 2 | 6 | 1 | 正の無限大 |
この時点でaから始まる3辺は完成しているので、点aが確定して再度移動することはありません。
残った未確定レコードのうち、d が最も短い(a から b までの距離が 1)ので、d から下を見ていきます(d は中央のジャンプポイントに属します)。
d から始まる 2 つの辺、つまり dc と de があります。このうち、dc の距離は 2 で、それに以前の a から d までの距離が 1 であるため、d ジャンプ後の a から c までの距離は 3 となり、前の 6 よりも小さくなります。そのため、ac 間の距離を更新し、同じ距離は正の無限大より 7 小さいです。それで、それも更新してください。dも決まります。
ある | b | c | d | e |
---|---|---|---|---|
0 | 2 | 3 | 1 | 7 |
次に、不確かな記録から小さいものから順に見ていく。点bから始まる辺にbeがあり、beの距離は9、aからbまでの距離は2なのでbeの距離は11となり更新されません。bも決まります。
ある | b | c | d | e |
---|---|---|---|---|
0 | 2 | 3 | 1 | 7 |
まだ c があり、点 c から始まる 2 つの辺、cb と ce があります。点 b は決定されており移動しないため、ce の 1 つの直線を見てください。ce 間の距離は 3、a 間の距離はc は 3 なので、ae と e 間の距離は 6 となり、点間距離は以前よりも小さくなり、点 e 間の距離が更新されます。
ある | b | c | d | e |
---|---|---|---|---|
0 | 2 | 3 | 1 | 6 |
このコードは
上記の分析に基づいてコードを実装していますが、minNode が見つかるたびにコレクションを 1 回走査するため、getMinDistanceAndUnSelectNode には欠陥があります。コードの最適化は以下で行われます。
public static HashMap<Node, Integer> dijkstra1(Node from) {
HashMap<Node, Integer> distanceMap = new HashMap<>();
distanceMap.put(from, 0);
//已经确定的边;
HashSet<Node> selectedNodes = new HashSet<>();
//根据已经确定的记录 和 map,找出没确定的中最小的记录
Node minNode = getMinDistanceAndUnSelectNode(distanceMap, selectedNodes);
while (minNode != null) {
int distance = distanceMap.get(minNode);
for (Edge edge : minNode.edges) {
Node toNode = edge.to;
if (!distanceMap.containsKey(toNode)) {
distanceMap.put(toNode, distance + edge.weight);
} else {
//edge.weight + distance 当前边的权重 + 我此时当做跳点的距离。
//distanceMap.get(toNode) 已经存在的距离
distanceMap.put(toNode, Math.min(distanceMap.get(toNode), (edge.weight + distance)));
}
}
//所有的边都已经遍历完,这个点可以确定了,放到确定的集合中。
selectedNodes.add(minNode);
//再次获取最小的记录
minNode = getMinDistanceAndUnSelectNode(distanceMap, selectedNodes);
}
return distanceMap;
}
public static Node getMinDistanceAndUnSelectNode(HashMap<Node, Integer> distanceMap, HashSet<Node> selectedNode) {
Node minNode = null;
int minDistance = Integer.MAX_VALUE;
for (Map.Entry<Node, Integer> entry : distanceMap.entrySet()) {
Node node = entry.getKey();
int distance = entry.getValue();
if (!selectedNode.contains(node) && distance < minDistance) {
minDistance = distance;
minNode = node;
}
}
return minNode;
}