标签:site 起点 com -o 自己的 ret sub xmlns 数据结构
一、本章内容小结
本章节主要讲解的是图这种数据结构,其中包括图的定义、存储结构,也有图的遍历方法和图的应用。相对于前面的知识而言,我觉得这一章是最难上手的一个章节。
图是由顶点和连接顶点的边构成的离散结构。在计算机科学中,图是最灵活的数据结构之一,很多问题都可以使用图模型进行建模求解。例如:生态环境中不同物种的相互竞争、人与人之间的社交与关系网络、化学上用图区分结构不同但分子式相同的同分异构体、分析计算机网络的拓扑结构确定两台计算机是否可以通信、找到两个城市之间的最短路径等等。图也是一种比线性表和树更复杂的结构,这种复杂的关系表现为结点的关系可以是任意的,图中任意两个数据元素之间都可能有关。
图包括有向图、无向图。有向图就是顶点对<x,y>是有序的图,无向图就是顶点对<x,y>是无序的图,如果图中任意连接两个顶点的边都是无向边,则称该图为无向图。图的存储结构可以分为四种,它们分别是:邻接矩阵、邻接表、十字链表和邻接多重表。
图的邻接矩阵存储方式是用两个数组来表示图:一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中边或弧的信息。
图的邻接矩阵存储方式是:顶点用一个一维数组存储,另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi的边表,有向图称为顶点vi作为弧尾的出边表。
十字链表:firstin头指针,指向该顶点的入边表中第一个结点,firstout表示出边表头指针,指向该顶点的出边表中第一个结点。tailvex是指弧起点在顶点表的下标,headvex是指弧终点在顶点表的下标,headlink是指入边表指针域,指向终点相同的下一条边,taillink是指边表指针域,指向起点相同的下一条边,如果是网,我们还要在其中加入权值域,来存储权值。
图的遍历有两种:深度优先搜索和广度优先搜索。深度优先搜索可概括为:当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。广度优先搜索可概括为:1.将根节点放入队列中。2.从队列中取出第一个节点,并检验它是否为目标。3.如果找到目标,则结束搜索并回传结果。否则将它所有尚未检验过的直接子节点加入队列中。4.若队列为空,表示整张图都检查过了——亦即图中没有欲搜索的目标。5.搜索并回传“找不到目标”。6.重复步骤2。
二、完成作业实践时的心得体会
第六章作业的编程题主要是关于DFS和BFS算法的应用。在这道题中,我采用的存储结构是邻接矩阵的存储结构。
typedef struct //定义图的结构 { int arcs[10][10]; //定义一个二维数组判断两个顶点之间是否连通 int vexnum,arcnum; //分别定义顶点数和边数 }Graph;
对于图的初始化,我们可以通过以下函数实现:
Graph Init_Graph(Graph a) //图的初始化 { int i,j,m,n; //定义参数 for(i=0;i<a.vexnum;i++) { visited[i]=false; //把bool类型的数组都初始化为false for(j=0;j<a.vexnum;j++) { a.arcs[i][j]=0; //把图的二维数组全部初始化为0 } } cin>>a.vexnum>>a.arcnum; // 分别输入顶点数以及边数 for(i=0;i<a.arcnum;i++) { cin>>m>>n; //分别输入两个顶点的编号 a.arcs[m][n]=1; a.arcs[n][m]=1; //令两个顶点对应的两个二维数组的值为1 } return a; //返回图 }
深度优先搜索算法:
void DFS(Graph a,int b) //深度优先搜索 { visited[b]=true; //令顶点对应的visited数组为true,表示该顶点已被访问过 cout<<b<<" "; //输出顶点编号及空格 for(int i=0;i<a.vexnum;i++) { if(a.arcs[b][i]==1 && visited[i]==false)DFS(a,i); //若顶点对应的邻接点未被访问,则递归调用DFS函数 } }
广度优先算法往往是通过定义一个队列来实现:
queue <int> q; //定义一个队列便于就行广度优先搜索 void BFS(Graph a,int b) //广度优先搜索 { int temp; //定义参数 while(!q.empty()) //若队列不为空 { temp=q.front(); //取队头元素值为temp q.pop(); //队头元素出队 cout<<temp<<" "; //输出temp值及空格 for(int i=0;i<a.vexnum;i++) { if(a.arcs[temp][i]==1 && visited[i]==false) //若顶点对应的邻接点未被访问,则邻接点入队 { q.push(i); //邻接点入队 visited[i]=true; //邻接点对应的visited数组取true,表示已被访问 } } visited[b]=true; //第一次入队的顶点对应的visited数组值取true,表示已被访问 } }
在int main()函数中,我们只需通过for循环调用函数即可得出最终的结果。
int main() { Graph a; //定义一个图 a=Init_Graph(a); //初始化图 int i; //定义参数 for(i=0;i<a.vexnum;i++) { if(visited[i]==false) //若有顶点未被访问,则循环调用DFS函数 { cout<<"{ "; //控制输出格式 DFS(a,i); cout<<"}"<<endl; //控制输出格式 } } for(i=0;i<a.vexnum;i++)visited[i]=false; //把visited数组初始化为false for(i=0;i<a.vexnum;i++) //若有顶点未被访问,则循环调用BFS函数 { if(visited[i]==false) { q.push(i); //未被访问的顶点入队 cout<<"{ "; //控制输出格式 BFS(a,i); cout<<"}"<<endl; //控制输出格式 } } return 0; }
三、目标完成情况和待改进的问题
关于上一章的学习我觉得书本上的东西不容易懂,而做编程题的时候往往是按照自己的思路一点一点地摸索。以至于在应对第五章的小测的时候成绩并不理想。我觉得可能是因为自己写的代码与书本上的表达方式有很大的不同之处而导致的。希望能深刻地理解书本上的内容,再回过头来分析书本上的代码的表达方式。
标签:site 起点 com -o 自己的 ret sub xmlns 数据结构
原文地址:https://www.cnblogs.com/lccgl/p/10891363.html