随笔 - 303  文章 - 0  评论 - 3  阅读 - 15万

数据结构之图结构

  图结构(简称为图)是一种比树结构更复杂的非线性结构(多对多关系)。在树结构中结点间具有分支层次关系,而图结构中任意两个结点之间都可能相关,即结点之间的邻接关系可以是任意的。

  讨论图结构的存储之前,介绍图的定义及其相关的术语:

  1、图的定义:图(Graph)由一个顶点集合V和一条边(或者弧)集合E组成,通常记为G=(V,E)。其中,V中有n(n>0)个顶点,E中有e(e不小于0)条边,且每一条边都依附于V中的两个顶点Vi, Vj(i,j = 1,2,……,n),该边用顶点偶对表示,记为(Vi, Vj)。

  2、无向图:在一个图中,如果任意两个顶点构成的偶对是无序的,即顶点之间的连线是没有方向的,则称该图为无向图。

      

  3、有向图:在一个图中,如果两个顶点之间的边是由方向的即构成的偶对是有序的则称该图为有向图。为了区别于无向图,有向图的边用<Vi, Vj>表示。在有向图中<Vi, Vj>和<Vj, Vi>是不同的边。有向边也称为弧,箭头一端称为弧头另一端称为弧尾。

      

  4、邻接点、邻接表:若(Vi, Vj)存在,即Vi和 Vj之间有边。互相称之为邻接点,(Vi, Vj)称为Vi, Vj邻接表。对于有向图,若<Vi, Vj>存在,称Vi邻接至 Vj,或称Vj邻接至Vi。

  5、完全图:在一个无向图中,如果任意两顶点都有一条边直接连接,则称该图为无向完全图。在一个有向图中,如果任意两个顶点之间都有方向互为相反的两条弧相连接,则称该图为有向完全图。显然,在一个含有n个顶点的无向完全图中,有n(n-1)/2条边。在一个含有n个顶点的有向完全图中,有n(n-1)条边。

  6、稠密图、稀疏图:若一个图接近完全图,称为稠密图;反之,边数很少的图称为稀疏图。

  7、顶点的度、入度、出度:顶点的度是指依附于某顶点V的边数,通常记为TD(v)。在有向图中,要区别顶点的入度与出度的概念。顶点v的入度是指以顶点v为终点的弧的数目,记为ID(v);顶点v的出度是指以顶点v为始点的弧的数目,记为OD(v)。显然,TD(v)=ID(v)+OD(v)。

  8、边的权、网图:与边有关的数据信息称为权。边上带权的图称为带权图或网图或网络(Network)。如果边是有方向的带权图则就是一个有向网图。

  9、路径和路径长度

  10、回路、简单路径、简单回路

  11、子图

  12、连通的、连通图、连通分量:在无向图中,如果从一个顶点Vi到另一个顶点Vj(i!=j)有路径,则称顶点Vi和Vj是连通的。如果图中任意两顶点都是连通的,则称该图是连通图。无向图的极大连通子图称为连通分量,对于连通图而言,连通分量就是它本身。

      

  13、强连通图、强连通分量

  14、连通图(或连通子图)的生成树:所谓连通图G的生成树就是包含G的全部n个顶点的一个极小连通子图。它必定包含且仅包含G的n-1条边。

  15、非连通图的生成森林:在非连通图中,由每个连通分量都可得到一个极小的连通子图,即一棵生成树,这些连通分量的生成树就组成了一个非连连通图的生产森林。

  涉及图的基本操作有:

    1)CreateGraph(G):建立图G的存储。

    2)DestroyGraph(G):释放图G占用的存储空间。

    3)GetVex(G, v):在图G中找到顶点v,并返回顶点v的相关信息。

    4)PutVex(G, v, value):在图G中找到顶点v,并将value值赋给顶点v。

    5)InsertVex(G,v):在图G中增添新顶点v。

    6)DeleteVex(G, v):在图G中,删除顶点v以及所有和顶点v相关联的边或弧。

    7)InsertArc(G, v, w):在图G中增添一条顶点v到顶点w的边或弧。

    8)DeleteArc(G, v, w):在图G中删除一条顶点v到顶点w的边或弧。

    9)Traverse(G, v):在图G中,从顶点v出发遍历图G。

    10)LocateVex(G, u):在图G中找到顶点u,返回该顶点在图中的存储位置。

    11)FirstAdjVex(G, v):在图G中,返回v的第一个邻接点。若顶点在G中没有邻接点则返回“空”。

    12)NextAdjVex(G, v, w):在图G中,返回v的(相对于w的)下一个邻接点。若w是v的最后一个邻接点,则返回“空”。

  在一个图中顶点是没有先后次序的,但当对它的存储中确定了顶点的次序后存储中的顶点次序构成了顶点之间的相对次序。同理,对一个顶点的邻接点也根据存储顺序觉得了第一个、第二个……的顺序。

  以上图基本操作ADT表示如下图:

    

  那么图用数据结构具体如何实现存储呢?下面介绍两种图的存储方法:

  一、邻接矩阵

    邻接矩阵法的存储基本思想是:对于图中的n个顶点采用顺序存储,不管任意两个顶点之间是否有邻接关系即是否有边,都用一个n*n的矩阵来表示。规定矩阵的元素为

      

     若G是网图,则邻接矩阵可定义为

      ,其中,Wij表示边(Vi, Vj)或<Vi, Vj>上的权值;

        

    从图的邻接矩阵存储方法容易得出这种表示具有以下特点:

      1)无向图的邻接矩阵一定是一个对称矩阵。因此在具体存放邻接矩阵时只需存放上(或下)三角矩阵的元素即可。当然,这样的存储可能会使一些操作较繁琐。

      2)对于无向图,邻接矩阵的第i行(或第i列)非零元素的个数是第i个顶点的度TD(Vi)。

      3)对于有向图,邻接矩阵的第i行(或第i列)非零元素的个数是第i个顶点的出度OD(Vi)(或入度(Vi))。

    根据邻接矩阵的存储思想可知,用邻接矩阵方法存储图很容易确定图中任意两个顶点之间是否有边相连。但是要确定图中有多少条边,则必须按行(或列)对每个元素进行检测花费的时间代价很大。这是用邻接矩阵存储图的局限性。

    根据以上的设计思想,用一个一维数组顺序存储顶点信息,用一个二维数组表示顶点间的邻接关系称之为邻接矩阵。将图的结点信息、图的邻接矩阵与图的结点数与边数封装到图的邻接矩阵存储类中定义如下,其中VertexType为图的结点类,EdgeType为图的边信息类:

      

    建立一个有向图的邻接矩阵存储的算法如下:

      

  二、邻接表

    邻接矩阵是图的顺序存储方法,邻接表是图的顺序存储与链式存储结合的存储方法。邻接表表示法类似于树的孩子链表表示法。存储思想是:每一条边用一个结点存储,把某个顶点Vi的所有邻接表(有向图中以Vi为弧尾)链接成一个单链表;同时将该单链表的头位置和这个顶点的信息作为顶点结点一次顺序存储起来,就构成了图的邻接表。

     在邻接表表示中有两个结点结构,如图示:

      

     一种是顶点结点结构,它由顶点域(vertex)和指向第一条邻接表的位置域(firstedge)构成;另一种是边(即邻接表)结点结构,它由邻接点域(adjvex)和指向下一条邻接边的位置域(next)构成。

    边的存储应注意以下两点:

    1)一条边由两个顶点构成,在边结点中却只有一个顶点的信息,这是因为在同一个链表中的边都是该点的邻接边即这些边和同一个顶点相关联,因此就省略了该顶点,只存储了它的邻接点。

    2)存放的是顶点的序号而不是顶点的信息,顶点的信息只存放在顶点结点的顶点域中。

      

     对于网图的边结点可根据需要再增设一个存储边上信息(如权值等)的域(info),网图的边结点结构如下图示:

      

     根据上述思想设计的采用邻接表表示图可定义为如下的类:

      

    建立一个有向图的邻接表存储的算法如下:

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

 

posted on   池塘里洗澡的鸭子  阅读(868)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示