图是计算机科学中非常常用的一类数据结构,有许许多多的计算问题都是用图来定义的。由于图也是最复杂的数据结构,对它讲解时,涉及到数组、链表、栈、队列、树等之前学的几乎所有数据结构。因此从某种角度来说,学好了图,基本就等于理解了数据结构这门课的精神。

    我们在图的定义这一节,介绍了一大堆定义和术语,一开始可能会有些迷茫,不过一回生二回熟,多读几遍,基本都可以理解并记住它们的特征,在图的定义这一节的末尾,我们已经有所总结,这里就不再赘述了。

    图的存储结构我们一共讲了五种,其中比较重要的是邻接矩阵和邻接表,它们分别代表着边集是用数组还是链表的方式存储。十字链表是针对有向图邻接表结构的优化,邻接多重表是针对无向图邻接表结构的优化。边集数组更多考虑的是对边的关注。用什么存储结构需要具体问题具体分析,通常稠密图,或读存数据较多,结构修改较少的图,用邻接矩阵要更合适,反之则应该考虑邻接表。

    图的遍历分为深度和广度两种,各有优缺点,就像人在追求卓越时,是着重深度还是看重广度,总是很难说得清楚。

    图的应用是我们这一章浓墨重彩的一部分,一共谈了三种应用:最小生成树、最短路径和有向无环图的应用。

    最小生成树,我们讲了两种算法:普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法。普里姆算法像是走一步看一步的思维方式,逐步生成最小生成树。而克鲁斯卡尔算法则更有全局意识,直接从图中最短权值的边入手,找寻最后的答案。

    最短路径的现实应用非常多,我们也介绍了两种算法。迪杰斯特拉(Dijkstra)算法更强调单源顶点查找路径的方式,比较符合我们正常的思路,容易理解原理,但算法代码相对复杂。而弗洛伊德(Floyd)算法则完全抛开了单点的局限思维方式,巧妙地应用矩阵的变换,用最清爽的代码实现了多顶点间最短路径求解的方案,原理理解有难度,但算法编写很简洁。

    有向无环图时常应用于工程规划中,对于整个工程或系统来说,我们一方面关心的是工程能否顺利进行的问题,通过拓扑排序的方式,我们可以有效地分析出一个有向图是否存在环,如果不存在,那它的拓扑序列是什么?另一方面关心的是整个工程完成所必须的最短时间问题,利用求关键路径的算法,可以得到最短完成工程的工期以及关键的活动有哪些。

    事实上,图的应用算法还有不少,本章节只是抛砖引玉,有兴趣的同学可以去查阅相关的书籍获得更多的知识。