图(邻接表)

# include <stdio.h>
# include <stdlib.h>
# include <string.h>

# define VERTEXMAXNUM 10 //最大数值
# define WEIGHTMAXNUM 10 //权值最大数值
# define GraphKind_NUM 5 //图的类型数量
# define GraphKindName_NUM 3 //图的类型名称长度

typedef char VertexType; //顶点类型
typedef enum{DG,UDG,DN,UDN} GraphKind;//图的类型
typedef char AllGraphKind[GraphKind_NUM];//将图的类型以字符串形式输出
typedef char AllGraphKindName[GraphKindName_NUM];//将图的类型名称以字符串形式输入
typedef int Weight;//权值

//弧/边
typedef struct ArcNode *Arc;
struct ArcNode
{
    int index;//记录邻接点在顶点数组中的下标
    Arc nextarc;//指向下一条弧/边的指针
    Weight weight;//图中边的权值
};

//顶点
typedef struct VertexNode
{
    VertexType data;//顶点用A~Z表示
    Arc firstarc;//顶点的第一条边(头插法)
    int cnt;//作为边/弧的第一个顶点出现的次数
}Vertex;

//图_邻接表
typedef struct GNode *Graph;
struct GNode
{
    int vexnum;//顶点数量
    int arcnum;//弧/边的数量
    Vertex vexs[VERTEXMAXNUM];//顶点数组      
    int len_thisvexs;//当前顶点数组的长度
    GraphKind kind;//图的类型
};

/*输入图的类型*/
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 < 0)
            {
                flag = false;
                   printf("输入的弧数量<0,请重新输入:\n");
            }
            else
            {
                flag = false;
                   printf("输入的弧数量>最大数值,请重新输入:\n");
            }
        }
        else
        {
            if(inputArcNum >= 0 && inputArcNum <= graph->vexnum*(graph->vexnum - 1)/2)
                graph->arcnum = inputArcNum;
            else if(inputArcNum < 0)
            {
                flag = false;
                printf("输入的边数量<0,请重新输入:\n");
            }
            else
            {
                flag = false;
                printf("输入的边数量>最大数值,请重新输入:\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].firstarc = NULL;//每个顶点指向第一条边的指针
        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;
    }
}

/*输出图*/
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 == DN || graph->kind == DG)
        printf("该图有%d个弧\n",graph->arcnum);
    else
        printf("该图有%d个边\n",graph->arcnum);
    
    /*输出图的顶点*/
    for(int i=0;i<graph->vexnum;i++)
        printf("第%d个顶点:%c\n",i+1,graph->vexs[i].data);
    
    /*输出图的当前顶点数量*/
    printf("该图当前有%d个顶点\n",graph->len_thisvexs);
    
    /*输出图的权值*/
    if(graph->kind == DN || graph->kind == UDN)
    {
        for(int i=0;i<graph->arcnum;i++)
        {
            Arc arcTemp = graph->vexs[i].firstarc;
            while(arcTemp)
            {
                if(graph->kind == DN)
                    printf("%c -> %c的权值:%d\n",
                    graph->vexs[i].data,graph->vexs[arcTemp->index].data,arcTemp->weight);
                else
                    printf("%c - %c的权值:%d\n",
                    graph->vexs[i].data,graph->vexs[arcTemp->index].data,arcTemp->weight);
                    
                arcTemp = arcTemp->nextarc;
            }
        }
    }
    
    /*展示图的邻接表结构*/
    printf("该图的邻接表结构是:\n");
    for(int i=0;i<graph->vexnum;i++)
    {
        printf("%c ",graph->vexs[i].data);//展示图中每个顶点
        
        Arc arcTemp = graph->vexs[i].firstarc;//创建一个中间容器存放边/弧
        while(arcTemp)
        {
            printf("-> ");
            printf("%c ",graph->vexs[arcTemp->index].data);
            arcTemp = arcTemp->nextarc;
        }
        
        printf("\n");//每个顶点隔开
    }
}

/*查询顶点在图中的位置(即顶点数组的下标)*/
int Index_Graph(VertexType vex,Graph graph)
{
    int index = -1;
    for(int i=0;i<graph->vexnum;i++)
    {
        if(vex == graph->vexs[i].data)
            index = i;
    }
    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;
    
    Arc arcTemp = graph->vexs[V1_Index].firstarc;//中间容器存放每个顶点的每一条边
    while(arcTemp)
    {
        if(arcTemp->index == V2_Index)
        {
            flag = true;
            if(graph->kind == DG || graph->kind == DN)
                printf("输入的弧已存在,请重新输入:\n");
            else
                printf("输入的边已存在,请重新输入:\n");
            break;
        }
        
        arcTemp = arcTemp->nextarc;
    }
     
    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;
            }                                            
        }
                
        /*创建V1 -> V2的弧结点*/
        Arc V1_arc_V2 = (Arc)malloc(sizeof(ArcNode));
        V1_arc_V2->index = V2_Index;
        V1_arc_V2->nextarc = graph->vexs[V1_Index].firstarc;
        V1_arc_V2->weight = -1;
        graph->vexs[V1_Index].firstarc = V1_arc_V2;        
    }
}

/*构造无向图*/
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,V1_Index))
            {
                if(!Check_InputArcIsRecurring(graph,V1_Index,V2_Index))
                    break;
            }
        }
                  
        /*创建V1~V2的边*/
        Arc V1_arc_V2 = (Arc)malloc(sizeof(ArcNode));
        V1_arc_V2->index = V2_Index;
        V1_arc_V2->nextarc = graph->vexs[V1_Index].firstarc;
        V1_arc_V2->weight = -1;
        graph->vexs[V1_Index].firstarc = V1_arc_V2;    
                    
        /*创建V2~V1的边*/
        Arc V2_arc_V1 = (Arc)malloc(sizeof(ArcNode));
        V2_arc_V1->index = V1_Index;
        V2_arc_V1->nextarc = graph->vexs[V2_Index].firstarc;
        V2_arc_V1->weight = -1;
        graph->vexs[V2_Index].firstarc = V2_arc_V1;   
    }
}

/*输入权值*/
bool Input_Weight(Arc arc,Weight weight)
{
    bool flag = true;
    
    if(weight >= 0 && weight <= WEIGHTMAXNUM)
        arc->weight = weight;    
    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;
            }
        }
        
        /*创建V1 -> V2的弧结点*/
        Arc V1_arc_V2 = (Arc)malloc(sizeof(ArcNode));
        while(true)//输入权值
        {
            printf("请输入第%d条弧的权值:",i+1);
            fflush(stdin);//去除回车干扰
            int ret = scanf("%d",&weight);
            if(ret && getchar()=='\n')
            {
                if(Input_Weight(V1_arc_V2,weight))
                    break;
            }
            else
                printf("无效数值,请重新输入:\n");
        }
        V1_arc_V2->index = V2_Index;
        V1_arc_V2->nextarc = graph->vexs[V1_Index].firstarc;
        graph->vexs[V1_Index].firstarc = V1_arc_V2;
    }
}

/*构造无向网*/
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;
            }
        }
        
        /*创建V1~V2的边*/
        Arc V1_arc_V2 = (Arc)malloc(sizeof(ArcNode));
        while(true)//输入权值
        {
            printf("请输入第%d条边的权值:",i+1);
            fflush(stdin); //清除缓存
            int ret = scanf("%d",&weight);
            if(ret && getchar()=='\n')
            {
                if(Input_Weight(V1_arc_V2,weight))
                    break;
            }
            else
                printf("无效数值,请重新输入:\n");
        }
        V1_arc_V2->index = V2_Index;
        V1_arc_V2->nextarc = graph->vexs[V1_Index].firstarc;             
        graph->vexs[V1_Index].firstarc = V1_arc_V2;
                    
        /*创建V2~V1的边*/
        Arc V2_arc_V1 = (Arc)malloc(sizeof(ArcNode));
        V2_arc_V1->index = V1_Index;
        V2_arc_V1->nextarc = graph->vexs[V2_Index].firstarc;
        V2_arc_V1->weight = V1_arc_V2->weight;
        graph->vexs[V2_Index].firstarc = V2_arc_V1;
    }
}

/*构造图*/
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;
    }
}

/*创建图/网的逆邻接数组(创建一个新数组)*/
Vertex* Create_InverseVexs(Graph graph)
{
    Vertex *vexs = (Vertex*)malloc(graph->vexnum*(sizeof(Vertex)));
    for(int i=0;i<graph->vexnum;i++)
    {
        vexs[i].data = graph->vexs[i].data;
        vexs[i].cnt = 0;
        vexs[i].firstarc = NULL;
    }
    return vexs;
}

/*创建图/网的逆邻接表*/
Vertex* Create_InverseGraph(Graph graph,Vertex *vexs)
{
    for(int i=0;i<graph->vexnum;i++)
    {
        Arc    arcTemp = graph->vexs[i].firstarc;
        while(arcTemp)
        {
            Arc newArc = (Arc)malloc(sizeof(ArcNode));
            newArc->index = i;
            newArc->nextarc = vexs[arcTemp->index].firstarc;
            vexs[arcTemp->index].firstarc = newArc;
            arcTemp = arcTemp->nextarc;
        }        
    }
    return vexs;
}

/*展示图/网的逆邻接表结构*/
void Show_InverseTable(Vertex *vexs,int len)
{
    printf("该图的逆邻接表结构是:\n");
    for(int i=0;i<len;i++)
    {
        printf("%c",vexs[i].data);
        Arc arcTemp = vexs[i].firstarc;
        while(arcTemp)
        {
            printf("->");
            printf("%c",vexs[arcTemp->index].data);
            arcTemp = arcTemp->nextarc;
        }
        printf("\n");
    }
}

int main ()
{
    Graph graph = (Graph)malloc(sizeof(GNode));
    Init_Graph(graph);
    Create_Graph(graph);
    Show_Graph(graph);
    if(graph->kind == DG || graph->kind == DN)
    {
        int len = graph->vexnum;
        Vertex* vexs = Create_InverseVexs(graph);
        vexs = Create_InverseGraph(graph,vexs);
        Show_InverseTable(vexs,len);
        free(vexs);
    }
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值