数据结构第6章小结
图的结构比树的结构要复杂很多,我们看着图觉得解决问题觉得很简单,但到了编程,个人觉得就很复杂了。而且图的概念比较多,复习时要仔细区分每个概念对应的图同时也要多复习,否则很容易混淆。
我们学习图的存储结构有两种,一种是邻接矩阵,是我们所熟悉的二维数组;一种是邻接表,有点像上一次做深入虎穴时使用的结构。先说说邻接矩阵,邻接矩阵是我们所熟悉的,也是一种比较简单的做法,
但是使用二维数组前通常要考虑的问题是数据量的问题,数据量太大时就没办法使用二维数组,而且邻接矩阵存储的是一张没有权值的图,那么此时的邻接矩阵就是一个稀疏矩阵,造成大量空间浪费。而邻接
表不需要担心这样的问题,但是最主要是邻接表使用的是一个一维数组带多个链表,链表我们这学期才接触,可以说对他不熟,使用得少,就觉得困难。
图的遍历分两种,一种是深度优先搜索,一种是广度优先搜索。深度优先搜索在编码方面比广度优先搜索简单,但是在个人看图方面,广度优先搜索更好理解。广搜需要用到队列的数据结构。深搜和广搜时,
在数据量不大时,使用邻接矩阵比较简单。如果是无向图,那么这个邻接矩阵还是个对称矩阵。
全局定义一个bool类型的vi数组,然后在主函数中将vi数组初始化为false,表示为该顶点未被访问。假设从v点出发深搜遍历一张图,此时需要将vi[v]置为true表示为已访问,避免等会重复访问,同时输出v。访
问完后,找出v的邻接点,由于我们使用的是邻接矩阵,因此只要判断v行中不为0的即为v的邻接点,但要注意,不能是访问过的点。找到邻接点后,调用深搜函数即可。
void DFS(AMGraph g,int v) {//从第v个顶点出发深度优先搜索遍历图g vi[v]=true; //置访问标志数组相应分量值为true cout<<v<<" "; //访问第v个顶点 for(int w=0;w<g.vexnum;w++) { if((g.arcs[v][w]!=0)&&(!vi[w])) //w是v的邻接点,w未被访问,则调用DFS函数 { DFS(g,w); }//if }//for }//DFS
在完成DFS算法后,还要使用BFS算法。还是假设从v点出发,我们想当然的就将vi[v]置为true,但是不要忘了,刚刚的深搜已经把所有顶点访问过了,因此我们要用BFS算法,就需要把vi数组再次置为false才
可以进行(这个在主函数进行了)。同样的,将vi[v]置为true,同时入队v,在队列不为空的情况下,取队头元素的值,出队v。找出v的邻接点入队。
void BFS(AMGraph g,int v) {//从第v个顶点出发广度优先搜索遍历图g int p; vi[v]=true; //置访问标志数组相应分量值为true queue<int> q; //定义一个队列q q.push(v); //v入队 while(!q.empty()) { p=q.front(); cout<<p<<" "; q.pop(); for(int i=0;i<g.vexnum;i++) { if((!vi[i])&&(g.arcs[p][i]!=0)) //i是p的邻接点,i未被访问,则调用BFS函数 { vi[i]=true; //置访问标志数组相应分量值为true q.push(i); }//if }//for }//while }//BFS
最小生成树学习了两个算法。一个是普里姆算法,一个是克鲁斯卡尔算法。普里姆算法总结起来就是三个步骤,选择、加入、刷新。克鲁斯卡尔算法比较简单,实际上就是先找出权值最小的几个不同的连通分
量,再从不同的连通分量之间找出权值最小的连线把不同的连通分量连接起来。普里姆算法适用于稠密图,而克鲁斯卡尔算法适用于稀疏图。
本章作业完成时间挺久的,拯救007那个作业知道要用广搜或者深搜,但是不太理解什么情况下才需要调用广搜或者深搜。
目标:本章很多概念,要多复习图的概念,以免混淆。