【算法分析与设计】PAT程序填空题 图的解析

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

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zz_Lambda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值