图-遍历及最小生成树
1 图的遍历(Traversing Graph)
从图中某个顶点出发游历图,访遍图中其余顶点,并且使图中的每个顶点仅被访问一次的过程。
1.1 深度优先搜索(Depth First Search)
深度优先搜索(Depth First Search)遍历类似于树的先根遍历,是树的先根遍历的推广。
从图中某个顶点 V 0 V_{0} V0 出发,访问此顶点,然后依次从 V 0 V_{0} V0 的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和 V 0 V_{0} V0 有路径相通的顶点都被访问到,若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。
//----使用的全局变量----
Boolean visited[MAX]; //访问标志数组
Status (*VisitFunc)(int v); //函数变量
void DFSTraverse(Graph G, Status (* Visit)(int v)){
//对图G作深度优先遍历。
visitFunc = Visit;
//使用全局变量visitFunc,使DFS不必设函数指针参数
for(v=0; v<G.vexnum; ++v){
visited[v] = FALSE, //访问标志数组初始化
}
for(v=0; v<G.vexnum; ++v){
if(!visited[v]){
DFS(G, v); //对尚未访问的顶点调用DPS
}
}
}
void DFS(Graph G, int v){
//从第v个顶点出发递归地深度优先遍历图G
visited[v] = TRUE;
VisitFunc(v); //访问第v个顶点
for(w=FirstAdjVex(G, v); w>=0; w=NextAdjVex(G, v, w)){
if(!visited[w]){
DFS(G, w); //对v的尚未访问的邻接顶点w递归调用DFS
}
}
}
1.2 广度优先搜索(Breadth First Search)
广度优先搜索(Breadth First Search)遍历类似于树的按层次遍历的过程。
从图中的某个顶点 V 0 V_{0} V0 出发,并在访问此顶点之后依次访问 V 0 V_{0} V0 的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和 V 0 V_{0} V0 有路径相通的顶点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,,直至图中所有顶点都被访问到为止。
void BFSTraverse(Graph G, Status (* Visit)(int v)){
//按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。
for (v=0; v<G.vexnum; ++v){
visited[v] = FALSE;
}
InitQueue(Q); //置空的辅助队列
for(v=0; v<G.vexnum; ++v){
if(!visited[v]){ //v尚未访问
visited[v] = TRUE;
Visit(v);
EnQueue(Q, v); //v入队列
while(!QueueEmpty(Q)){
DeQueue(Q, u); //队头元素出队并置为u
for(w=FirstAdjVex(G, u); w>=0; w=NextAdjVex(G, u, w)){
if(!visited[w]){ //w为u的尚未访问的邻接顶点
visited[w] = TRUE;
Visit(w);
EnQueue(Q,w);
} //if
}
} //while
} //if
}
} //BFSTraverse
遍历图的过程实质上是通过边或弧找邻接点的过程,因此广度优先搜索遍历图的时间复杂度和深度优先搜索遍历相同,两者不同之处仅仅在于对顶点访问的顺序不同。
1.3 遍历应用举例
1.3.1 求一条从顶点i到顶点s的简单路径
void DFSearch(int v, int s, char *PATH){
//从第v个顶点出发递归地深度优先遍历图G,
//求得一条从v到s的简单路径,并记录在PATH中
visited[v] = TRUE; //访问第v个顶点
Append(PATH, getVertex(v));
for (w=FirstAdjVex(v); w!=0&&!found; w=NextAdjVex(v)){
if(w==s){
found = TRUE;
Append(PATTH, w);
}else if(!visited[w]){
DFSearch(w, s, PATH);
}
}
if(!found){
Delete(PATH);
}
}
1.3.2 求两个顶点之间的一条路径长度最短的路径
基于广度优先搜索遍历,并修改链队列的结点结构及其入队列和出队列的算法。
例如:求下图中顶点3至顶点5的一条最短路径。
链队列的状态如下所示:
1)将链队列的结点改为“双链”结点,即结点中包含next和priou两个指针;
2)修改入队列的操作,插入新的队尾结点时,令其priou域的指针指向刚刚出队列的结点,即当前的队头指针所指结点;
3)修改出队列的操作,出队列时,仅移动队头指针,而不将队头结点从链表中删除。
typedef DuLinkList QueuePtr;
void InitQueue(LinkQueue &Q){
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
Q.front->next = Q.rear->front = NULL;
}
void EnQueue(LinkQueue &Q, QelemType e){
p = (QueuePtr)malloc(sizeof(QNode));
p->data = e;
p->next = NULL;
p->priou = Q.front;
Q.rear->next = p;
Q.rear = p;
}
void DeQueue(LinkQueue &Q, QelemType &e){
Q.front = Q.front->next;
e = Q.front->data;
}
——《数据结构图 (C语言版) 严蔚敏》 学习笔记