几种ACM常见的存图方式

几种ACM常见的存图方式

1.邻接矩阵:
我之前一直在用的就是邻接矩阵,非常简单,不过占用空间比较多,另外遍历时间比较长,因此不推荐。

2.vector实现邻接表:

struct node
{
    int end, w;
} temp;
vector<node> start[10010];
int main()
{
    int u, v, w;
    while (cin >> u >> v >> w) //存图
    {
        temp.end = v;
        temp.w = w;
        start[u].push_back(temp);
    }
    return 0;
}

3.链式前向星,这也是最重要、最高效的存图方式。稍微有点难理解。
首先,链式前向星由一个结构体edge[]数组head[]组成

  • edge[]数组:首先是记录u,v,w这三个基本信息,还有链式前向星的灵魂之一:next
struct node
{
    int u, v, w, next; 
    //起点,终点,边权,next为要遍历的下一条边的编号
} edge[M];
  • head[]数组:head[i]记录输入的以i为起点的最后一条边的编号

我们先模拟一遍最简单的情况,看看链式前向星是如何做到快速访问所有同一起点的所有边的。假设输入三条边,这三条边的信息如下:

3
1 2 5
1 3 6
1 6 3

按照代码,模拟之后,我们可以得到下图:

在这里插入图片描述

这样建立好关系之后,怎么快速遍历所有以1为起点的边呢?上面已经提到head[i]记录的是以i为起点的最后一条边的编号,因此,我们显然可以从head[1]开始遍历,那么以1为起点的倒数第二条边的编号是多少呢?这就要用到next了,是edge[head[1]].next。当edge[i].next为0的时候,那么就遍历完了所有起点为1的边。所以我们遍历的for循环就可以写成下面这种形式:

for(int i=head[1];i!=0;i=edge[i].next)

可以发现,我们遍历时访问的顺序和输入的顺序是刚好相反的


链式前向星代码如下:

#define N 10 //N个点
#define M 10 //M条边
struct node
{
    int u, v, w, next; //起点,终点,边权,next为要遍历的下一条边的编号
} edge[M];
int head[N]; //head[i]表示输入的以i为起点的最后一条边的编号
int main()
{
    fill(head, head + 10000, 0);
    int ct = 1; //边的编号
    int u, v, w;
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> u >> v >> w;
        edge[ct].u = u;
        edge[ct].v = v;
        edge[ct].w = w;
        edge[ct].next = head[u]; //连接当前这条边与上一条,形成链表
        head[u] = ct++;          //更新以u为起点的最后一条边的编号
    }
    int k;
    k = 1;
    cout << endl;
    for (int i = head[k]; i != 0; i = edge[i].next)
        cout << edge[i].u << ' ' << edge[i].v << ' ' << edge[i].w << endl;
    return 0;
}

事实上 ,结构体中的u是可以省略的,为什么呢?我们可以把所有和结构体的u有关的代码其全部删去看看。其实以head[i]为源点,我们已经可以遍历所有以i为起点的边了,因此结构体中的u可以删去。

最终代码:

#define N 10 //N个点
#define M 10 //M条边
struct node
{
    int v, w, next;
} edge[M];
int head[N];
int main()
{
    fill(head, head + 10000, 0);
    int ct = 1;
    int u, v, w;
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> u >> v >> w;
        edge[ct].v = v;
        edge[ct].w = w;
        edge[ct].next = head[u];
        head[u] = ct++;
    }
    int k;
    k = 1;
    cout << endl;
    for (int i = head[k]; i != 0; i = edge[i].next)
        cout << k << ' ' << edge[i].v << ' ' << edge[i].w << endl;
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值