zoukankan      html  css  js  c++  java
  • 数据结构之图的邻接矩阵

    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;
    }

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

     
  • 相关阅读:
    高德车载导航自研图片格式的探索和实践
    导航定位向高精定位的演进与实践
    高德算法工程一体化实践和思考
    机器学习在高德用户反馈信息处理中的实践
    UI自动化技术在高德的实践
    高德网络定位算法的演进
    系统重构的道与术
    基于深度学习的图像分割在高德的实践
    MySQL索引那些事
    如何优雅的将Mybatis日志中的Preparing与Parameters转换为可执行SQL
  • 原文地址:https://www.cnblogs.com/famousli/p/4240774.html
Copyright © 2011-2022 走看看