7.2 图-遍历及简单应用

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语言版) 严蔚敏》 学习笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值