408数据结构学习笔记——图的存储

目录

1.邻接矩阵

1.1.邻接矩阵的定义

1.2.求度、入度和出度

1.3.邻接矩阵的性能

1.4.邻接矩阵的性质

2.邻接表法

2.1.邻接表的定义

2.2.邻接表的空间复杂度

2.3.邻接表的度、入度和出度

2.4.邻接表与邻接矩阵的不同点

3.十字链表(有向图)

4.邻接多重表(无向图)

5.图的基本操作

6.王道课后题


1.邻接矩阵

1.1.邻接矩阵的定义

采用一维数组存放顶点数据,二维数组存放边的数据(各顶点是否邻接)

  1. 无向图:A[i][j] = 0,则图中Vi和Vj不邻接;A[i][j] = 1,则图中Vi和Vj邻接
  2. 有向图:A[i][j] = 0,则图中没有Vi指向Vj的边;A[i][j] = 1,则图中有Vi指向Vj的边
#define MAXVERTEXNUM 100    //顶点数最大值为100

typedef struct MGraph{
    char Vex[MAXVERTEXNUM];    //一维数组,存放顶点数据
    int Edge[MAXVERTEXNUM][MAXVERTEXNUM];    //二维数组,存放邻接矩阵
    int verNum, arcNum;    //顶点数,弧数
}MGraph;

1.2.求度、入度和出度

  1. 度:第 i 行或者第 i 列的非0元素的个数
  2. 入度:第 i 列非0元素的个数
  3. 出度:第 i 行非0元素的个数 

1.3.邻接矩阵的性能

  • 空间复杂度O(n^{2})(二维数组 顶点数*顶点数)
  • 适合存储稠密图
  • 如果是无向图,可以只存储上三角或者下三角(特殊矩阵的压缩)

1.4.邻接矩阵的性质

设图G的邻接矩阵为A,A^{n}的元素A^{m}[i][j]等于由顶点 i 到顶点 j 的长度为 n 的路径数目

2.邻接表法

2.1.邻接表的定义

邻接表为图中每个顶点都建立一个单链表,该表中存放该顶点的所有邻接结点,并成为边表;而边表的头指针和顶点的数据信息采用顺序存储,称为顶点表

 其中firstarc指向该顶点的第一个邻边,nextarc指向该顶点的下一个邻边

#define MAXVERTEXNUM 100    //最大顶点数

typedef struct ArcNode{    //边表结点
    int adjevex;    //该弧指向的顶点的数组下标
    struct ArcNode *next;    //指向下一条弧的指针
    //InfoType info;    //网的边权值
}ArcNode;

typedef struct VNode{    //顶点表结点
    VertexType data;    //顶点信息
    ArcNode *first;    //指向第一条邻边的指针
}VNode, AdjList[MAXVERTEXNUM];

typedef struct{
    AdjList vertices;    //邻接表
    int vexNum, arcNum;    //顶点数和弧数
}ALGraph;

2.2.邻接表的空间复杂度

无向图中,每一条边都被保存了两次,因此空间复杂度为O(|V| + 2|E|)

有向图中,每一条边只被保存了一次,因此空间复杂度为O(|V| + |E|)

2.3.邻接表的度、入度和出度

度:遍历该顶点的边表,有几个则度就为几

出度:遍历该顶点的边表,有几个则出度就为几

入度:遍历除该顶点外的其他所有顶点边表,共有几个指向该顶点的弧,则入度就为几

2.4.邻接表与邻接矩阵的不同点

邻接矩阵:稠密图;确定顶点编号则图唯一

邻接表:稀疏图;图不唯一

3.十字链表(有向图)

十字链表弥补了邻接表查找入度困难的缺点,它既容易查找顶点的入度,也容易找顶点的出度

顶点结点的data域存放数据,firstin域存放第一个指向它的弧的指针,firstout域存放第一个指出的指针

弧结点的tailvex域存放弧尾的顶点,haedvex域存放弧头的顶点,hlink域存放下一个弧头和该顶点相同的弧的指针,tlink域存放下一个弧尾和该顶点相同的弧的指针

找入度:从该顶点结点的firstin开始找,再进入弧结点的hlink

找出度:从该顶点结点的firstout开始找,再进入弧结点的tlink 

4.邻接多重表(无向图)

邻接表存放无向图时,每条边会存放两次,浪费大量空间,因此,采用邻接多重表

邻接多重表的结构类似十字链表

边结点:mark标记是否被搜索过;ivex和jvex标记两个顶点在图中的位置;ilink指向下一条依附于顶点i的边;jlink指向下一条依附于顶点j的边;info存放信息,类似边的权值

 顶点结点:data存放顶点结点的数据;firstedge存放第一条依附于该节点的边

5.图的基本操作

Adjacent(G, x, y);    //判断图是否存在边<x, y>或者(x, y)

最好时间复杂度O(1):该顶点的下一个边结点即为要搜索的边

最坏时间复杂度O(|V|):该顶点的最后一个边界点是要搜索的边O(|V| - 1)

Neighbors(G, x);    //列出图G与顶点x邻接的边

无向图:

  1. 最好时间复杂度O(1):该顶点只有一个边(邻接表)
  2. 最坏时间复杂度O(|V|):该顶点的边有V - 1条(邻接表);遍历整行n个顶点(邻接矩阵)

有向图:

  1. 最好时间复杂度O(1):出边:该顶点只有一个出边(邻接表)
  2. 最坏时间复杂度:遍历整行n个结点O(|V|)(邻接矩阵);入边:遍历全部边结点O(|E|)(邻接表)
InsertVertex(G, x);   //在图中插入顶点x 

时间复杂度为O(1):有向图、无向图、邻接矩阵、邻接表都一样(新顶点刚开始不连任何边)

DeleteVertex(G, x);    //在图中删除顶点x

无向图:

  1. 最好时间复杂度O(1):该顶点没有相邻的边(邻接表)
  2. 最坏时间复杂度:删除该顶点的行和列O(|V|)(邻接矩阵);该顶点邻接了尽可能多的边,则需要遍历其他所有边O(|E|)(邻接表)

有向图:

  1. 邻接矩阵:删除行列O(|V|)
  2. 邻接表:
    1. 删出边:O(1)没有出边,O(|V|)
    2. 删入边:O(|E|)遍历所有边
AddEdge(G, x, y);    //添加<x, y>或者(x, y)

邻接矩阵:O(1)顺序表随机存储特性

邻接表:O(1)头插法,O(|V|)尾插法

FirstNeighhbor(G, x);    //求图G中顶点x的第一个邻接顶点

无向图:

  1. 邻接矩阵:遍历行,最好时间复杂度第一个O(1),最坏时间复杂度最后一个或不存在O(|V|)
  2. 邻接表:顶点结点连着的第一个边结点O(1)

有向图:

  1. 邻接矩阵:出边行,入边列 O(1) ~ O(n)
  2. 邻接表:
    1. 入边O(1),指定节点的第一个边结点
    2. 出边O(1),遍历所有边O(1) ~ O(|E|)
NextNeighbor(G, x, y);    //顶点y是图G中顶点x的一个邻接点,返回除y外的下一个邻接点

6.王道课后题

1.无向图:邻接矩阵中遍历上三角或者下三角,统计有多少个非零元素;邻接表中遍历所有边结点,边的数量为边结点的一半

有向图:邻接矩阵种遍历所有行,统计有多少个非零元素;邻接表中遍历所有边结点,边的数量即为边结点数量

2.无向图:邻接矩阵中查找第 i 行 j 列是否为非零;邻接表中遍历 i 的顶点结点相连的边结点是否有指向j的边结点

有向图:邻接矩阵中查找第 i 行 j 列和第 j 行 i 列是否为非零;邻接表中分别遍历 i 和 j 的顶点结点相连的边结点

3.无向图:邻接矩阵中遍历行,非零元素的个数即为度;邻接表中遍历其相连的边结点,边结点个数即为度

有向图:邻接矩阵中出度遍历行,入度遍历列,非零元素个数即为度;邻接表中出度遍历该节点的边结点,边结点个数即为出度;入度需遍历全部边结点

#define MaxVertexNum 100
typedef struct ArcNode{
    struct ArcNode *next;
    int adjvex;
}ArcNode;

typedef struct VNode{
    elemtype data;
    ArcNode *first;
}VNode, AdjList[MaxVertexNum];

typedef struct Grpah{
    AdjList vertices;
    int vexNum, arcNum;
}Graph
void Convert(Graph &G, int arr[][]){
    for (int i = 0; i < G.vexNum; i++){
        //找到第一个结点
        ArcNode *p = (G->vertices[i]).first;
        //循环遍历下一个结点
        while(p){
            //将第i行p->adjvex列置为1
            arr[i][p->adjvex] = 1;
            p = p->next;
        }
    }
}

int IsExitEl(MGraph G){
    int degree;
    int n = 0;
    //遍历图的各个顶点
    for (int i = 0; i < G.numVertices; i++){
        //度清零
        degree = 0;
        //二维数组的当前元素值不等于0,则度数+1
        for (int j = 0; j < G.numVertices; j++) if (Edge[i][j]) degree++;
        //度数为奇数,则个数+1
        if (degree % 2) n++;
    }//for
    //个数为0或者2,return 1;否则,return 0
    if (n == 0 || n == 2) return 1;
    else return false;
}

cda备考学习学习笔记——基础知识篇(二)主要涉及了计算机科学与技术领域的基本概念和知识。 首先,它介绍了计算机网络的基础知识。网络是将多台计算机通过通信链路连接起来,使它们能够相互通信和共享资源的系统。笔记中详细介绍了网络的组成、拓扑结构和通信协议等重要内容。 其次,笔记还解释了计算机系统的基本组成。计算机系统由硬件和软件两部分组成,其中硬件包括中央处理器、存储器、输入输出设备等,而软件则分为系统软件和应用软件。笔记详细介绍了各种硬件和软件的功能和作用。 此外,笔记还对数据库管理系统进行了介绍。数据库管理系统是一种用于管理和组织数据的软件系统,它能够实现数据的存储、检索和更新等操作。笔记中详细介绍了数据库的概念、结构和操作等内容。 最后,笔记还包括了算法和数据结构的基础知识。算法是解决问题的一系列步骤和规则,而数据结构则是组织和存储数据的方式。笔记中介绍了常用的算法和数据结构,如排序算法、树和等。 总之,通过学习CDA备考学习笔记中的基础知识篇(二),我们能够更好地理解计算机网络、计算机系统、数据库管理系统以及算法和数据结构等相关概念和知识。这些基础知识对于我们深入研究计算机科学与技术领域是非常重要的,也为我们日后的学习和工作奠定了坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值