前言
数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷。
也因如此,它作为博主大二上学期最重要的必修课出现了。由于大家对于上学期C++系列博文的支持,我打算将这门课的笔记也写作系列博文,既用于整理、消化,也用于同各位交流、展示数据结构的美。
此系列文章,将会分成两条主线,一条“数据结构基础”,一条“数据结构拓展”。“数据结构基础”主要以记录课上内容为主,“拓展”则是以课上内容为基础的更加高深的数据结构或相关应用知识。
欢迎关注博主,一起交流、学习、进步,往期的文章将会放在文末。
说起图论算法,最经典的莫过于最短路径了。他永远是图论入门难以绕开的经典问题,也常常是学习图论遇到的容易卡住的难点。
说起最短路径,那首先研究的对象就是两点间的路径,它要有起点和终点。图中两个连通结点之间至少存在一条路径,最短路径就是其中权值和最小的路径。
算法中对权值定义可以很广泛,他可以是点权,也可以是边权,也可能多关键字的权重…总之不论权值如何定义,重要的只是权值和能够被表示出来且能够被比较。但在本文中,我们讨论的只有边权,且权值为正数的正权图。
这篇文章,我们探讨的最短路径分为两种:单源最短路径 和 任意两点间最短路径
以及实现他们的两种经典算法:dijkstra算法和floyd算法
单源最短路径
单源最短路径,是指从一点出发到图中其他所有点的最短路径。
通常,只要求出到各点的最短路径长度。
有时,也会要求打印出最短路径。
例如:对于如下图
从源点1出发到其他节点的最短路径及距离为:
2 : 1 , 3 , 2 3 2:1,3,2\quad3 2:1,3,23
3 : 1 , 3 1 3:1,3\quad1 3:1,31
4 : 1 , 3 , 4 5 4:1,3,4\quad5 4:1,3,45
5 : 1 , 3 , 5 6 5:1,3,5\quad6 5:1,3,56
6 : 1 , 3 , 5 , 6 7 6:1,3,5,6\quad7 6:1,3,5,67
求解单源最短路径,可行的算法有很多,下面来介绍一种非常经典的算法:dijkstra算法
迪杰斯特拉(dijkstra)算法
dijkstra算法的核心思想是将全部结点分成两个集合,一个是已知最短路的集合 A A A,剩下的是未知最短路的集合 B B B,同时记录每个节点到源点的最短距离 d i s dis dis。
约定:源点到自身的最短距离为0,即 d i s s = 0 dis_s = 0 diss=0。无路径的两点间的距离为无穷大。
算法步骤如下:
- 一开始,已知最短路的集合中仅有源点一个元素。且仅记录与源点直接相连的节点的距离 d i s dis dis,其余结点默认为无穷大
- 每次从 B B B中找出一个距离最短的结点 k k k,加入集合 A A A。
- 使用结点 k k k更新源点到 B B B中结点的最短距离,即是否经过 k k k到该结点比先前到该结点的方案更优
- 重复上述过程,直至所有结点都加入结合 A A A
- 最短路径长度就是结点的 d i s dis dis值
对于上图,将每一次挑选节点的过程中 d i s dis dis用表格画出来就是:
在编写算法之前,有必要先来说明一下图的存储。有关图的存储方式,可以参考这篇博文
下面的算法中,存储方式都采用数组模拟的邻接表的方式。最短路径使用数组dis进行存储;