有向图的两种存储类型创建和遍历(邻接矩阵/邻接链表)(深度优先遍历/广度优先遍历)

本文介绍有向图的邻接矩阵和邻接链表两种存储方式,以及深度优先和广度优先遍历算法的实现。通过实例展示图的创建、输出及遍历过程。

有向图的两种存储类型创建和两种遍历

任务: 给定一个有向图,实现图的深度优先, 广度优先遍历算法,并输出相关结果。
功能要求: 输入图的基本信息,并建立图存储结构(有相应提示),输出遍历序列。

相关具体实验图形如下:
在这里插入图片描述
有向图信息:
顶点6个: A,B,C,D,E,F
8条边: A->B,A->D,A->F,B->E,C->E,D->E,F->C,C->E
深度优先遍历结果: A B C E D F
广度优先遍历结果: A B D F C E
注意事项
在命令行输入时请以英文形式输入
例如:printf("第%d条边:",k); scanf("%c,%c",&vex1,&vex2);
输入:A,B[Enter]

(一)图的结构体、队列、标记数组的声明

1. 变量、队列等声明

#include <stdio.h>
#include <malloc.h>
#define MAXVEX 50
int visited[MAXVEX];  //为遍历准备的标志数组全局变量 
char enter;				//吃scnaf %c中[enter]键 
//广度遍历中需使用到队列 
//队列的结构体 
typedef struct SqQueue{
	int vex[MAXVEX];
}Queue;
//队列的全局变量  
int front;			
int rear;

2. 邻接链表的结构体

//邻接链表的结构体 
typedef struct edge{  //边结点 
	int adjvex; 
	char vex;
	struct edge *next;
}ELink; 

typedef struct vex{  //顶点结点 
	char vex;
	ELink * first;
}VLink;

typedef struct list{    //链表信息 
	int vexnum;			//顶点数目 
	int arcnum;			//边数目 
	VLink Vex[MAXVEX];	//顶点矩阵 
}List;

3. 邻接矩阵的结构体

typedef struct Node{
	int arcs[MAXVEX][MAXVEX];   //邻接矩阵 
    char vex[MAXVEX];			// 顶点值 
    int vexnum;  				//顶点数目 
    int arcnum;  				//边数目 
}Adj;

4. 初始化标记数组、队列、获取顶点位置

//标志数组初始化 
void initialvisitedadj(Adj G){//邻接矩阵类型的初始化
	for(int i = 1;i<=G.vexnum;i++){
		visited[i] = 0;
	} 
}
void initialvisitedlist(List list){//邻接链表类型的初始化
	for(int i = 1;i<=list.vexnum;i++){
		visited[i] = 0;
	} 
}

//队列的初始化 
void initialqueue(){
	front = -1;
	rear = -1;
}
//获取顶点位置
 int locatevex(Adj G, int v) {
	int i;
	for ( i = 1; i <= G.vexnum; i++) {
		if (G.vex[i] == v) {
			return i;
		}
	}
	return 0;
}

(二)有向图的创建

1. 邻接矩阵存储的创建

Adj Create(Adj G){ 
	int i,j,k;
	char vex1,vex2;
	
	printf("请输入有向图中的顶点数和边数:\n");
	scanf("%d,%d",&G.vexnum,&G.arcnum);
	for(i = 1;i<=G.vexnum;i++) //先把所有数组顶点设置为0;
	{
		for(j = 1;j<=G.vexnum;j++)
		{
			G.arcs[i][j] = 0;
		}
	}

	printf("请输入有向图中%d个顶点:\n",G.vexnum);

	for(i = 1;i<=G.vexnum;i++)
	{
		scanf("%c",&enter);
		printf("输入第%d个顶点:",i);
		scanf("%c",&G.vex[i]);
	}
	
	printf("请输入有向图的%d条边\n",G.arcnum);
	
	for(k = 1;k<=G.arcnum;k++)
	{	
		scanf("%c",&enter);
		printf("第%d条边:",k);
		scanf("%c,%c",&vex1,&vex2);
		
		printf("%c<--->%c\n",vex1,vex2);
		i = locatevex(G, vex1);
		j = locatevex(G, vex2);
		G.arcs[i][j] = 1;
	}
	return G;
}

2. 邻接链表的创建

//创建邻接链表 
List createlist(List list){
	Adj G; //创建邻接矩阵 得到G.arcs[i][j] 矩阵 根据矩阵标记0/1创建链表 
	int i,j,k;
	char vex1,vex2;
	printf("请输入有向图中的顶点数和边数:\n");
	scanf("%d,%d",&G.vexnum,&G.arcnum);
	for(i = 1;i<=G.vexnum;i++) //先把所有数组顶点设置为0;
	{
		for(j = 1;j<=G.vexnum;j++)
		{
			G.arcs[i][j] = 0;
		}
	}

	printf("请输入有向图中%d个顶点:\n",G.vexnum);

	for(i = 1;i<=G.vexnum;i++)
	{
		scanf("%c",&enter);
		printf("输入第%d个顶点:",i);
		scanf("%c",&G.vex[i]);
	}
	
	printf("请输入有向图的%d条边\n",G.arcnum);
	
	for(k = 1;k<=G.arcnum;k++)
	{	
		scanf("%c",&enter);
		printf("第%d条边:",k);
		scanf("%c,%c",&vex1,&vex2);
		
		printf("%c<--->%c\n",vex1,vex2);
		i = locatevex(G, vex1);
		j = locatevex(G, vex2);
		G.arcs[i][j] = 1;
	}
	
	//邻接链表的创建开始 
	for(i =1;i<=G.vexnum;i++){  //邻接链表顶点结点的初始化 
		list.Vex[i].vex = G.vex[i];
		list.Vex[i].first = NULL;
	}
	
	ELink *p =NULL;		//创建边结点 
	for(i=1 ;i<=G.vexnum;i++)
		for(j=G.vexnum ; j>0 ;j--)		//头插法插入 
			if(G.arcs[i][j] != 0){ 	//根据邻接矩阵是否有边 
				p =(ELink*)malloc(sizeof(ELink));   
				p->adjvex = j;
				p->next = list.Vex[i].first;
				list.Vex[i].first = p;
			}
	list.arcnum = G.arcnum;
	list.vexnum = G.vexnum;
	return list;
}

(三)有向图的输出

1. 邻接矩阵的输出

//邻接矩阵的输出
void displayadj(Adj G){
	int i,j;
	for(i=1 ; i<=G.vexnum ;i++){
		printf("顶点%d:",i);
			for(j=1 ; j<=G.vexnum ;j++){
				printf("%d ",G.arcs[i][j]);
			}
		printf("\n"); 
	}
}

2. 邻接链表的输出

//邻接链表的输出
void displaylist(List list){     
	int i;
	ELink *p;
	printf("图的邻接表存储\n");
	for(i=1;i <= list.vexnum ;i++)
	{
		p=list.Vex[i].first;
		printf("编号 %d 的顶点 %c : ",i-1,list.Vex[i].vex);
		while(p != NULL)
		{
			printf("%d -> ",p->adjvex-1);  //输出邻接顶点的编号
			p=p->next;
		}
		printf("^\n");
	}
}

(四)邻接矩阵的遍历

1. 邻接矩阵的深度优先遍历

顶点编号为v 的第一个邻接点

int FirstAdj(Adj G,int v){
	for(int i = 1;i<=G.vexnum;i++){
		if(G.arcs[v][i]==1 && visited[i]!=1){
			return i;
		}
	}
	return -1;
}

寻找它的下一个邻接点

int NextAdj(Adj G,int v,int w)
{
	for(int i = w+1 ; i<=G.vexnum;i++)
	{
		if(G.arcs[v][i]==1 && visited[i]!=1)
		{
			return i;
		}
	}
	return -1;
}

邻接矩阵的深度优先遍历

//邻接矩阵的深度优先遍历
void DFSadj(Adj G, int v)
{
	int w; 
	printf("%c  ",G.vex[v]);
	visited[v] = 1;    
	w = FirstAdj(G, v);
	while(w != -1) {
		if (visited[w]==0)
		{
			DFSadj(G, w);
		}
		w = NextAdj(G, v, w);
	}
}

对图深度优先遍历的主算法如下:

void MDFSadj(Adj G) //最终深度遍历结果 
{
	int i;
	initialvisitedadj(G); 
	for (i=1;i<=G.vexnum;i++)
		if(visited[i]==0)
			DFSadj(G,i);
}

2. 邻接矩阵的广度优先遍历

void BFSadj(Adj G,int v){
	printf("%c  ",G.vex[v]);
	visited[v]= 1;
	rear++;
	Queue Q;
	Q.vex[rear] =v; //入队
	
	while(front != rear)
	{
		front++; //出队
		v = Q.vex[front];
		int w = FirstAdj(G,v);
		while(w!=-1){
			if(visited[w]==0){
				printf("%c  ",G.vex[w]);
				visited[w]=1;
				rear++;
				Q.vex[rear] = w;
			}
			w = NextAdj(G,v,w);
		}
	}
}

对图广度优先遍历的主算法如下:

void MBFSadj(Adj G){//最终广度遍历结果 
	int i;
	initialvisitedadj(G); 
	initialqueue();
	for (i=1;i<=G.vexnum;i++)
		if(visited[i]==0)
			BFSadj(G,i);
}

(五)邻接链表的遍历

1. 邻接链表的深度优先遍历

void DFSList(List list, int v){
    visited[v] = 1;  
    printf("%c ", list.Vex[v].vex);  
    ELink *p = list.Vex[v].first;
    while(p!=NULL){
        if(visited[p->adjvex] == 0){
            DFSList(list,p->adjvex); 
        }
        p = p->next;
    }
}

2. 邻接链表的广度优先遍历

//邻接链表的广度优先遍历 
void BFSList(List list){  
    int i;
    Queue Q;
    initialvisitedlist(list);	//初始化标记 
    initialqueue();		//初始化队列 
    for (i=1; i<= list.vexnum; i++){  
        if(visited[i] == 0){  
            visited[i] = 1;  
            printf("%c ", list.Vex[i].vex);  
            rear++;  //入队 
 			Q.vex[rear] = i;
            while (front != rear){  
            	front++;  
            	i = Q.vex[front]; //出队 
                ELink *p = list.Vex[i].first;  
                while (p!=NULL){  
                    if (visited[p->adjvex] == 0){  
                        visited[p->adjvex] = 1;
                        printf("%c ", list.Vex[p->adjvex].vex);
                        rear++;  
 						Q.vex[rear] = p->adjvex;
                    }  
                    p = p->next;  
                }
            }
        }  
    }    
}

主函数main()

int main()
{
	int i ,j;
	//邻接矩阵 
	Adj adjmatirx;	
	//邻接链表 
	List list;
	
	int select;
	int select1; 
	while(1)
	{
		printf("\t\t\t\t请你选择图的存储结构\n"); 
		printf("\t\t\t\t\t1.邻接矩阵存储方法\n");
		printf("\t\t\t\t\t2.邻接链表存储方法\n");
		printf("\t\t\t\t请输入(1/2):");
		scanf("%d",&select);
		switch (select){
			case 1:
			{ 
				adjmatirx = Create(adjmatirx);
				printf("图的邻接矩阵如下:\n\n");
				displayadj(adjmatirx);
				printf("\n深度遍历结果:\n");
				MDFSadj(adjmatirx);
				printf("\n广度遍历结果:\n");
				MBFSadj(adjmatirx);
				printf("\n\n");
				break;
			} 
			case 2:
			{ 
				list = createlist(list);
				printf("图的邻接链表如下:\n\n");
				displaylist(list);
				printf("\n深度遍历结果:\n");
				DFSList(list,1);
				printf("\n广度遍历结果:");
				BFSList(list);
				printf("\n\n");
				break;
			} 
			default :
				printf("错误!请输入正确的数值!");
		}
		printf("\t\t\t\t是否退出(1)?:");//按1退出
		scanf("%d",&select1);
		if(select1 == 1)
			return 0;
	}
}

运行结果

在这里插入图片描述
在这里插入图片描述

评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AMAZZED

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

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

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

打赏作者

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

抵扣说明:

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

余额充值