站内搜索

无向图转换&遍历&MST

原帖地址:http://bbs.bccn.net/thread-129767-1-1.html

请不吝赐教,多多指点...多谢了!
//"有向图"参见http://bbs.bccn.net/thread-130955-1-1.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define MaxSize 250
#define MaxLine 20
typedef int Status;
typedef int ElemType;
typedef struct{
    ElemType VNode;
    }VexType;
typedef struct Arcs{
    ElemType Adj;
    unsigned int Weight;
    struct Arcs *NextArc;
    }ArcType;
typedef struct{
    VexType Vex[MaxSize];
    ArcType *FirstArc[MaxSize];
    int VexNums;
    }ALGraph;    //定义图的无向邻接表;
typedef struct{
    VexType Vex[MaxSize];
    unsigned int Weight[MaxSize][MaxSize];
    int VexNums;
    }AMGraph;    //定义图的邻接矩阵;
typedef struct{
    ElemType head,tail;
    unsigned int Weight;
    }MST;        //最小生成树辅助结构;
//=================================================================================
Status CreateALGraph(ALGraph *ALG,FILE *fp);        //创立无向图的邻接表;
Status AL2AM(ALGraph ALG,AMGraph *AMG);            //转换为图的邻接矩阵;
Status ALG_Travers(ALGraph ALG);                //图的遍历;
Status ALG_DFS(ALGraph ALG,int v,int *Visited);            //深度遍历(递  归);
Status ALG_DFS_Uni(ALGraph ALG,int v,int *Visited);        //深度遍历(非递归);
Status ALG_BFS(ALGraph ALG,int v,int *Visited);            //广度遍历;
Status CreateMST(ALGraph ALG,AMGraph AMG);        //构造最小生成树;
Status AMG_Prim(AMGraph AMG,MST *MST_P);         //(邻接矩阵)Prim;
Status ALG_Prim(ALGraph ALG,MST *MST_P);         //(邻 接 表)Prim;
Status ALG_Kruskal(ALGraph ALG,MST *MST_K);        //(邻 接 表)Kruskal;
Status AMG_Kruskal(AMGraph AMG,MST *MST_K);        //(邻接矩阵)Kruskal;
Status FindVex(int *Vex,int v);    //(Kruskal)查找顶点所在树的根结点在数组Vex中的序号;
Status Prn_ALGraph(ALGraph ALG);            //输出邻接表;
Status Prn_AMGraph(AMGraph AMG);            //输出邻接矩阵;
Status PrintMST(MST *MT);                //输出最小生成树;
//=================================================================================
int main(void)
{
    ALGraph ALG;
    AMGraph AMG;
    FILE *fp;
    char FileName[MaxLine];
    printf("/t/t<<<<<<  无向图的应用演示  >>>>>>/n创立无向图:/n");
    printf("==============================================================/n");
    printf("  包含图信息的文本文件的格式为:/n第一行:  12/t<--- 顶点总数;/n");
    printf("第二行:   1  6  16/n");
    printf("/t   ↑ ↑ ↑/n");    
    printf("/t   │ │ └───  AB边的权值Weight;/n");
    printf("/t   │ └────   A边所依附的另一顶点B;/n");
    printf("/t   └──────  某顶点A。/n第m行 :以后各行与第二行类似。/n");
    printf("==============================================================/n");
    printf("输入文本文件名(输入quit退出)。/n");
    do{
        printf("    输入文件名:");
        gets(FileName);
        if(!strcmp(FileName,"quit"))    exit (1);
    }while(FileName[0] == '/0' || !(fp = fopen(FileName,"r")));

    printf("/n/n 一、创立无向图的邻接表(Adjacency List):/n");    
    CreateALGraph(&ALG,fp);
    fclose(fp);
    Prn_ALGraph(ALG);
    printf("/n/n 二、邻接表的图的遍历(Traversing graph):/n");    
    ALG_Travers(ALG);
     printf("/n/n 三、图的邻接表转换为邻接矩阵(Adjacency Matrix):/n");    
    AL2AM(ALG,&AMG);
    Prn_AMGraph(AMG);
     printf("/n/n 四、构建最小生成树MST(mininum cost spaning tree):/n");    
    CreateMST(ALG,AMG);
    printf("/n");system("pause");
    return 0;
}

Status CreateALGraph(ALGraph *ALG,FILE *fp)//创立无向图的邻接表;
{
    ArcType *p = NULL;
    int i,j,w;
    
    fscanf(fp,"%d",&ALG->VexNums);
    for(i = 1;i <= ALG->VexNums;i++)    //初始化;
    {
        ALG->Vex[i].VNode = i;
        ALG->FirstArc[i] = NULL;
    }
    while(fscanf(fp,"%d%d%d",&i,&j,&w) == 3)
    {
        if(!(p = (ArcType *)malloc(sizeof(ArcType))))
            {printf("/n内存溢出。");return 1;}
        p->Adj = j;
        p->Weight = w;
        p->NextArc = ALG->FirstArc[i];
        ALG->FirstArc[i] = p;                            
        if(!(p = (ArcType *)malloc(sizeof(ArcType))))
            {printf("/n内存溢出。");return 1;}
        p->Adj = i;        //无向邻接表,反向赋值...:-(
        p->Weight = w;
        p->NextArc = ALG->FirstArc[j];
        ALG->FirstArc[j] = p;
    }
    return 0;
}
//=================================================================================
Status AL2AM(ALGraph ALG,AMGraph *AMG)    //转换为图的邻接矩阵;
{
    int i,j;
    ArcType *p = NULL;
    AMG->VexNums = ALG.VexNums;
    for(i = 1;i <= AMG->VexNums;i++)        //初始化;
        for(j = 1;j <= AMG->VexNums;j++)
            AMG->Weight[i][j] = INT_MAX;
    for(i = 1;i <= ALG.VexNums;i++)
    {
        AMG->Vex[i] = ALG.Vex[i];
        p = ALG.FirstArc[i];
        while(p != NULL)
        {
            AMG->Weight[i][p->Adj] = p->Weight;
            p = p->NextArc;
        }
    }
    return 0;
}
//=================================================================================
Status ALG_Travers(ALGraph ALG)            //图的遍历;
{
    int i,Visited[MaxSize];
    printf("/n  1. 图的深度遍历:");    
    printf("/n递  归:");
    for(i = 1;i <= ALG.VexNums;i++)        Visited[i] = 0;
    for(i = 1;i <= ALG.VexNums;i++)
        if(Visited[i] == 0)        ALG_DFS(ALG,i,Visited);
    printf("/n非递归:");
    for(i = 1;i <= ALG.VexNums;i++)        Visited[i] = 0;
    for(i = 1;i <= ALG.VexNums;i++)
        if(Visited[i] == 0)        ALG_DFS_Uni(ALG,i,Visited);
    printf("/n/n  2. 图的广度遍历:/n/t");    
    for(i = 1;i <= ALG.VexNums;i++)        Visited[i] = 0;
    for(i = 1;i <= ALG.VexNums;i++)
        if(Visited[i] == 0)        ALG_BFS(ALG,i,Visited);
    return 0;
}
//=================================================================================
Status ALG_DFS(ALGraph ALG,int v,int *Visited)    //图的深度遍历(递  归);
{
    ArcType *p = NULL;
    Visited[v] = 1;
    printf("%2d ->",v);
    p = ALG.FirstArc[v];
    while(p != NULL)
    {
        if(Visited[p->Adj] == 0)    ALG_DFS(ALG,p->Adj,Visited);
        p = p->NextArc;
    }
    return 0;
}
//=================================================================================
Status ALG_DFS_Uni(ALGraph ALG,int v,int *Visited)//图的深度遍历(非递归);
{
    ElemType Stack[MaxSize];
    ArcType *p = NULL;
    int top = -1;
    Visited[v] = 1;
    printf("%2d ->",v);
    Stack[++top] = v;
    while(top != -1)
    {
        p = ALG.FirstArc[Stack[top]];
        while(p != NULL)
        {
            if(Visited[p->Adj] == 0)
            {
                Visited[p->Adj] = 1;
                printf("%2d ->",p->Adj);
                Stack[++top] = p->Adj;
                break;
            }
            p = p->NextArc;
        }
        if(p == NULL)    --top;
    }
    return 0;
}
//=================================================================================
Status ALG_BFS(ALGraph ALG,int v,int *Visited)    //图的广度遍历;
{
    int rear,front;
    ElemType Queue[MaxSize];
    ArcType *p = NULL;
    rear = front = 0;
    Visited[v] = 1;
    printf("%2d ->",v);
    rear =(rear + 1)%MaxSize;
    Queue[rear] = v;
    while(rear != front)
    {
        front = (front + 1)%MaxSize;
        p = ALG.FirstArc[Queue[front]];
        while(p != NULL)
        {
            if(Visited[p->Adj] == 0)
            {
                Visited[p->Adj] = 1;
                printf("%2d ->",p->Adj);
                rear =(rear + 1)%MaxSize;
                Queue[rear] = p->Adj;
            }
            p = p->NextArc;
        }
    }
    return 0;
}
//=================================================================================
Status CreateMST(ALGraph ALG,AMGraph AMG)//构造最小生成树;
{
    MST MST_MP[MaxSize],MST_LP[MaxSize],MST_MK[MaxSize],MST_LK[MaxSize];  
    printf("/n/n  1. Prim普里姆(图的邻接矩阵):/n");    
    AMG_Prim(AMG,MST_MP);        PrintMST(MST_MP);
    printf("/n/n  2. Kruskal克鲁斯卡尔(图的邻接表):/n");
    ALG_Kruskal(ALG,MST_LK);    PrintMST(MST_LK);
    printf("/n/n  3. Prim普里姆(图的邻接表):/n");    
    ALG_Prim(ALG,MST_LP);    PrintMST(MST_LP);
    printf("/n/n  4. Kruskal克鲁斯卡尔(图的邻接矩阵):/n");
    AMG_Kruskal(AMG,MST_MK);        PrintMST(MST_MK);
    return 0;
}
//=================================================================================
Status AMG_Prim(AMGraph AMG,MST *MST_P) //Prim普里姆(邻接矩阵),适于稠密网;
{
    int i,j,k,Vex[MaxSize];            //最小生成树结点;
    unsigned int min,lowcost[MaxSize];    //(由Vex[i]到i)权值;
    for(i = 2;i <= AMG.VexNums;i++)
    {
        Vex[i] = 1;            //表示V-U中各点与U(当前仅含顶点1)的关系;
        lowcost[i] = AMG.Weight[1][i];    //各点对U的权值(1到各点的权值);
    }
//    Vex[1] = 1;                //从顶点1开始遍历;
    lowcost[1] = 0;                //U中仅包含顶点1;                  
    for(i = 1;i <= AMG.VexNums;i++)
    {
        k = i;
        min = INT_MAX;
        for(j = 1;j <= AMG.VexNums;j++)//得到与当前点i相临且权值最小min的顶点k;
        {
            if(lowcost[j] < min && lowcost[j] != 0)//找(V-U)各点对U中权值最小的;
            {
                min = lowcost[j];
                k = j;
            }
        }
        if(min == INT_MAX)    break;  //若U与V-U再没有边(不连通或V==U),退出循环;
        printf("[%2d,%2d];",Vex[k],k);
        MST_P[i].head = Vex[k];        //将得到的MST各点送入MST_P;
        MST_P[i].tail = k;
        MST_P[i].Weight = lowcost[k];
//        vex[k] = 0;
        lowcost[k] = 0;            //顶点k并入U;

        for(j = 1;j <= AMG.VexNums;j++)    //重新计算U与V-U间各个权值;
        {
            if(AMG.Weight[k][j] < lowcost[j])
            {
                Vex[j] = k;
                lowcost[j] = AMG.Weight[k][j];
            }
        }
    }
    if(i == AMG.VexNums) MST_P[0].Weight = i - 1;    
    else MST_P[0].Weight = 0;//MST结点数如与图中总数不等,则不能生成MST或有误;
    return 0;
}
//=================================================================================
Status ALG_Prim(ALGraph ALG,MST *MST_P) //(图的邻接表)Prim普里姆,适于稠密网;
{
//    struct    {ElemType Vex;    unsigned int lowcost;}closedge[MaxSize];
    int i,j,k,Vex[MaxSize];
    unsigned int min,lowcost[MaxSize];
    ArcType *p = NULL;
    for(i = 1;i <= ALG.VexNums;i++)
    {
        Vex[i] = 1;
        p = ALG.FirstArc[1];    //从[1]开始遍历;
        while(p != NULL)
        {
            if(p->Adj == i)        lowcost[i] = p->Weight;
            p = p->NextArc;
        }
    }
//    Vex[1] = 1;
    lowcost[1] = 0;
    for(i = 1;i <= ALG.VexNums;i++)
    {
        k = i;
        min = INT_MAX;
        for(j = 1;j <= ALG.VexNums;j++)
        {
            if(lowcost[j] < min && lowcost[j] != 0)
            {
                min = lowcost[j];
                k = j;
            }
        }
        if(min == INT_MAX)    break;  //若U与V-U再没有边(不连通或V==U),退出循环;
        printf("[%2d,%2d];",Vex[k],k);
        MST_P[i].head = Vex[k];        //将得到的MST各点送入MST_P;
        MST_P[i].tail = k;
        MST_P[i].Weight = lowcost[k];
//        vex[k] = 0;
        lowcost[k] = 0;            //顶点k并入U;

        for(j = 1;j <= ALG.VexNums;j++)
        {
            p = ALG.FirstArc[k];
            while(p != NULL)
            {
                if(p->Adj == j && p->Weight < lowcost[j])
                {
                    lowcost[j] = p->Weight;
                    Vex[j] = k;
                }
                p = p->NextArc;
            }
        }
    }
    if(i == ALG.VexNums) MST_P[0].Weight = i - 1;    
    else MST_P[0].Weight = 0;//MST结点数如与图中总数不等,则不能生成MST或有误;
    return 0;
}
//=================================================================================
Status FindVex(int *Vex,int v)//(Kruskal)找顶点所在树的根结点在数组Vex中的序号;
{
    int t;
    t = v;
    while(Vex[t] > 0)
        t = Vex[t];
    return t;
}
//=================================================================================
Status AMG_Kruskal(AMGraph AMG,MST *MST_K)//Kruskal(邻接矩阵),适于稀疏网;
{
typedef struct{    ElemType v1,v2;    unsigned int cost;    }EdgeType;
    EdgeType Edgs[MaxSize];
    int i,j,k,vex1,vex2,Vex[MaxSize];
    ElemType tv;
    unsigned int tc;
    k = 1;
    Edgs[0].cost = 0;                //记录总边数到Edgs[0].cost中;
    for(i = 1;i <= AMG.VexNums;i++)  //将所有两点间关系初始化到Edgs中;
    {
        for(j = 1;j < i;j++)
        {
            Edgs[k].v1 = AMG.Vex[j].VNode;    //j变化快,赋予v1(较小的坐标在前);
            Edgs[k].v2 = AMG.Vex[i].VNode;
            Edgs[k].cost = AMG.Weight[i][j];
            if(AMG.Weight[i][j] < INT_MAX)        ++Edgs[0].cost;
            ++k;
        }
    }
    for(i = 1;i < AMG.VexNums*AMG.VexNums;i++)    //Edgs按cost值,非递减排序;
    {
        k = i;
        for(j = i+1;j <= AMG.VexNums*AMG.VexNums;j++)
            if(Edgs[k].cost > Edgs[j].cost)        k = j;
        if(k != i)
        {
            tv = Edgs[i].v1; Edgs[i].v1 = Edgs[k].v1; Edgs[k].v1 = tv;
            tv = Edgs[i].v2; Edgs[i].v2 = Edgs[k].v2; Edgs[k].v2 = tv;
            tc = Edgs[i].cost; Edgs[i].cost = Edgs[k].cost; Edgs[k].cost = tc;
        }
    }

    for(i = 1;i <= AMG.VexNums;i++)    Vex[i] = 0;    //各点初始均独立;
    i = k = 1;
    while(k < AMG.VexNums)
    {
        vex1 = FindVex(Vex,Edgs[i].v1);
        vex2 = FindVex(Vex,Edgs[i].v2);
        if(vex1 != vex2)
        {
            Vex[vex2] = vex1;
            printf("[%2d,%2d];",Edgs[i].v1,Edgs[i].v2);
            MST_K[k].head = Edgs[i].v1;    //将得到的MST各点送入MST_K;
            MST_K[k].tail = Edgs[i].v2;
            MST_K[k].Weight = Edgs[i].cost;
            if(++k >= (int)Edgs[0].cost - 1)    break;
        }
        ++i;
    }
    if(k - 1 == AMG.VexNums - 1)    MST_K[0].Weight = AMG.VexNums - 1;
    else MST_K[0].Weight = 0;
    return 0;
}
//=================================================================================
Status ALG_Kruskal(ALGraph ALG,MST *MST_K)//Kruskal(邻接表),适于稀疏网;
{
typedef struct{ElemType v1,v2;unsigned int cost;}    EdgeType;
    int i,j,k;
    ElemType Vex[MaxSize],v1,v2,tv;
    unsigned int tc;
    ArcType *p = NULL;
    EdgeType Edge[MaxSize];
    
    for(j = 1,i = 1;i <= ALG.VexNums;i++)    //将所有两点间关系初始化到Edgs中;
    {
        Edge[j].v1 = ALG.Vex[i].VNode;
        p = ALG.FirstArc[i];
        while(p != NULL)
        {
            Edge[j].v2 = p->Adj;
            Edge[j].cost = p->Weight;
            p = p->NextArc;
            Edge[j].v1 = ALG.Vex[i].VNode;
            if(Edge[j].v1 < Edge[j].v2)    ++j;
        }
    }
    if(Edge[j].v1 > Edge[j].v2)    Edge[0].cost = j - 1;
    else Edge[0].cost = j;            //记录总边数到Edgs[0].cost中;
    
    for(i = 1;i < (int)Edge[0].cost;i++)      //Edgs按cost值,非递减排序;
    {
        k = i;
        for(j = i + 1;j <= (int)Edge[0].cost;j++)
            if(Edge[k].cost > Edge[j].cost)        k = j;
        if(k != i)
        {
            tv = Edge[i].v1; Edge[i].v1 = Edge[k].v1; Edge[k].v1 = tv;
            tv = Edge[i].v2; Edge[i].v2 = Edge[k].v2; Edge[k].v2 = tv;
            tc = Edge[i].cost; Edge[i].cost = Edge[k].cost; Edge[k].cost = tc;
        }
    }
    
    for(i = 1;i <= (int)Edge[0].cost;i++)    Vex[i] = 0;
    for(k = 1,i = 1;i <= (int)Edge[0].cost;i++)
    {
        v1 = FindVex(Vex,Edge[i].v1);
        v2 = FindVex(Vex,Edge[i].v2);
        if(v1 != v2)
        {
            Vex[v2] = v1;
            printf("[%2d,%2d];",Edge[i].v1,Edge[i].v2);
            MST_K[k].head = Edge[i].v1;
            MST_K[k].tail = Edge[i].v2;
            MST_K[k].Weight = Edge[i].cost;
            ++k;
        }
    }
    if(k - 1 == ALG.VexNums - 1)    MST_K[0].Weight = ALG.VexNums - 1;
    else MST_K[0].Weight = 0;
    return 0;
}
//================================================================================
Status Prn_ALGraph(ALGraph ALG)            //输出邻接表;
{
    int i;
    ArcType *p = NULL;
    for(i = 1;i <= ALG.VexNums;i++)
    {
        printf("/n  %2d ==>  ",i);
        p = ALG.FirstArc[i];
        while(p != NULL)
        {
            printf("%2d(%3d) ->",p->Adj,p->Weight);
            p = p->NextArc;
        }
    }
    printf("/n");
    return 0;
}
//=================================================================================
Status Prn_AMGraph(AMGraph AMG)            //输出邻接矩阵;
{
    int i,j;
    for(i = 1;i <= AMG.VexNums;i++)
    {
        printf("/n/t");
        for(j = 1;j <= AMG.VexNums;j++)
        {
            if(AMG.Weight[i][j] < INT_MAX)    printf(" %3d ",AMG.Weight[i][j]);
            else printf("  ∞ ");
        }                                    
        printf("/n");
    }
    return 0;
}
//=================================================================================
Status PrintMST(MST *MT)            //输出最小生成树;
{
    unsigned int i = 1;
    if(MT[0].Weight == 0)    {printf("/n/t不能生成最小生成树。/n");return 1;}
    printf("/n/t边 信 息/t权  值");
    for(i = 1;i <= MT[0].Weight;i++)
        printf("/n/t(%2d,%2d)/t/t[%4d]",MT[i].head,MT[i].tail,MT[i].Weight);
    return 0;
}

  • 上一篇:链表基本操作的程序实现
  • 下一篇:Huffman编码生成程序