Dijkstra算法
这是一种用于找出从点A到点B的最短路径的算法。
在计算机术语中,我们将路径简化为由节点和连线组成的图。每个节点代表一个中间点,而每个连线连接两个节点,并具有表示穿越这两个节点的成本(非负)的权值。
要实现该算法,您需要两个列表:
- finished:一组(node, cost),其中您已经计算出到达的最小成本。
- working:已经检查过的(node, cost)的排序列表。
算法:
working.addNode(Start, 0); // No cost to get to start.
for( (node, cost) = working.popHead(); node
{
// If we have already processed this node ignore it.
if (finished.find(node))
{ continue;
}
// We have just removed a node from working.
// Because it is the top of the list it is guaranteed to be the shortest route to
// the node. If there is another route to the node it must go through one of the
// other nodes in the working list which means the cost to reach it will be higher
// (because working is sorted). Thus we have found the shortest route to the node.
// As we have found the shortest route to the node save it in finished.
finished.addNode(node,cost);
// For each arc leading from this node we need to find where we can get to.
foreach(arc in node.arcs())
{
dest = arc.dest();
if (NOT (finished.find(dest)))
{
// If the node is already in finished then we don't need to worry about it
// as that will be the shortest route other wise calculate the cost and add
// this new node to the working list.
destCost = arc.cost() + cost;
working.addNode(dest,destCost); // Note. Working is sorted list
}
}
}
如果你想了解这个算法。假设你正在从伦敦前往曼彻斯特。
finished = {} // empty.
working = { (London,0) }
使用以下成本矩阵:
L S O B N M W
(L) ondon - 50 60 100 130 - -
(S) outhampton 50 - 70 - - - -
(O) xford 60 70 - 50 - 200 -
(B) irmingham 100 - 50 - - 80 110
(N) orwich 130 - - - - - -
(M) anchester - - 200 80 - - 80
Ne(W) castle - - - 110 - 80 -
现在你可以将伦敦从工作列表中移除(因为它位于首位),并将其放入已完成列表。然后将所有与伦敦直接相连的城镇添加到工作列表中。
finished = { (London,0) }
working = { (Southampton, 50), (Oxford, 60), (Birmingham, 100), (Norwich,130) }
考虑工作集中的城镇是从伦敦扩展出来的泡沫的外边缘。Dijkstra算法的任务是不断扩大泡沫,直到我们到达曼彻斯特(不重复走已经走过的步骤)。所以泡沫总是向外扩展,我们总是扩展最小部分的泡沫。
所以下一步是取列表的头并重复。从南安普敦只有两个目的地。回到伦敦(我们将其丢弃,因为它在完成的列表中)和牛津。到达牛津的成本是50加上从南安普敦到牛津的成本(请注意,它在工作列表中出现了两次,但不要担心,我们将在后面将其丢弃,因为它不是最优路线)。
finished = { (London,0), (Southampton,50) }
working = { (Oxford, 60), (Birmingham, 100), (Oxford, 120), (Norwich,130) }
重复循环。列表的头部是牛津。从牛津我们可以前往曼彻斯特(200),伯明翰(50)或返回伦敦(60)或南安普顿(请记住,我们需要将到达牛津的费用添加到上述每个费用中。请注意,从牛津我们本可以去南安普顿,但我们已经找到了到南安普顿的最短路径,因此不需要处理)这将使我们得到:
finished = { (London,0), (Southampton,50), (Oxford, 60) }
working = { (Birmingham, 100), (Birmingham,110), (Oxford, 120), (Norwich,130), (Manchester,200)}
请注意,我们现在的工作列表中有曼彻斯特(这是我们的目的地)。但我们需要继续努力,因为可能会找到更短的路线。所以现在我们从伯明翰开始扩展。从那里我们可以去牛津(50),曼彻斯特(80),伦敦(100),纽卡斯尔(110)。加上到达伯明翰的成本,这给我们带来了:
finished = { (London,0), (Southampton,50), (Oxford, 60), (Birmingham, 100) }
working = { (Birmingham,110), (Oxford, 120), (Norwich,130), {Manchester, 180), (Manchester,200), (Newcastle, 210)}
下面的两个节点牛津和伯明翰已经在完成的列表中,所以我们可以忽略它们。因此,除非从诺里奇到曼彻斯特的路线少于50英里,否则我们将在随后的迭代中到达曼彻斯特。