#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#define MAXSIZE 100
int vis[MAXSIZE];///这个是访问数组
typedef struct arcnode
{
int adjvex;///该弧所指向的顶点位置,邻接点域
struct arcnode *nextarc;///指向下一条弧的指针域
}ArcNode;
typedef struct VNode
{
int data;///顶点信息
ArcNode *firstarc;///指向第一条依附该顶点的弧的指针
}AdjList[MAXSIZE];
typedef struct graph///这个结构图是图的整个信息,包括了它的顶点数和弧数,以及各个弧的信息
{
AdjList vertices;
int vexnum,arcnum;
}ALGraph;
typedef struct queue///循环队列的结构体
{
int *base;///存数据的
int front,rear;///队首和队尾
}Queue;
int LocateVex(ALGraph G,int v);///定位顶点的位置
void creat_graph(ALGraph *G);///创建图
void dfs(ALGraph G,int v);///深搜
void DFSTraverse(ALGraph G);///深度优先搜索
void Init_Queue(Queue *Q);///初始化队列
int empty_Queue(Queue Q);///判断队列是否为空
void push_Queue(Queue *Q,int e);///入队
void pop_Queue(Queue *Q,int *e);///出队
void BFSTraverse(ALGraph G);///广度优先搜索
void clear();///清屏
int main()
{
ALGraph G;///定义一个图
int choose;///菜单选择
do{///页面设计
printf("\t\t\t****************\n");
printf("\t\t\t*1.图的创建 *\n");
printf("\t\t\t*2.深度优先遍历*\n");
printf("\t\t\t*3.广度优先遍历*\n");
printf("\t\t\t*0.退出 *\n");
printf("\t\t\t****************\n");
printf("请输入你需要操作的菜单:");
scanf("%d",&choose);
if(choose==0)
{
printf("\t\t\t欢迎下次再使用!\n");
break;
}
switch(choose)
{
case 1:creat_graph(&G);break;///创建图
case 2:puts("深度优先遍历如下:");DFSTraverse(G);puts("");break;///深度优先搜索
case 3:puts("广度优先遍历如下:");BFSTraverse(G);puts("");break;///广度优先搜索
default:printf("输入错误,请重新输入\n");break;
}
clear();///清屏
}while(1);
return 0;
}
///定位顶点的位置
int LocateVex(ALGraph G,int v)
{
int i;
for(i=0;i<G.vexnum;i++)///遍历去查找
{
if(G.vertices[i].data==v)///找到该位置
return i;///查找到就返回它的位置
}
return -1;///查找不到就返回-1
}
///创建图
void creat_graph(ALGraph *G)
{
ArcNode *p,*t;///p的作用是创建弧的时候要申请的空间,而t是用来遍历的
int i,j,k;
int v1,v2;///头,尾
printf("请输入顶点数和弧数:");
scanf("%d%d",&G->vexnum,&G->arcnum);
printf("请输入顶点:");
for(i=0;i<G->vexnum;i++)
{
scanf("%d",&G->vertices[i].data);///先创建每个顶点,然后初始化他们的弧都是空的
G->vertices[i].firstarc=NULL;
}
printf("请输入弧:\n");
for(k=0;k<G->arcnum;k++)///输入弧的信息
{
scanf("%d%d",&v1,&v2);
i=LocateVex(*G,v1);///这个是定位顶点的位置,因为我开的是数组形式存储,也就是要先找到顶点的位置
j=LocateVex(*G,v2);///然后这个箭头所指的顶点,那么我这个也要找到这个的位置是在哪里,它同样也是一个顶点
p=(ArcNode *)malloc(sizeof(ArcNode));///申请一个弧的空间
p->nextarc=NULL;///让它的next先指向空的,
p->adjvex=j;///然后把这个箭头所指向的顶点存在这个弧里面,接下来就是衔接了
if(G->vertices[i].firstarc==NULL)///如果我们创建的顶点还没有任何指向,那么它的firstarc就直接指向这个头
G->vertices[i].firstarc=p;
else
{
t=G->vertices[i].firstarc;///如果它的firstarc已经有指向的顶点了,那么我们就需要去遍历到它的末尾,也就是还没有指向的位置,然后进行衔接过去
while(t->nextarc)///如果它的nextarc是空的,那么也就是到这个顶点的末尾了,进行指向
t=t->nextarc;
t->nextarc=p;///进行指向,让它指向刚才申请的弧空间
}
}
puts("操作成功!");
}
///深搜
void dfs(ALGraph G,int v)
{
ArcNode *p;///这个是暂时的弧结构体,用在接下来的遍历
printf("%d ",G.vertices[v].data);///输出顶点信息
vis[v]=1;///访问完这个顶点,就赋值1,代表它已经被访问过了
for(p=G.vertices[v].firstarc;p;p=p->nextarc)///遍历这个从这个顶点出发,去遍历它所有指向的顶点,并去搜索
if(!vis[p->adjvex])///这个前提还要是未访问的
dfs(G,p->adjvex);///这个顶点没被访问过就进行搜索
}
///深度优先搜索
void DFSTraverse(ALGraph G)
{
int i;
for(i=0;i<G.vexnum;i++)
vis[i]=0;///先把访问数组都进行初始化为0
for(i=0;i<G.vexnum;i++)///然后从第一个顶点开始搜索
if(!vis[i])///没访问过的就可以进行搜索,如果访问过就不需要再进行搜索
dfs(G,i);///进行搜索
}
///初始化队列
void Init_Queue(Queue *Q)
{
Q->base=(int *)malloc(MAXSIZE*sizeof(int));///申请一个maxsize的数组空间
Q->front=Q->rear=0;///循环队列一开始都是指向初始位置0,队首和队尾指在同一位置
}
///队列是否为空的
int empty_Queue(Queue Q)
{
if(Q.rear==Q.front)///如果队首和队尾指在同一位置就说明是空的
return 1;///返回1,说明队列是空的
return 0;///否则就是0,说明不是空的
}
///入队
void push_Queue(Queue *Q,int e)
{
if((Q->rear+1)%MAXSIZE==Q->front)///每次入队之后,rear都会先指向下一个,所以先判断rear+1是不是到了front的位置,是的话说明队列满了
return ;///满了就说明无法进行入队了
Q->base[Q->rear]=e;///空间足够就入队
Q->rear=(Q->rear+1)%MAXSIZE;///入队之后,rear要指向下一个,模它的最大空间,因为是循环队列
}
///出队
void pop_Queue(Queue *Q,int *e)
{
if(Q->rear==Q->front)///在出队之前先判断front和rear都指向同一个位置,如果是就跟初始化一样,也就是队列是空的
return ;
*e=Q->base[Q->front];///把出队的值赋值给e,e返回的时候进行输出
Q->front=(Q->front+1)%MAXSIZE;///出队之后要指向下一个,因为循环队列,要取模MAXSIZE
}
///广度优先搜索
void BFSTraverse(ALGraph G)
{
int u,v;
Queue Q;///定义一个循环队列
ArcNode *p;
for(v=0;v<G.vexnum;v++)
vis[v]=0;///在广度搜索之前先把访问数组进行初始化为0
Init_Queue(&Q);///初始化队列
for(v=0;v<G.vexnum;v++)///遍历每个顶点,这样就不会漏掉,而且都是优先序号小的先访问
if(!vis[v])///该顶点没有被访问就进行操作
{
printf("%d ",G.vertices[v].data);///并输出该顶点
vis[v]=1;///访问了该顶点之后就把这个顶点的访问数组赋值为1
push_Queue(&Q,v);///然后就让这个顶点入队,因为我们不是进行深搜,是把该层的顶点都进行输出之后再访问下一层的
while(!empty_Queue(Q))///如果不是空的话就进下这一层的其他的顶点的输出
{
pop_Queue(&Q,&u);///u就是刚才那个顶点,然后这样就可以找到这个顶点的层里还有其他的顶点,没有就进行下一层
for(p=G.vertices[u].firstarc;p;p=p->nextarc)///这个就是把这个下一层的顶点都进行输出,并入队,不会直接进入下一层
if(!vis[p->adjvex])///没被访问过就进行输出,并入队
{
printf("%d ",G.vertices[p->adjvex].data);
vis[p->adjvex]=1;///访问了该顶点之后就把这个顶点的访问数组赋值为1
push_Queue(&Q,p->adjvex);///入队
}
}
}
}
///清屏
void clear()
{
printf("请按任意键继续......");
getch();
system("cls");
}
图的应用(深度优先搜索和广度优先搜索)
最新推荐文章于 2024-05-12 07:20:19 发布