<转--剑紫青天>

对于ACM图论方面的题目总是免不了首先要建图存图,使用合适的存图方式不但是AC的必要条件,解题事半功倍。

以下主要分析三种常见的存图方式的优缺点以及代码实现

邻接矩阵

邻接矩阵是三种存图方式中最简单也最为暴力的一种存图方式了。

存图思想

使用一个矩阵来描述一个图,对于矩阵的第i行第j列的值,表示编号为i的顶点到编号为j的顶点的权值。

代码实现

对于邻接矩阵来说,它的代码实现都十分简单,二维数组就可以了。

12345678910111213141516171819202122232425262728293031323334
#include <stdio.h>#include <string.h>

// 最大顶点数const int V = 1000;

// 邻接矩阵的定义// mat[i][j] 表示 顶点`i`到顶点`j`的权值

int mat[V][V];

// 邻接矩阵的初始化操作// 假设权值为零表示没有该边

memset(mat, 0, sizeof(mat))

// 增加边// 新增顶点`i`到顶点`j`的边,权值为`w`

mat[i][j] = w;

// 删除边// 删除顶点`i`到顶点`j`的边

mat[i][j] = 0;

// 查询边// 查询顶点`i`到顶点`j`的边权

mat[i][j];

优点

使用邻接矩阵来进行建图存图有以下优点

缺点

邻接矩阵存图虽然简单优雅,但是它的一些缺点却几乎是致命的。

邻接表

邻接表在三种常用的存图方式中属于较为中庸和普遍的存图方式了,缺点不致命,优点不明显。

存图思想

邻接矩阵对于每个顶点使用定长的数组来存储以该点出发的边的情况。第i个数组的第j个值存储的是从顶点i到顶点j的边的权值。
而邻接表则是对于每个顶点使用不定长的链表来存储以该点出发的边的情况。因此对于第i个链表的第j个值实际上存储的是从编号为i的顶点出发的第j条边的情况。

一般来说,如果有边权的话,邻接表的链表存储的是一个结构体,这个结构体存储该边的终点以及边权。

下面给个邻接表与邻接矩阵存图的示例比较。

links&matrix.png

代码实现

在ACM题目中,动态的数据结构一般是不被推荐的,因为动态开辟内存比较消耗时间,且写起来复杂容易出错。
大部分情况我们使用C++STL里的vector作为链表来实现图的邻接表。

1234567891011121314151617181920212223242526272829303132333435
#include <vector>

using namespace std;

// 最大顶点数const int V = 100000;

// vector实现的邻接表的定义// 不考虑边权,存储类型为int型

vector<int> e[V];

// 邻接表的初始化操作// 将起点为`i`的边链表全部清空

e[i].clear();

// 增加边// 新增顶点`i`到顶点`j`的边

e[i].push_back(j);

// 查询边

e[i][0];    // 查询以`i`为起点的第一条边`i->e[i][0]`

for (int j=0; j<(int)e[i].size(); ++j) {    if (e[i][j] == k) {     // 查询边`i->k`        // do something.    }}

优点

  • 较为简单易学

    相比邻接矩阵,无非是数组转链表加上存储值的意义不同而已,不需要转太大的弯。

  • 代码易写,不复杂

    代码实现已经演示过了,较简单,不容易写错。

  • 内存利用率较高

    对于顶点数V与边数E,空间复杂度为O(V+E)O(V+E)。能较好处理稀疏图的存储。

  • 对不确定边的操作方便效率也不错

    比如,要遍历从某点出发的所有边,不会像邻接矩阵一样可能会遍历到不存在的边。

缺点

  • 重边不好处理

    判重比较麻烦,还要遍历已有的边,不能直接判断。
    一般情况下使用邻接表存图是会存储重边的,不会做重边的判断。
    所以如果要解决重边的影响一般不在存边的情况下做文章。

  • 对确定边的操作效率不高

    比如对于给定i->j的边要进行查询或修改等操作只有通过遍历这种方式找到了。

链式前向星

链式前向星是前向星的升级版,因为它可以完美代替前向星,所以就跳过前向星的学习,直接学习链式前向星。

存图思想

这种存图方式的数据结构主要是边集数组,顾名思义,图的边是用数组来存储的。
当然想要完美表示图结构,光有一个边集数组还不够,还要有一个数组存储指向每一个点的第一条边的“指针”。
而每一条边都需要存储接下来一条边的“指针”,这样就能够像类似邻接表一样方便遍历每一个点的所有边了。

代码实现

1234567891011121314151617181920212223242526272829303132333435363738
#include <stdio.h>#include <string.h>

// 最大顶点数const int V = 100000;// 最大边数const int E = 100000;

// 边结构体的定义struct Edge {    int to;         // 表示这条边的另外一个顶点    int next;       // 指向下一条边的数组下标,值为-1表示没有下一条边};

// head[i] 表示顶点`i`的第一条边的数组下标,-1表示顶点`i`没有边int head[V];Edge edge[E];

// 链式前向星初始化,只需要初始化顶点数组就可以了memset(head, -1, sizeof(head));

// 增加边的方式// 新增边 a -> b,该边的数组下标为`id`inline void AddEdge(int a, int b, int id){    edge[id].to = b;    edge[id].next = head[a];    // 新增的边要成为顶点`a`的第一条边,而不是最后一条边    head[a] = id;    return;}

// 遍历从`a`点出去的所有边for (int i=head[a]; i!=-1; i=e[i].next) {    // e[i] 就是你当前遍历的边 a -> e[i].to}

优点

  • 内存利用率高

    相比vector实现的邻接表而言,可以准确开辟最多边数的内存,不像vector实现的邻接表有爆内存的风险。

  • 对不确定边的操作方便效率也不错

    这点和邻接表一样,不会遍历到不存在的边。

缺点

  • 难于理解,代码较复杂

    这种存图方式相对于邻接表来说比较难理解,代码虽然不是很复杂但是不熟练的话写起来也不是方便。

  • 重边不好处理

    这点与邻接表一样,只有通过遍历判重。

  • 对确定边的操作效率不高

    也与邻接表一样,不能通过两点马上确定边,只能遍历查找。

总结

对于邻接矩阵存图来说,由于内存消耗的局限性,它的适用范围比较狭窄,几乎只能在简单图论题目中见到。

邻接表存图是最为常见的一种,绝大部分采用C++STL中的vector实现,一般情况下大部分图论题目都能使用该存图方式。

但是链式前向星其实是一种较好替代邻接表来存图的数据结构,在邻接表存图不能使用时可以使用,几乎可以用于全部图论题目。

ACM图论之存图方式相关推荐

  1. 用html2canvas长按保存h5页面,html2canvas - 微信中长按存图 - 将h5活动结果保存到本地...

    现在有很多在微信里流行的h5活动页.这些小h5大部分都是简单的交互然后得出一个abcd早就拟定好的结果,根据你的选项分几种情况,最终得到其中一个作为你测试的答案.比如这个就是最后那张结果图: 当时自己 ...

  2. 算法提高课-图论-单源最短路的建图方式-AcWing 920. 最优乘车:bfs求最短路、建图

    题目分析 来源:acwing 分析: 本题难在抽象建图上,这里采用的建图方式是:同一条公交线路上,前面的站点都可以连一条有向边到其后面的站点,且边权都为1. 由于边权都是1,可以用bfs来求最短路. ...

  3. 【图论——第一讲】图论基础以及图的储存

    ฅ(๑˙o˙๑)ฅ 大家好, 欢迎大家光临我的博客:面向阿尼亚学习算法学习笔记系列持续更新中~ 文章目录 一.前言 推荐大家一个图形编译器[很好用](https://csacademy.com/app ...

  4. 【数据结构与算法】图论基础与图存储结构

    前言 由于后续更新好几篇文章都涉及到 图 这种数据结构,因此打算先普及一下 图 的相关理论支持,如果后面的相关内容有些点不太容易理解,可以查阅此篇文章.本文不建议一口气阅读完毕,可以先浏览一遍,在后续 ...

  5. 图论之分层图最短路总结 与经典例题

    一.分层图 分层图只是建图时有区别,但跑最短路板子都是一样的,正所谓图论最难的就是建图,只要有合适的建图方法,那么问题就很简单了. 分层图是指有很多个平行的图,各个平行的图之间有特殊的连接边. 如何更 ...

  6. uoni扫地机器人好用吗_能存图、会思考,Uoni由利扫地机器人深度体验:看得到的好用...

    原标题:能存图.会思考,Uoni由利扫地机器人深度体验:看得到的好用 简单聊聊 在帮助用户释放双手这方面,我想扫地机器人应该是目前消费大众最容易接受的产品之一.就我个人看来,扫地机器人迎合了我&quo ...

  7. 图很难理解?看这篇图论基础与图存储结构就够了

    点击上方↑↑↑蓝字关注我们~ 「2019 Python开发者日」,购票请扫码咨询 ↑↑↑ 作者 | 程序员吴师兄 转载自五分钟学算法(ID:CXYxiaowu) 1 前言 打算先普及一下图的相关理论支 ...

  8. android 系统的切图方式_UI设计切图规范

    移动UI设计切图是UI设计师最重要的设计输出物,切图资源输出是否规范直接影响到工程师对设计效果的还原度.设计师的切图输出物是是体现一个设计师专业水准的重要标准,同时也是设计师表达自己对设计态度的最有力 ...

  9. OpenGL:使用FBO为渲染对象并从GPU取出存图

    OpenGL 使用FBO为渲染对象并从GPU取出存图的代码 #include "gl/glew.h" #include "gl/glut.h" #include ...

最新文章

  1. Python设计模式-解释器模式
  2. 传入一个日期 返回该月的第一天是星期几_Excel VBA 编程开发应用系列 (二十一)— Excel常用的日期函数...
  3. 在项目中引入领域驱动设计的经验
  4. 油价新年首涨:“五连跌”终结 一箱油多花4元
  5. android ViewPager滑动事件讲解
  6. ubuntu12.04默认gcc4.6.3,如何升级到gcc4.8
  7. JSTL(JSP 标准标签库)和EL表达式联合使用时,进行字符的比较
  8. kube-controller-manager 配置参数解读
  9. DCMTK:演示状态的VR和IOD检查器
  10. 兰州理工大学c语言试题答案,兰州理工大学c语言题库81058116.doc
  11. Google的面试题长啥样
  12. Stackoverflow的见解:投票最多的是Spring 4问题
  13. 在窗体上画图,并响应手标事件的实例
  14. MFC中修改应用程序主窗口的标题
  15. 服务器测试网址填写注意事项
  16. 房费制 它 结账BUG
  17. 21、OSPF配置实验之特殊区域totally stub
  18. Vue 事件绑定 事件修饰符 条件判断 循环遍历
  19. 宅男福利:Python爬取某站所有漫画(赶紧收藏)
  20. 502 java_502 Bad Gateway

热门文章

  1. 两百万美元“NFT”消失的惨案
  2. php仿京东幸运大转盘抽奖,原生js vue 抽奖插件 仿京东大转盘抽京豆(原创)...
  3. (8)web安全|渗透测试|网络安全 常见的站点搭建类型分析,子域名爆破,旁注等,WAF防护分析及绕过,wafwoof工具的安装和使用
  4. jQuery 下载保存图片的方法
  5. 护照阅读器助力港珠澳大桥拓展大湾区
  6. 【汇编程序】从键盘上输入一系列以‘$’为结束符的字符串,然后对其中的字母字符计数,并显示出计数结果
  7. 解决 canvas隐藏后出现滚动条的问题
  8. 分享时刻—今日一收获
  9. 3500字干货 | 大家都在谈的数据思维,到底要怎么建立?
  10. Cadence Allegro通孔PAD制作图文教程及视频演示