【算法笔记】图的存储

图的存储

参考:知乎:Pecco 算法学习笔记(3) : 存图

邻接矩阵

邻接表

邻接矩阵中有大量的元素是0,有大量的空间浪费了,我们希望可以跳过这些0,直达有边的地方

邻接表:用链表存储每一行
【算法笔记】图的存储_第1张图片

邻接表的实现方式一:std::vector

// 图的存储_邻接表
#include 
using namespace std;

const int MAXN = 100; //总节点数

/* 用于存储边的结构体(链表edges[i]中的节点)
* to: 边的终点
* edge: 边的权重
*/
struct Edge
{
    int to, w;
};

/* 用于存储图的邻接表(链表数组)
* 用vector来模拟链表
* 从节点i发出的边的链表: edges[i],数据类型:vector
*/
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) 时:

  1. 给这条边赋予一个新的编号 cnt = cnt+1(可以通过该边的编号在edges数组中访问该边)
edges[++cnt].w = w;    //新增一条编号为cnt+1的边,边权为w
edges[cnt].to = to;    //该边的终点为to
  1. 将这条边插入到起点 (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;      //该边成为当前起点新的第一条边
}

【算法笔记】图的存储_第2张图片

你可能感兴趣的:(算法学习笔记,算法,图论)