• 链式前向星


    链式前向星

    在之前先来看一下边集数组。

    边集数组是图的表示法的一种,前向星是边集数组的一种,链式前向星是前向星的一种。

    前向星

    前向星是把边的起点从小到大排序,起点一样按同样的规则排终点。所以前向星使用之前要(O(nlog_2n))排序一下。

    使用两个数组,一个head,head[i]记录以i为起点的边在边的数组里面的第一个位置,一个len,len[i]记录以

    i为起点的边有多少条。

    比如:1->2->3,2->4,2->5,3->5

    edge 1---------2--------3---------4-------5

    --------1->2----2->3----2->4----2->5----3->5

    head 1-------2--------3----------4---------5

    -------1-------2--------5----------0--------0

    len 1-------2--------3----------4--------5
    ------1-------3---------1----------0--------0

    链式前向星

    传说前向星使用不是那么方便,而链式前向星可以更快更简洁的实现dfs,spfa等。

    链式前向星的表示是这样的:

    还是需要一个边集数组edge记录边,边的属性有:边的终点to,这条边指向上一条边在edge里的编号next

    一个数组head,head[i]里面装的是以i为起点的最后添加的一条边的编号

    实际上这样表示就可以通过一个head[i]来访问i指向的最后一条边,然后最后一条边的next属性存放着i指向的倒数第二条边,然后倒数第二条边的next指向i指向的倒数第三条边,一个类似于链表的结构可以逆序访问i节点指向的所有边。

    相关代码如下:

    //链式前向星
    int n;
    int head[max_n];
    struct edge
    {
        int to;//指向的节点
        int next;//上一条边的标号
        int w;//边的权重
    }e[max_n<<1];//边数组
    int cnt = 0;//记录边标号
    void add(int u,int v) 
    {
        e[++cnt].to = v;//边的指向节点
        e[cnt].next = head[u];//指向u节点为起点的上次添加的一条边
        head[u] = cnt;//更新u节点开始的最后加入的一条边的编号
    }
    void print(int s)
    {
        for(int i = head[s];i;i=e[i].next)//逆序输出
        {
            cout << e[i].to << " ";
        }
        cout << endl;
    }
    

    实例可见参考文章。

    下面是链式前向星实现dfs和spfa的代码模板

    void spfa(int x)//链式前向星的spfa
    {
        d[x] = 0;
        for(int i = 0;i<n;i++)
        {
            d[i] = INF;
        }
        queue<int> que;
        que.push(x);
        inq[x] = 1;
        while(!que.empty())
        {
            int k = que.front();
            que.pop();
            inq[k] = 0;//队列中已无k节点
            for(int i = head[k];i;i=e[i].next)//i为边的标号
            {
                int j = e[i].to;//j为节点标号
                if(d[j]>d[k]+e[i].w) //k到j的距离可以松弛
                {
                    d[j] = d[k]+e[i].w;
                    if(!inq[j])//若队列中无j节点,加入
                    {
                        que.push(j);
                    }
                }
            }
        }
    }
    void dfs(int x,int from)//链式前向星的dfs
    {
        for(int i = head[x];i;i=e[i].next)
        {
            if(e[i].to==from) continue;//不重复dfs
            //process
            dfs(e[i].to,x);
        }
    }
    

    代码汇总:

    #include <iostream>
    #include <queue>
    #define max_n 1005
    #define INF 0x3f3f3f3f
    using namespace std;
    int d[max_n];//最短距离
    int inq[max_n];//标记数组
    //链式前向星
    int n;
    int head[max_n];
    struct edge
    {
        int to;//指向的节点
        int next;//下一条边的标号
        int w;//边的权重
    }e[max_n<<1];//边数组
    int cnt = 0;//记录边标号
    void add(int u,int v) 
    {
        e[++cnt].to = v;//边的指向节点
        e[cnt].next = head[u];//u节点开始指向上次添加的一条边
        head[u] = cnt;//u节点开始的最后加入的一条边
    }
    void print(int s)
    {
        for(int i = head[s];i;i=e[i].next)
        {
            cout << e[i].to << " ";
        }
        cout << endl;
    }
    void spfa(int x)//链式前向星的spfa
    {
        d[x] = 0;
        for(int i = 0;i<n;i++)
        {
            d[i] = INF;
        }
        queue<int> que;
        que.push(x);
        inq[x] = 1;
        while(!que.empty())
        {
            int k = que.front();
            que.pop();
            inq[k] = 0;//队列中已无k节点
            for(int i = head[k];i;i=e[i].next)//i为边的标号
            {
                int j = e[i].to;//j为节点标号
                if(d[j]>d[k]+e[i].w) //k到j的距离可以松弛
                {
                    d[j] = d[k]+e[i].w;
                    if(!inq[j])//若队列中无j节点,加入
                    {
                        que.push(j);
                    }
                }
            }
        }
    }
    void dfs(int x,int from)//链式前向星的dfs
    {
        for(int i = head[x];i;i=e[i].next)
        {
            if(e[i].to==from) continue;//不重复dfs
            //process
            dfs(e[i].to,x);
        }
    }
    int main()
    {
        add(1,2);
        add(1,3);
        add(1,4);
        print(1);
        return 0;
    }
    
    

    参考文章:

    Dreamers_Boy,【链式前向星+存图】讲解,https://blog.csdn.net/lookqaq/article/details/81304637

  • 相关阅读:
    从 Qt 的 delete 说开来
    Qt信号槽的一些事
    Qt 线程基础(QThread、QtConcurrent等)
    QThread使用——关于run和movetoThread的区别
    重点:怎样正确的使用QThread类(注:包括推荐使用QThread线程的新方法QObject::moveToThread)
    重要:C/C++变量的自动初始化
    C++中基类的析构函数为什么要用virtual虚析构函数
    如何打印Qt中的枚举所对应的字符串
    用route命令解决多出口的问题
    C/C++预处理指令
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11294148.html
Copyright © 2020-2023  润新知