• 数据结构之图的邻接矩阵


    1.定义:

    邻接矩阵(Adjacency Matrix):是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中V={v1,v2,…,vn}。G的邻接矩阵是一个具有下列性质的n阶方阵:
    ①对无向图而言,邻接矩阵一定是对称的,而且对角线一定为零(在此仅讨论无向简单图),有向图则不一定如此。
    ②在无向图中,任一顶点i的度为第i列所有元素的和,在有向图中顶点i的出度为第i行所有元素的和,而入度为第i列所有元素的和。
    ③用邻接矩阵法表示图共需要n^2个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要n(n-1)/2个空间。
     
    2.特点:
    无向图的邻接矩阵一定是对称的,而有向图的邻接矩阵不一定对称。因此,用邻接矩阵来表示一个具有n个顶点的有向图时需要n^2个单元来存储邻接矩阵;对有n个顶点的无向图则只存入上(下)三角阵中剔除了左上右下对角线上的0元素后剩余的元素,故只需1+2+...+(n-1)=n(n-1)/2个单元。
    无向图邻接矩阵的第i行(或第i列)非零元素的个数正好是第i个顶点的度。
    有向图邻接矩阵中第i行非零元素的个数为第i个顶点的出度,第i列非零元素的个数为第i个顶点的入度,第i个顶点的度为第i行与第i列非零元素个数之和。
    用邻接矩阵表示图,很容易确定图中任意两个顶点是否有边相连。
    3.表示法:
    在图的邻接矩阵表示法中:
    ① 用邻接矩阵表示顶点间的相邻关系
    ② 用一个顺序表来存储顶点信息
    图的矩阵
    设G=(V,E)是具有n个顶点的图,则G的邻接矩阵是具有如下性质的n阶方阵:
     
    【例】
    下图中无向图G 5 和有向图G 6 的邻接矩阵分别为A l 和A 2 。
     
    网络矩阵
    若G是网络,则邻接矩阵可定义为:
     
    其中:
    w ij 表示边上的权值;
    ∞表示一个计算机允许的、大于所有边上权值的数。
    【例】下面带权图的两种邻接矩阵分别为A 3 和A 4 。
     
    图的邻接矩阵存储结构形式说明
    #define MaxVertexNum l00 //最大顶点数,应由用户定义
    typedef char VertexType; //顶点类型应由用户定义
    typedef int EdgeType; //边上的权值类型应由用户定义
    typedef struct
    {     VextexType vexs[MaxVertexNum] //顶点表
           EdeType edges[MaxVertexNum][MaxVertexNum];//邻接矩阵,可看作边表
          int n,e; //图中当前的顶点数和边数
    }MGragh;
    注意:
    ① 在简单应用中,可直接用二维数组作为图的邻接矩阵(顶点表及顶点数等均可省略)。
    ② 当邻接矩阵中的元素仅表示相应的边是否存在时,EdgeTyPe可定义为值为0和1的枚举类型
    无向图的邻接矩阵对称矩阵,对规模特大的邻接矩阵可压缩存储。
    ④邻接矩阵表示法的空间复杂度S(n)=0(n 2 )。
    ⑤建立无向网络的算法。
    void CreateMGraph(MGraph *G){
    //建立无向网的邻接矩阵表示 
    int i,j,k,w; 
    scanf("%d%d",&G->n,&G->e); //输入顶点数和边数 
    for(i = 0;i < n;i++) //读入顶点信息,建立顶点表 
    {    G->vexs=getchar();  } 
    for(i = 0;i < G->n;i++) 
    {    for(j = 0;j <G->n;j++)   
    {      G->edges[i][j] = 0; //邻接矩阵初始化   
    for(k = 0;k < G->e;k++) 
    {//读入e条边,建立邻接矩阵   
    scanf("%d%d%d",&i,&j,&w); //输入边(v i ,v j )上的权w   
    G->edges[i][j]=w;   
    G->edges[j][i]=w; 
    }
    }//CreateMGraph
    该算法的执行时间是0(n+n 2 +e)。由于e
    根据图的定义可知,图的逻辑结构分为两部分:V和E的集合。因此,用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,称这个二维数组为邻接矩阵。邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵。
    Matlab表达N=4;//图中的节点数目dag=zeros(N,N);//邻接矩阵初始化,值均为0C=1;S=2;R=3;W=4;//制定各节点编号dag(C,[RS])=1;//有两条有向边:C->R,C->Sdag(R,W)=1;//有向边:R->Wdag(S,W)=1;//有向边:S->W
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <queue>
    using namespace std;
    #define MAX 0x1f1f1f1f
    #define N 200
    bool visit[N];
    typedef char VerterType[20];
    typedef struct tu
    {
        VerterType vexs[N];//顶点数组
        int arc[N][N];//邻接矩阵数组
        int numpoint,numedge; //图的顶点数和边数
        int kind;//图的类型
    } graph;
    //1、确定顶点的位置
    int locates(graph &head,VerterType a)
    {
        int i,j;
        for(i=0; i<head.numpoint; i++)
        {
            if(strcmp(head.vexs[i],a)==0)
            {
                j=i;
                break;
            }
        }
        return j;
    }
    //2、创建图
    void graphcreate(graph &head)
    {
        int i,j,k;
        printf("输入顶点数和边数,图的类型:1.无向图,2.无向网,3.有向图,4.有向网
    ");
        cin>>head.numpoint>>head.numedge>>head.kind;
        printf("输入定点数组:
    ");
        for(i=0; i<head.numpoint; i++)
        {
            cin>>head.vexs[i];
        }
        for(i=0; i<head.numpoint; i++)
        {
            for(j=0; j<head.numpoint; j++)
            {
                head.arc[i][j]=MAX;
            }
        }
        VerterType a,b;
        int quan;
        if(head.kind%2==1)
            printf("请输入弧尾、弧头:
    ");
        else
            printf("请输入弧尾、弧头和权值:
    ");
        if(head.kind==1)
        {
            for(i=0; i<head.numedge; i++)
            {
                cin>>a>>b;
                int s1=locates(head,a),s2=locates(head,b);
                head.arc[s1][s2]=1;
                head.arc[s2][s1]=1;
            }
        }
        else if(head.kind==2)
        {
            for(i=0; i<head.numedge; i++)
            {
                cin>>a>>b>>quan;
                int s1=locates(head,a),s2=locates(head,b);
                head.arc[s1][s2]=quan;
                head.arc[s2][s1]=quan;
            }
        }
        else if(head.kind==3)
        {
            for(i=0; i<head.numedge; i++)
            {
                cin>>a>>b;
                int s1=locates(head,a),s2=locates(head,b);
                head.arc[s1][s2]=1;
            }
        }
        else
        {
            for(i=0; i<head.numedge; i++)
            {
                cin>>a>>b>>quan;
                int s1=locates(head,a),s2=locates(head,b);
                head.arc[s1][s2]=quan;
            }
        }
    
    }
    //3.遍历整个邻接矩阵
    void printGraph(graph &g)
    {
        int i, j;
        for(i = 0; i < g.numpoint; i++)
        {
            for(j = 0; j < g.numpoint; j++)
            {
                printf("%d", g.arc[i][j]);
                if(j!=g.numpoint-1) printf(" ");
                else printf("
    ");
            }
        }
    }
    //4、两个顶点是否存在边。
    void find(VerterType a,VerterType b,graph &p)
    {
        int i,s1,s2;
        s1=locates(p,a);
        s2=locates(p,b);
        if(p.arc[s1][s2]<MAX&&p.arc[s1][s2]>0)
        {
            if(p.kind%2==1)cout<<"yes"<<endl;
            else
            {
                cout<<"yes"<<endl;
                cout<<a<<"--"<<b<<"的度为:"<<p.arc[s1][s2]<<endl;
            }
        }
        else  cout<<"no"<<endl;
    }
    //5.查找一个定点的度。(有向图输出入度加出度之和)
    void findextent(graph &p,VerterType a)
    {
        int n,i,j,k,sum=0;
        if(p.kind<=2)
        {
            k=locates(p,a);
            for(i=0; i<p.numpoint; i++)
            {
                if(p.arc[k][i]!=MAX&&p.arc[k][i]!=0) sum++;
            }
            cout<<"度为:"<<sum<<endl;
        }
        else
        {
            k=locates(p,a);
            for(i=0; i<p.numpoint; i++)
            {
                if(p.arc[k][i]!=MAX&&p.arc[k][i]!=0) sum++;
                if(p.arc[i][k]!=MAX&&p.arc[i][k]!=0) sum++;
            }
            cout<<"度为:"<<sum<<endl;
        }
    }
    int maxx;
    void DFS(graph &p,int i)
    {
        maxx++;
        int j;
        visit[i]=true;
        cout<<p.vexs[i];
        if(maxx!=p.numpoint) cout<<" ";
        else cout<<endl;
        for(j=0; j<p.numpoint; j++)
        {
            if(p.arc[i][j]>0&&p.arc[i][j]<MAX&&visit[j]==false)
            {
                DFS(p,j);
            }
        }
    }
    void DFSTraverse(graph g)
    {
        int i;
        memset(visit,false,sizeof(visit));
        for(i = 0; i < g.numpoint; i++)
        {
            if(!visit[i])
            {
                DFS(g,i);
            }
        }
    }
    void BFS(graph &p)
    {
        int i,j;
        int sum=0;
        queue<int>q;
        memset(visit,false,sizeof(visit));
        for(i=0; i<p.numpoint; i++)
        {
            if(!visit[i])
            {
                visit[i]=true;
                cout<<p.vexs[i];
                sum++;
                if(sum!=p.numpoint) cout<<" ";
                else cout<<endl;
                q.push(i);
                while(!q.empty())
                {
                    int m;
                    m=q.front();
                    q.pop();
                    for(j=0; j<p.numpoint; j++)
                    {
                        if(p.arc[m][j]>0&&p.arc[m][j]<MAX&&!visit[j])
                        {
                            visit[j]=true;
                            cout<<p.vexs[j];
                            sum++;
                            if(sum!=p.numpoint) cout<<" ";
                            else cout<<endl;
                            q.push(j);
                        }
                    }
                }
            }
        }
    }
    int main()
    {
        graph head;
        VerterType a,b;
        int n;
        cin>>n;
        while(n--)
        {
            maxx=0;
            graphcreate(head);
            printf("输出链接矩阵:
    ");
            printGraph(head);
            printf("请输入两个顶点:
    ");
            cin>>a>>b;
            printf("判断两顶点之间是否存在边:
    ");
            find(a,b,head);
            printf("请输入一个顶点:
    ");
            cin>>a;
            printf("它的度为:
    ");
            findextent(head,a);
            printf("深度优先搜索遍历:
    ");
            DFSTraverse(head);
            printf("广度优先搜索遍历:
    ");
            BFS(head);
        }
        return 0;
    }

    详细解读代码便可分析出相应的知识点了。

     
  • 相关阅读:
    poj 2411 Mondriaan's Dream 骨牌铺放 状压dp
    zoj 3471 Most Powerful (有向图)最大生成树 状压dp
    poj 2280 Islands and Bridges 哈密尔顿路 状压dp
    hdu 3001 Travelling 经过所有点(最多两次)的最短路径 三进制状压dp
    poj 3311 Hie with the Pie 经过所有点(可重)的最短路径 floyd + 状压dp
    poj 1185 炮兵阵地 状压dp
    poj 3254 Corn Fields 状压dp入门
    loj 6278 6279 数列分块入门 2 3
    VIM记事——大小写转换
    DKIM支持样本上传做检测的网站
  • 原文地址:https://www.cnblogs.com/famousli/p/4240774.html
Copyright © 2020-2023  润新知