图——概念,存储结构

图——概念,存储结构

基本概念

多对多的逻辑结构

  • 我们假设ABCDEFG是7个电话,之间的连线表示修有通信线路

  • 电话就是图的顶点Vi∈V,通信线路是ei∈E,G={V,E}就是一个图

  • 只要两个电话间有线路,就可以相互通话 即 无向图

  • 电话(顶点)连接的线路(边)数量:

  • ABCDE和GF之间消息无法传递:不连通

  • ABCDE和GF是两个联通分量

  • 假设ABCDE是五个电话,之间的连线表示修有通信线路,数字表示该线路的电话费

  • 不同通信线路上的电话费不同:加权图

  • 假设ABCDE是五个城市,带箭头连线表示该方向上有航班运营

  • 例如航班A->D只能支持A飞往D,边是单向的=>有向图

  • 飞来某地的航班数量 :入度

  • 从某地起飞的航班数量:出度

  1. 在一个无向图中,所有顶点的度数之和为边数量的2倍
  2. 在一个有向图中,所有顶点的出度之和==所有顶点的入度之和

存储结构

邻接矩阵(无向图)

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

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

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

图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图。

一个一维数组存储图中顶点信息,一个二维数组(称为矩阵)存储图中边或弧的信息。

对称矩阵:所谓对称矩阵就是n阶矩阵的元满足a[i][j]=a[j]i

即从矩阵的左上角到右下角的主对角线为轴,右上角的元与左下角相对应的元全都是相等的。

  • 要判定任意两顶点是否有边无边就非常容易了;
  • 要知道个某个顶点的度,其实就是这个顶点Vi在邻接矩阵中第i行(或第i列)的元素之和;
  • 求顶点Vi的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接接点。

邻接矩阵(有向图)

矩阵并不对称,例如由V1到V0有弧,得到arc[1][0]=1,而V0到V1没有弧,因此arc[0][1]=0

另外有向图是有讲究的,要考虑入度和出度。

邻接矩阵(网)

每条边上带有权的图叫网。

网即是有权值的图。

  • 网中数组array中元素表示两个顶点之间的关系。
  • 如果array[ i ] [ j ]=weight表示顶点 i 到(和)顶点 j 之间有一条边,其权值为weight。
  • 如果array[ i ] [ j ]=正无穷表示顶点 i 到(和)顶点 j 之间没有边。
  • 如果i和j是同一顶点,array[ i ] [ j ]=0。当然也可以为正无穷,灵活变化。
#include <stdio.h>
#define Maxlnt 32767     //表示极大值,即 ∞ 
#define MVNum 100        //最大顶点数 
typedef char VerTexType; //设顶点的数据类型为字符型 
typedef int ArcType;     //假设边的权值类型为整型 

typedef struct{
	VerTexType vexs[MVNum];      //顶点表 
	ArcType arcs[MVNum][MVNum];  //邻接矩阵
	int vexnum,arcnum;           //图的当前点数和边数 
}AMGraph;

邻接表(无向图)

对于边数相对顶点较少的图,邻接矩阵是对存储空间的巨大浪费。

因此我们可以考虑另外一种存储结构方式,例如把数组与链表结合一起来存储,这种方式在图结构也适用,我们称为邻接表

邻接表的处理方法是这样:

  • 图中顶点用一个一维数组存储。
  • 图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不确定,所以我们选择用单链表存储。
代码实现
#include <stdio.h>
#include<stdlib.h>
#define MaxVertices 100
typedef struct EdgeNode EdgeNode;
typedef struct EdgeNode //边表
{
    int adjvex;
    EdgeNode *next;
}EdgeNode; 

typedef struct //顶点表
{
    int vertex;
    EdgeNode *edgenext
}VertexNode;

typedef VertexNode AdjList[MaxVertices];///顶点表数组


typedef struct 
{
    AdjList adjlist;
    int n,e;
}AdjMatrix;

void CreateGraph(AdjMatrix *G)//生成邻接表
{
    int i,j,k;
    EdgeNode *s;
    printf("输入顶点数和边数(中间以空格分开):");
    scanf("%d%d",&G->n,&G->e);

    printf("建立顶点表\n"); 
    for ( i = 0; i < G->n; i++)
    {
        getchar();
        printf("请输入第%d个顶点的信息:",i+1);
        G->adjlist[i].vertex=getchar();
        G->adjlist[i].edgenext=NULL;
    }
    //前插法 
    printf("建立边表\n");  
    for ( k = 0; k < G->e; k++)
    {
        printf("输入有连接的顶点序号(中间以空格分开):"); 
        scanf("%d%d",&i,&j);
        i -=1;j -=1;
        //对于直接相连的进行编入(即对输入“0 1”时,在0对应的边表中编入1) 
        s=(EdgeNode*)malloc(sizeof(EdgeNode));
        s->adjvex=j;
        s->next=G->adjlist[i].edgenext;
        G->adjlist[i].edgenext=s;
        //对于间接相连的进行编入(即对输入“0 1”时,在1对应的边表中编入0)
        s=(EdgeNode*)malloc(sizeof(EdgeNode));
        s->adjvex=i;
        s->next=G->adjlist[j].edgenext;
        G->adjlist[j].edgenext=s;
    }
}
void ShowGraph(AdjMatrix *G)
{
    int i;
    for ( i = 0; i < G->n; i++)
    {
        printf("%d->",i+1);
        while (1)
        {
            if(G->adjlist[i].edgenext==NULL)
            {
                printf("^");
                break;
            }
            printf("%d->",G->adjlist[i].edgenext->adjvex+1);
            G->adjlist[i].edgenext=G->adjlist[i].edgenext->next;
        }
        printf("\n");
    }
}
int main()
{
    AdjMatrix *G=(AdjMatrix*)malloc(sizeof(AdjMatrix));
    CreateGraph(G);
    ShowGraph(G);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值