图的存储结构
1.二维数组邻接矩阵存储
邻接矩阵的参考程序段
#include<iostream>
using namespace std;
int i,j,k,e,n;
double g[101][101];
double w;
int main()
{
int i,j;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
g[i][j] = 0x3f3f3f3f(赋一个超大值); //初始化,对于不带权的图g[i][j]=0,表示没有边连通。这里用0x3f3f3f3f代替无穷大。
cin >> e;
for (k = 1; k <= e; k++)
{
cin >> i >> j >> w; //读入两个顶点序号及权值
g[i][j] = w; //对于不带权的图
g[i][j]=1 g[j][i] = w; //无向图的对称性,如果是有向图则不要有这句!
}
…………
return 0;
}
建立邻接矩阵时,有两个小技巧:
初始化数组大可不必使用两重for循环。
-
如果是int数组,采用memset(g, 0x7f, sizeof(g))可全部初始化为一个很大的数(略小于0x7fffffff),使用memset(g, 0, sizeof(g)),全部清为0,使用memset(g, 0xaf, sizeof(g)),全部初始化为一个很小的数。
-
如果是double数组,采用memset(g,127,sizeof(g));可全部初始化为一个很大的数1.38*10306,使用memset(g, 0, sizeof(g))全部清 为0.
2.数组模拟邻接表存储
图的邻接表存储法,又叫链式存储法。本来是要采用链表实现的,但大多数情况下 只要用数组模拟即可。
两种情况要具体而用
图的遍历
(一)深度优先与广度优先遍历
从图中某一顶点出发系统地访问图中所有顶点,使每个顶点恰好被访问一次,这种 运算操作被称为图的遍历。为了避免重复访问某个顶点,可以设一个标志数组visited[i], 未访问时值为false,访问一次后就改为true。 图的遍历分为深度优先遍历和广度优先遍历两种方法,两者的时间效率都是O(n*n)。
深度优先遍历
深度优先遍历与深搜DFS相似,从一个点A出发,将这个点标为已访问 visited[i]:=true;,然后再访问所有与之相连,且未被访问过的点。当A的所有邻接点都被 访问过后,再退回到A的上一个点(假设是B),再从B的另一个未被访问的邻接点出发, 继续遍历。
广度优先遍历
广度优先遍历并不常用,从编程复杂度的角度考虑,通常采用的是深度优先遍历。 广度优先遍历和广搜BFS相似,因此使用广度优先遍历一张图并不需要掌握什么新的 知识,在原有的广度优先搜索的基础上,做一点小小的修改,就成了广度优先遍历算法。
(二)一笔画问题
如果一个图存在一笔画,则一笔画的路径叫做欧拉路,如果最后又回到起点,那这 个路径叫做欧拉回路。 我们定义奇点是指跟这个点相连的边数目有奇数个的点。对于能够一笔画的图,我 们有以下两个定理。 定理1:存在欧拉路的条件:图是连通的,有且只有2个奇点。 定理2:存在欧拉回路的条件:图是连通的,有0个奇点。 两个定理的正确性是显而易见的,既然每条边都要经过一次,那么对于欧拉路,除 了起点和终点外,每个点如果进入了一次,显然一定要出去一次,显然是偶点。对于欧 拉回路,每个点进入和出去次数一定都是相等的,显然没有奇点。 求欧拉路的算法很简单,使用深度优先遍历即可。 根据一笔画的两个定理,如果寻找欧拉回路,对任意一个点执行深度优先遍历;找 欧拉路,则对一个奇点执行DFS,时间复杂度为O(m+n),m为边数,n是点数。