实现图的遍历算法

该博客主要介绍图的遍历算法,包括深度优先和广度优先算法。输出有向图从顶点0开始的深度优先遍历序列(递归和非递归)及广度优先遍历序列,使用邻接表存储图,还提及了算法中的关键操作和执行结果。

实现图的遍历算法

领会图的两种遍历,深度优先算法和广度优先算法。

输出:

(1)输出有向图G从顶点0开始的深度优先遍历序列(递归算法)。
(2)输出有向图G从顶点0开始的深度优先遍历序列(非递归算法)。
(3)输出有向图G从顶点0开始的广度优先遍历序列。

设备:

计算机,VC6.0

注意点:
(1)图的深度优先递归算法

void DFS(AdjGraph *G,int v)
 {	  
  ArcNode *p;	
  printf(" %d",v);//访问顶点v
  visited[v]=1;//访问后标记
  p=G->adjlist[v].firstarc;//p指向顶点v的下一个弧头结点	
    while(p!=NULL)	
    {		
     if(visited[p->adjvex]==0)//若未访问过	
     DFS(G,p->adjvex);//则递归访问	
     p=p->nextarc;//否则找下一个结点	
    }
 } 

(1)图的深度优先非递归算法(栈)

 void DFS1(AdjGraph *G,int v)
 {   ArcNode *p;
     int St[MAXV];//栈元素存放的数组
     int top=-1,x,w,i;	
     for(i=0;i<G->n;i++)
     visited[i]=0;//顶点全部置为0
     printf(" %d",v);//访问顶点v
     visited[v]=1;//访问后标记	
     top++;//top指针加一
     St[top]=v;//v进栈
     while(top>-1)
     {		
        x=St[top];//取出x
        p=G->adjlist[x].firstarc;//p指向x的相邻结点	
        while(p!=NULL)//第二重循环		
        {			
            w=p->adjvex;//有相邻结点,将值赋给w	
            if(visited[w]==0)//未访问过	
            {			
 	         printf(" %d",w);//访问		
 	         visited[w]=1;//标记	
 	         top++;			
 	         St[top]=w;//进栈		
 	         break;//直接退出第二重循环,不执行p=p->nextarc	
 	      }			
             p=p->nextarc;否则(访问过),找下一个结点	
        }	
 	    	if(p==NULL)top--;	
    }  
 	 printf("\n");
}

关键:

break;//直接退出第二重循环,不执行p=p->nextarc

在这里插入图片描述
结果:

0,1,2,5,4,3
(1)图的广度优先非递归算法(队列)

     void BFS(AdjGraph *G,int v)
     {	ArcNode *p;	
        int queue[MAXV],front=0,rear=0;//环形队列,并初始化
 	int visited[MAXV];//存放顶点访问信息的数组	
 	int w,i;	
 	for(i=0;i<G->n;i++)	
 	 visited[i]=0;//顶点全部置为0	
 	 printf(" %d",v);//访问顶点v	
 	 visited[v]=1;//访问后标记	
 	 rear=(rear+1)%MAXV;//rear增加
 	 queue[rear]=v;//顶点v进队
         while(front!=rear)	
         {		
 	    front=(front+1)%MAXV;//front增加
 	    w=queue[front];//出队	
            p=G->adjlist[w].firstarc;//p指向相邻结点	
 	    while(p!=NULL)	
            {			
              if(visited[p->adjvex]==0)//未访问过,添加该顶点的所有相邻结点
              {		
                printf(" %d",p->adjvex);//访问	
 		visited[p->adjvex]=1;//访问后标记	
 		rear=(rear+1)%MAXV;//rear增加
 	        queue[rear]=p->adjvex;//进队	
               }			
               p=p->nextarc;//找下一个结点,直到->∧,退出第二重循环	
            }
         }	
 	printf("\n");
 }

如图:

在这里插入图片描述
关键:

进队,到空,出队;再进队,到空,出队如此循环。

结果:

0,1,3,2,5,4

存储:

图有两种存储方式,邻接矩阵和邻接表,这里用邻接表存储

#include<stdio.h>
#include<malloc.h>
#define INF 32767
#define MAXV 100
int visited[MAXV];
typedef struct Anode
{
  int adjvex;
  struct Anode *nextarc;	
  int weight;
  }ArcNode;

typedef struct Vnode
{	
  int count;	
  ArcNode *firstarc;
  }VNode;

typedef struct
{
  VNode adjlist[MAXV];	
  int n,e; 
}AdjGraph;

//邻接表的创建,输出,销毁
void CreateAdj(AdjGraph *&G,int A[MAXV][MAXV],int n,int e)
{	
  int i,j;	
  ArcNode *p;
  G=(AdjGraph *)malloc(sizeof(AdjGraph));
  for(i=0;i<n;i++;
  G->adjlist[i].firstarc=NULL;
  for(i=0;i<n;i++)	 
     for(j=n-1;j>=0;j--)	
	if(A[i][j]!=0&&A[i][j]!=INF)
	{	
	  p=(ArcNode *)malloc(sizeof(ArcNode));
	  p->adjvex=j;				
	  p->weight=A[i][j];				
	  p->nextarc=G->adjlist[i].firstarc;				
	  G->adjlist[i].firstarc=p;			
	}			
	G->n=n;G->e=e;
}

void DispAdj(AdjGraph *G)
{
   ArcNode *p;   
   for(int i=0;i<G->n;i++)   
   {	   
      p=G->adjlist[i].firstarc;	   
      printf("%3d:",i);	   
      while(p!=NULL)	   
      {		   
          printf("%3d[%d]->",p->adjvex,p->weight);		   
          p=p->nextarc;	   
      }	   
      printf("∧\n");   
   }
}

void DestroyAdj(AdjGraph *&G)
 {	
    ArcNode *pre,*p;	
    for(int i=0;i<G->n;i++)	
    {		
       pre=G->adjlist[i].firstarc;		
       if(pre!=NULL)		
       {			
            p=pre->nextarc;			
            if(p!=NULL)			
            {			 
               free(pre);			 
               pre=p;p=p->nextarc;			
             }			
           free(pre);		
        }
   }	
     free(G);
}

主函数:

int main()
{	
  AdjGraph *G;	
  int A[MAXV][MAXV]={		
      {0,5,INF,7,INF,INF},{INF,0,4,INF,INF,INF},		
      {8,INF,0,INF,INF,9},{INF,INF,5,0,INF,6},		
      {INF,INF,INF,5,0,INF},{3,INF,INF,INF,1,0}};		
  int n=6,e=10;		
  CreateAdj(G,A,n,e);		
  printf("图G的邻接表:\n");		
  DispAdj(G);		
  printf("从顶点0开始的深度优先算法(递归):\n");		
  DFS(G,0);		
  printf("\n");		
  printf("从顶点0开始的深度优先算法(非递归):\n");		
  DFS1(G,0);		
  printf("从顶点0开始的广度优先算法(非递归):\n");		
  BFS(G,0);		
  DestroyAdj(G);	
  return 1;
}

执行结果:

在这里插入图片描述

2. 系统设计 1.用到的抽象数据类型的定义 的抽象数据类型定义: ADT Graph{ 数据对象V:V是具有相同特性的数据元素的集合,称为顶点集 数据关系R: R={VR} VR={<v,w>|v,w∈V且P(v,w),<v,w>表示从v到w的弧, 谓词P(v,w)定义了弧<v,w>的意义或信息} 基本操作P: CreatGraph(&G,V,VR) 初始条件:V是的顶点集,VR是中弧的集合 操作结果:按V和VR的定义构造G DestroyGraph(&G) 初始条件:G存在 操作结果:销毁G InsertVex(&G,v) 初始条件:G存在,v和中顶点有相同特征 操作结果:在G中增添新顶点v …… InsertArc(&G,v,w) 初始条件:G存在,v和w是G中两个顶点 操作结果:在G中增添弧<v,w>,若G是无向的则还增添对称弧<w,v> …… DFSTraverse(G,Visit()) 初始条件:G存在,Visit是顶点的应用函数 操作结果:对进行深度优先遍历,在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦Visit()失败,则操作失败 BFSTraverse(G,Visit()) 初始条件:G存在,Visit是顶点的应用函数 操作结果:对进行广度优先遍历,在遍历过程中对每个顶点调用函数Visit一次且仅一次。一旦Visit()失败,则操作失败 }ADT Graph 栈的抽象数据类型定义: ADT Stack{ 数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0} 数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n} 约定an端为栈顶,ai端为栈底 基本操作: InitStack(&S) 操作结果:构造一个空栈S DestroyStack(&S) 初始条件:栈S已存在 操作结果:将S清为空栈 StackEmpty(S) 初始条件:栈S已存在 操作结果:若栈S为空栈,则返回TRUE,否则FALSE …… Push(&S,e) 初始条件:栈S已存在 操作结果:插入元素e为新的栈顶元素 Pop(&S,&e) 初始条件:栈S已存在且非空 操作结果:删除S的栈顶元素,并用e返回其值 StackTraverse(S,visit()) 初始条件:栈S已存在且非空 操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit(),一旦visit()失败,则操作失效 }ADT Stack 队列的抽象数据类型定义: ADT Queue{ 数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0} 数据关系:Rl={<ai-1,ai>|ai-1,ai∈D,i=2,…,n} 约定其中ai端为队列头,an端为队列尾。 基本操作: InitQueue(&Q) 操作结果:构造一个空队列Q DestroyQueue(&Q) 初始条件:队列Q已存在 操作结果:队列Q被销毁,不再存在 QueueEmpty(Q) 初始条件:队列Q已存在 操作结果:若Q为空队列,则返回TRUE,否则FALSE …… EnQueue(&Q,e) 初始条件:队列Q已存在 操作结果:插入元素e为Q的新的队尾元素 DeQueue(&Q,&e) 初始条件:Q为非空队列 操作结果:删除Q的队头元素,并用e返回其值 }ADT Queue 2.主程序的流程: 调用CreateDN函数创建的邻接表G; 调用PrintDN函数输出邻接表G; 调用DFSTraverse函数深度优先遍历; 调用BFSTraverse函数广度优先遍历
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值