图的存储
邻接矩阵
邻接表
邻接矩阵中有大量的元素是0,有大量的空间浪费了,我们希望可以跳过这些0,直达有边的地方。
邻接表:用链表存储每一行
邻接表的实现方式一:std::vector
// 图的存储_邻接表
#include <vector>
using namespace std;
const int MAXN = 100; //总节点数
/* 用于存储边的结构体(链表edges[i]中的节点)
* to: 边的终点
* edge: 边的权重
*/
struct Edge
{
int to, w;
};
/* 用于存储图的邻接表(链表数组)
* 用vector来模拟链表
* 从节点i发出的边的链表: edges[i],数据类型:vector<Edge>
*/
std::vector<Edge> edges[MAXN];
// 向图中添加一条有向边 from -w-> to
// (新增边插入到起点from对应的边链表的尾部)
inline void add(int from, int to, int w)
{
Edge e = {to, w};
edges[from].push_back(e);
}
// 向图中添加一条无向边 (u, v)
inline void add2(int u, int v, int w)
{
add(u, v, w);
add(v, u, w);
}
邻接表的实现方式二:链表前向星
链表前向星用数组模拟链表:
- 为每一条边(每一个Edge对象)编号,按照边的插入顺序编号从1开始递增(用变量cnt来记录当前边的最大编号)
- edges数组中的元素是Edge对象,数组下标对应边的编号
- head数组中存储以每一个节点为起点的第一条边的编号
- 每一个Edge对象包含一个next属性,存储边链表中下一条边的编号;
next=0
意味着已经是边链表中的最后一个Edge对象了 - 新增边插入到起点from对应的边链表的头部
当插入一个新的边 (from)-w->(to) 时:
- 给这条边赋予一个新的编号
cnt = cnt+1
(可以通过该边的编号在edges数组中访问该边)
edges[++cnt].w = w; //新增一条编号为cnt+1的边,边权为w
edges[cnt].to = to; //该边的终点为to
- 将这条边插入到起点 (from) 所对应的边链表的头部:
- 令当前Edge对象的next属性指向原本的边链表头节点
- 将当前Edge对象设为边链表头节点(令head[from]指向当前Edge对象)
edges[cnt].next = head[from]; //把下一条边,设置为当前起点的第一条边
head[from] = cnt; //该边成为当前起点新的第一条边
// 图的存储_链表前向星
// MAXN: 节点总数; MAXM: 边总数
const int MAXN = 100, MAXM = 100;
// edges[i]: 编号i为边
struct Edge
{
int to, w, next;
}edges[MAXM];
int head[MAXN]; // head[from]: 以节点i为起点的第一条边的编号
int cnt; // cnt: 当前边的编号
// 新增一条有向边(新增边插入到起点from对应的边链表的头部)
inline void add(int from, int to, int w)
{
edges[++cnt].w = w; //新增一条编号为cnt+1的边,边权为w
edges[cnt].to = to; //该边的终点为to
edges[cnt].next = head[from]; //把下一条边,设置为当前起点的第一条边
head[from] = cnt; //该边成为当前起点新的第一条边
}