• 一种实用的边的存储结构--链式前向星


    前言

    我们对于图的存储方式常用的有邻接矩阵(适用于稠密图),对于边的查询效率较低,也有邻接表,对于边的查询效率高,但是会有扩容消耗,用数组实现也不好控制内存。而我们有一种中庸的数据结构叫做前向星,用类似邻接表的结构对其加以改造,就得到了一种效率得到极大提升的链式前向星。

    前向星

    定义

    把图中所有的边存储在连续的数组中,按照边的起点进行排序,我们称这种对边的存储方式为前向星

    前向星其实就是按照边的起点进行排序的边集数组

    存储结构

    以该图为例

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    如下就是该图边集的前向星表示形式,idx为数组下标,边存储了边的起点u,中点v和权值w

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    优缺点

    实现简单,但是将所有边插入的基础上进行了一次排序,带来了时间开销,实用性较差,一旦有新边插入就要再次排序,只适用于离线算法。

    链式前向星

    链式前向星是一种用于存储和处理稀疏图的数据结构,并且在实际应用中通常比邻接矩阵更加高效。其思想就是用静态链表来实现邻接表。

    邻接表的每个位置都是一个链表,代表下表i发出的所有边,但是vector带来扩容开销,数组实现又要内存控制,也有一定开销,我们就想到了初学时看似鸡肋的静态链表,即以下一条边的下标索引代替下一条边的指针,同时维护head数组,head[ i ]代表i发出边的链表的头节点下标,这样我们可以实现像邻接表插入那样的伪头插。

    具体实现我们需要edges数组存储边,head数组存储i发出的边链头节点在edges中下标,edgecount当前的边的数目,maxn最大边的存储数目

    边的定义

    typedef int W;
    struct Edge
    {
        int _u;
        int _v;
        W _w;
        int _next;
    } edges[maxn];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    边的插入

    void addEdge(int u, int v, W w)
    {
        edges[edgecount]._u = u;
        edges[edgecount]._v = v;
        edges[edgecount]._w = w;
        edges[edgecount]._next = head[u];//head初始所有值为-1
        head[u] = edgecount++;//edgecount初始为1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这其实就是一个静态链表的头插,显然整个插入过程时间复杂度为O(1)

    边的查找

    我们只要从head中拿到结点vertex边链的头节点下标,然后不断访问_next,直到-1为止

    (我们初始化head所有值为-1,~i为结束条件即-1补码取反是0)

        for (int i = head[vertex]; ~i; i = edges[i]._next)
        {
            //...
        }
    
    • 1
    • 2
    • 3
    • 4

    运行示例

        memset(head, -1, sizeof(head));
    
        int vertex = 0;
        addEdge(1, 2, 1);
        addEdge(2, 3, 2);
        addEdge(3, 4, 3);
        addEdge(1, 3, 4);
        addEdge(4, 1, 5);
        addEdge(1, 5, 6);
        addEdge(3, 5, 7);
    
        for (int vertex = 1; vertex <= 4; vertex++)
        {
            for (int i = head[vertex]; ~i; i = edges[i]._next)
            {
                cout << vertex << "->" << edges[i]._v << ":" << edges[i]._w << " ";
            }
            cout << endl;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    总结

    在工程中邻接表显然比链式前向星更为实用,但是对于OJ题目而言,链式前向星省去了vector的扩容开销同时提高了一些效率,还是很有用的。

  • 相关阅读:
    基于php+thinkphp的网上书店购物商城系统
    华为云大数据BI 为中小型企业智慧运营保驾护航
    Hadoop完全分布式搭建
    Spring常见问题解决 - this指针造成AOP失效
    C++ 语言学习 day10 复习(1)
    flutter 循环数据展示
    小程序轻松实现IM即时通讯多人聊天室
    _linux 进程间通信(命名管道)
    实践自定义弹框列表数据 slot 操作数据
    【数据结构-堆】堆
  • 原文地址:https://blog.csdn.net/EQUINOX1/article/details/134060478