zoukankan      html  css  js  c++  java
  • 数据结构之有关图的算法(图的矩阵表示法)

    本篇意在总结有关图的一些基本算法

    包括有图的最小生成树(Prim,Kruscal),最短路径(Dijkstra,Floyd),拓扑排序等算法

    本篇图的数据结构为矩阵表示法

    // project1.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include<string.h>
    #include<assert.h>
    #include<stdio.h>
    #include<stdlib.h>
    
    #define MAX 100
    #define INFINITY (unsigned int)-1
    
    //邻接矩阵表示法
    struct MGraph{
        char vexs[MAX];//顶点
        unsigned int edges[MAX][MAX];//
        int vexnum,edgenum;
        int kind; //图的类型,0无向图,1有向图,2带权无向图,3带权有向图
        MGraph(int vn=0,int en=0,int kind=0):vexnum(vn),edgenum(en),kind(kind){
        }
    };
    
    //通过输入创建图矩阵
    void createMGraphFromStdin(MGraph *g){
        assert(g);
        printf("input vexnum, edgenum, and graph kind:
    ");
        assert(scanf("%d,%d,%d",&g->vexnum,&g->edgenum,&g->kind)==3);
        fflush(stdin);
    
        printf("input every vertex info:
    ");
        for(int i=0;i<g->vexnum;i++){//初始化顶点信息
            assert(scanf("%c",&g->vexs[i])==1);
            fflush(stdin);
        }
       
        char svex,tvex;
        int weight;
        switch(g->kind){
        case 0://无向图
            memset(g->edges,0,sizeof(int)*MAX*MAX);
            printf("input edges with format i,j
    ");
            for(int k=0;k<g->edgenum;k++){
                assert(scanf("%c,%c",&svex,&tvex)==2);
                fflush(stdin);
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=g->edges[j][i]=1;
            }
            break;
        case 1://有向图
            memset(g->edges,0,sizeof(int)*MAX*MAX);
            printf("input edges with format i,j
    ");
            for(int k=0;k<g->edgenum;k++){
                assert(scanf("%c,%c",&svex,&tvex)==2);
                fflush(stdin);
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=1;
            }
            break;
        case 2://带权无向图
            memset(g->edges,0xFF,sizeof(int)*MAX*MAX);
            printf("input edges with format i,j,weight
    ");
            for(int k=0;k<g->edgenum;k++){
                g->edges[k][k]=0;
                assert(scanf("%c,%c,%d",&svex,&tvex,&weight)==3);
                fflush(stdin);
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=g->edges[j][i]=weight;
            }
            break;
        case 3://带权有向图
            memset(g->edges,0xFF,sizeof(int)*MAX*MAX);
            printf("input edges with format i,j,weight
    ");
            for(int k=0;k<g->edgenum;k++){
                g->edges[k][k]=0;
                assert(scanf("%c,%c,%d",&svex,&tvex,&weight)==3);
                fflush(stdin);
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=weight;
            }
            break;
        }
       
    }
    
    //通过文件创建图矩阵
    void createMGraphFromFile(MGraph *g,char *file){
        assert(g && file);
        
        FILE* fp=fopen(file,"r");
        assert(fp);
    
        char str[256];
        if(fgets(str,255,fp)!=NULL){
            sscanf(str,"%d,%d,%d",&g->vexnum,&g->edgenum,&g->kind);
        }
    
        for(int i=0;i<g->vexnum;i++){//初始化顶点信息
            if(fgets(str,255,fp)!=NULL){
                sscanf(str,"%c",&g->vexs[i]);
            }
        }
    
        char svex,tvex;
        int weight;
        switch(g->kind){
        case 0://无向图
            memset(g->edges,0,sizeof(int)*MAX*MAX);
            for(int k=0;k<g->edgenum;k++){
                if(fgets(str,255,fp)!=NULL){
                    sscanf(str,"%c,%c",&svex,&tvex);
                }
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=g->edges[j][i]=1;
            }
            break;
        case 1://有向图
            memset(g->edges,0,sizeof(int)*MAX*MAX);
            for(int k=0;k<g->edgenum;k++){
                if(fgets(str,255,fp)!=NULL){
                    sscanf(str,"%c,%c",&svex,&tvex);
                }
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=1;
            }
            break;
        case 2://带权无向图
            memset(g->edges,0xFF,sizeof(int)*MAX*MAX);
            for(int k=0;k<g->edgenum;k++){
                g->edges[k][k]=0;
                if(fgets(str,255,fp)!=NULL){
                    sscanf(str,"%c,%c,%d",&svex,&tvex,&weight);
                }
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=g->edges[j][i]=weight;
            }
            break;
        case 3://带权有向图
            memset(g->edges,0xFF,sizeof(int)*MAX*MAX);
            for(int k=0;k<g->edgenum;k++){
                g->edges[k][k]=0;
                if(fgets(str,255,fp)!=NULL){
                    sscanf(str,"%c,%c,%d",&svex,&tvex,&weight);
                }
                int i,j;
                for(i=0;g->vexs[i]!=svex;i++);//找到编号
                for(j=0;g->vexs[j]!=tvex;j++);
                g->edges[i][j]=weight;
            }
            break;
        }
       
    }
    
    int findVex(MGraph* g,char vex){
        for(int i=0;i<g->vexnum;i++)
            if(g->vexs[i]==vex)
                return i;
        return -1;
    }
    
    //最小生成树之Prim,Kruscal算法
    //松弛操作
    void relaxation(MGraph *g,unsigned int dist[],char vex){
        int j=findVex(g,vex);
        assert(j!=-1);
        for(int i=0;i<g->vexnum;i++){
            if(j==i)
                dist[i]=0;
            else if(g->edges[j][i] <dist[i])//<j,i>
                dist[i]=g->edges[j][i];
        }
    }
    
    void relaxation_Dijkstra(MGraph* g,unsigned int dist[],char svex,char tvex){
        int i=findVex(g,svex);
        int j=findVex(g,tvex);
        assert(j!=-1 && i!=-1);
        for(int k=0;k<g->vexnum;k++){
            if(g->edges[j][k]!=INFINITY && (dist[j]+g->edges[j][k])<dist[k]){
                dist[k]=dist[j]+g->edges[j][k];
            }
        }
    }
    
    int findMin(unsigned int dist[],int length){
        unsigned int min=INFINITY;
        int pos=-1;
        for(int i=0;i<length;i++){
            if(dist[i] !=0 && dist[i]<min){
                min=dist[i];
                pos=i;
            }
        }
        return pos;
    }
    //sp[vexnum]标记源点到该点是否已是最短路径
    int findMin_Dijkstra(unsigned int dist[],int length,bool sp[]){
        unsigned int min=INFINITY;
        int pos=-1;
        for(int i=0;i<length;i++){
            if(sp[i]==false && dist[i] !=0 && dist[i]<min){
                min=dist[i];
                pos=i;
            }
        }
        return pos;
    }
    
    void MST_Prim(MGraph* g,char beg_vex){
        unsigned int dist[MAX];//辅助数组
        char prim_vex[MAX];//记录依次加入的点
        int vexs=0;//记录已加入点的数目
        prim_vex[vexs++]=beg_vex;
    
        relaxation(g,dist,beg_vex);
        while(vexs<g->vexnum){
            int i=findMin(dist,g->vexnum);
            assert(i!=-1);
            prim_vex[vexs++]=g->vexs[i];
            
            relaxation(g,dist,g->vexs[i]);
        }
        prim_vex[vexs]='';
        printf("Prim MST sequence:%s
    ",prim_vex);
    }
    
    struct EdgeType{
        int s,t;
        unsigned int cost;
    };
    
    int cmp(const void* a,const void *b){
        return (*(EdgeType *)a).cost - (*(EdgeType *)b).cost;
    }
    
    //寻找vex所在树的根结点
    int findFather(int father[],int vex){
        int t=vex;
        while(father[t]>=0)
            t=father[t];
        return t;
    }
    
    void MST_Kruscal(MGraph* g,char beg_vex){
        int k=0;
        EdgeType *edges = new EdgeType[g->edgenum];
        for(int i=0;i<g->vexnum;i++)
            for(int j=i+1;j<g->vexnum;j++){
                if(g->edges[i][j]<INFINITY){
                    edges[k].s=i;edges[k].t=j;
                    edges[k++].cost=g->edges[i][j];
                }
                if((g->kind==1 || g->kind==3) && g->edges[j][i]<INFINITY){//如果有向
                    edges[k].s=j;edges[k].t=i;
                    edges[k++].cost=g->edges[j][i];
                }
            }
        qsort(edges,g->edgenum,sizeof(EdgeType),cmp);
                
        int father[MAX];//初始所有点属于不同的连通分量
        for(int i=0;i<g->edgenum;i++)//初始化
            father[i]=-1;
        int j=0,i=0;
    
        while(j<g->edgenum && i<g->vexnum){
            int svex=findFather(father,edges[j].s);
            int tvex=findFather(father,edges[j].t);
            if(svex != tvex){
                father[tvex]=svex;
                i++;
                printf("<%c,%c> ",g->vexs[svex],g->vexs[tvex]);
            }
            j++;
        }
        
        delete[] edges;
        printf("
    ");
    }
    
    void ShortestPath_Dijkstra(MGraph* g,char source_vex){
        unsigned int sp_dist[MAX];//最短路径数组
        bool sp[MAX]={false};//标记是否已是最短
        int j=findVex(g,source_vex);
        assert(j!=-1);
        memset(sp_dist,0xFF,sizeof(int)*MAX);
        sp_dist[j]=0;
        sp[j]=true;
        relaxation_Dijkstra(g,sp_dist,source_vex,source_vex);
        char tvex;
        
        int rounds=1;
        while(rounds<g->vexnum){
            int j=findMin_Dijkstra(sp_dist,g->vexnum,sp);
            assert(j!=-1);
            sp[j]=true;
    
            relaxation_Dijkstra(g,sp_dist,source_vex,g->vexs[j]);
            rounds++;
        }
        for(int i=0;i<g->vexnum;i++)
            printf("Shortest Path from %c to %c is %d
    ",source_vex,g->vexs[i],sp_dist[i]);
    }
    
    //若P[v][w][u]为TRUE,则u 是从v 到w 当前求得的最短路径上的顶点
    bool P[MAX][MAX][MAX];
    unsigned int D[MAX][MAX];
    
     void ShortestPath_Flyod(MGraph *g){
         /* 使用一个n*n的方阵D,D[s][t]表示<s,t>的最短路径
          * 但是为了D[s][t],需要更新n次D矩阵
          * D(k)[s][t]表示经过k次更新后,当前<s,t>的最短路径,可能最终不是
          * D(-1)[s][t]=edges[s][t]
          * D(k)[s][t]=min{ D(k-1)[s][t],D(k-1)[s][k]+D(k-1)[k][t] }
          * D(k)的计算是尝试把顶点k加到每对顶点<s,t>之间
         */
         
        memset(D,0xFF,sizeof(unsigned int)*MAX*MAX);
        for(int i=0;i<g->vexnum;++i){//初始化D矩阵 
            for(int j=0;j<g->vexnum;++j){
                D[i][j]=g->edges[i][j]; //D(-1)
                for(int u=0;u<g->vexnum;++u) 
                    P[i][j][u]=false;
                if (D[i][j]<INFINITY){ /*从v 到w 有直接路径*/
                    P[i][j][i]=true;
                    P[i][j][j]=true;
                }
            }
        }
    
        for(int k=0; k<g->vexnum; ++k){//计算D(k),总共n次,这个循环一定要在最外层
            for(int s=0; s<g->vexnum; ++s){//D(k)[s]
                for(int t=0;t<g->vexnum;++t){//D(k)[s][t]
                    if(D[s][k]<INFINITY && D[k][t]<INFINITY && (D[s][k]+D[k][t])<D[s][t]){ //如果顶点k属于<s,t>最短路径上
                        D[s][t]=D[s][k]+D[k][t];
                        //更新P[s][t],当前P[s][t]最短路径上有哪些顶点
                        for(int i=0;i<g->vexnum;++i)
                            P[s][t][i]=P[s][k][i] || P[k][t][i];
                    }
                }
            }
        }
        //输入每对顶点的最短路径上的顶点
        for(int s=0;s<g->vexnum;s++)
            for(int t=0;t<g->vexnum;++t){
                printf("The Shortest Path Vertexes of <%c,%c> are:
    ",g->vexs[s],g->vexs[t]);
                for(int i=0;i<g->vexnum;i++)
                    if(P[s][t][i])
                        printf("%c ",g->vexs[i]);
                printf("
    ");
            }
     }
    
     //拓扑排序
     void Topo_Sort(MGraph* g){
         char topo[MAX];//保存拓扑排序的顶点序列
         int vexs=0;
         bool visited[MAX];//记录顶点是否已排序
         int indegree[MAX];//记录顶点的入度
         
         for(int i=0;i<g->vexnum;i++){//初始化入度数组
             indegree[i]=0;
             visited[i]=false;
             for(int j=0;j<g->vexnum;j++){
                 if(i!=j && g->edges[j][i]<INFINITY)
                     indegree[i]++;
             }
         }
    
         while(vexs<(g->vexnum-1)){//Topo_Sort
             int i;
             for(i=0;i<g->vexnum;i++){//寻找入度为0的顶点
                 if(indegree[i]==0 && visited[i]==false){
                     topo[vexs++]=g->vexs[i];
                     visited[i]=true;
    
                     //修改入度
                     for(int j=0;j<g->vexnum;j++){
                         if(j!=i && g->edges[i][j]<INFINITY)
                             indegree[j]--;
                     }
                    break;
                 }
             }
             if(i>=g->vexnum){
                 printf("Cannot Topo Sort!
    ");
                 return;
             }
         }
    
         topo[vexs]='';
         printf("Topo Sort: %s
    ",topo);
     }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        char beg_vex='f';
        MGraph *g=new MGraph();
        createMGraphFromStdin(g);
        if(g->kind==2 || g->kind==3)
            MST_Prim(g,beg_vex);
    
        MGraph *g2=new MGraph();
        char *file="./in.txt";
        createMGraphFromFile(g2,file);
    
        if(g2->kind==2 || g2->kind==3){
            MST_Prim(g2,beg_vex);
            MST_Kruscal(g2,beg_vex);
            ShortestPath_Dijkstra(g2,beg_vex);
            ShortestPath_Flyod(g2);
            Topo_Sort(g2);
        }
    
        delete g2;
        return 0;
    }
  • 相关阅读:
    web前端开发规范
    前端工程构建工具之Yeoman
    javascript编码规范
    IOS和安卓不同浏览器常见bug
    SASS对css的管理
    移动端开发注意事项
    性能调试工具
    前端开发和其他类别工程师配合的那些事!
    前端工程师常见的面试题
    前端性能优化浏览器+服务器篇
  • 原文地址:https://www.cnblogs.com/abc123456789/p/3446167.html
Copyright © 2011-2022 走看看