教学指路:
握如下基本结构:
①
图的两种存储结构。图算法都是基于某种存储结构的,如果连存储结构都含糊不清楚,肯定 是设计不出来正确的算法,更谈不上设计好的图算法。因此务必去熟悉图的邻接矩阵和邻接 表的存储结构。
②
图的两种遍历算法。很多图的算法基本都是基于图的遍历算法(正如二叉树的算法是基于 二叉树的基本遍历算法一样)。一般涉及不带权图的最短或最长路径时可以考虑采用广度优先遍历算法;而涉及到查找所有简单路径时可考虑采用深度优先遍历算法。
邻接矩阵结构:
#define MaxVertexNum 100 //顶点数目的最大值
typedef char VertexType; //顶点的数据类型
typedef int EdgeType; //带权图中边上权值的数据类型
typedef struct
{
VertexType Ver[MaxVertexNum]; //顶点表
EdgeType Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵、边表
int vexnum, arcnum;
}MGraph;
邻接表结构:
#define MaxVertexNum 100 // 顶点数目的最大值
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 是以邻接表存储的图类型
跟图相关联系的两种遍历算法必须背会
深度优先遍历:
深度优先遍历类似于树的先序遍历,它的基本过程如下:
① 从图中的某个初始顶点 v 出发,首先访问初始顶点 v。
② 选择一个与顶点 v 相邻且没有被访问过的顶点 w 为初始顶点,再从 w 出发进行深度优
先遍历,直到图中与当前顶点 v 邻接的所有顶点都被访问过为止。
bool visited[MAX_VERTEX_NUM]; //访问标记数组
void DFSTraverse(Graph G)
{
for(v = 0; v<G.vexnum; v++)
visited[v] = FALSE; //初始化已访问标记数组
for(v = 0; v<G.vexnum; v++)
if(!visited[v])
DFS(G,v);
}
void DFS(Graph G, int v) //从顶点 v 出发,深度优先遍历图 G
{
visit(v);
visited[v] = TRUE;
for(w = FirstNeighbor(G,v); w>=0; w = NextNeighbor(G,v,w))
if(!visited[w]) //w 为 u 尚未访问过的邻接顶点
DFS(G,w);
}
广度优先遍历:
广度优先遍历:
深度优先遍历类似于树的层次遍历,它的基本过程如下:
①访问初始点 v,接着访问 v 的所有未被访问过的邻接点 v
1
,v
2
,…,v
n
。
②按照 v
1
,v
2
,…,v
n
的次序,访问每个顶点的所有未被访问过的邻接点。
③依次类推,直到图中所有和初始点 v 有路径的顶点都被访问过为止。
bool visited[MAX_VERTEX_NUM]; // 访问标记数组
void BFSTraverse(Graph G) {
for(i = 0; i < G.vexnum; i++)
visited[i] = FALSE; // 初始化已访问标记数组
InitQueue(Q); // 初始化辅助队列 Q
for(i = 0; i < G.vexnum; i++) { // 从 0 号顶点开始遍历
if (!visited[i]) { // 对每个连通分量调用一次 BFS
BFS(G, i); // vi 未被放过过,从 vi 开始 BFS
}
}
}
void BFS(Graph G, int v) { // 从顶点 v 出发,广度优先遍历图 G
visit(v); // 访问初始顶点 v
visited[v] = TRUE; // 对 v 做访问标记
EnQueue(Q, v); // 顶点 v 入队
while (!isEmpty(Q)) {
DeQueue(Q, v); // 顶点 v 出队列
for (w = firstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w)) {
// 检测 v 的所有邻接点
if (!visited[w]) { // w 为 v 的尚未访问过的邻接顶点
visit(w); // 访问顶点 w
visited[w] = TRUE; // 对 w 做已访问标记
EnQueue(Q, w); // 顶点 w 入队列
}
}
}
}
重点必会题目:
1.假设图采用邻接表存储,分别写出基于 DFS 和 BPS 遍历的算法来判别顶点 i 和顶点 j (i≠j)之间是否有路径
[算法思想]先置全局数组 visited[]所有元素为 0,然后从顶点 i 开始进行某种遍历,遍历结束 之后,若 visited[j]=0,说明顶点 i 与顶点 j 之间没有路径;否则说明它们之间存在路径。
// 基于 DFS 遍历的算法
int DFSTrave(AGraph *G, int i, int j) {
int k;
for (k = 0; k < G->n; k++)
visited[k] = 0;
DFS(G, i); // 从顶点 i 开始进行深度优先遍历
if (visited[j] == 0)
return 0;
else
return 1;
}
// 基于 BFS 遍历的算法
int BFSTrave(AGraph *G, int i, int j) {
int k;
for (k = 0; k < G->n; k++)
visited[k] = 0;
BFS(G, i); // 从顶点 i 开始进行广度优先遍历
if (visited[j] == 0)
return 0;
else
return 1;
}