研究了很长时间,注释就是我的心得体会
//dfs,bfs的多种实现
//code 1 邻接矩阵
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>
#include<stdbool.h>
#define INF __INT_MAX__ //最大值,有向网,无向网用
#define MAXSIZE 50 //最多几个节点
typedef int Staus;//实现功能函数
typedef int HStaus;//辅助函数
typedef char VertexType[4]; //节点名称,也就是每个节点叫啥
typedef char IntoPtr;//用来指定弧的信息
typedef int VRType;//是否有弧(网时有权值)
typedef enum{DG,DN,UDG,UDN} GraphKind;//图的类型(有向图,有向网,无向图,无向网)
typedef struct{
VRType adj;//邻接矩阵的0 1存储位置
IntoPtr*info;//储存信息,先给指针数组的头结点,之后有需要开辟新空间
}ArcNode,AdjMatrix[MAXSIZE][MAXSIZE];/*邻接表,要用的!*/
typedef struct{
VertexType vex[MAXSIZE];//用于存储节点信息,只需要把节点记在一个数组中即可,不用附加其他条件
AdjMatrix arc;//直接把邻接矩阵放在这个图的定义里,方便后续拿取
int vernum,arcnum;//顶点数和弧的数目
GraphKind kind;//图的类型
}MGraph;
bool visted[MAXSIZE];
//创建列表
HStaus CreateGraphALL(MGraph &N);
//创建有向图
Staus CreateGraphDG(MGraph &N);
//创建无向图
Staus CreateGraphUDG(MGraph &N);
//创建有向网
Staus CreateGraphDN(MGraph &N);
//创建无向网
Staus CreateGraphUDN(MGraph &N);
//深度优先算法
void DFS(MGraph N,int checknum);
void DFSTra(MGraph N);//这个函数的目的是使visited数组初始化,并且还能规避不连通图
//广度优先算法
void BFSTraverse(MGraph G);
//定义队列
typedef struct{
int data[MAXSIZE];
int front;
int rear;
}Queue;
//初始化空队列
HStaus InitQueue(Queue &Q);
//判断队列是否为空
HStaus QueueEmpty(Queue Q);
//插入
HStaus EnQueue(Queue&Q,int*e);
//删除
HStaus DeQueue(Queue&Q,int&e);
//找到节点的位置,用于构建领接矩阵
HStaus FindPos(VertexType str,MGraph N);
//展示图
void ShowGraphA(MGraph N);
//展示网
void ShowGraphB(MGraph N);
//销毁图
void DestoryGraph(MGraph &N);
int main(void)
{
MGraph GraA;
int ret=0;
printf("创建一个图GraA!\n");
ret=CreateGraphALL(GraA);
switch(ret)
{
case 1:ShowGraphA(GraA);break;
case 2:ShowGraphB(GraA);break;
default:break;
}
DFSTra(GraA);
BFSTraverse(GraA);
DestoryGraph(GraA);
return 0;
}
HStaus CreateGraphALL(MGraph &N)
{
int ki=0;
printf("请输入图的类型(有向图:1,有向网:2,无向图:3,无向网:4)");
scanf("%d",&ki);
switch(ki)
{
case 1: CreateGraphDG(N);return true;
case 2: CreateGraphDN(N);return true+1;
case 3: CreateGraphUDG(N);return true;
case 4: CreateGraphUDN(N);return true+1;
default: printf("error!");return false;
}
}
Staus CreateGraphDG(MGraph &N)
{
MGraph* ptr=&N;
printf("请输入节点个数:");
scanf("%d",&ptr->vernum);
printf("请输入%d个节点(小于四个字符)的值,每个节点之间用‘ ’区分:",ptr->vernum);
//输入节点
for(int i=0;i<ptr->vernum;i++)
{
char tempchar[4]={'\0'};
scanf("%s",tempchar);
strcpy(ptr->vex[i],tempchar);
}
//初始化邻接矩阵
for(int i=0;i<ptr->vernum;i++)
{
for(int j=0;j<ptr->vernum;j++)
{
ptr->arc[i][j].adj=0;
ptr->arc[i][j].info=NULL;
}
}
//输入弧
printf("请输入有几条弧:");
scanf("%d",&ptr->arcnum);
printf("请指定%d条弧的弧头、弧尾 (若弧包含信息,请输入1)\n",ptr->arcnum);
printf("格式为:弧头 弧尾 是否有信息:");
for(int i=0;i<ptr->arcnum;i++)
{
VertexType v1={'\0'},v2={'\0'};
int message=0;
int v1num=0,v2num=0;
printf("第%d次输入",i+1);
scanf("%s %s %d",v1,v2,&message);
v1num=FindPos(v1,N);
//printf("\n v1num:%d",v1num);
v2num=FindPos(v2,N);
//printf("\n v2num:%d",v2num);
ptr->arc[v1num][v2num].adj=1;
//有信息执行
if(message==1)
{
char Mestemp[10]={'\0'};
printf("请输入该弧的信息(不超过10个字节)");
scanf("%s",Mestemp);
ptr->arc[v1num][v2num].info=(char*)malloc(sizeof(Mestemp));
strcpy(ptr->arc[v1num][v2num].info,Mestemp);
}
}
return true;
}
HStaus FindPos(VertexType str,MGraph N)
{
int i=0;
for(i=0;i<N.vernum;i++)
{
if(strcmp(str,N.vex[i])==0)
{
return i;
}
}
return false;
}
void ShowGraphA(MGraph N)
{
printf("图的类型为:");
switch(N.kind)
{
case DG:printf("有向图\n");break;
case DN:printf("有向网\n");break;
case UDG:printf("无向图\n");break;
case UDN:printf("无向网\n");break;
default:printf("error!");return;
}
printf("图的节点有:\n");
for(int i=0;i<N.vernum;i++)
{
printf("%s",N.vex[i]);
printf("\n");
}
printf("图的邻接矩阵有:\n");
for(int i=0;i<N.vernum;i++)
{
for(int j=0;j<N.vernum;j++)
{
printf("%4d",N.arc[i][j].adj);
}
printf("\n");
}
}
Staus CreateGraphUDG(MGraph &N)
{
MGraph* ptr=&N;
printf("请输入节点个数:");
scanf("%d",&ptr->vernum);
printf("请输入%d个节点(小于四个字符)的值,每个节点之间用‘ ’区分:",ptr->vernum);
//输入节点
for(int i=0;i<ptr->vernum;i++)
{
char tempchar[4]={'\0'};
scanf("%s",tempchar);
strcpy(ptr->vex[i],tempchar);
}
//初始化邻接矩阵
for(int i=0;i<ptr->vernum;i++)
{
for(int j=0;j<ptr->vernum;j++)
{
ptr->arc[i][j].adj=0;
ptr->arc[i][j].info=NULL;
}
}
//输入弧
printf("请输入有几条边(一半):");
scanf("%d",&ptr->arcnum);
printf("请指定%d条弧的弧头、弧尾 (若弧包含信息,请输入1)\n",ptr->arcnum*2);
printf("格式为:弧头 弧尾 是否有信息:");
for(int i=0;i<ptr->arcnum;i++)
{
VertexType v1={'\0'},v2={'\0'};
int message=0;
int v1num=0,v2num=0;
printf("第%d次输入",i+1);
scanf("%s %s %d",v1,v2,&message);
v1num=FindPos(v1,N);
//printf("\n v1num:%d",v1num);
v2num=FindPos(v2,N);
//printf("\n v2num:%d",v2num);
ptr->arc[v1num][v2num].adj=1;
ptr->arc[v2num][v1num].adj=1;
//有信息执行
if(message==1)
{
char Mestemp[10]={'\0'};
printf("请输入该弧的信息(不超过10个字节)");
scanf("%s",Mestemp);
ptr->arc[v1num][v2num].info=(char*)malloc(sizeof(Mestemp));
ptr->arc[v2num][v1num].info=(char*)malloc(sizeof(Mestemp));
strcpy(ptr->arc[v1num][v2num].info,Mestemp);
strcpy(ptr->arc[v2num][v1num].info,Mestemp);
}
}
return true;
}
void DestoryGraph(MGraph &N)
{
for(int i=0;i<N.vernum;i++)
{
for(int j=0;j<N.vernum;j++)
{
if(N.arc[i][j].adj!=INF)
{
if(N.arc[i][j].info!=NULL)
{
free(N.arc[i][j].info);
N.arc[i][j].info=NULL;
}
}
}
}
N.vernum=0;
N.arcnum=0;
}
Staus CreateGraphDN(MGraph &N)
{
MGraph* ptr=&N;
printf("请输入节点个数:");
scanf("%d",&ptr->vernum);
printf("请输入%d个节点(小于四个字符)的值,每个节点之间用‘ ’区分:",ptr->vernum);
//输入节点
for(int i=0;i<ptr->vernum;i++)
{
char tempchar[4]={'\0'};
scanf("%s",tempchar);
strcpy(ptr->vex[i],tempchar);
}
//初始化邻接矩阵
for(int i=0;i<ptr->vernum;i++)
{
for(int j=0;j<ptr->vernum;j++)
{
ptr->arc[i][j].adj=INF;
ptr->arc[i][j].info=NULL;
}
}
//输入弧
printf("请输入有几条弧:");
scanf("%d",&ptr->arcnum);
printf("请指定%d条弧的弧头、弧尾 权值(若弧包含信息,请输入1)\n",ptr->arcnum);
printf("格式为:弧头 弧尾 权值 是否有信息:");
for(int i=0;i<ptr->arcnum;i++)
{
VertexType v1={'\0'},v2={'\0'};
int message=0;
int v1num=0,v2num=0;
int rig=0;
printf("第%d次输入",i+1);
scanf("%s %s %d %d",v1,v2,&rig,&message);
v1num=FindPos(v1,N);
//printf("\n v1num:%d",v1num);
v2num=FindPos(v2,N);
//printf("\n v2num:%d",v2num);
ptr->arc[v1num][v2num].adj=rig;
//有信息执行
if(message==1)
{
char Mestemp[10]={'\0'};
printf("请输入该弧的信息(不超过10个字节)");
scanf("%s",Mestemp);
ptr->arc[v1num][v2num].info=(char*)malloc(sizeof(Mestemp));
strcpy(ptr->arc[v1num][v2num].info,Mestemp);
}
}
return true;
}
void ShowGraphB(MGraph N)
{
printf("图的类型为:");
switch(N.kind)
{
case DG:printf("有向图\n");break;
case DN:printf("有向网\n");break;
case UDG:printf("无向图\n");break;
case UDN:printf("无向网\n");break;
default:printf("error!");return;
}
printf("图的节点有:\n");
for(int i=0;i<N.vernum;i++)
{
printf("%s",N.vex[i]);
printf("\n");
}
printf("图的邻接矩阵有:\n");
for(int i=0;i<N.vernum;i++)
{
for(int j=0;j<N.vernum;j++)
{
if(N.arc[i][j].adj==INF)
{
printf(" ∞");
}
else
{
printf("%4d",N.arc[i][j].adj);
}
}
printf("\n");
}
}
Staus CreateGraphUDN(MGraph &N)
{
MGraph* ptr=&N;
printf("请输入节点个数:");
scanf("%d",&ptr->vernum);
printf("请输入%d个节点(小于四个字符)的值,每个节点之间用‘ ’区分:",ptr->vernum);
//输入节点
for(int i=0;i<ptr->vernum;i++)
{
char tempchar[4]={'\0'};
scanf("%s",tempchar);
strcpy(ptr->vex[i],tempchar);
}
//初始化邻接矩阵
for(int i=0;i<ptr->vernum;i++)
{
for(int j=0;j<ptr->vernum;j++)
{
ptr->arc[i][j].adj=INF;
ptr->arc[i][j].info=NULL;
}
}
//输入弧
printf("请输入有几条边(一半):");
scanf("%d",&ptr->arcnum);
printf("请指定%d条弧的弧头、弧尾 权值(若弧包含信息,请输入1)\n",ptr->arcnum*2);
printf("格式为:弧头 弧尾 权值 是否有信息:");
for(int i=0;i<ptr->arcnum;i++)
{
VertexType v1={'\0'},v2={'\0'};
int message=0;
int v1num=0,v2num=0;
int rig=0;
printf("第%d次输入",i+1);
scanf("%s %s %d %d",v1,v2,&rig,&message);
v1num=FindPos(v1,N);
//printf("\n v1num:%d",v1num);
v2num=FindPos(v2,N);
//printf("\n v2num:%d",v2num);
ptr->arc[v1num][v2num].adj=rig;
ptr->arc[v2num][v1num].adj=rig;
//有信息执行
if(message==1)
{
char Mestemp[10]={'\0'};
printf("请输入该弧的信息(不超过10个字节)");
scanf("%s",Mestemp);
ptr->arc[v1num][v2num].info=(char*)malloc(sizeof(Mestemp));
ptr->arc[v2num][v1num].info=(char*)malloc(sizeof(Mestemp));
strcpy(ptr->arc[v1num][v2num].info,Mestemp);
strcpy(ptr->arc[v2num][v1num].info,Mestemp);
}
}
return true;
}
void DFS(MGraph N,int checknum)
{
visted[checknum]=true;//开始访问这个节点了,所以要标记一下
printf("%4s",N.vex[checknum]);
for(int i=0;i<N.vernum;i++)//现在的checknum是固定的,现在找与checknum链接的节点,然后搜索到的节点继续往下深搜
{
if(!visted[i]&&N.arc[checknum][i].adj==1)//未访问而且有路能找到这个节点
{
DFS(N,i);//往下深度搜索,其实有隐含着return的条件:一条路也找不见就直接返回了
}
}
}
void DFSTra(MGraph N)
{
printf("开始深度搜索!\n");
for(int i=0;i<N.vernum;i++)
{
visted[i]=false;//初始全是未访问
}
for(int i=0;i<N.vernum;i++)
{
if(!visted[i])
{
DFS(N,i);//正因为visted数组是全局变量,所以这里吧vis修改后就不变了
}
}
printf("\n");
}
HStaus InitQueue(Queue &Q)
{
Queue*ptr=&Q;
ptr->front=0;
ptr->rear=0;
return true;
}
HStaus EnQueue(Queue&Q,int e)
{
Queue*ptr=&Q;
if((ptr->rear+1)%MAXSIZE==ptr->front)
{
return false;
}
ptr->data[ptr->rear]=e;
ptr->rear=(ptr->rear+1)%MAXSIZE;
return true;
}
HStaus QueueEmpty(Queue Q)
{
if(Q.front==Q.rear)
{
return true;
}
else
{
return false;
}
}
HStaus DeQueue(Queue&Q,int*e)
{
Queue*ptr=&Q;
if(ptr->front==ptr->rear)//判断是不是空队列
{
return false;
}
*e=ptr->data[ptr->front];//用于返回删除的值
ptr->front=(ptr->front+1)%MAXSIZE;
return true;
}
void BFSTraverse(MGraph G)
{
Queue Q;
printf("开始广度优先遍历!\n");
for(int i=0;i<G.vernum;i++)//初始化访问数组
{
visted[i]=false;
}
InitQueue(Q);//初始化辅助队列
for(int i=0;i<G.vernum;i++)
{
if(!visted[i])
{
visted[i]=true;
printf("%4s",G.vex[i]);
EnQueue(Q,i);
while (!QueueEmpty(Q))
{
DeQueue(Q,&i);
for(int j=0;j<G.vernum;j++)
{
if(G.arc[i][j].adj==1&&!visted[j])
{
visted[j]=true;
printf("%4s",G.vex[j]);//从母节点开始,把与母节点相连的都放进队列里
EnQueue(Q,j);//在下一回循环时就能把下一个节点输出,并且把下一层加到队列中
}//这样不断的就能慢慢把信息输出完
}
}
}
}
printf("\n");
}