# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# define VERTEXMAXNUM 10 //顶点最大数量
# define WEIGHTMAXNUM 10 //权值最大数值
# define GraphKind_Num 5 //图的类型数量
# define GraphKindName_Num 3 //图的类型名称最大长度
typedef enum{DG,UDG,DN,UDN} GraphKind;//图的类型
typedef char AllGraphKind[GraphKind_Num];//将图的类型以字符串形式输出
typedef char AllGraphKindName[GraphKindName_Num];//将图的类型名称以字符串形式输入
typedef char VertexType;//顶点类型
typedef int AdjORWeight;//两点相邻或边/弧的权值
typedef int Weight;//权值
//顶点
typedef struct VertexNode
{
VertexType data;//顶点用A~Z表示
int cnt;//作为边/弧的第一个顶点出现的次数
}Vertex;
//弧/边
typedef struct ArcNode
{
AdjORWeight adjORweight;
}Arc[VERTEXMAXNUM][VERTEXMAXNUM];
//图
typedef struct GNode *Graph;
struct GNode
{
int vexnum;//顶点数量
int arcnum;//边/弧的数量
GraphKind kind;//图的类型
Vertex vexs[VERTEXMAXNUM];//顶点数组
int len_thisvexs;//当前数组长度
Arc arcMatrix;//图的邻接矩阵
};
/*输入图的类型*/
bool Input_GraphKind(Graph graph)
{
bool flag = true;
AllGraphKindName inputGraphKind;//存放输入的图的类型
printf("请输入图的类型:");
scanf("%s",inputGraphKind);
if(!strcmp(inputGraphKind,"DG"))
graph->kind = DG;
else if(!strcmp(inputGraphKind,"UDG"))
graph->kind = UDG;
else if(!strcmp(inputGraphKind,"DN"))
graph->kind = DN;
else if(!strcmp(inputGraphKind,"UDN"))
graph->kind = UDN;
else
{
flag = false;
printf("无效数值,请重新输入:\n");
}
return flag;
}
/*输入顶点数量*/
bool Input_GraphVexNum(Graph graph)
{
bool flag = true;
int inputVexNum;
printf("请输入顶点数量:");
fflush(stdin); //清除缓存
int ret = scanf("%d",&inputVexNum);
if(ret && getchar() == '\n')//防止输入无效字符
{
if(inputVexNum > 0 && inputVexNum <= VERTEXMAXNUM)
graph->vexnum = inputVexNum;
else if(inputVexNum <= 0)
{
flag = false;
printf("顶点数量<=0,请重新输入:\n");
}
else
{
flag = false;
printf("顶点数量>最大数值,请重新输入:\n");
}
}
else
{
flag = false;
printf("无效数值,请重新输入:\n");
}
return flag;
}
/*输入弧/边的数量*/
bool Input_GraphArcNum(Graph graph)
{
bool flag = true;
int inputArcNum;
if(graph->kind == DG || graph->kind == DN)
printf("请输入弧数量:");
else
printf("请输入边数量:");
fflush(stdin); //清除缓存
int ret = scanf("%d",&inputArcNum);
if(ret && getchar() == '\n')//防止输入无效字符
{
if(graph->kind == DG || graph->kind == DN)
{
if(inputArcNum >= 0 && inputArcNum <= graph->vexnum*(graph->vexnum - 1))
graph->arcnum = inputArcNum;
else if(inputArcNum > graph->vexnum*(graph->vexnum - 1))
{
flag = false;
printf("输入的弧数量>最大数值,请重新输入:\n");
}
else
{
flag = false;
printf("输入的弧数量<0,请重新输入:\n");
}
}
else
{
if(inputArcNum >= 0 && inputArcNum <= graph->vexnum*(graph->vexnum - 1)/2)
graph->arcnum = inputArcNum;
else if(inputArcNum > graph->vexnum*(graph->vexnum - 1)/2)
{
flag = false;
printf("输入的边数量>最大数值,请重新输入:\n");
}
else
{
flag = false;
printf("输入的边数量<0,请重新输入:\n");
}
}
}
else
{
flag = false;
printf("无效数值,请重新输入:\n");
}
return flag;
}
/*检查输入的顶点是否重复*/
bool Check_InputVexIsRecurring(Graph graph,VertexType inputVex)
{
bool flag = false;
for(int i=0;i<graph->len_thisvexs;i++)
{
if(inputVex == graph->vexs[i].data)
{
flag = true;
printf("输入的顶点已存在,请重新输入:\n");
break;
}
}
return flag;
}
/*输入顶点*/
bool Input_GraphVex(Graph graph)
{
graph->len_thisvexs = 0;
bool flag = true;
VertexType inputVex;
for(int i=0;i<graph->vexnum;i++)
{
while(true)
{
printf("请输入第%d个顶点:",(i+1));
fflush(stdin); //清除缓存
scanf("%c",&inputVex);
if(!Check_InputVexIsRecurring(graph,inputVex))
break;
}
graph->vexs[i].data = inputVex;
graph->vexs[i].cnt = 0;
graph->len_thisvexs++;
}
return flag;
}
/*图的初始化*/
void Init_Graph(Graph graph)
{
/*输入图的类型*/
while(true)
{
if(Input_GraphKind(graph))
break;
}
/*输入顶点数量*/
while(true)
{
if(Input_GraphVexNum(graph))
break;
}
/*输入边/弧数量*/
while(true)
{
if(Input_GraphArcNum(graph))
break;
}
/*输入顶点*/
while(true)
{
if(Input_GraphVex(graph))
break;
}
/*初始化邻接矩阵*/
for(int i=0;i<graph->vexnum;i++)
{
for(int j=0;j<graph->vexnum;j++)
graph->arcMatrix[i][j].adjORweight = -1;
}
}
/*输出图*/
void Show_Graph(Graph graph)
{
printf("\n");//与输入的数据隔开
/*输出图的类型*/
AllGraphKind thisGraphKind[GraphKind_Num] = {"DG","UDG","DN","UDN"};
printf("该图的类型是:%s\n",thisGraphKind[graph->kind]);
/*输出图的顶点数量*/
printf("该图的顶点数量:%d\n",graph->vexnum);
/*输出图的边/弧数量*/
if(graph->kind == DG || graph->kind == DN)
printf("该图的弧数量:%d\n",graph->arcnum);
else
printf("该图的边数量:%d\n",graph->arcnum);
/*展示图的邻接矩阵*/
printf("该图的邻接矩阵:\n");
for(int i=0;i<=graph->vexnum;i++)
{
for(int j=0;j<=graph->vexnum;j++)
{
if(i==0 && j==0)
printf(" ");
else if(i==0 && j!=0)
printf("%c ",graph->vexs[j-1]);
else if(i!=0 && j!=0)
{
if(graph->arcMatrix[i-1][j-1].adjORweight == -1)
printf("%d ",graph->arcMatrix[i-1][j-1]);
else
printf(" %d ",graph->arcMatrix[i-1][j-1]);
}
else if(i!=0 && j==0)
printf("%c ",graph->vexs[i-1]);
}
printf("\n");
}
}
/*查询顶点在图中的位置(即数组下标)*/
int Index_Graph(VertexType vex,Graph graph)
{
int index = -1;
for(int i=0;i<graph->vexnum;i++)
{
if(graph->vexs[i].data == vex)
{
index = i;
break;
}
}
return index;
}
/*创建弧/边时,检查输入的两个顶点是否在图中(即顶点数组中)*/
bool Check_InputVexBelongsToGraph(Graph graph,int index)
{
bool flag = true;
if(index == -1)
{
flag = false;
printf("输入的顶点不在图中,请重新输入:\n");
}
return flag;
}
/*检查输入的边/弧的第一个顶点是否重复超出规定次数*/
bool Check_InputFirstVexOfArcIsRecurring(Graph graph,int V1_Index)
{
bool flag = false;
graph->vexs[V1_Index].cnt++;
if(graph->vexs[V1_Index].cnt >= graph->vexnum)
{
flag = true;
printf("输入的顶点已重复,请重新输入:\n");
}
return flag;
}
/*检查输入的边/弧是否重复*/
bool Check_InputArcIsRecurring(Graph graph,int V1_Index,int V2_Index)
{
bool flag = false;
if(graph->arcMatrix[V1_Index][V2_Index].adjORweight > -1)
{
flag = true;
if(graph->kind == DG || graph->kind == DN)
printf("输入的弧已存在,请重新输入:\n");
else
printf("输入的边已存在,请重新输入:\n");
}
return flag;
}
/*构造有向图*/
void Create_DG(Graph graph)
{
VertexType V1,V2;//一条弧/边需要两个顶点 V1:弧头 V2:弧尾
int V1_Index,V2_Index;//两个顶点的位置
for(int i=0;i<graph->arcnum;i++)
{
while(true)
{
printf("请输入第%d条弧的第1个顶点V1:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V1);
/*查询V1的位置*/
V1_Index = Index_Graph(V1,graph);
if(Check_InputVexBelongsToGraph(graph,V1_Index))
{
if(!Check_InputFirstVexOfArcIsRecurring(graph,V1_Index))
break;
}
}
while(true)
{
printf("请输入第%d条弧的第2个顶点V2:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V2);
/*查询V2的位置*/
V2_Index = Index_Graph(V2,graph);
if(Check_InputVexBelongsToGraph(graph,V2_Index))
{
if(!Check_InputArcIsRecurring(graph,V1_Index,V2_Index))
break;
}
}
graph->arcMatrix[V1_Index][V2_Index].adjORweight = 1;
}
}
/*构造无向图*/
void Create_UDG(Graph graph)
{
VertexType V1,V2;//一条弧/边需要两个顶点 V1:弧头 V2:弧尾
int V1_Index,V2_Index;//两个顶点的位置
for(int i=0;i<graph->arcnum;i++)
{
while(true)
{
printf("请输入第%d条弧的第1个顶点V1:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V1);
/*查询V1的位置*/
V1_Index = Index_Graph(V1,graph);
if(Check_InputVexBelongsToGraph(graph,V1_Index))
{
if(!Check_InputFirstVexOfArcIsRecurring(graph,V1_Index))
break;
}
}
while(true)
{
printf("请输入第%d条弧的第2个顶点V2:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V2);
/*查询V2的位置*/
V2_Index = Index_Graph(V2,graph);
if(Check_InputVexBelongsToGraph(graph,V2_Index))
{
if(!Check_InputArcIsRecurring(graph,V1_Index,V2_Index))
break;
}
}
graph->arcMatrix[V1_Index][V2_Index].adjORweight = 1;
graph->arcMatrix[V2_Index][V1_Index].adjORweight = 1;
}
}
/*输入权值*/
bool Input_Weight(Weight weight)
{
bool flag;
if(weight >= 0 && weight <= WEIGHTMAXNUM)
flag = true;
else if(weight < 0)
{
flag = false;
printf("输入的权值<0,请重新输入:\n");
}
else
{
flag = false;
printf("输入的权值>最大数值,请重新输入:\n");
}
return flag;
}
/*构造有向网*/
void Create_DN(Graph graph)
{
VertexType V1,V2;//一条弧/边需要两个顶点 V1:弧头 V2:弧尾
int V1_Index,V2_Index;//两个顶点的位置
Weight weight;
for(int i=0;i<graph->arcnum;i++)
{
while(true)
{
printf("请输入第%d条弧的第1个顶点V1:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V1);
/*查询V1的位置*/
V1_Index = Index_Graph(V1,graph);
if(Check_InputVexBelongsToGraph(graph,V1_Index))
{
if(!Check_InputFirstVexOfArcIsRecurring(graph,V1_Index))
break;
}
}
while(true)
{
printf("请输入第%d条弧的第2个顶点V2:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V2);
/*查询V2的位置*/
V2_Index = Index_Graph(V2,graph);
if(Check_InputVexBelongsToGraph(graph,V2_Index))
{
if(!Check_InputArcIsRecurring(graph,V1_Index,V2_Index))
break;
}
}
while(true)
{
printf("请输入第%d条弧的权值:",i+1);
fflush(stdin); //清除缓存
int ret = scanf("%d",&weight);
if(ret && getchar()=='\n')
{
if(Input_Weight(weight))
{
graph->arcMatrix[V1_Index][V2_Index].adjORweight = weight;
break;
}
}
else
printf("无效数值,请重新输入:\n");
}
}
}
/*构造无向网*/
void Create_UDN(Graph graph)
{
VertexType V1,V2;//一条弧/边需要两个顶点 V1:弧头 V2:弧尾
int V1_Index,V2_Index;//两个顶点的位置
Weight weight;
for(int i=0;i<graph->arcnum;i++)
{
while(true)
{
printf("请输入第%d条弧的第1个顶点V1:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V1);
/*查询V1的位置*/
V1_Index = Index_Graph(V1,graph);
if(Check_InputVexBelongsToGraph(graph,V1_Index))
{
if(!Check_InputFirstVexOfArcIsRecurring(graph,V1_Index))
break;
}
}
while(true)
{
printf("请输入第%d条弧的第2个顶点V2:",i+1);
fflush(stdin); //清除缓存
scanf("%c",&V2);
/*查询V2的位置*/
V2_Index = Index_Graph(V2,graph);
if(Check_InputVexBelongsToGraph(graph,V2_Index))
{
if(!Check_InputArcIsRecurring(graph,V1_Index,V2_Index))
break;
}
}
while(true)
{
printf("请输入第%d条弧的权值:",i+1);
fflush(stdin); //清除缓存
int ret = scanf("%d",&weight);
if(ret && getchar()=='\n')
{
if(Input_Weight(weight))
{
graph->arcMatrix[V1_Index][V2_Index].adjORweight = weight;
graph->arcMatrix[V2_Index][V1_Index].adjORweight = weight;
break;
}
}
else
printf("无效数值,请重新输入:\n");
}
}
}
/*构造图*/
void Create_Graph(Graph graph)
{
/*根据图的类型构造图*/
switch(graph->kind)
{
case DG:Create_DG(graph);
break;
case UDG:Create_UDG(graph);
break;
case DN:Create_DN(graph);
break;
case UDN:Create_UDN(graph);
break;
}
}
int main ()
{
Graph graph = (Graph)malloc(sizeof(GNode));
Init_Graph(graph);
Create_Graph(graph);
Show_Graph(graph);
return 0;
}