Dijkstra 算法求解最短路径问题
本文使用 Python 实现了 Dijkstra 算法求解最短路径问题。在算法实现中,使用数组存储网络中各结点之间的距离,使用二叉堆存储 T 集合,并尽量使用向量化计算加快运行速度。
最终在三种网络结构下的运行时间为:
输入文件 | grid_150_150 | random_20000_40000 | dense_1000 |
---|---|---|---|
运行时间 | 302.93ms | 292.14ms | 135.29ms |
但在最开始实现 Dijkstra 算法时,我的程序需要花 5 秒才能完成计算。经过逐步优化,运行时间可以降为 3 秒甚至 0.13 秒。把算法效率优化到极致的过程是非常有收获的,既加深了对算法本身的理解,又学习了许多优化算法的经验。
优化算法的经验
- 多考虑用向量化计算,尽量避免使用 for 循环。
- 想清楚算法的终止条件是什么。例如,在 One-to-all 问题中,可以把“遍历完T集合中的所有元素,直到 T 集合为空集”作为终止条件,也可以把“ P 集合中的元素个数等于网络中的结点个数”作为终止条件。虽然两者都能得到正确的结果,但当 P 集合中的元素个数等于网络中的结点个数时,T 集合中的元素是不需要再更新的,所以后者比前者所需要的运算次数少得多。
- 熟悉
NumPy
等科学计算库的实现细节。例如,在NumPy
中,np.ones
和np.empty
都可以用来创建指定形状的数组,其中np.ones
会创建一个填充 1 的数组,而np.empty
会在一块内存上创建一个未初始化的数组。由于np.empty
不会进行初始化,因此生成速度要比np.ones
更快。 - 使用合适的数据类型。例如,若问题中的变量可以肯定为整数,则可以考虑用
dtype=np.int32
或者dtype=np.int16
,节约内存空间。不同整数数据类型所能表示的整数范围如下:
Type | Capacity |
---|---|
Int16 | (-32,768 to +32,767) |
Int32 | (-2,147,483,648 to +2,147,483,647) |
Int64 | (-9,223,372,036,854,775,808 to +9,223,372,036,854,775,807) |