38. 数据结构笔记之三十八图的邻接矩阵存储实现

38. 数据结构笔记之三十八图的邻接矩阵存储实现

“世界上有两种人,一种人,虚度年华;另一种人,过着有意义的生活。在第一种人的眼里,生活就是一场睡眠,如果在他看来,是睡在既温暖又柔和的床铺上,那他便十分心满意足了;在第二种人眼里,可以说,生活就是建立功绩......人就在完成这个功绩中享到自己的幸福。 --别林斯基”

    来看下图的邻接存储实现。

1.  邻接矩阵存储原理

对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放。树结构是一对多的关系,所以我们要将数组和链表的特性结合在一起才能更好的存放。

看如下图1


因为任意两个顶点之间都可能存在联系,因此无法以数据元素在内存中的物理位置来表示元素之间的关系(内存物理位置是线性的,图的元素关系是平面的)。

考虑到图是由顶点和边或弧两部分组成,合在一起比较困难,那就很自然地考虑到分为两个结构来分别存储。

顶点因为不区分大小、主次,所以用一个一维数组来存储是狠不错的选择。 

而边或弧由于是顶点与顶点之间的关系,一维数组肯定就搞不定了,那我们不妨考虑用一个二维数组来存储。

1.1         邻接矩阵(无向图) 

图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。如下图2


设置两个数组,顶点数组为vertex[4]={V0,V1,V2,V3},边数组arc[4][4]为对称矩阵(0表示不存在顶点间的边,1表示顶点间存在边)。 

1.2         邻接矩阵(有向图) 

有向图来存放, 如下图3

 

可见顶点数组vertex[4]={V0,V1,V2,V3},弧数组arc[4][4]也是一个矩阵,但因为是有向图,所以这个矩阵并不对称,例如由V1到V0有弧,得到arc[1][0]=1,而V0到V1没有弧,因此arc[0][1]=0。

另外有向图是有讲究的,要考虑入度和出度,顶点V1的入度为1,正好是第V1列的各数之和,顶点V1的出度为2,正好是第V1行的各数之和。 

1.3         邻接矩阵(网)

在图的术语中,我们提到了网这个概念,事实上也就是每条边上带有权的图就叫网。如下图4


有了这些概念,是不是顿时感觉很清晰了?让我们来看下代码吧。

2.  代码实现

2.1      定义结构体

结构体包含一个顶点表,邻接矩阵表,以及当前顶点数和边数。

typedefstruct

{

    VertexTypevexs[MAXVEX];            //顶点表

    EdgeType   arc[MAXVEX][MAXVEX];         //邻接矩阵,可看作边

    intnumVertexes, numEdges;      //图中当前的顶点数和边数

}Graph;

2.2      main

通过creategraph函数来创建图,然后打印图。如下图5 所示:

 

其中65535表示权值为无穷大。

 

 

 

2.3      locates

输入图的指针,一个字符,判断是否是节点的值。

如果不是则返回-1,如果是则返回是第几个点。

 

2.4      CreateGraph

建立一个无向网图的邻接矩阵。

输入顶点数和边数。

输入每个顶点的字符,不能为\n符号。

初始化arc 数组,每个值都为65535。

输入每个边的权值,并保存,同时设置矩阵对称。。

 

2.5      printGraph

依次输出边的权值。

3.  源码

#include<stdio.h>

#include<stdlib.h>

#include<curses.h>

 

typedef char VertexType;               //顶点类型应由用户定义

typedef int EdgeType;                  //边上的权值类型应由用户定义

 

#defineMAXVEX 100             //最大顶点数,应由用户定义

#defineINFINITY    65535              //用65535来代表无穷大

#define DEBUG

 

typedef struct

{

    VertexTypevexs[MAXVEX];           //顶点表

    EdgeType  arc[MAXVEX][MAXVEX];         //邻接矩阵,可看作边

    intnumVertexes, numEdges;      //图中当前的顶点数和边数

}Graph;

 

//定位

int locates(Graph*g, char ch)

{

    inti = 0;

    for(i= 0; i < g->numVertexes; i++)

    {

        if(g->vexs[i]== ch)

        {

            break;

        }

    }

    if(i>= g->numVertexes)

    {

        return-1;

    }

     

    returni;

}

 

//建立一个无向网图的邻接矩阵表示

void CreateGraph(Graph*g)

{

    inti, j, k, w;

    printf("输入顶点数和边数:\n");

    scanf("%d,%d",&(g->numVertexes), &(g->numEdges));

     

    #ifdefDEBUG

    printf("%d%d\n", g->numVertexes, g->numEdges);

    #endif

 

    for(i= 0; i < g->numVertexes; i++)

    {

        g->vexs[i]= getchar();

        while(g->vexs[i]== '\n')

        {

            g->vexs[i]= getchar();

        }

    }

     

    #ifdefDEBUG

    for(i= 0; i < g->numVertexes; i++)

    {

        printf("%c", g->vexs[i]);

    }

    printf("\n");

    #endif

 

 

    for(i= 0; i < g->numEdges; i++)

    {

        for(j= 0; j < g->numEdges; j++)

        {

            g->arc[i][j]= INFINITY; //邻接矩阵初始化

        }

    }

    for(k= 0; k < g->numEdges; k++)

    {

        charp, q;

        printf("输入边(vi,vj)上的下标i,下标j和权值:\n");

         

        p= getchar();

        while(p== '\n')

        {

            p= getchar();

        }

        q= getchar();

        while(q== '\n')

        {

            q= getchar();

        }

        scanf("%d",&w);   

         

        intm = -1;

        intn = -1;

        m= locates(g, p);

        n= locates(g, q);

        if(n== -1 || m == -1)

        {

            fprintf(stderr,"there is no this vertex.\n");

            return;

        }

        //getchar();

        g->arc[m][n]= w;

        g->arc[n][m]= g->arc[m][n];  //因为是无向图,矩阵对称

    }

}

 

//打印图

void printGraph(Graphg)

{

    inti, j;

    for(i= 0; i < g.numVertexes; i++)

    {

        for(j= 0; j < g.numVertexes; j++)

        {

            printf("%d ", g.arc[i][j]);

        }

        printf("\n");

    }

}

 

int main(int argc,char **argv)

{

    Graphg;

     

    //邻接矩阵创建图

    CreateGraph(&g);

    printGraph(g);

    return0;

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值