现实世界中,事物之间的关系是错综复杂的,最简单的是线性关系(线性表,至多有一个前驱一个后继),稍微复杂一些的是树关系(每个元素至多有一个前驱,可能有零个或多个后继)。

这片博客我讲一种更为复杂的数据结构——图结构。特征是:每个元素可以有多个前驱、多个后继。

1.图逻辑结构

(1)定义:图是一种数据结构,它由顶点(Vertex)集合(即数据元素)及顶点间的边(Edge)集合(即元素之间的关系)组成。

(2)结构化定义:

Graph = (D,R) = (V,E)

其中 V = {x|x∈D0},即V是顶点的有 穷非空集合

E = {(x,y)|x,y∈V} 或 E = {<x,y>|x,y∈V&&Path(x,y)},即E是顶点之间关系的有穷集合,也叫做边集合。Path(x,y)表示从x到y的一条单向通路,它是有方向的。

(3)基本概念

1)顶点(Vertex):数据元素;

2)边(Edge):数据元素之间的关系;

3)有向边:数据元素之间的关系有序,即x与y的关系不同于y与x的关系,用尖括号表示,<x,y>≠<y,x>

4)无向边:数据元素之间的关系无序,即x与y的关系等价于y与x的关系,用圆括号表示,(x,y)=(y,x)

5)权 Weight:图赋予了一种含义,边具有一个关联的数值,这个数值称为权。(根据这个定义,图可分为带权图、不带权图)

6)邻接:无向图,若(u,v)∈E,则称u,v相互邻接;有向图,若<u,v>∈E,则称u邻接到v,或v临接于u。

7)关联(依附):若(u,v)∈E或<u,v>∈E,则称边依附于顶点u,v或顶点u,v与边相关联。

8)顶点的度(Degree):与顶点相关联的边的数目,记作Td(v);入度:与顶点相关联的引入边的数目,记作Id(v);出度:与顶点相关联的出入边的数目,记作Od(v)。Td(v)=Id(v)+Od(v)

9)路径:在图 G=(V, E) 中, 若从顶点 vi 出发, 沿一些边经 过一些顶点 vp1, vp2, …, vpm,到达顶点vj。则称顶点序列 (vi vp1 vp2 ... vpm vj) 为从顶点vi 到顶点 vj 的路径。它经过的边(vi, vp1)、 (vp1, vp2)、...、(vpm, vj) 应是属于E的边。

10)路径长度:带权路径长度、非带权路径长度

简单路径:若路径上各顶点 v1, v2, ..., vm 均不互相重复, 则 称这样的路径为简单路径。

回路:若路径上第一个顶点 v1 与最后一个顶点vm 重合, 则 称这样的路径为回路或环。

简单回路:路径上除起点与终点相同外,其余顶点都不相同;

11)子图:设有两个图G=(V,E)和G'=(V',E')。若V'包含于V且E'包含于E,则称图G'是图G的子图。

一个图的子图包括其自身,就像一个集合的子集包括其本身一样。

12)顶点连通:(无向图)两个顶点vi,vj之间有路径;

顶点强连通:(有向图)两个顶点vi到vj,vj到vi之间都有有向路径;

连通图:如果图中任意一对顶点都是连通的, 则称此 图是连通图;

连通分量:(非)连通图的极大连通子图(连通图的连通分量只有一个,那就是它本身;非连通图的连通分量有多个);

强连通图:在有向图中, 若对于每一对顶点vi和vj, 都存在 一条从vi到vj和从vj到vi的路径, 则称此图是强连通图;

强连通分量:非强连通图的极大强连通子图。

13)生成树:连通图的极小连通子图,它包含图的所有n个顶点,(n-1)条边;

有向树:一个有向图恰有一个入度为0的顶点,其余顶点的入度均为1;

生成树森林:

无向图:各个连通分量的生成树;

有向图:由若干有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的边;

(4)图的种类

①有向图( Undirected Graph or Undigraph):由有向边构成的图。

②无向图( Directed Graph or Digraph):由无向边构成的图。

③简单图:若图满足:任一边(u,v)或<u,v>,有u≠v,即自己不能与自己有关系;一条边不允许重复出现,即两个元素不能有相同的多个关系。

④完全图(Conplete Graph):包括所有可能边的简单图,即具有最大边数的简单图。

有n个顶点的无向完全图有n*(n-1)/2条边(意思就是任意两个结点之间都有边相连)。

有n个顶点的有向完全图有n*(n-1)条边(意思就是任意两个结点之间都有双向的两条边)。

⑤稠密图(Sparse Graph):边数远远少于完全图的图。

⑥稠密图(Dense Graph):与稀疏图相反的图。

⑦平面图:存在一种画法,使各条边仅在顶点处相交。

⑧非平面图:无论怎么画,都有边在非定点处相交。

2.图结构上定义的操作

图初始化 Init_Graph(g)
求顶点在图中的位置 Loc_vertex(g,v)
访问图的顶点 Get_vertex(g,i)
求图中v的第一个邻接点 First_adj(g,v)
求图中v的w后的下一个邻接点 Next_adj(g,v,w)
插入顶点 Ins_vertex(g,u)
插入边 Ins_edge(g,u1,u2)
删除顶点 Del_vertex(g,u)
删除边 Del_edge(g,u1,u2)
图的遍历 Traversal_g(g,u)

3.图的ADT定义

4.图存储结构

(1)随着数据结构的复杂,其关系的存储(表示)也越来越麻烦,特别是顺序存储方式是靠物理上的相邻来表示逻辑关系的,表示关系的能力很弱。因此,面对图这种复杂逻辑结构,顺序存储已经不再能满足图的存储需求。所以,图结构没有顺序存储方式。

链式存储方式是靠存储相关元素地址(指针)来表示关系的,表示关系能力很强。应该说可以存储任意复杂的逻辑关系。所以,对图结构来说,最容易想到的就是链式存储结构,即在存储数据元素的同时,用指针表示它们之间的关系。

因为每个结点的出度不都相同,所以图的结点存储形式分为定长结点和不定长结点两种,如图所示:

简单来说,定长结点就是规定每个结点出度的大小,因为空间一开始就开辟出来了,所以操作方便,但是容易出现溢出问题和存储空间冗余的问题;不定长结点,出度是多少就开辟多少个空间,所以不会出现溢出和存储空间冗余的问题,但是操作相对较为麻烦。

(2)由于图结构的复杂,其顺序存储方式不存在,而一般的链式存储又存在一些缺点。为此,提出了专门针对图结构的一些存储方式。这些存储方式的基本原则是:

①存储数据元素(一般采用顺序存储方式)

②存储(表示)数据之间的关系

(按照我的理解,就是把图分成两块存储,一块存储所有图结点的数据元素,另一块存储图结点之间的关系。)

对于②中的存储形式,主要有:用二维表表示关系的,例如邻接矩阵和关联矩阵;用指针表示关系的,例如邻接表、十字链表和邻接多重表。

(3)(顺序)存储方式:用连续的地址空间存储图的数据元素及元素之间的关系(邻接关系),如图所示:

(左边)VerticesList:一维数组,存放数据元素(顶点)

(右边)Edge:二维数组,存放数据之间的关系

至于二维数组中填的内容,如下图所示:

上面是非加权图的计算方法;下面是加权图的计算方法。

给大家稍微解释一下,其实很简单的,对于非加权图,如果两个顶点之间有关联,那么二维数组中相关的空就填1,否则填0;对于加权图,二维数组空格中填的内容为“权”的大小,如果两个顶点之间有关联,那么填二者之间权的大小,否则填无穷,如果是同一个顶点,则填零。

举例:

要注意的是,有向图中,如果a、b两点相连,那么二维表中(a,b)与(b,a)的空位中都填1;有向图中,对于a、b两点,如果只有a指向b的箭头而没有b指向a的箭头,那么二维表中(a,b)填1,(b,a)则填0。

对于无向图(非加权):

①矩阵是对称的;

②第i行或第i 列1的个数为顶点vi 的度;

③矩阵中1的个数的一半为图中边的数目;

④很容易判断顶点vi 和顶点vj之间是否有边相连;

对于有向图(非加权):

① 矩阵不一定是对称的;

② 第i 行中1的个数为顶点vi 的出度;

③ 第i列中1的个数为顶点 vi的入度;

④ 矩阵中1的个数为图中弧的数目;

⑤ 很容易判断顶点vi 和顶点vj 是否有弧相连;
类定义:

typedef 边类型 E;//边的类型(权值)
typedef 元素类型 T;//元素类型(顶点)class Graphmtx{friend istream& operator >> ( istream& in,   Graphmtx & G);    //输入 friend ostream& operator << (ostream& out, Graphmtx & G);  //输出
public:int maxVertices;  //允许图的顶点个数的最大值int numVertices;  //图的顶点数int numEdges;  //图的边数T *VerticesList;  //一维数组,存放元素(顶点)E **Edge;  //二维数组,存放邻接矩阵(关系)
public:int getVertex(T vertex);  //确定元素在图中的存储位置Graphmtx(int sz=DefaultVertices);  //构造函数~Graphmtx(){ delete [ ]VerticesList;  delete [ ]Edge; } //析构函数T getValue (int i);  //取顶点 i 的值E getWeight (T v1, T v2) ; //取边(v1,v2)上权值 T getFirstNeighbor(T v); //取顶点 v 的第一个邻接顶点 T getNextNeighbor(T v, T w); //取 v 的邻接顶点 w 的下一邻接顶点 bool insertVertex(const T vertex); //插入顶点vertex bool insertEdge(T v1, T v2, E cost); //插入边(v1, v2),权值为cost bool removeVertex(T v);  //删去顶点 v 和所有与它相关联的边 bool removeEdge(T v1, T v2); //在图中删去边(v1,v2) BFS_traversal(T v);  //图的广度遍历 DFS_traversal(T v);  //图的深度遍历
};

(4)(链式)存储方式:用连续的地址空间存储图的数据元素,用单链表(非顺序 空间)存储(表示)元素之间的邻接关系;即把元素与哪 些元素有关系通过链表表示出来。如图:

从无向图邻接表可以得到如下结论:

①第i 个链表中结点数目为顶点vi的度;

②所有链表中结点数目的一半为图中边数;

③占用的存储单元数目为n+2e 。

从有向图的邻接表可以得到如下结论:

①第i 个链表中结点数目为顶点vi的出度;

②所有链表中结点数目为图中弧数;

③占用的存储单元数目为n+e 。

类定义:

struct Edge //边结点(邻接点)的定义
{int dest;  //边的另一顶点位置E cost;  //边上的权值Edge *link;  //下一条边链指针Edge();  //构造函数Edge(int num,E cost):dest(num),weight(cost),link(NULL){};  //构造函数bool operator != (Edge& R) const { return dest != R.dest; } //判边等否
};struct Vertex  //顶点的定义
{T data;  //顶点元素Edge *adj;  //边链表的头指针
};class Graphlnk  //图的类定义
{friend istream& operator >> (istream& in, Graphlnk& G); //输入 friend ostream& operator << (ostream& out,Graphlnk & G);  //输出
private:Vertex *NodeTable;  //顶点表(各边链表的头结点)
public:int getVertexPos(const T vertx);//给出顶点vertex在图中的位置Graphlnk(int sz=DefaultVertices);//构造函数~Graphlnk();   T getValue(int i);第i个存储位置的元素值E getWeight (T v1, T v2); //取边(v1,v2)权值 bool insertVertex (const T& vertex); bool removeVertex (T v); bool insertEdge (T v1, T v2, E cost); bool removeEdge (T v1, T v2); int getFirstNeighbor(T v); int getNextNeighbor(T v, T w); BFS_traversal(T v); DFS_traversal (T v);
};

数据结构:图(一) 图的基本知识相关推荐

  1. 数据结构基础:图结构的学习笔记

    1.图的定义 图是比树更加复杂的数据结构,在图的结构当中,任意两个节点之间都有可能有直接关系,所以图中一个节点的前驱和后继的数目是没有限制的. 2.图的用途 用于描述各种复杂的数据对象,在自然科学.社 ...

  2. 关于图计算图学习的基础知识概览:前置知识点学习(PGL)[系列一]

    关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL)) 0.1图计算基本概念 首先看到百度百科定义: 图计算(Graph Processin ...

  3. Neo4j ① <图论>图,节点,关系,属性<知识图谱和图库>图谱,图库,优势<基础>模块,应用场景,环境搭建,浏览器

    目录 第一部分 图 和 Neo4j 1.1 图论 1.1.1 图论起源 --- 柯尼斯堡(Konigsberg)七桥问题 1.1.2 图 和 节点 1.1.3 节点关系表达 1.1.4 属性图模型规则 ...

  4. 【数据结构基础】图的遍历方法与应用

    前言 数据结构,一门数据处理的艺术,精巧的结构在一个又一个算法下发挥着他们无与伦比的高效和精密之美,在为信息技术打下坚实地基的同时,也令无数开发者和探索者为之着迷. 也因如此,它作为博主大二上学期最重 ...

  5. 学习数据结构--第五章:图(图的应用)

    第五章:图(图的应用) 1.最小生成树 生成树:连通图包含全部顶点的一个极小连通子图 这里需要注意的是是一个极小连通子图 上面第一个是一个连通图,右侧两个图实它的生成树,他们包含了全部顶点且是极小连通 ...

  6. A.关于图计算图学习的基础知识概览:前置知识点学习(Paddle Graph L)【一】

    图学习图神经网络算法专栏简介:主要实现图游走模型(DeepWalk.node2vec):图神经网络算法(GCN.GAT.GraphSage),部分进阶 GNN 模型(UniMP标签传播.ERNIESa ...

  7. 知识图:从图和数据库中获取知识

    知识图:从图和数据库中获取知识 知识图到底是什么,以及关于它们的所有炒作是什么?如果想成为世界各地的Airbnbs,Amazon,Google和LinkedIn,那么学会区分真实的炒作,定义不同类型的 ...

  8. 数据结构 -- 图与图存储

    我们在使用像QQ ,微信,微博,快手,抖音等社交软件的过程中经常需要添加好友,关注好友和被好友关注.这个过程中 这样的社交网络中的好友关系就需要被存储下来,存储在各个公司的后台服务器之上,都会作为每个 ...

  9. 一图看懂新一代人工智能知识体系大全

    来源:财经头条 摘要:人工智能的发展离不开基础支持层和技术层,基础支持层包括大数据.计算力和算法:技术层包括计算机视觉.语音识别和自然语言处理.人工智能的技术本质是什么,本文会详细分析. 人工智能的发 ...

  10. C++版数据结构继承关系图

    文章目录 1 C++版数据结构继承关系图 1 C++版数据结构继承关系图 http://www.plantuml.com/plantuml/png/RP0nJaCn38Ptd-AfUs_0K4JPAW ...

最新文章

  1. visual MySQL 教程_MySql轻松入门系列——第二站 使用visual studio 对mysql进行源码级调试...
  2. 在Putty或mRemote下输入和显示中文
  3. 过河卒(Noip2002)
  4. ExtJS中如何根据combobox的选值,动态地决定组件的显隐?
  5. LINUX内核完全注释
  6. stm32 薄膜键盘原理_市面上的笔记本键盘优缺点解析,看完秒懂
  7. Ubuntu下GTK的安装、编译和测试
  8. 不能All in的人别去创业公司
  9. Windows10下编译Nginx源码
  10. 内网神器-Bettercap
  11. “追光者谢崇进:如何让光通信极速飙车?
  12. 卡方值计算-python代码
  13. 忠告7 成功 = 能力 X 努力 X 态度
  14. 在机自学院自强队的这一年
  15. mac 上格式化磁盘出现MediaKit报告设备上的空间不足以执行请求的解决办法
  16. 工具分享--IDM下载工具利器,让下载速度提升一百倍
  17. CAD中插入外部参照字体会变繁体_为什么在原点附近的图纸作为外部参照插入后却离插入点很远?...
  18. 浅谈Java中类的相关内容
  19. 188. 武士风度的牛 C++ bfs(宽度优先搜索)
  20. 02-感知机 读书笔记

热门文章

  1. SpringBoot+自定义注解实现多数据源配置
  2. dataSource配置oracle,SpringBoot数据源配置DataSourceConfig
  3. Android 零基础学习之路
  4. 校招面试真题 | 实习生和应届生有什么区别?
  5. Android程序员:如何成为一个更好的Android开发者?经典好文
  6. oracle数据库锁表查询,解锁,kill缩表进程
  7. java统计string中文数字英文_Java学习(4):统计一个文件中的英文,中文,数字,其他字符以及字符总数...
  8. 萤石开放平台-怎么做账号之间的联动操作?(设备托管)
  9. 解决SendMessage函数向QQ好友发送中文消息时出现乱码
  10. 通过活动策划做精准引流