首先,其实我们在课程中创建的无向图,本质就是有向图,只不过 a 到 b 和 b 到 a 都有有向边而已。
所以,我们在这一章的这一个图代码,既支持无向图,又支持有向图:https://git.imooc.com/coding-370/Play-with-Graph-Theory-Algorithm/src/master/13-Directed-Graph/01-Directed-Graph/src/Graph.java
具体是无向图还是有向图,靠 15 行传入的参数 directed 决定。directed 最大的功能,就是对于无向图,如果 a 到 b 有边,就自动再加一条 b 到 a 的边,如 42 - 43 所示。相应的,在维护图的时候,也要考虑这一点,比如 95-96 行,如果我们要在无向图删除一条 ab 边,就要自动删除 ba 边。
上述代码的图是无权图,在这个基础上,将无权图和有权图做统一,其实也很简单。无权图就是所有的边的权值是 1。在我的这个课程中没有做这件事情,你要感兴趣可以封装一个更加“全面”的图 class。
==========
具体你说的这个软件,我没有用过。但是,我要提醒的是,图论是一种建模的工具,具体图上的顶点和边到底是什么意义,是靠应用定义的,而不是可以一概而论的。
比如,你说在你看到的这个实现中,cost 为负值表示该方向没有路径,但是在另外一些应用中,cost 为负值就代表这条路径上的消耗为负值(换句话说是有增益)。比如我们对一个金融系统建模,图的顶点表示不同的金融产品,边表示金融产品之间的转换(最典型的是汇率转换),那么从一个金融产品专项另一个金融产品,可能会赚钱,也可能会赔钱,就可以很自然地用边上权值的正负表示。
实际上,在你说的这个应用中,我严重怀疑反向边的负值,本质是我在这个课程中介绍的网络流算法的残量图。在我在这个课程的网络流法中,将残量图和原始图分开成了两张图。但是用你说的这个方法,用边的正负可以来区分这条边是原图的边,还是残量图的边。这样在一张图中,就可以运行最大流算法。再一次,此时,负权边是被残量图这个概念所定义的,而残量图,是解决最大流问题的一种使用图论的建模方式。
==========
整体,图是一种数据结构,数据结构只不过是一种提供特定接口的“容器”,具体这个容器里装什么?装的东西是怎么定义的?怎么取他们,把他们取出来怎么用,都是被应用所决定的,不能一概而论。
你说的“导航系统”,是最典型的能应用“图”这种数据结构的情况,其他情况包括但不限于:
我上面举的例子,在一个复杂的金融交易系统中,可以用图建模;
社交网络是典型的能用图建模的结构。(在我毕业的年代,是社交网络最发达的年代,在那个年代,算法工程师近乎等加入熟悉“图论”这个领域。)
编译器中使用状态机做字符串分析,状态机就是一个图。有向无权,但边上包含别的信息(状态转移条件);除此之外,状态机还有非常多的应用;
如我在这个课程中的第七章所介绍,很多人工智能算法,本质也是将问题的解空间做图建模,然后使用图论算法解决。(只不过这个课程介绍的是最简单的建模后直接 bfs);
更进一步,现在最火的“神经网络”,本身也是一张图;
等等等等。
上面都是图的应用,如果你想要实践图论算法在更真实的场景中应用,应该去看这些一个一个更具体的领域。每个领域都即有他们独特的算法,又有和这个领域相关比较有名的开源工具。这本身就是学习算法和数据结构的意义,它是在帮助我们去更进一步学习计算机专业的其他特有领域。
继续加油!:)