在这一小节,我们使用索引堆,实现了 Dijkstra 算法。使用索引堆实现,时间复杂度是 O(ElogV) 的。
实际上,对于 Dijkstra 算法,我们完全可以仅仅使用一个优先队列(普通的堆),而非索引堆来实现。大家可以先思考一下,怎样实现。
在这里,我给出了一个参考代码:
我添加了必要的注释,关键点在于:
1)建立一个最小堆,最小堆中存储顶点,按照距离当前找到的和源点 s 的距离排序。(43-45行)
2)使用最小堆,而不是索引堆的核心区别在于,当修改 distTo 以后,最小堆里面的顶点排序不会变化。对此,解决方案是,我们但凡修改一个顶点的距离,就把这个顶点重新推入优先队列一次。在重新推入的过程中,这个顶点肯定会根据当前新计算出的距离,放在队列的正确位置。(73-76行)
3)但是,这样做,队列中就会有重复元素。所以,在 while 循环中,对于已经计算的元素,忽略掉。(55-56行)
这样做,我们的算法实际复杂度是 O(ElogE),这个复杂度比使用索引堆的 O(ElogV) 要差,但实际相差不多。由于在大多数语言的标准库中,都给出了优先队列的接口,而没有给出索引堆的接口,所以,在很多情况下,使用这个思路编码更容易。
希望同学们可以自己理解这个思路。同时,这个课程之前介绍的 Prim 算法,我们也是使用索引堆完成的。但是,仅仅使用优先队列(一个普通的堆),就可以实现 Prim 算法,大家试试看?
大家加油!:)