首先在解决图这一类问题时,我们第一要考虑的是如何存储一个图。一般来说分为两种:1. 邻接表 2.邻接矩阵

在无权图中,可以直接用二维数组来存储图的边的关系。有向图只用存一个方向,无向图存储两个方向。也可以用邻接矩阵,有连接的两个节点就填1,没有连接的就是0。
在有权图中,需要用字典来记录相邻的边和对应的权重。也可以用邻接矩阵,相连的节点对应的坐标里的值就是权重。

其次,是图的几个典型的应用

  1. 首先是拓扑排序,一般用BFS算法框架。首先计算节点的入度,将节点为0的节点入队。进行BFS不断弹出节点,并将这些节点指向的节点的入度减一。判断哪些节点的入度为零,不断重复这个过程。如果所有的节点都能被遍历到说明不存在环,如果有没遍历到的节点说明无环。记录节点的弹出顺序就是一个拓扑排序。
  2. 并查集,并查集是一个很常用的算法。主要的逻辑只有两个,一个是合并,一个是查询。并查集可以计算图的连通性,即一共有多少个连通分量。也可以用来判断无向图是否有环。
  3. 路径问题,典型的路径问题算法有 迪杰斯特拉算法(计算无负权值边的单源最短路径),贝尔曼福德算法(可以计算有负权值边的单源最短路径),弗洛伊德算法(计算多源最短路径算法),SPFA(双端队列优化bellman-ford算法),基本BFS(计算无权最短路径)。在网络延迟中总结了这几个算法的模板。
  4. 二分图问题,二分图结构在某些场景可以更高效地存储数据。比如电影演员关系这种。用一个visited数组记录访问过的节点,一个color数组记录节点的颜色。由于图不一定是连通的,所以每个节点都要作为起点遍历一次。没访问过的节点我们让它和相邻节点的颜色不同,访问过的节点我们判断它和相邻节点的颜色是否不同,是的话继续,不是直接返回False。注意加入访问的位置最好在for循环内,速度比较快
  5. 最小生成树问题,最小生成树就是在一个图的所有可能的生成树中,权重和最小的那棵。具体有两种方法可以实现:
    1 是Kruskal 最小生成树算法,它将所有边按照权重从小到大排序,从权重最小的边开始遍历,如果这条边和mst中的其它边不会形成环,则这条边是最小生成树的一部分,将它加入mst集合;否则,这条边不是最小生成树的一部分,不要把它加入mst集合。注意环的判断直接用并查集就行。
    2 是Prim 算法,prim算法使用 BFS 算法思想 和 visited 布尔数组避免成环,来保证选出来的边最终形成的一定是一棵树。算法的核心思想是切分定理,任选一个节点开始切分,选择这个节点连接的的所有节点中最小权重的边连接,之后计算这两个节点相邻的所有节点中最短的边连接的节点,连接之后不断重复这个过程直到所有节点都已经连接。这里通过优先队列来维护这个最短的边。保证每次选的的是最短的。注意这里要使用一个visited数组保证访问过的边直接跳过就行。
  6. 名流问题,名人定义是: 1、所有其他人都认识名人。2、名人不认识任何其他人。由此得知只要观察任意两个候选人的关系,一定能确定其中的一个人不是名人,把他排除。这样我们每次排除一个,最后只剩下一个候选人。最后判断一下剩下的这个人是不是名人。