第七章-图(3)图的遍历

1、和树的遍历类似,我们希望从图中某一顶点出发遍历访问图中其余顶点,且使每一个顶点仅被访问一次。


分为深度优先与广度优先:

--------------------------------------------------------------------------------------------------------------------------------

代码:

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#define ERROR                    0        
#define OK                       1  
#define INFINITY                 INT_MAX  //最大值
#define MAX_VERTEX_NUM           21       //最大顶点个数

bool visited[MAX_VERTEX_NUM];

typedef enum{ DG,DN,UDG,UDN } GraphKind;   //{有向图,有向网,无向图,无向网}

//--------图的邻接表存储表示---------------//
typedef struct ArcNode{
	int adjvex;              //该弧所指向的顶点的位置
	int quan;
	struct ArcNode *nextarc; //指向下一条弧的指针
}ArcNode,*AList;              //表结点
typedef struct VNode{
	char data;            //顶点信息
	AList firstarc;       //指向第一条依附该顶点的弧的指针
}VNode,AdjList[MAX_VERTEX_NUM];       //头结点
typedef struct{
	AdjList vertices;
	int vexnum,arcnum;       //图的当前顶点数和弧数
	GraphKind kind;          //图的种类标志
}ALGraph;

//--------------队列与栈的操作----------------//
typedef struct QNode{
	char data;
	struct QNode *next;
}QNode,*QueuePre;
typedef struct{ 
	QueuePre front;      //头指针
	QueuePre rear;        //尾指针
}LinkQueue;          //队列
typedef struct{
	int *base;
	int *top;
	int stacksize;
}SqStack;           //栈
//----------------------------------------//

//队列的创建
int InitQueue(LinkQueue &Q){
	Q.front=Q.rear=(QueuePre)malloc(sizeof(QNode));
	if(!Q.front) return ERROR;
	Q.front->next=NULL;
	return OK;
}

//元素入队
int EnQueue(LinkQueue &Q,int e){
	QueuePre p;
	p=(QueuePre)malloc(sizeof(QNode));
	if(!p) return OK;
	p->data=e;
	p->next=NULL;
	Q.rear->next=p;
	Q.rear=p;
	return OK;
}

//元素除队列
int DeQueue(LinkQueue &Q,int &e){
	QueuePre p;
	if(Q.front==Q.rear) return ERROR;
	p=Q.front->next;
	e=p->data;
	Q.front->next=p->next;     //将队列的下一元素赋值给 Q.front
	if(Q.rear==p)
		Q.rear=Q.front;
	free(p);
	return OK;
}

//判断队列是否为空
int QueueEmpty(LinkQueue Q){
	if(Q.front==Q.rear)
		return OK;
	return ERROR;
}

//邻接表顶点定位
int LocateVex(ALGraph G,char v){
	int m;
	for(m=1;m<=G.vexnum;m++){
		if(G.vertices[m].data==v)
			return m;
	}
	printf("你输入的顶点不存在!");
	return ERROR;
}

//创建无向图邻接表
int CreatAList(ALGraph &G){
	int i,j,m,n,key[MAX_VERTEX_NUM];
    char x,y;
	AList p,q;
	printf("邻接表,请输入顶点的个数和弧个数:");
	scanf("%d %d",&G.vexnum,&G.arcnum);

	if(G.vexnum>20){     //顶点个数过多
		printf("你输入的顶点个数超过最大值");
		return ERROR;
	}
	printf("请输入 %d 个顶点数:\n",G.vexnum);
	for(i=1;i<=G.vexnum;i++){
		fflush(stdin);
		scanf("%c",&G.vertices[i].data);            //构造顶点向量的值
		G.vertices[i].firstarc=NULL;     //指向下一条弧的指针 先初始化为 NULL
		key[i]=0;             //
	}
	printf("请输入弧(如 A B ,其中 AB 与 BA是不同的弧):");
	for(j=1;j<=2*G.arcnum;j++){       //输入弧
		fflush(stdin);
		scanf("%c %c",&x,&y);
		m=LocateVex(G,x);        //定位
		n=LocateVex(G,y);
		p=G.vertices[m].firstarc;     // AList p,q 

		q=(AList)malloc(sizeof(ArcNode));
		if(!q) return ERROR;
		q->nextarc=NULL;                    //q初始化的过程
		q->adjvex=n;

		while(key[m] && p->nextarc){
			p=p->nextarc;
			key[m]++;
		}
		if(!key[m]){      //key[m]为0 
			G.vertices[m].firstarc=q;
			key[m]++;
		}
		else
			p->nextarc=q;
	}
	return OK;
}

//打印输出
int OutPut(ALGraph G2){
	int i,j;
	AList s;
	printf("无向图的邻接表: \n");
	for(i=1;i<=G2.vexnum;i++){      //将邻接表输出
		printf("%c",G2.vertices[i]);
		s=G2.vertices[i].firstarc;
		while(s){
			j=s->adjvex;        //该顶点在数组中的位置
			fflush(stdin);
			printf("(%c",G2.vertices[i]);
			printf(",%c)",G2.vertices[j]);
			s=s->nextarc;
		}
		printf("\n");
	}
	return OK;
}

//返回数组指针 的  第一个位置
int FirstAdjVex(ALGraph G,int v){
	if(G.vertices[v].firstarc)
		return G.vertices[v].firstarc->adjvex;     
	return 0;
}

int NextAdjVex(ALGraph G,int v,int w){
	AList s;
	s=G.vertices[v].firstarc;
	while(s->adjvex != w)
		s=s->nextarc;
	if(s->nextarc)
		return s->nextarc->adjvex;
	return 0;
}

//从第 v 个顶点出发递归地深度优先遍历图G
void DFS(ALGraph G,int v){
	int w;
	visited[v]=1;          //访问第 v 个顶点
	printf("%c",G.vertices[v]);
	for(w=FirstAdjVex(G,v) ; w>=1 ; w=NextAdjVex(G,v,w)){
		if(!visited[w])
			DFS(G,w);
	}
}

//深度优先遍历
int DFSTraverse(ALGraph G){
	int v;
	visited[0]=1;           //使用全局变量 visited[],使 DFS 不必设函数指针参数
	for(v=1;v<=G.vexnum;v++)
		visited[v]=0;                   //访问标志数组初始化
	for(v=1;v<=G.vexnum;v++)            //对尚未访问的顶点调用 DFS
		if(!visited[v])
			DFS(G,v);
	return OK;
}

//广度优先遍历
int BFSTraverse(ALGraph G){
	int v,w,u;
	LinkQueue Q;
	for(v=1;v<=G.vexnum;v++)
		visited[v]=0;       //初始化为0
	visited[0]=1;
	InitQueue(Q);
	for(v=1;v<=G.vexnum;v++)
		if(!visited[v]){    //如果visited[v]没有被访问过
			visited[v]=1;
			printf(" %c",G.vertices[v]);
			EnQueue(Q,v);
			while(!QueueEmpty(Q)){
				DeQueue(Q,u);
				for(w=FirstAdjVex(G,u);w>=1;w=NextAdjVex(G,u,w)){
					if(!visited[w]){
						visited[w]=1;
						printf(" %c",G.vertices[w]);
						EnQueue(Q,w);
					}
					else
						break;
				}
			}
		}
	return OK;
}

//主函数
void main(){
	ALGraph G;
	CreatAList(G);
	OutPut(G);

	printf("无向图的深度优先遍历: \n");
	DFSTraverse(G);
	printf("\n\n");
	printf("无向图的广度优先遍历: \n");
	BFSTraverse(G);
}

猜你喜欢

转载自blog.csdn.net/qq_40191710/article/details/79521980