数据结构——图的建立与操作
源码:
#include<stdio.h>
#include<windows.h>
#define INFINITY 65535
#define MAX_VARTEX_NUM 10
#define Status int
#define OK 0
#define ERROR 1
#define OVERFLOW -2
//标志数组
bool visited[MAX_VARTEX_NUM]={false};
//图的类型的构建
typedef enum {DG,DN,AG,AN} GraphKind;
typedef struct AreCell
{
int adj;//顶点关系
}ArCell,AdjMatrix[MAX_VARTEX_NUM][MAX_VARTEX_NUM];
typedef struct
{
char vexs[MAX_VARTEX_NUM];//顶点向量
AdjMatrix arcs;//邻接矩阵
int vexnum,arcnum;//图的当前顶点数和弧数
int flag;//标志变量
GraphKind kind;//图的标志的种类
}MGraph;
//队列的类型的构建
typedef struct QNode
{
int data;//数据域
struct QNode *next;//指针域
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
//创建队列函数
Status InitQueue(LinkQueue &Q)//创建空的队列
{
Q.front=Q.rear=(struct QNode *)malloc(sizeof(struct QNode));
if(!Q.front)
exit(OVERFLOW);
Q.front->next=NULL;//将队头指针的指针域置空
return OK;
}
//队列插入函数
Status EnQueue(LinkQueue &Q,int e)//插入函数
{
QueuePtr p;//申请一个结点
p=(struct QNode *)malloc(sizeof(struct QNode));//动态申请一个结点
if(!p)
exit(OVERFLOW);//存储分配失败
p->data=e;
p->next=NULL;//将结点的指针域赋值为空
Q.rear->next=p;//将结点p链接到队列尾部
Q.rear=p;//将尾指针直线结点p
return OK;
}
//判断队列是否为空
Status QueueEmpty(LinkQueue Q)//判断队列是否为空
{
if(Q.front==Q.rear)
return ERROR;
else
return OK;
}
//队列的删除函数
Status DeQueue(LinkQueue &Q,int &e)//删除队列的头元素
{
QueuePtr p;//定义一个结点
if(Q.front==Q.rear)
return ERROR;
p=Q.front->next;//将队列头赋值给p
e=p->data;
Q.front->next=p->next;//直接将队列头指针指向p的后继
if(Q.rear==p)
Q.rear=Q.front;//队列头尾重合,队列为空
free(p);//释放空间p
return OK;
}
//顶点的位置
Status LocateVex(MGraph &G,char e)
{
int i;//循环变量
for(i=0;i<G.vexnum;i++)
if(G.vexs[i]==e)
return i;
return OK;
}
//寻找第一个后继元素
Status FirstAdjVex(MGraph &G,int i)
{
int j=0;//标志变量
int k;//循环变量
if (G.kind==1||G.kind==3)//网
j=INFINITY;
for(k=0;k<G.vexnum;k++)
if(G.arcs[i][k].adj!=j)
return k;
return -1;
}
//寻找后继元素
Status NextAdjVex(MGraph &G,int i,int k)
{
int j=0;//标志变量
int x;//循环变量
if (G.kind==1||G.kind==3)//网
j=INFINITY;
for(x=k+1;x<G.vexnum;x++)
if(G.arcs[i][x].adj!=j)
return x;
return -1;
}
//深度优先遍历(递归算法)
Status DFSM(MGraph G,int i)
{
int j;//循环变量
if(G.flag!=1)//判断图是否存在
return ERROR;
printf("%2c",G.vexs[i]);
visited[i]=true;//将访问过的标记为1
for(j=0;j<G.vexnum;j++)
if(G.arcs[i][j].adj==1&&visited[j]==false)
DFSM(G,j);//新出发点
return OK;
}
//广度优先遍历
Status BFS(MGraph &G,int i)
{
int u,w;//循环变量
LinkQueue Q;//定义队列
if(G.flag!=1)
return ERROR;
InitQueue(Q);//置空的辅助队列
printf("%2c",G.vexs[i]);
visited[i]=true;//将标志变量改变为true
EnQueue(Q,i);//将i入队列
while(QueueEmpty(Q)!=ERROR)
{
DeQueue(Q,u);//出队列并置为u
for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
{
if(visited[w]==false)
{
printf("%2c",G.vexs[w]);
visited[w]=true;
EnQueue(Q,w);//入队列
}
}
}
return OK;
}
//顶点向量
Status Out_Vexs(MGraph G)
{
int i;//循环变量
if(G.flag!=1)
return ERROR;
printf("\n顶点向量为:");
printf("[");
for(i=0;i<G.vexnum;i++)
printf("%c,",G.vexs[i]);
printf("\b]\n");
return OK;
}
//邻接矩阵
Status Out_arcs(MGraph &G)
{
int i,j;//循环变量
if(G.flag!=1)
return ERROR;
printf("\n该图的邻接矩阵为:\n\n");
printf("\t");
for(i=0;i<G.vexnum;i++)//横排输出顶点
printf("%c\t",G.vexs[i]);
printf("\n\n");
for(i=0;i<G.vexnum;i++)//输出邻接矩阵
{
printf("%c\t",G.vexs[i]);
for(j=0;j<G.vexnum;j++)
{
if(G.arcs[i][j].adj==INFINITY)
printf("∞");
else
printf("%d\t",G.arcs[i][j]);
}
printf("\n\n");
}
return OK;
}
//创建有向图的函数
Status CreateDG(MGraph &G)
{
int i,j,k;//循环变量
char v1,v2;//存储输入的顶点的字符
//采用邻接矩阵表示,构造有向图 G
printf("\n有向图的顶点数:");
scanf("%d",&G.vexnum);
printf("\n有向图的边数:");
scanf("%d",&G.arcnum);
getchar();//吸收字符
for(i=0;i<G.vexnum;i++)
{
printf("\n第%d个顶点为: ",i+1);
scanf("%c",&G.vexs[i]);
getchar();//吸收回车符
}
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=0;
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("\n第%d条边:\n",k+1);
printf("第一个顶点:");scanf("%c",&v1);getchar();
printf("第二个顶点:");scanf("%c",&v2);getchar();
i=LocateVex(G,v1);
j=LocateVex(G,v2);//确定v1和v2在G中的位置
G.arcs[i][j].adj=1;//将有关系标记为1
}
G.flag=1;//标志变量赋值为1
return OK;
}
//创建有向网的函数
Status CreateDN(MGraph &G)
{
int i,j,k,w;//循环变量
char v1,v2;//存储输入的顶点的字符
//采用邻接矩阵表示,构造有向网 G
printf("\n有向网的顶点数:");
scanf("%d",&G.vexnum);
printf("\n有向网的边数:");
scanf("%d",&G.arcnum);
getchar();//吸收字符
for(i=0;i<G.vexnum;i++)
{
printf("\n第%d个顶点为: ",i+1);
scanf("%c",&G.vexs[i]);
getchar();//吸收回车符
}
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=INFINITY;
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("\n第%d条边:\n",k+1);
printf("第一个顶点:");scanf("%c",&v1);getchar();
printf("第二个顶点:");scanf("%c",&v2);getchar();
printf("对应的权值:");scanf("%d",&w);getchar();
i=LocateVex(G,v1);
j=LocateVex(G,v2);//确定v1和v2在G中的位置
G.arcs[i][j].adj=w;//将有关系标记为w
}
G.flag=1;//标志变量赋值为1
return OK;
}
//创建无向图的函数
Status CreateAG(MGraph &G)
{
int i,j,k;//循环变量
char v1,v2;//存储输入的顶点的字符
//采用邻接矩阵表示,构造无向图 G
printf("\n无向图的顶点数:");
scanf("%d",&G.vexnum);
printf("\n无向图的边数:");
scanf("%d",&G.arcnum);
getchar();//吸收字符
for(i=0;i<G.vexnum;i++)
{
printf("\n第%d个顶点为: ",i+1);
scanf("%c",&G.vexs[i]);
getchar();//吸收回车符
}
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=0;
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("\n第%d条边:\n",k+1);
printf("第一个顶点:");scanf("%c",&v1);getchar();
printf("第二个顶点:");scanf("%c",&v2);getchar();
i=LocateVex(G,v1);
j=LocateVex(G,v2);//确定v1和v2在G中的位置
G.arcs[i][j].adj=1;//将有关系标记为1
G.arcs[j][i].adj=G.arcs[i][j].adj;//无向图的对称顶点
}
G.flag=1;//标志变量赋值为1
return OK;
}
//创建无向网的函数
Status CreateAN(MGraph &G)
{
int i,j,k,w;//循环变量
char v1,v2;//存储输入的顶点的字符
//采用邻接矩阵表示,构造无向网 G
printf("\n无向网的顶点数:");
scanf("%d",&G.vexnum);
printf("\n无向网的边数:");
scanf("%d",&G.arcnum);
getchar();//吸收字符
for(i=0;i<G.vexnum;i++)
{
printf("\n第%d个顶点为: ",i+1);
scanf("%c",&G.vexs[i]);
getchar();//吸收回车符
}
for(i=0;i<G.vexnum;++i)//初始化邻接矩阵
for(j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=INFINITY;
for(k=0;k<G.arcnum;++k)//构造邻接矩阵
{
printf("\n第%d条边:\n",k+1);
printf("第一个顶点:");scanf("%c",&v1);getchar();
printf("第二个顶点:");scanf("%c",&v2);getchar();
printf("对应的权值:");scanf("%d",&w);getchar();
i=LocateVex(G,v1);
j=LocateVex(G,v2);//确定v1和v2在G中的位置
G.arcs[i][j].adj=w;//将有关系标记为w
G.arcs[j][i].adj=G.arcs[i][j].adj;//无向网的对称顶点
}
G.flag=1;//标志变量赋值为1
return OK;
}
//操作有向图的函数
Status UseDG(MGraph &G)
{
int j;//循环变量
int x;//存储用户的操作选项
int i;//存储用户输入的开始的顶点
system("cls");//清屏函数
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("☆ ☆\n");
printf("☆ 有向图的相关操作算法 ☆\n");
printf("☆ ☆\n");
printf("☆ <1> 有向图的构建 <2> 有向图的深度遍历(递归) ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 有向图的广度遍历 <4> 顶点向量 ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 邻接矩阵 ☆\n");
printf("☆ ☆\n");
printf("☆ ☆\n");
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
while(x!=88)
{
switch(x)
{
case 1:
if(CreateDG(G)!=ERROR)
printf("\n有向图构建成功!\n");
break;
case 2:
for(j=0;j<G.vexnum;j++)//标志数组的初始化
visited[j]=false;
printf("\n请输入你要开始深度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(DFSM(G,i-1)==ERROR)
printf("\n该有向图不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
DFSM(G,j);
printf("\n");
break;
case 3:
for(j=0;j<G.vexnum;j++)//标志数组的初始化
visited[j]=false;
printf("\n请输入你要开始广度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(BFS(G,i-1)==ERROR)
printf("\n该有向图不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
BFS(G,j);
printf("\n");
break;
case 4:
if(Out_Vexs(G)==ERROR)
printf("\n该有向图不存在,操作失败!\n");
break;
case 5:
if(Out_arcs(G)==ERROR)
printf("\n该有向图不存在,操作失败!\n");
break;
default:
printf("\n你的操作有误,请重新输入。\n");
UseDG(G);//调用此函数
}
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
}
return OK;
}
//操作有向网的函数
Status UseDN(MGraph &G)
{
int j;//循环变量
int x;//存储用户的操作选项
int i;//存储用户输入的开始的顶点
system("cls");//清屏函数
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("☆ ☆\n");
printf("☆ 有向网的相关操作算法 ☆\n");
printf("☆ ☆\n");
printf("☆ <1> 有向网的构建 <2> 有向网的深度遍历(递归) ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 有向网的广度遍历 <4> 顶点向量 ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 邻接矩阵 ☆\n");
printf("☆ ☆\n");
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
while(x!=88)
{
switch(x)
{
case 1:
if(CreateDN(G)!=ERROR)
printf("\n有向网构建成功!\n");
break;
case 2:
printf("\n请输入你要开始深度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(DFSM(G,i-1)==ERROR)
printf("\n该有向图不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
DFSM(G,j);
printf("\n");
break;
case 3:
for(j=0;j<G.vexnum;j++)//标志数组的初始化
visited[j]=false;
printf("\n请输入你要开始广度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(BFS(G,i-1)==ERROR)
printf("\n该有向网不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
BFS(G,j);
printf("\n");
break;
case 4:
if(Out_Vexs(G)==ERROR)
printf("\n该有向网不存在,操作失败!\n");
break;
case 5:
if(Out_arcs(G)==ERROR)
printf("\n该有向网不存在,操作失败!\n");
break;
default:
printf("\n你的操作有误,请重新输入。\n");
UseDN(G);//调用此函数
}
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
}
return OK;
}
//操作无向图的函数
Status UseAG(MGraph &G)
{
int j;//循环变量
int x;//存储用户的操作选项
int i;//存储用户输入的开始的顶点
system("cls");//清屏函数
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("☆ ☆\n");
printf("☆ 无向图的相关操作算法 ☆\n");
printf("☆ ☆\n");
printf("☆ <1> 无向图的构建 <2> 无向图的深度遍历(递归) ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 无向图的广度遍历 <4> 顶点向量 ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 邻接矩阵 ☆\n");
printf("☆ ☆\n");
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
while(x!=88)
{
switch(x)
{
case 1:
if(CreateAG(G)!=ERROR)
printf("\n无向图构建成功!\n");
break;
case 2:
for(j=0;j<G.vexnum;j++)//标志数组的初始化
visited[j]=false;
printf("\n请输入你要开始深度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(DFSM(G,i-1)==ERROR)
printf("\n该无向图不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
DFSM(G,j);
printf("\n");
break;
case 3:
for(j=0;j<G.vexnum;j++)//标志数组的初始化
visited[j]=false;
printf("\n请输入你要开始广度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(BFS(G,i-1)==ERROR)
printf("\n该无向图不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
BFS(G,j);
printf("\n");
break;
case 4:
if(Out_Vexs(G)==ERROR)
printf("\n该无向图不存在,操作失败!\n");
break;
case 5:
if(Out_arcs(G)==ERROR)
printf("\n该无向图不存在,操作失败!\n");
break;
default:
printf("\n你的操作有误,请重新输入。\n");
UseAG(G);//调用此函数
}
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
}
return OK;
}
//操作无向网的函数
Status UseAN(MGraph &G)
{
int j;//循环变量
int x;//存储用户的操作选项
int i;//存储用户输入的开始的顶点
system("cls");//清屏函数
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("☆ ☆\n");
printf("☆ 无向网的相关操作算法 ☆\n");
printf("☆ ☆\n");
printf("☆ <1> 无向网的构建 <2> 无向网的深度遍历(递归) ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 无向网的广度遍历 <4> 顶点向量 ☆\n");
printf("☆ ☆\n");
printf("☆ <3> 邻接矩阵 ☆\n");
printf("☆ ☆\n");
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n");
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
while(x!=88)
{
switch(x)
{
case 1:
if(CreateAN(G)!=ERROR)
printf("\n无向网构建成功!\n");
break;
case 2:
printf("\n请输入你要开始深度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(DFSM(G,i-1)==ERROR)
printf("\n该无向网不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
DFSM(G,j);
printf("\n");
break;
case 3:
for(j=0;j<G.vexnum;j++)//标志数组的初始化
visited[j]=false;
printf("\n请输入你要开始广度遍历的顶点在顶点向量中的位置:");
scanf("%d",&i);
if(BFS(G,i-1)==ERROR)
printf("\n该无向网不存在,操作失败!\n");
for(j=0;j<G.vexnum;j++)
if(visited[j]==false)
BFS(G,j);
printf("\n");
break;
case 4:
if(Out_Vexs(G)==ERROR)
printf("\n该无向网不存在,操作失败!\n");
break;
case 5:
if(Out_arcs(G)==ERROR)
printf("\n该无向网不存在,操作失败!\n");
break;
default:
printf("\n你的操作有误,请重新输入。\n");
UseAN(G);//调用此函数
}
printf("\n请输入你要进行操作的序号:");
scanf("%d",&x);
}
return OK;
}
//选择构图函数
Status CreateGraph(MGraph &G)
{
//采用数据(邻接矩阵)表示法,构造图G
printf("请输入你要构建的图的标号:");
scanf("%d",&G.kind);
switch(G.kind)
{
case 0:return UseDG(G);//构造有向图 G
case 1:return UseDN(G);//构造有向网 G
case 2:return UseAG(G);//构造无向图 G
case 3:return UseAN(G);//构造无向网 G
default:printf("您的输入有误,请重新输入。");CreateGraph(G);
}
return OK;
}
//主菜单函数
Status OperateMenu()
{
system("color fc");
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n\n");
Sleep(300);
system("color f1");
printf("☆ 图的相关操作算法 ☆\n\n");
Sleep(300);
system("color f5");
printf("☆ <0> 有向图的构建(DG) <1> 有向网的构建(DN) ☆\n\n");
Sleep(300);
system("color f6");
printf("☆ <2> 无向图的构建(AG) <3> 无向网的构建(AN) ☆\n\n");
Sleep(300);
system("color fc");
printf("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆\n\n");
return OK;
}
int main()
{
MGraph G;//定义图
HWND hwnd=GetForegroundWindow();//移动输出框的位置以及改变输出框的大小
MoveWindow(hwnd,100,100,800,400,1);
OperateMenu();//调用菜单函数
CreateGraph(G);//调用选择图的函数
return 0;
}