图
图的存储和基本操作
1.邻接矩阵法:数组实现的顺序存储,空间复杂度高,不适合存储稀疏图。
#define MaxVertexnum 100 //邻接矩阵 typedef char VertexType;//顶点的数据类型 typedef int EdgeType;//顶点权值的数据类型 typedef struct { VertexType Vex[MaxVertexnum];//顶点表 EdgeType Edge[MaxVertexnum][MaxVertexnum];//邻接矩阵,边表 int vexnum, arcnum;//当前顶点数和弧数 }MGraph;
注:(1)无向图的邻接矩阵一定是一个对称矩阵且唯一,对于规模特大的邻接矩阵可采用压缩存储。
(2)对于无向图,第i行或第i列,非零元素个数正好是顶点i的度
(3)对于有向图,第i行非零元素的个数正好是顶点i的出度,第i列非零元素的个数正好是顶点i的入度
(4)用邻接矩阵存储图,很容易确定图中任意两个顶点之间是否有边相连,但要确定有多少条边,所花时间代价很大。
(5)稠密图适合使用邻接矩阵的存储表示
(6)邻接矩阵表示法的空间复杂度为O(n2),其中n为图的顶点数|V|,只和顶点有关,和实际的边数无关
2.邻接表法:结合了顺序存储和链式存储方法
typedef struct ArcNode {//边表结点 int adjvex;//该弧所指向的顶点的位置 struct ArcNode* next;//指向下一条弧的指针 //InfoType info;//网的边权值 }ArcNode; typedef struct Vnode {//顶点表结点 VertexType data;//顶点信息 ArcNode* first;//指向第一条依附该顶点的弧的指针 }VNode,AdjList[MaxVertexnum]; typedef struct { AdjList vertices;//邻接表 int vexnum, arcnum;//图的顶点数和弧数 }ALGraph;//ALGraph是以邻接表存储的图的类型
注:
(1)无向图所需的存储空间为O(|V|+2|E|),有向图所需的存储空间为O(|V|+|E|),无向图中的倍数2是由于无向图中,每条边在邻接表中出现了两次
(2)对于稀疏图,采用邻接表极大地节省存储空间
(3)计算一个顶点出度只需计算其邻接表中的结点个数,但求其顶点的入度则需要遍历整个邻接表
(4)邻接表的表示并不唯一,因为在每个顶点对应的单链表中,各边结点的链接次序可以是任意的,它取决于建立邻接表的算法以及边的输入次序。
(5),计算入度、度不方便
3.十字链表:只能用于存储有向图,表示不唯一
4.邻接多重表:只能存储有向图,表示不唯一
图的遍历
1.广度优先遍历:首先访问起始顶点v,由v出发,依次访问v的各个未被访问过的邻接结点w1,w2,...,然后依次访问w1,w2,.....未被访问过的邻接顶点,再从这些访问过的顶点出发,访问它们所有未被访问过的邻接顶点,直至所有顶点都被访问为止。若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作为始点,重复上述过程,直至图中所有顶点都被访问到为止。
广度优先搜索是一种分层的查找过程,每向前走一步可能访问一批顶点,不想深度优先搜索那样有回退的情况,因此它不是一个递归的算法。为了实现逐层的访问,算法必须借助一个辅助队列,以记忆正在访问的顶点的下一层顶点。
#define true 1 #define false 0 int visited[MaxVertexnum]; void BFS(MGraph G, int v) { visit(v);//从顶点v出发 visited[v] = true;//对v做已访问标记 EnQueue(Q,v);//顶点v入队列Q while (!IsEmpty(Q)) { DeQueue(Q, v);//顶点v出队列 for (w = FirstNeighbor(G, v); w >= 0; w = NextNeightbor(G, v, w));//检查v所有邻接点 if (!visited[w]) {//w为v的未被访问过的邻接顶点 visit(w);//访问顶点w visited[w] = true;//对w做已访问标记 EnQueue(Q, w);//顶点w入队列 } } } void BFStraverse(MGraph G) {//对图进行广度优先遍历 for (int i = 0; i < G.vexnum; ++i) visited[i]= false;//访问标记数组初始化 InitQueue(&Q);//初始化辅助队列 for (int i = 0; i < G.vexnum; ++i)//从0号顶点开始遍历 if (!visited[i])//对每个连通分量调用一次BfS BFS(G, i);//对于未被访问的顶点,以该顶点为始点,调用BFS }
注:
(1)对于无向图,调用BFS函数的次数=连通分量的个数
(2)广度优先搜索遍历算法是二叉树的层次遍历算法的扩展
(3)BFS需借助一个队列,最坏情况下,空间复杂度为O(|V|)
(4)邻接表存储,访问v个顶点,需要O(|V|)的时间,查找各个顶点的邻接点共需O(|E|)的时间,时间复杂度为O(|V|+|E|);邻接矩阵存储:访问|V|个顶点需要O(|V|)的时间,查找每个顶点的邻接点都需要O(|V|)的时间,总共有|v|个顶点,时间复杂度为O(|V|)+O(|V|2)=O(|V|2)
2.深度优先遍历:首先访问图中某一起始顶点v,然后由v出发,访问与v邻接且未被访问的任一顶点w1,再访问与w1邻接且未被访问的任一顶点w2......重复上述过程。当v不能再向下访问时,依次退回到最近被访问的顶点,若它还有邻接点未被访问过,则从该点开始继续上述搜索过程,直至图中左右顶点均被访问过为止。
int visited[MaxVertexnum]; void DFS(MGraph G, int v) { visit(v);//访问顶点v visited[v] = true;//设已访问标记 for (w = FirstNeighbor(G, v); w >= 0; w = NextNeightbor(G, v, w)) if (!visited[w]) {//w为v的尚未访问的邻接顶点 DFS(G, w); } } void DFSTraverse(MGraph G) { for (int v = 0; v < G.vexnum; ++v) visited[v] = false;//访问标记数组初始化 for (int v = 0; v < G.vexnum; ++v)//从v=0开始遍历 if (!visited[v]) DFS(G, v); }
注:
(1)深度优先搜索类似于树的先序遍历,这种搜索算法所遵循的搜索策略是尽可能“深”地搜索一个图。
(2)DFS算法是一个递归算法,需要借助一个递归工作栈,空间复杂度为O(|V|)
(3)邻接矩阵表示时,查找每个顶点的邻接点所需要的时间为O(|V|),故总的时间复杂度为O(|V|2);
以邻接表表示时,查找顶点的邻接点是O(|E|),访问顶点所需的时间为O(|V|)总的时间复杂度为O(|V|+|E|)
3.无向图G是否为一棵树:若是树,则该树为有n-1条边的连通图
采用深度优先搜索遍历算法,在遍历过程中统计访问到的结点数和边数,若一次就能遍历到n个顶点和n-1条边,则可判定是一棵树
int isTree(MGraph G) { for (int i = 0; i < G.vexnum; i++) visited[i] = false;//访问标记数组初始化 int Vnum=0, Enum=0;//记录顶点数和边数 DFS1(G, 1, Vnum, Enum, visited); if (Vnum == G.vexnum && Enum == 2 * (G.vexnum - 1)) return true;//符合树的条件 else return false; //不符合树的条件 } void DFS1(MGraph G, int v, int Vnum, int Enum, int visited[]) { visited[v] = true;//作访问标记 Vnum++;//顶点计数 int w = FirstNeighbor(G, v);//取v的第一个邻接点 while (w != -1) {//当邻接点存在 Enum++;//边存在,边计数 if (!visited[w])//当该邻接点未被访问过 DFS1(G, w, Vnum, Enum, visited); w = NextNeightbor(G, v, w); } }
4.图的深度优先搜索非递归算法:借助栈实现
(1)先将v0入栈(2)只要栈不空,则栈顶元素出栈,如果未被访问,则访问并置访问标志,然后将该结点所有未被访问过的邻接点入栈
void DFSfd(MGraph G, int v) { int w,k; InitStack(&S); for (int i = 0; i < G.vexnum; i++) visited[i]; Push(S, v); visited[v] = true; while (!IsEmpty(S)) { k = Pop(S); visit(k); for (w = FirstNeighbor(G, k); w >= 0; w = NextNeightbor(G, k, w)); if (!visited[w]) { Push(S, w); visited[w] = true; } } }

浙公网安备 33010602011771号