图,在日常生活中,常常会用到,但是平日里在纸上只是几个圆圈,几个数字,几笔几画便可以了。
但是在编程中,需要的是各种各样的类型定义,一次方便存储,也方便我们结构化。不同的存储结构,命名也不同,许许多多加起来,有各自嵌套,一个字,乱!
(以下是以邻接表的存储结构为样例)
首先,分清楚图有哪些东西要存放的。
1、图的总顶点数,图的总边数,以及图的所有顶点集合。
2、在图的所有顶点集合中,每一个顶点包含该顶点本身的数据,还有所有与该顶点有边相连接的顶点的存储位置。
3、边节点的类型定义(在存储所有与该顶点有边相连接的顶点的存储位置需要边节点的类型定义)
这是我定义的代码,别的不说,对于刚接触图的萌新贼不友好,没有注释就只能翻来翻去的看。
1 //图的定义 2 typedef struct 3 { 4 int vex, arc; //图的顶点数量(vex)和边数量(arc) 5 AdjList vertices; 6 }ALGraph; 7 8 //顶点列表的定义 9 typedef struct VNode 10 { 11 int data; 12 struct ArcNode *firstArc; //该顶点的第一条边的指针 13 }VNode, AdjList[MVNum]; //AdjList表示邻接表类型 14 15 //边节点的定义 16 typedef struct ArcNode 17 { 18 int adjvex; //当前的节点的顶点位置 19 struct ArcNode *nextArc; //下一条边的指针 20 }ArcNode, *L;
大概的结构图是这样的:
图 { 顶点数量和边数量 顶点列表 { 顶点内容信息 第一条边的指针->边节点 { 当前点的信息 下一条边的指针->边节点 } } }
反正我是。。。。。。。。。。。。。。。。。
对于我而言,用邻接表存储图更容易理解图的深度搜索和广度搜索,因为其的操作与树的先序遍历与层次遍历很相似,还是粘代码。
两者之间,明显的差别就是在输出前调用一个数组判断当前节点是否已被访问过(visited[]={false})。
深度搜索:
1 //深度搜索 2 void DFS_AL(ALGraph G, int v) 3 { 4 // 访问当前的顶点 5 cout << " " << v; 6 visited[v] = true; 7 8 L p; //与顶点连接的下一边 9 int w; //顶点连接的下一点 10 11 p = G.vertices[v].firstArc; 12 while(p != NULL) 13 { 14 // 取得这一条边链接的点,看是否已访问 15 w = p->adjvex; 16 if(!visited[w]) 17 DFS_AL(G, w); //未访问则递归 18 p = p->nextArc; 19 } 20 }
广度搜索(因为不是二叉树,所以用一个for循环依次遍历入队):
1 //广度搜索 2 void BFS_AL(ALGraph G, int v) 3 { 4 // 队列q,u用作存储出队的元素的下标 5 queue<int> q; 6 int u; 7 8 // 访问顶点 9 cout << " " << v; 10 visited[v] = true; 11 12 // 入队 13 q.push(v); 14 while(!q.empty()) 15 { 16 u = q.front(); 17 q.pop(); 18 19 // for循环,进行出队元素的所有的边的点访问,入队 20 for(L p=G.vertices[u].firstArc; p!=NULL; p=p->nextArc) 21 { 22 //对于出队的点,判断是否有邻接点,有则访问,然后入队 23 if(!visited[p->adjvex]) 24 { 25 cout << " " << p->adjvex; 26 visited[p->adjvex] = true; 27 q.push(p->adjvex); 28 } 29 } 30 } 31 }
这就是我理解的图的邻接表的大概,如果有什么不足的欢迎提出。
接下来得理解好图的相关应用——普里姆算法,克鲁斯卡尔算法等。。。。。
坚持不懈方能水滴石穿!
原文地址:https://www.cnblogs.com/ZwQuan/p/10891294.html
时间: 2024-11-09 02:52:02