目录
1、图的介绍
1.1、顶点
图中的节点
1.2、边
连接顶点的线
1.3、邻接
如果两个顶点被同一条边连接,就称这两个顶点是邻接的,如上图的I和G就是邻接的,而I和F就不是。
1.4、路径
路径是边的序列,eg:从顶点B到顶点J的路径为BAEJ,当然还有别的路径BCDJ,BACDJ等等。
1.5、连通图
从任意一个节点开始,至少有一条路径可以连接到其他所有的节点,那么这个图就是连通图。
有连通图就有非连通图
1.6、有向图和无向图
如果图中的边没有方向,可以从任意一边到达另一边,则称为无向图。
如果图中的边有方向,称为有向图。eg:如下图,只能从顶点V1到V2,不能从V2直接到V1
1.7、有权图和无权图
边被赋予一个权值,这种图被称为有权图;
边没有赋值的则称为无权图。
权值是一个数字,它能代表两个顶点间的物理距离,或者从一个顶点到另一个顶点的时间。
2、图的表示方式
2.1、邻接矩阵
就是一个二维数组,数据项表示两点间是否存在边。
如果图有N个顶点,邻接矩阵就是N*N的数组。
上图的邻接矩阵如下图:
1表示有边,0表示没有边,顶点与自身相连用0表示。
2.2、邻接表
邻接表是一个链表数组(或者是链表的链表),每个单独的链表 表示有哪些顶点与当前顶点邻接。
3、图的搜索
3.1、深度优先搜索DFS
Depth First Search
要尽可能的远离起始点
通过栈来实现
深度优先搜索算法规则:
规则1:如果可能,访问一个邻接的、未访问的顶点,标记它,并将它放入栈中。
如下图:假设选取A顶点为起始点,并按照字母优先顺序进行访问;
接下来访问顶点B,标记它,并将它放入栈中;
接下来访问顶点F,标记它,并将它放入栈中;
接下来访问顶点H,标记它,并将它放入栈中。
规则2:当不能执行规则1时,如果栈不为空,就从栈中弹出一个顶点。
到了顶点H,发现不能执行规则1了,从栈中弹出H;
回到顶点F,发现也不能执行规则1,从栈中弹出F;
回到顶点B,发现也不能执行规则1,从栈中弹出B;
回到顶点A,继续执行规则1......
规则3:如果不能执行规则1和规则2时,就完成了整个搜索过程。
3.2、广度优先搜索BFS
Breadth First Search
要尽可能的靠近起始点
通过队列来实现
广度优先搜索算法规则:
规则1:访问下一个未访问的邻接点(如果存在),这个顶点必须是当前顶点的邻接点,标记它,并把它插入到队列中。
规则2:不能执行规则1时,从队列列头取出一个顶点(如果存在),使其为当前顶点。
不能执行规则1时:当前顶点已经没有未访问的邻接点
规则3:不能执行规则2,则搜索结束。
不能执行规则2:就是队列为空
4、最小生成树
对于图的操作,还有一个最常用的就是找到最小生成树,最小生成树就是用最少的边连接所有顶点。
最小生成树的边的数量E总是比顶点V的数量小1,即:E = V - 1
因为DFS访问所有顶点,只访问一次,绝对不会两次访问同一个顶点,从来不遍历走不通的边,所以DFS算法走过整个图的路径必定是最小生成树。
5、有向图的拓扑排序
5.1、拓扑排序
给定一副有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素(或者说明无法做到这一点)。
拓扑排序能得出结果的前提:图必须是有向无环图(Directed Acyclic Graph,DAG)
6、带权图最小生成树
如下图:
5条边就可以连接6个城市,我们应该选择哪5条边呢?不同的城市之间搭建线路的造价是有差异的,
所以,我们应该选择总造价成本最低的5条线路,符合这个要求的线路就是带权图最小生成树。
实现思路:
1、任意选择一个顶点作为起点,一般选择A作为起始点,设U集合为当前找到的最小生成树的顶点,TE集合为找到的边
即现在状态为:U={A};TE={};
2、查找A的邻接顶点,找与A邻接的顶点中,权值最小的边,就找到了顶点D
现在状态为:U={A,D};TE={{A,D}};
3、查找A、D的邻接顶点,找与A、D邻接的顶点中,权值最小的边(不在TE集合中的其他边),就找到了顶点B
现在状态为:U={A,D,B};TE={{A,D},{A,B}};
4、查找A、D、B的邻接顶点,找与A、D、B邻接的顶点中,权值最小的边(不在TE集合中的其他边),就找到了顶点E
现在状态为:U={A,D,B,E};TE={{A,D},{A,B},{B,E}};
就这样循环下去,直到所有顶点都在集合U中结束。
7、带权图的最短路径问题
算法思路:
1、指定一个节点
eg:我们要计算A到其他顶点的最短路径
2、引入两个集合S、U,S集合包含:已求出的最短路径的点(和相应的最短长度),
U集合包含:未求出最短路径的点(和A到该点的路径)
注意:如上图所示,由于A、C没有直接相连,初始值为无穷大
3、初始化两个集合,S集合初始时:只有当前要计算的节点(A到A为0)
U集合初始时:A到B为50,A到C为无穷大,A到D为80,A到E为无穷大
4、从U集合中找出路径最短的点,加入S集合
eg:A到B为50
5、更新U集合路径,如果:'B到D,C,E的距离' + 'AB距离' < 'A到D,C,E的距离',则更新U里的对应数据
eg:如果:'B到C的距离' + 'AB距离' < 'A到C的距离',等价于(60+50<无穷大),
满足条件就更新U里的数据:由“A到C为无穷大”改为“A到C为110(经B)”,
就按照这个公式将U里的所有边都更新一遍,这一遍更新完后,再从这些边中找出最短路径,加入S集合。
6、循环执行4、5两步骤,直至遍历结束,得到A到其他顶点的最短路径