邻接表
作为一名现役Oier在做过无数图论题目和搜索题目之后,可以说是相当熟悉了,但是今天做的一道题,让我对于邻接表表示直接懵逼,原来在跑最短路的时候还是明白每个数组各自的作用的,然而一旦在其它题目中遇到就不会了,所以今天特意复习,并决定好好整理一下,以后别再懵逼了…


附上神犇ahalei的Blog:http://blog.csdn.net/ahalei/article/details/23356781
(里面对于邻接表的解释还是很透彻的)


邻接表

但什么是邻接表呢(・ω・。)ʃฺ??

众所周知,邻接矩阵是用矩阵实现存图的一类数据结构
而邻接矩阵,则是用链表(好多个)来实现存图的一类数据结构
但是手打链表mdzz,指针都不怎么用啊(一直都是在用数组下标模拟)
所以说对于邻接表我们也可以用数组来模拟实现

代码(结构体封装)

int head[maxn];struct node{int from,to,cost,next;
}e[maxn << 1];//无向图(maxn << 1)

初始化

for(int i = 1;i <=n;i++){//n由题意而来head[i] = -1;
}//当然也可以一步写成memset(head,-1,sizeof(head)),但是实测比for一遍更慢

这里,head 数组存的是我们建图时,某个点所存的最后一条边的编号

例如我们存入点1的一条边,这条边是总第5条边,则我们将head[1]赋值为5,但是之前我们1号点若已经记录过一条边,如果我们这时修改head[1]那么之前那条边不就没了吗,但是显然我们不能让这条边消失,而是应该想办法让它在head修改之后依然能够被找到

这时候别忘了,我们用的可是链表啊,这时候就要用到我们所建结构体中的next,从next字面意思上就可以理解,即为head所记录边的“下一条”边,简单地说就是记录当前head[i]所存边之前,head[i]所存的那条边,但是如果我们再像head一样存边是不可能的了,那么我们next应该存什么呢?我们在e[i].next中应该存的是记录第i条边前,所记录的是第几条边( 即这条边的编号 )

例如我们存入1号点的第5条边之前,head[1] = 3,即当前由1发出的边是总数的第3条边,这时令head[1] = 5,再令e[5].next = 3,意思是从第五条开始的 所指向的下一条边是第3号边,这样一来就保证了每条被记录的边都可以被找到且记录上不会冲突,同时因为第5条边是从1号点发出的,同时第五条边也仅仅指向第3条边,这就保证了我们当前所访问的点都是从1号点发出的,由head可以知道发出点是哪一个。

代码建边:

void build(int f,int t,int c){tot++;//当前记录的是总数第几条边,因为正在加边所以tot++e[tot].from = f;//在很多情况下这一步其实是不必要的,因为head已记录e[tot].to = t;e[tot].cost = c;//在图有权值的情况下e[tot].next = head[f];//这一步就是上文所述的内容head[f] = tot;
}

同时因为还记录了from和to,且from和to所代表的点记录时顺序编号相同并且编号唯一(对于第i条边,它的两端点编号一定是i,当然一个点可以存在于多条边上,所以可以被记录多次,但是在访问某一条边的时候是不会冲突的(废话太多233))所以知道了编号也就可以知道这个点经过这条边所指向的点的是谁(e[i].to)

因此可以想到如何到遍历一个点所联通的所有边
即从head[i]一直遍历到该点所存的第一条边(例如第一条存的就是第一条边,即e[1].next,当我们扫到以该边起始的第一条边的时候,就会得到e[].next == -1了,这时候结束循环即可)

代码如下

//遍历1号节点连接的边
int k = head[1];
for(int i = k;i != -1;i = next[i]){//do something...
}

在实际应用中邻接表建图更加适用于稀疏图(边数较少的图)
但当边数较多的时候用邻接表建图便不够优秀了,因为它用的是链表存图,当你要查询一条很早之前记录的边的时候,你要将这条边之后所有记录过的边都遍历一遍,用时相当之慢,还不如邻接矩阵(但邻接矩阵当点太多的时候,n^2空间复杂度无法接受)

最后放上CODE[VS]1557 热浪的代码来体现邻接表在应用中的特点

题目地址(裸的最短路模板题)http://codevs.cn/problem/1557/

代码如下(SPFA+SLF优化)

/*
作者:Loi_Peacefuldoge
题目:p1557 热浪
*/#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <queue>const int maxn = 100005; using namespace std;int tot;
int t,c,ts,te;
int dist[maxn];
int head[maxn];
bool used[maxn];struct node
{int f,t,c,next;
}es[maxn << 1];inline void rd(int &x)
{scanf("%d",&x);
} inline void build(int x,int y,int z)
{tot++;es[tot].f = x;es[tot].t = y;es[tot].c = z;es[tot].next = head[x];head[x] = tot;
}deque<int >q;inline void spfa(int be)
{memset(dist,0x3f,sizeof(dist));while(!q.empty())q.pop_front();q.push_back(be);used[be] = true;dist[be] = 0;while(!q.empty()){int u = q.front();used[u] = false;q.pop_front();for(int i = head[u];i;i = es[i].next){int v = es[i].t;if(dist[v] > dist[u] + es[i].c){dist[v] = dist[u]+es[i].c;if(!used[v]){if(dist[v] < dist[q.front()]) q.push_front(v);else q.push_back(v);used[v] = true; }}}}
}void init()
{memset(used,0,sizeof(used));memset(head,0,sizeof(head));tot = 0;return ;
}int main()
{init();rd(t);rd(c);rd(ts);rd(te);for(int i = 1;i <= c;i++){int x,y,z;rd(x);rd(y);rd(z);build(x,y,z);build(y,x,z);}spfa(ts);printf("%d\n",dist[te]);
return 0;
}

【图论】关于邻接表建图相关推荐

  1. vector邻接表建图+DFS+BFS

    以边操作为主的图用边集数组存储比较好,相比链式前向星,vector建图更容易懂. #include <iostream> #include <cstdio> #include ...

  2. vector邻接表建图+dijkstra模板

    本文节点的编号从0开始计算 思路 dijkstra伪算法(未优化)源点到自己的距离为0,其余点到源点的距离为无穷大 记录当前节点now为源点s 循环下面的步骤V次,V是结点的个数now标记已访问遍历n ...

  3. 迪杰斯特拉最全详解(朴素版,堆优化+邻接表存图/链式前向星存图)

    迪杰斯特拉 迪杰斯特拉算法分析 迪杰斯特拉(朴素版) 迪杰斯特拉堆优化(邻接表存图) 迪杰斯特拉堆优化(链式前向星存图) 最短路--spfa(链式前向星存图) 迪杰斯特拉算法分析 一般用三种数据结构存 ...

  4. 邻接表存储图的广度优先遍历

    试实现邻接表存储图的广度优先遍历. 函数接口定义: void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) ); 其中LGraph是邻接表存储 ...

  5. 邻接表建立图(c语言)

    邻接表建立图 有向图 无向图 邻接表存图进行拓扑排序 不得不说网上的真的是太乱了,看得我脑壳疼 自己写的可以,感觉好的话可以当成模板. 有向图 代码: #include<stdio.h> ...

  6. 邻接表存储图利用BFS遍历

    //今天上机写的邻接表存储图利用BFS遍历: #include<stdio.h> #include<stdlib.h> #include<string.h> #in ...

  7. mysql 邻接表_图的邻接表存储结构详解

    通常,图更多的是采用链表存储,具体的存储方法有 3 种,分别是邻接表.邻接多重表和十字链表. 本节先讲解图的邻接表存储法.邻接表既适用于存储无向图,也适用于存储有向图. 在具体讲解邻接表存储图的实现方 ...

  8. QDUOJ 生化危机 邻接表存图+BFS

    生化危机 发布时间: 2015年10月10日 18:05   时间限制: 1000ms   内存限制: 256M 描述 X博士想造福人类, 研发一种可以再生肢体的药物, 可是很不幸......研究失败 ...

  9. 用邻接表存储图c语言,邻接表、邻接多重表、十字链表及C语言实现

    上一节介绍了如何使用顺序存储结构存储邻接多重表和 邻接的意思是顶点之间有边或者弧存在,通过当前顶点,可以直接找到下一个顶点. 邻接表 使用邻接表存储图时,对于图中的每一个顶点和它相关的邻接点,都存储到 ...

最新文章

  1. POJ-2584 T-Shirt Gumbo 最大流
  2. jsp:include和%@include%的区别
  3. iphone照片删掉又出现_iPhone 内存不够用,原因在这儿!
  4. BZOJ1117 [POI2009]救火站Gas 贪心
  5. 【项目管理】外包和采购
  6. RN的stylesheet的属性及方法
  7. http中响应状态码表示的意义?
  8. MAC搭建ios自动化测试环境
  9. 双线性的定义以及他的性质
  10. 华为鸿蒙os2.0游戏,华为鸿蒙os2.0系统下载-华为鸿蒙系统官方下载入口2.0下载 - 一游网手机游戏...
  11. Html中跳转到其他页面
  12. java获取某年度有多少周_java获取一年共有多少周
  13. TeamCity VS Jenkins:选择正确的CI / CD工具
  14. (零基础)如何使用python下载哔哩哔哩视频?
  15. 使用jira管理Scrum敏捷项目实战(四)jira自定义电子看板、敏捷看板、KANBAN配置
  16. 【Eclipse】--Eclipse简介和安装
  17. adb 工具源码修改
  18. 把图片隐藏进音频详细教程(含软件下载及使用方法)
  19. 力扣1024视频拼接
  20. c语言 inc文件夹,汇编 inc 和 dec 指令

热门文章

  1. [量子客] 12月全球量子资讯周报
  2. socket是什么?套接字是什么?
  3. GBase 8s 特性简介
  4. 关于冲正,需要知道的那点事
  5. 基于html和Node.js的网页音乐播放器设计
  6. 微信企业号开发:自定义菜单
  7. 【Grasshopper基础13】创建可在画布上自由传递的自定义类型数据(上)—— IGH_Goo接口的重要性及其实现
  8. 学习java的第17天
  9. 安全生产月知识竞赛——新安法知多少
  10. 【华为云技术分享】敏捷设计,高效协同,凸显设计端云协同价值