1. 什么是图
图由点和边组成。
边上有箭头叫有向图,没箭头叫无向图。
边上的数值叫做权重,有权重的图叫有权图。
有环形回路的图叫做有环图。
图用于模拟不同的东西是如何连接的。
2.图的表示
图的表示方式先确定好,这关系到之后在实现遍历算法的时候如何访问图上的节点和权重等信息。
两种表示方式:邻接矩阵、邻接表
以表示下面的图为例,下图是一个带权值的有向图,顶点为:V0-V5,边上的数值为权重
(1)邻接矩阵
(2)连接表,在图特别系数的情况下,链接表更有效
邻接矩阵比较容易理解不再赘述,补充一个链接表的使用方法。
一种用数组实现链接表的方式(目前还不会其他方式,会了再补充。方法出处《啊哈!算法》)
用三个数组存放数据,用三个数组完成表示,分别为u、v、w,u中存放起点,v中存放终点,w中存放对u和v中对应两点的间路径的权重。还有个fist和next数组,这两个比较难理解。
如上图所示,共有4个节点,5条边,u、v、w三个数组存放起始点和权重值。
first数组存放数组下标对应的节点第一次出现的位置,以节点1为例,在first数组中对应的下标就是1,读入第一条边,节点1出现,出现在u数组中的下标为1,因此fisrt[1]=1;在读入第三条边的时候,节点1再次出现,此时在u中的下标为3,更新first数组,fisrt[1]=3。注意这里的顺序是反的,u[1]相比u[3]要先读入,却成了第二次出现,个人认为反过来也无所谓。
next数组存放下一个对应u中下标的节点的下条边出现的位置,有点绕,还以1为例,在加入第一条边是,还没有下条边,也就是顶点u[1]现在只有一条边,在读入第三条边之后,u[3]=1,并不是顶点1的唯一一条边,那么下一条在哪呢,就是未更新之前的first[1]=1,所以在更新first之前,先next[3] = first[1],然后first[1]=3.
怎么用这五个数组遍历一个表,数组创建完整之后如下:
u={1, 4, 1, 2, 1}
v={4, 3, 2, 4, 3}
w={9, 8, 5, 6, 7}
first = {5, 4, -1, 2}
next = {-1, -1, 1, -1, 3}
遍历节点1的所有边的代码如下:
k = first[1];
while(k != -1){
printf(“%d to %d weight is %d \n”, u[k], v[k], w[k]);
k=next[k];
}
遍历整张图的所有边的代码如下:
for(int i= 0; i < n -1; ++i) {
k = first[i];
while(k != -1){
printf(“%d to %d weight is %d\n”, u[k], v[k], w[k]);
k=next[k];
}
}
3.图的遍历
广度优先遍历(Breath First)
广度优先和深度优先主要的区别在于遍历的顺序。广度优先以一个未被访问过的顶点为起始顶点,访问与其相邻的所有顶点,然后再访问相邻点的未被访问过的所有相邻点,直到访问完所有顶点。
用《图解算法》中的方式来解释,就是先杀熟。中间的“你”想知道周围认识的人中谁是代购,假设关系越近买东西越便宜,先问一遍关系最近的也就是途中的一度关系,然后再问一度关系朋友的朋友,也就是二度关系,方式跟遍历一度关系一致,问一遍一度关系中每个节点的所有相邻节点。
广度优先遍历需要用到队列,来存放已经访问过的点和确定接下来要访问的点。
代码链接:https://github.com/Victcode/AlgorithmsLearning/blob/main/AhaAlgorithm/graph_bfs.cpp
深度优先遍历(Depth Fisrt)
从一个未被访问过的节点开始,访问与它相连的节点,直到访问到某个节点没有与它相连的节点,然后返回上一个节点,继续访问与它相连的其他节点,直到图中所有节点都被访问到。
还以下图为例,从“你”开始,与三个节点相连,选择其中一个小猪Clare,然后访问一个跟clare相连的节点Jonny,Jonny没有相连节点,返回到Clare,访问跟Clare相连的还未被访问到的节点Thom,Thom没有相连节点,返回到Clare,此时跟Clare相连的节点已经全部被访问过,放回Clare的上一个节点“你”,“你”还有未被访问的相连节点Bob和Alice,继续安照上述过程进行访问。
由上述过程可知,算法实现用到了递归。
源码链接:https://github.com/Victcode/AlgorithmsLearning/blob/main/AhaAlgorithm/graph_dfs.cpp
网友评论