图的存储方式

本文详细介绍了图的两种常见存储方式:邻接矩阵和邻接表。邻接矩阵适用于存储有向图、无向图和带权图,包括创建、初始化、插入与删除顶点和边、展示图以及难点与注意事项。邻接表则使用链表存储边和点,同样涵盖初始化、插入与删除操作,以及邻接表的特点和难点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图的存储方式

一.邻接矩阵

  • 用矩阵存储边
  • 用数组存储点
    可以完成有向图、无向图和带权图,区别于矩阵上的数值

宏定义存储点的最大容量

#define MAX_V 10

1.创建数据结构体

typedef struct graph
{
    int maxv;//存放点的最大容量
    int numv;//存放点的数量
    int numedges;//存放边的数量
    
    char**edges;//存放边的矩阵结构
    char *v;//存放点的数组结构
}GRAPH

2.初始化图

  • 需要初始化数值,将默认最大容量进行赋值,
  • 边数和点数默认为0,之后再添加时不断++
  • 然后为存储边和点的矩阵和数组开辟空间,以最大的顶尖个数开辟
  • 在为边开辟空间时,因为是二维数组,所以应该先开辟一个(int**)的空间,在根据最大容量遍历,为(int*)开辟空间
void init(GRAPH*g)
{
    g->maxv=MAX_V;
    g->numv=g->numedges=0;
    //为数组开辟空间
    g->v=(char*)malloc(sizeof(char)*g->maxv;
    //为矩阵开辟空间
    g->edges=(char**)malloc(sizeof(char*)*g->maxv);
    for(int i=0;i<g->maxv;i++)
    {
        g->edges[i]=(char*)malloc(sizeof(char)*g->maxv);
    }
    //将矩阵中的数值初始为0
    for(int i=0;i<g->maxv;i++)
    {
        for(int j=0;j<g->maxv;j++)
        {
            edges[i][j]=0;
        }
    }
}

3.展示图

  • 遍历循环矩阵

4.插入顶点

调用
insert(&gm,'A');
函数
  • 先判断顶点最大容量是否大于目前的顶点个数,才可以插入
  • 插入时,将定点插入到最后,再将顶点个数++
g->v[g->numv++]=v; 

5.插入边

调用
insertedges(&gm,'A','B');
函数
  • 给出函数:获取某定点在数组中的位置,如果找不到返回-1
  • 创建插入函数:通过获取两个点的位置,判断是否已经插入过,若没有,就将对应的矩阵的值赋值为1,然后将边++

6.删除顶点

  • 删除数组中的顶点:找到顶点的位置,再将所有数组中的顶点向前移动
  • 删除与定点相连的所有边:遍历一遍定点所在行,求出数值为1的个数,在边数中将其删除,再将矩阵中定点所在的行和列都删除掉,并且行列都往前移动一个位置

7.删除边

  • 调用:deleteedges(&gm,'A','B');
  • 函数:与创建相似,先得到两个点的位置,然后判断是否找到,并且有边存在,如果有,就将矩阵中对应点的值改为0,然后边数–

8.销毁图

  • 释放数组空间
  • 释放矩阵空间:二维数据要从里到外一层一层释放掉它的地址
for(int i=0;i<g->numv;i++)
{
    free(g->edges[i]);
}
free(g->edges);
g->edges=NULL;
  • 将边数和点数重新赋值为0

9. 求邻接第一个邻接顶点

  • 找到它的位置,在矩阵中找到第一个不为空的点,返回点的位置

10.求两个顶点的下一个邻接顶点

  • 从第一个顶点的行和第二个顶点的列开始遍历,得到下一个数值为1的顶点,返回它的位置

11.邻接矩阵的难点和注意点:

  • 难点:删除点时要删除与其相关的所有边
  • 在删除和添加时记得给边数和点数增减
  • 在初始化矩阵和删除矩阵时要注意其方法
  • 创建一个可以找到点在数组中位置的函数会比较方便

二.邻接表:用链表存储边和点

typedef struct edge
{
    int dest;
    struct edge*link;
}Edge;//存储边的链表结构
typedef struct v
{
    char data;//点中的数据
    Edge*adj;//指向边的指针
}V;//存储点的数组结构

根据边和点创建图结构:

typedef struct graph
{
    int maxv;
    int numv;
    int numedges;
    
    V*NodeTable;//创建一个顶点表,实际上是一个数组结构
}Graph;

1.初始化

  • 为边数、点数和最大点数赋值
  • 为节点数组初始化,要乘上最大顶点个数,然后将V中的指针赋空,数值不用管他
g->NodeTable=(V*)malloc(sizeof(V)*g->maxv);
for(int i=0;i<g->maxv;i++)
{
    g->NodeTable[i].adj=NULL;
}

2.循环遍历展示

  • 根据数组一行一行打印,并在遍历每一行的所有链表将其打印
void show(Gragh*g)
{
    edge*s;
    for(int i=0;i<g->numv;i++)
    {
    print(%c,g->NodeTable[i].data);
        s=g->NodeTable[i].adj;
        while(s!=NULL)
        {
            print("%d",s->dest);
            s=s->link;
        }
        print("NULL\n");
    }
    print("\n");
}

3.插入顶点

-判断容量是否充足,之后进行插入

4.插入边

  • 创建获取顶点在数组中位置的函数,返回值为在数组中的位置,否则返回-1
  • 无向图需要插入两次:首先申请边的节点空间,为其赋值,再利用链表的头插法进行插入

5.删除顶点

  • 删除与该顶点相连的所有边,无向图要把其他点的边也要删除一些与它相关的
  • 删除数组中该顶点:将最后一个顶点覆盖掉要删除的顶点,并将最后一个顶点所指向的指针更改为原先所指向的链表
  • 找到与最后一个顶点相连的所有边并将他们存储的数值进行修改

6.删除边

  • 找到两个顶点的位置,再第一个顶点的链表中找到与下标相等的节点,再将其删除掉,删除时最好用一个节点记录一下它的前驱。无向图要在两个顶点处都把边删除

7.销毁图

  • 对数组遍历,删除每一个数组中的所有链表节点全部释放
  • 将数组释放
  • 将数值赋值为空

8.获取第一个邻接顶点

  • 得到顶点位置,很容易就得到了

9.获取第二个邻接顶点

  • 得到两个顶点位置,遍历链表进行查找返回下标值,没有就返回-1

10.难点和重点

  • 在对边进行操作时,创建新函数得到顶点位置很有用呀
  • 利用临接表时难点在构造结构体中,需要对边和顶点都重新构造一个新的结构体
  • 比较麻烦的时删除顶点,需要清楚步骤

三 .邻接表和邻接矩阵的比较

  • 顶点多边比较少时用邻接表,用邻接矩阵创建矩阵浪费较多
  • 顶点和边都比较多用邻接矩阵

四.十字链表法

主要针对有向图

五. 临界多重表

是无向图的一种链式存储结构,解决邻接表无向图重复创建边的问题

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值