5-8 深度优先遍历邻接表存储的图
DFS 思想:
深度优先遍历图的方法是,从图中某顶点v出发:
1.访问顶点v;
2.依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
3.若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
DFS伪代码:
DFS(当前被访问的节点pos)
{
pos被标记访问过
遍历与pos相连的节点(有边相连)
如果这个节点没有被访问过
搜索(DFS)当前节点
}
思路:这道题的关键是理解深度优先遍历时额外设定的visited[]数组的作用:用来标记是否访问过这个结点,从而确定遍历时是否回退。
typedef int Vertex;
typedef struct AdjNode {
Vertex AdjV;
struct AdjNode *Next;
struct AdjNode *FirstEdge;
}AdjVNode;
typedef struct {
AdjVNode G[MAX];
}Graph;
typedef Graph* LGraph;
/* 邻接表存储的图 - DFS */
bool Visited[MAX];
typedef AdjVNode* PtrToAdjVNode;
void Visit( Vertex V )
{
printf("正在访问顶点%d\n", V);
}
/* Visited[]为布尔类型的全局数组,已经初始化为false */
void DFS( LGraph Graph, Vertex V, void (*Visit)(Vertex) ) //Graph表示邻接矩阵存储的图 V表示当前访问的节点 第三个参数为输出节点的函数
{
PtrToAdjVNode W;
Visit(V); //访问V时打印访问的顶点
Visited[V]=true; //标记V被访问过,此后不再访问
for( W=Graph->G[V].FirstEdge; W; W=W->Next )
if ( !Visited[W->AdjV] ) //如果当前节点V与遍历的节点w有边相连,且w没有被访问过
DFS(Graph,W,Visit); //从W开始搜索访问
}
5-9 基于邻接矩阵表示的深度优先遍历
思路:这道题给的代码很全,比较简单。
#include <stdio.h>
#define MVNum 100
typedef struct{
char vexs[MVNum];
int arcs[MVNum][MVNum];
int vexnum,arcnum;
}AMGraph;
int visited[MVNum];
void CreateUDN(AMGraph &G);//实现细节隐藏
void DFS(AMGraph G, int v){
printf("%c ",G.vexs[v]); visited[v] =1;
int w;
for(w = 0; w < G.vexnum; w++)
if((visited[w]==0)&&(arcs[v][w]==1)) //visited[w]==0判断是否访问过,arcs[v][w]==1判断v和w之间有没有边存在
DFS(G, w);
}
void DFSTraverse(AMGraph G){
int v;
for(v = 0; v < G.vexnum; ++v)
visited[v] = 0;
for(v = 0; v < G.vexnum; ++v)
if(!visited[v]) //!visited[v]判断是否访问过
DFS(G,v);
}
int main(){
AMGraph G;
CreateUDN(G);
DFSTraverse(G);
return 0;
}
5-10 基于邻接表表示的广度优先遍历
BFS思想:
广度优先搜索——使用队列(queue)来实现,整个过程也可以看做一个倒立的树形:
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。 4、如果遍历整个树还没有找到,结束程序。
BFS伪代码:
BFS(需要访问的节点S)
{
定义队列
队列中加入S
S被标记访问过
当队列不为空时
取出队首的元素pos
输出pos,表示访问到pos
遍历与pos相连的节点(有边与pos相连)
如果当前节点没有被访问过
标记当前节点被访问过
加入队列
}
#include <stdio.h>
#include <stdlib.h>
#define MVNum 100
#define MAXQSIZE 100
int visited[MVNum];
typedef struct ArcNode{
int adjvex;
struct ArcNode *nextarc;
int info;
}ArcNode;
typedef struct VNode{
char data;
ArcNode *firstarc;
}VNode, AdjList[MVNum];
typedef struct{
AdjList vertices;
int vexnum, arcnum;
}ALGraph;
int CreateUDG(ALGraph &G);//实现细节隐藏
void BFS(ALGraph G, int v){
int Q[MAXQSIZE],f=0,r=0,u,w;//f,r表示队列队头队尾,注意这里特别声明了u,w,可能后面代码要用到
printf("%c ",G.vertices[v].data); visited[v] = 1;
Q[r++]=v;//队列存入访问的第一个节点v
while(f!=r){ //当队列不为空时(首部没有到达尾部)
u=Q[++f]; //取出队列首部节点
ArcNode *p = G.vertices[u].firstarc;
while(p != NULL){
w=p->adjvex; //定义邻接点w(题面中给出定义)
if(!visited[w]){
printf("%c ",G.vertices[w].data); visited[w] = 1; //打印并标记为1
Q[++r]=w; //把这个节点加入到队列中
}
p = p->nextarc;
}
}
}
void BFSTraverse(ALGraph G){
int v;
for(v = 0; v < G.vexnum; ++v) visited[v] = 0;
for(v = 0; v < G.vexnum; ++v)
if(!visited[v]) BFS(G, v);
}
int main(){
ALGraph G;
CreateUDG(G);
BFSTraverse(G);
return 0;
}
5-11 本题要求实现对图的深度优先遍历,并输出结点信息,采用邻接矩阵表示方法。
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>//使用INT_MAX宏,指定整数变量不能存储超出此限制的任何值
typedef struct GRAPHMATRIX_STRU
{
int size; //图中结点的个数
int **graph; //二维数组保存图
}GraphMatrix;
GraphMatrix* InitGraph(int num);//创建图,略
void ReadGraph(GraphMatrix* graphMatrix);//输入顶点和权值,略
/*从结点i开始深度优先遍历 */
void DFS(GraphMatrix* graphMatrix, int * visited, int i) //参数1表示图graphMatrix,参数2表示标记数组visited,参数3表示访问顶点位置i
{
int j;
visited[i] = 1;
printf("%d ", i);
for (j = 0; j < graphMatrix->size; j++) //在顶点i的基础上继续深度遍历与之相连的顶点间的边
{
if (graphMatrix->graph[i][j] != INT_MAX && !visited[j]) //没有访问过,并且i与j之间有边
DFS(graphMatrix,visited,j); //在j的基础上继续DFS遍历
}
}
/*图的深度优先遍历*/
void DFSGraphMatrix(GraphMatrix* graphMatrix) //参数表示图graphMatrix
{
int i;
int *visited = (int*)malloc(sizeof(int)* graphMatrix->size);
for (i = 0; i < graphMatrix->size; i++) //将visited数组初始值全部置为0,表示没有访问过
visited[i] = 0;
for (i = 0; i < graphMatrix->size; i++) //依次遍历图的顶点
if(!visited[i]) //i没有访问过的话,则DFS
DFS(graphMatrix,visited,i); //传入顶点i的参数
}
int main()
{
GraphMatrix *graphMatrix = NULL;
graphMatrix = InitGraph(7); //传入顶点个数7
ReadGraph(graphMatrix);
DFSGraphMatrix(graphMatrix);
return 0;
}
5-12 本题要求实现对图的广度优先遍历,并输出结点信息,采用邻接矩阵表示方法。
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>//使用INT_MAX宏,指定整数变量不能存储超出此限制的任何值
typedef int DataType;
struct Node
{
DataType data;
struct Node *link;
};
typedef struct Node *PNode;
struct Queue
{
PNode f;
PNode r;
};
typedef struct Queue *LinkQueue;
LinkQueue SetNullQueue_Link(); //创建一个空队列,略
int IsNullQueue_Link(LinkQueue lqueue); //判断队列是否为空,略
void EnQueue_link(LinkQueue lqueue, DataType x); //x入队,略
void DeQueue_link(LinkQueue lqueue); //队首元素出队,略
DataType FrontQueue_link(LinkQueue lqueue); //打印队头元素,略
typedef struct GRAPHMATRIX_STRU
{
int size; // 图中结点的个数
int **graph; //二维数组保存图
}GraphMatrix;
GraphMatrix* InitGraph(int num); //创建图,略
void ReadGraph(GraphMatrix* graphMatrix); //输入顶点和权值,略
/*从结点i开始广度优先遍历 */
void BFS(GraphMatrix* graphMatrix, int * visited, int i)
{
int j;
int tempVex;
LinkQueue waitingQueue = NULL;
waitingQueue = SetNullQueue_Link();
if (!visited[i])
{
visited[i] = 1;
printf("%d ", i);
EnQueue_link(waitingQueue, i);
while (!IsNullQueue_Link(waitingQueue))
{
tempVex = FrontQueue_link(waitingQueue);
DeQueue_link(waitingQueue);
for (j = 0; j<graphMatrix->size; j++)
{
if (graphMatrix->graph[tempVex][j] != INT_MAX && !visited[j])//与i相连且没有访问过的
{
visited[j]=1; //标记被访问
EnQueue_link(waitingQueue, j); //被访问的结点j入队
printf("%d ", j); //打印与i相连的结点j
}
}
}
}
}
void BFSGraphMatrix(GraphMatrix* graphMatrix)
{
int i;
int *visited = (int*)malloc(sizeof(int)* graphMatrix->size);
for (i = 0; i < graphMatrix->size; i++) //设置所有结点都没有被访问,其中1为访问过,0为没有被访问
visited[i] = 0;
for (i = 0; i < graphMatrix->size; i++)
{
BFS(graphMatrix,visited,i); //从0号结点开始进行广度优先遍历
}
}
int main()
{
GraphMatrix *graphMatrix = NULL;
graphMatrix = InitGraph(7); //传入顶点个数7
ReadGraph(graphMatrix);
BFSGraphMatrix(graphMatrix);
return 0;
}
5-15 对一个给定的图G执行拓扑排序,其中TopNum[]从1开始记录拓扑序。
拓扑排序思路:
此拓扑排序的思想是:
1.从有向图中选取一个没有前驱的顶点(入度为0),并输出之;
2.从有向图中删去此顶点以及所有以它为尾的弧;
3.重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。
void Topsort( Graph G )
{
Queue Q;
Vertex V, W;
NodePtr ptr;
int counter = 0;
Q = CreateEmptyQueue(NumVertex); //创建一个空队列
for ( V=0; V<G->NumV; V++ )
if ( Indegree[V] == 0 ) //入度0,入队
Enqueue(V, Q);
while (!IsEmpty(Q)){ //队列不空
V = Dequeue(Q); //V队首出队
TopNum[V] = ++counter; //记录这个顶点的序列号,且序号从1开始,是前置自增
for(ptr=G->List[V]; ptr; ptr=ptr->Next) {
W = ptr->Vertex;
if ( Indegree[W] == 0 )//W入度0,入队
Enqueue(W, Q);
}
}
if ( counter != NumVertex )
printf("ERROR: Graph has a cycle.\n");
DisposeQueue(Q);
}
参考链接:https://blog.csdn.net/qq_20087731/article/details/90713746