图的存储
邻接矩阵法
邻接矩阵存储不带权图
0 - 表示两个顶点不邻接
1 - 表示两个顶点邻接
在无向图中,每条边在矩阵中对应两个1
在有向图中,每条边在矩阵中对应一个1
c
//不带权图的邻接矩阵存储
#define MaxVertexNum 100 //顶点数目的最大值
typedef struct{
char Vex[MaxVertexNum];
int Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵,边表
int vexnum,arcnum; //图当前顶点数和边数/弧数
}MGraph;
因为矩阵中只需要存放0和1,所以也可以将Edge(二维数组)定义为bool类型或枚举类型,让矩阵变得更小,节省存储空间
求顶点的度、入度、出度
无向图:第i个顶点的度 = 第i行(或第i列)的非零元素个数 时间复杂度O(|V|)
有向图:第i个顶点的入度 = 第i行的非零元素个数 时间复杂度O(|V|)
第i个顶点的出度 = 第i列的非零元素个数 时间复杂度O(|V|)
第i个顶点的度 = 第i行和第i列的非零元素个数之和 时间复杂度O(|V|)
邻接矩阵存储带权图(网)
c
//邻接矩阵存储带权图(网)
#define MaxVertexNum 100 //顶点数目的最大值
#define INFINITY 最大的int值 //宏定义常量"无穷" 使用int的上限值表示"无穷"
typedef char VertexType; //顶点的数据类型
typedef int EdgeType; //带权图中边上权值的数据类型
typedef struct{
VertexType Vex[MaxVertexNum]; //顶点
EdgeType Edge[MaxVertexNum][MaxVertexNum]; //边的权
int vexnum,arcnum; //图的当前定点数和弧数
}
若两个顶点间没有边,则权值为无穷
也有一些教材将一个顶点与自身的权值记作0,所以在使用邻接矩阵表示带权图(网)时,如果两个点之间权值为0或∞,则代表这两个顶点间没有边
邻接矩阵法的性能分析
空间复杂度:O(|V|2) -- 只和顶点数相关,和实际边数无关
当边数较少时,有大量的空间被浪费,所以邻接矩阵法适用于存储稠密图
无向图的邻接矩阵是对称矩阵,可以进行压缩存储(只存储上三角区/下三角区)
邻接矩阵的性质
设图G的邻接矩阵为A(矩阵元素为0/1),则An的元素An[i][j]
等于由顶点i到顶点j的长度为n的路径的数目
邻接表法(顺序+链式存储)
c
//用邻接表存储的图
typedef struct{
AdjList vertices;
int vexnum,arcnum;
}ALGraph;
//顶点
typedef struct VNode{
VertexType data; //顶点信息
ArcNode *first; //第一条边/弧
}VNode,AdjList[MaxVertexNum];
//"边/弧"
typedef struct ArcNode{
int adjvex; //边/弧指向哪个结点
struct ArcNode *next; //指向下一条弧的指针
//InfoType info //边权值
}ArcNode;
//与树的孩子表示法相同
空间复杂度
无向图:边结点的数量为2|E|,整体的空间复杂度为O(|V|+2|E|)
有向图:边结点的数量为|E|,整体的空间复杂度为O(|V|+|E|)
求顶点的度、入度、出度
无向图:度 = 顶点指向的边链表中结点的数量
有向图:度 = 入度 + 出度
出度 = 顶点指向的边链表中结点的数量
入度 = 指向当前结点的弧的数量(需要遍历所有结点的边链表)
同一个图的邻接表表示方式不唯一(边链表各结点的顺序是任意的)
邻接表和邻接矩阵
邻接表 | 邻接矩阵 | |
---|---|---|
空间复杂度 | 无向图:O(|V|+2|E|);有向图:O(|V|+|E|) | O(|V|2) |
适用于 | 存储稀疏图 | 存储稠密图 |
表示方式 | 不唯一 | 唯一 |
计算度/入度/出度 | 计算有向图的度和入度不方便,其余很方便 | 必须遍历对应的行和列 |
找相邻的边 | 找有向图的入边不方便,其余很方便 | 必须遍历对应的行和列 |
十字链表法、邻接多重表
十字链表法(存储有向图)
【有向图存储】
邻接表:入度、入边寻找计算不方便
邻接矩阵:空间复杂度高
空间复杂度:O(|V|+|E|)
找出边:顺着绿色线路找
找入边:顺着橙色路线找
注意:十字链表法只能用于存储有向图
邻接多重表(存储无向图)
【存储无向图】
邻接表:每条边对应两份冗余信息,删除顶点、删除边时间复杂度高
邻接矩阵:空间复杂度高

空间复杂度:O(|V|+|E|)
删除边、删除节点等操作很方便
注意:邻接多重表只适用于存储无向图
小结
邻接表 | 邻接矩阵 | 十字链表法 | 邻接多重表 | |
---|---|---|---|---|
空间复杂度 | 无向图:O(|V|+2|E|);有向图:O(|V|+|E|) | O(|V|2) | O(|V|+|E|) | O(|V|+|E|) |
适用于 | 存储稀疏图 | 存储稠密图 | 只能存有向图 | 只能存无向图 |
表示方式 | 不唯一 | 唯一 | 不唯一 | 不唯一 |
删除边或顶点 | 无向图中删除边或删除顶点都不方便 | 删除边很方便,删除顶点需要大量移动数据 | 很方便 | 很方便 |
找相邻的边 | 找有向图的入边必须遍历整个邻接表 | 遍历对应行或列,时间复杂度O(|V|) | 很方便 | 很方便 |