数据结构 - 图的存储结构

图的抽象数据类型定义

图是一种数据结构,加上一组基本操作就构成了图的抽象数据类型。
图的抽象数据类型定义如下:
ADT Graph{
数据对象V:具有相同特性的数据元素的集合,称为顶点集。
数据关系R:R={VR}
VR={<v,w>|<v,w>| v,w?V∧p(v,w) ,<v,w>表示                                     从v到w的弧,P(v,w)定义了弧<v,w>的信息 }
基本操作P:
Create_Graph() : 图的创建操作。
初始条件:无。
     操作结果:生成一个没有顶点的空图G。GetVex(G, v) : 求图中的顶点v的值。
初始条件:图G存在,v是图中的一个顶点。
操作结果:生成一个没有顶点的空图G。
… …
DFStraver(G,V):从v出发对图G深度优先遍历。
    初始条件:图G存在。
    操作结果:对图G深度优先遍历,每个顶点访问且只访问一次。
          ? ?
BFStraver(G,V):从v出发对图G广度优先遍历。
      初始条件:图G存在。
      操作结果:对图G广度优先遍历,每个顶点访问且只访问一次。
} ADT Graph

图的存储结构

  图的存储结构比较复杂,其复杂性主要表现在:

◆ 任意顶点之间可能存在联系,无法以数据元素在存储区中的物理位置来表示元素之间的关系,所以不能用简单的顺序存储结构来表示。

◆ 图中顶点的度不一样,有的可能相差很大,若按度数最大的顶点设计结构,则会浪费很多存储单元,反之按每个顶点自己的度设计不同的结构,又会影响操作。

图的常用的存储结构有:邻接矩阵、邻接链表、十字链表、邻接多重表和边表。

邻接矩阵(数组)表示法

  图的邻接矩阵基本思想:用两个数组来表示图:一个一维数组存储顶点信息,一个二维数组存储边或弧的信息。该二维数组称为邻接矩阵。

无权图邻接矩阵的特点

无向图邻接矩阵的特性

邻接矩阵是对称方阵;

对于顶点vi,其度数是第i行的非0元素的个数;

无向图的边数是上(或下)三角形矩阵中非0元素个数。

无向图的邻接矩阵中非零元个数 = 2*无向图边数

有向图邻接矩阵的特性

对于顶点vi,第i行的非0元素的个数是其出度OD(vi);第i列的非0元素的个数是其入度ID(vi) 。

邻接矩阵中非0元素的个数就是图的弧的数目。

3 图的邻接矩阵的创建

图的邻接矩阵的实现比较容易,定义两个数组分别存储顶点信息(数据元素)和边或弧的信息(数据元素之间的关系) 。其存储结构形式定义如下:


#define MAXVEX 100         /* 最大顶点数,应由用户定义 */
#define INFINITY 65535

typedef char VertexType; /* 顶点类型应由用户定义  */
typedef int EdgeType; /* 边上的权值类型应由用户定义 */
typedef struct
{
   VertexType vexs[MAXVEX];     /* 顶点表 */
   EdgeType arc[MAXVEX][MAXVEX]; /* 邻接矩阵,可看作边表 */
   int numVertexes, numEdges; /* 图中当前的顶点数和边数  */
}MGraph;
(1)  图的创建
/* 建立无向网图的邻接矩阵表示 */
void CreateMGraph(MGraph *G)
{
    输入顶点数numVertexes和边数numEdges ;
    for(i = 0;i <G-> numVertexes;i++)
               读入顶点信息,建立顶点表
    for(i = 0;i <G-> numVertexes;i++)
         for(j = 0;j <G-> numVertexes;j++)
               G->arc[i][j]=INFINITY;/* 邻接矩阵初始化 */
    for(k = 0;k <G->numEdges;k++)
                    读入numEdges条边,建立邻接矩阵
}
   其他操作

(2) 图的顶点定位

确定一个顶点在vexs数组中的位置(下标) ,其过程完全等同于在顺序存储的线性表中查找一个数据元素。

根据下标,读出顶点信息。

(3) 向图中增加顶点

类似在顺序存储的线性表的末尾增加一个数据元素。

(4) 向图中增加一条弧

根据给定的弧或边所依附的顶点,修改邻接矩阵中所对应的数组元素。

邻接链表法

基本思想:数组与链表相结合。

具体办法:

顶点用一个一维数组存储,每个数据元素还需要存储指向第一个邻接点的指针。

每个顶点vi的所有邻接点构成一个单链表,无向图称为顶点vi的边(链)表,有向图称为顶点vi作为弧尾的出边表(或作为弧头的入边表

邻接表的相关操作

求某结点的度,只需查找该顶点的边表中结点的个数(或者直接将顶点结点的结构再增加一项,用以存储其邻接点的个数);

判断顶点vi到vj是否存在边,检查顶点vi的边表中是否存在结点vj的下标j即可;

求顶点的所有邻接点,只需对该顶点的边表进行遍历即可。

注:在无向图的邻接表中,边表结点的个数=2 * 边数

2 邻接表法的特点

◆ 在边或弧稀疏的条件下,用邻接表表示比用邻接矩阵表示节省存储空间;

◆ 在无向图,顶点Vi的度是第i个链表的结点数;

◆ 对有向图可以建立正邻接表或逆邻接表。正邻接表是以顶点Vi为出度(即为弧的起点)而建立的邻接表;逆邻接表是以顶点Vi为入度(即为弧的终点)而建立的邻接表;

◆ 在有向图中,第i个链表中的结点数是顶点Vi的出 (或入)度;求入 (或出)度,须遍历整个邻接表;

3  结点及其类型定义
#define MAX_VEX  30              /*  最大顶点数  */
typedef char VertexType; /* 顶点类型应由用户定义 */
typedef int EdgeType;      /* 边上的权值类型应由用户定义 */

typedef struct EdgeNode  /* 边表结点  */
{
    int adjvex;    /* 邻接点域,存储该顶点对应的下标 */
    EdgeType info;   /* 用于存储权值,对于非网图可以不需要 */
    struct EdgeNode *next; /* 链域,指向下一个邻接点 */
}EdgeNode;
typedef struct VertexNode /* 顶点表结点 */
{
    VertexType data;          /* 顶点域,存储顶点信息 */
    /*  int  indegree ;    //顶点的度, 有向图是入度或出度       (亦可不要) */
    EdgeNode *firstarc;   /* 边表头指针 */
}VertexNode, AdjList[MAX_VEX];

typedef struct
{
    AdjList adjList;  //顶点数组(亦成为头结点向量)
    int numNodes,numEdges; /* 图中当前顶点数和边数 */
}GraphAdjList;

利用上述的存储结构描述,可方便地实现图的基本操作。


(1)  图的创建     /* 建立图的邻接表结构 */
void  CreateALGraph(GraphAdjList *G)
{     输入顶点数G->numNodes和边数G->numEdges
      for(i = 0;i < G->numNodes;i++)
            读入顶点信息   G->adjList[i].data,
                                     G->adjList[i].firstedge)/* 将边表置为空表 */
     for(k = 0;k < G->numEdges;k++) /* 建立边表 */
    {     输入边(vi,vj)上的顶点序号;
          向内存申请空间,生成边表结点;
          将新生成的结点插入到以顶点vi为头结点的链表上;
       ( 用头插入法or尾插入法方便?)
          此处需注意:如果是无向图,一条边对应两个顶点,所以应同时修正以vi为头结点和以vj为头结点的链表。
     }
}

其他操作:

(2) 图的顶点定位

图的顶点定位实际上是确定一个顶点在AdjList数组中的某个元素的data域内容。

(3) 向图中增加顶点

向图中增加一个顶点的操作,在AdjList数组的末尾增加一个数据元素。

(4) 向图中增加一条弧

根据给定的弧或边所依附的顶点,修改单链表:无向图修改两个单链表;有向图修改一个单链表。

十字链表法

十字链表(Orthogonal List)是有向图的另一种链式存储结构,是将有向图的正邻接表和逆邻接表结合起来得到的一种链表。

在这种结构中,每条弧的弧头结点和弧尾结点都存放在链表中,并将分别组织到以弧尾结点为头(顶点)结点和以弧头结点为头(顶点)结点的链表中。

◆  data域:存储和顶点相关的信息;
◆ firstin:指向以该顶点为弧头的第一条弧所对应的弧结点;
◆ firstout:指向以该顶点为弧尾的第一条弧所对应的弧结点;

◆ tailvex:指示弧尾顶点在顶点表中的下标;
◆ headvex:指示弧头顶点在顶点表中的下标;
◆ hlink:指向弧头相同的下一条弧;
◆ tlink:指向弧尾相同的下一条弧;
◆ Info域:指向该弧的相关信息,如网的权值
结点类型定义
#define INFINITY  MAX_VAL     /* 最大值∞ */
#define MAX_VEX  30     //  最大顶点数
typedef struct ArcNode
{   int  tailvex , headvex ;   //  尾结点和头结点在顶点表中的下标;
InfoType    info  ;          // 与弧相关的信息, 如权值
struct ArcNode  *hlink , *tlink ;
}ArcNode ;    /*  弧结点类型定义   */
typedef struct VexNode
{  VexType  data;     // 顶点信息
ArcNode  *firstin , *firstout ;
}VexNode ;    /*  顶点结点类型定义   */
typedef struct
{  int vexnum ;
VexNode  xlist[MAX_VEX] ;
}OLGraph ;   /*  图的类型定义   */

邻接多重表(Adjacency Multilist)

       邻接多重表(Adjacency Multilist)是无向图的另一种链式存储结构。
       在无向图的邻接表中,一条边(v,w)的两个表结点分别被选在以v和w为头结点的链表中。如果关注的重点是顶点,则邻接表是不错的选择,但在涉及到边的操作会带来不便。
      邻接多重表的结构和十字链表类似,每条边用一个结点表示;邻接多重表中的顶点结点与邻接表中的完全相同

Data域:存储和顶点相关的信息;

firstedge:指向依附于该顶点的第一条边所对应的表结点;

mark:用以标识该条边是否被访问过;

ivex和jvex:分别保存该边所依附的两个顶点在顶点表中的下标;

info域:保存该边的相关信息;

ilink:指向依附于顶点ivex的下一条边;

jlink:指向依附于顶点jvex的下一条边;

结点类型定义
#define INFINITY  65535     /* 最大值∞ */
#define MAX_VEX  30     /*  最大顶点数  */
typedef  emnu {unvisited , visited}  Visitting ;
typedef struct EdgeNode
{  Visitting  mark ;    // 访问标记
int  ivex , jvex  ;   // 该边依附的两个结点在图中的位置
InfoType    info  ;       // 与边相关的信息, 如权值
struct EdgeNode  *ilink , *jlink ;
// 分别指向依附于这两个顶点的下一条边
}EdgeNode ;    /*  弧边结点类型定义   */
typedef struct VexNode
{  VexType  data;     // 顶点信息
ArcNode  *firsedge ;   //指向依附于该顶点的第一条边
}VexNode ;    /*  顶点结点类型定义   */
typedef struct
{  int vexnum ;
VexNode mullist[MAX_VEX] ;
}AMGraph ;

图的边表存储结构

在某些应用中,有时主要考察图中边的权值以及所依附的两个顶点,即图的结构主要由边来表示,称为边表存储结构。

边表结构采用顺序存储,用2个一维数组构成,一个存储顶点信息,一个存储边的信息。边数组的每个元素由三部分组成:

边的起点下标

边的终点下标

边的权值

边表存储结构的形式描述如下:
#define INFINITY  MAX_VAL     /* 最大值∞ */
#define MAX_VEX  30     /*  最大顶点数  */
#define MAX_EDGE  100     /*  最大边数  */
typedef struct ENode
{  int  begin , end  ;   /*   边所依附的两个顶点  */
WeightType    weight  ;       /*   边的权值   */
}ENode ;    /*  边表元素类型定义   */
typedef struct
{  int  vexnum , edgenum ;     /*   顶点数和边数    */
VexType  vexs[MAX_VEX] ;    /*   顶点表    */
ENode  edges[MAX_EDGE] ;     /*   边表    */
}ELGraph ;
时间: 2024-10-22 22:50:38

数据结构 - 图的存储结构的相关文章

数据结构 - 图的存储结构表示及其遍历 (DFS &amp;&amp; BFS)

1.邻接矩阵表示的图结构 /* 邻接矩阵表示的图结构 */ #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <queue> #include <stack> using namespace std; typedef char VertexType; //顶点类型应由用户定义 typedef int EdgeType; /

java 数据结构 图中使用的一些常用算法 图的存储结构 邻接矩阵:图的邻接矩阵存储方式是用两个数组来标示图。一个一位数组存储图顶点的信息,一个二维数组(称为邻接矩阵)存储图中边或者弧的信息。 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 实例如下,左图是一个无向图。右图是邻接矩阵表示:

以下内容主要来自大话数据结构之中,部分内容参考互联网中其他前辈的博客. 图的定义 图是由顶点的有穷非空集合和顶点之间边的集合组成,通过表示为G(V,E),其中,G标示一个图,V是图G中顶点的集合,E是图G中边的集合. 无边图:若顶点Vi到Vj之间的边没有方向,则称这条边为无项边(Edge),用序偶对(Vi,Vj)标示. 对于下图无向图G1来说,G1=(V1, {E1}),其中顶点集合V1={A,B,C,D}:边集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)}: 有向图:若

数据结构之图(一)图的存储结构

图的存储结构相对于线性表和树来说更为复杂,因为图中的顶点具有相对概念,没有固定的位置.那我们怎么存储图的数据结构呢?我们知道,图是由(V, E)来表示的,对于无向图来说,其中 V = (v0, v1, ... , vn),E = { (vi,vj) (0 <=  i, j <=  n且i 不等于j)},对于有向图,E = { < vi,vj > (0 <=  i, j <=  n且i 不等于j)}.V是顶点的集合,E是边的集合.所以我们只要把顶点和边的集合储存起来,那么

数据结构(五)图---图的存储结构5种

一:图的抽象数据类型 ADT 图(Graph) Data 顶点的有穷非空集合和边的集合 Operation CreateGraph(*G,V,VR):按照顶点集V和边弧集VR的定义构造图G DestroyGraph(*G):图G存在则销毁 LocateVex(G,u):若图G中存在顶点u,则返回图中位置 GetVex(G,v):返回图中顶点v的值 PutVex(G,v,value):将图G中顶点v赋值给value FirstAdjVex(G,*v):返回顶点v的一个邻接顶点,若顶点在G中无邻接顶

《大话数据结构》笔记(7-2)--图:存储结构

第七章  图 图的存储结构 图不能用简单的顺序存储结构来表示. 而多重链表的方式,即以一个数据域和多个指针域组成的结点表示图中的一个顶点,尽管可以实现图结构,但是会有问题,比如若各个顶点的度数相差很大,按度数最大的顶点设计结点结构会造成很多存储单元的浪费,而若按每个顶点自己的度数设计不同的顶点结构,又带来操作的不便. 对于图来说,如何对它实现物理存储是个难题.图有以下五种不同的存储结构. 邻接矩阵 图的邻接矩阵(Adjacency Matrix)存储方式使用过两个数组来表示图.一个一维数组存储图

(转)数据结构之图(存储结构、遍历)

一.图的存储结构 1.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 看一个实例,下图左就是一个无向图. 从上面可以看出,无向图的边数组是一个对称矩阵.所谓对称矩阵就是n阶矩阵的元满足aij = aji.即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的. 从这个矩阵中,很容易知道图中的信息. (1)要判断任意两顶点是否有

图的存储结构(邻接矩阵)

图的存储结构(邻接矩阵) 让编程改变世界 Change the world by program 图的存储结构 图的存储结构相比较线性表与树来说就复杂很多. 我们回顾下,对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放.树结构是一对多的关系,所以我们要将数组和链表的特性结合在一起才能更好的存放. 那么我们的图,是多对多的情况,另外图上的任何一个顶点都可以被看作是第一个顶点,任一顶点的邻接点之间也不存在次序关系. 我们仔细观察以下几张图,然后深刻领悟一下: 因为任意两个顶点之间都可能

图的存储结构及遍历

一.图的存储结构 1.1 邻接矩阵 图的邻接矩阵存储方式是用两个数组来表示图.一个一维数组存储图中顶点信息,一个二维数组(邻接矩阵)存储图中的边或弧的信息. 设图G有n个顶点,则邻接矩阵是一个n*n的方阵,定义为: 看一个实例,下图左就是一个无向图. 从上面可以看出,无向图的边数组是一个对称矩阵.所谓对称矩阵就是n阶矩阵的元满足aij = aji.即从矩阵的左上角到右下角的主对角线为轴,右上角的元和左下角相对应的元全都是相等的. 从这个矩阵中,很容易知道图中的信息. (1)要判断任意两顶点是否有

数据--第41棵 - 图的存储结构

第41棵 - 图的存储结构 1. 邻接矩阵法 用一维数组存储顶点--描述顶点相关的数据. 用二维数组存储边--描述顶点的边. 设图A = (V,E)是一个有n个顶点的图,图的邻接矩阵为Edge[n][n],则:Edge[i][j] = W,W>0,i和j连接:Edge[i][j] = 0,i == j 或者i和j不链接. 注:W为权值,当需要权值时,取W为1表示结点间连接. 无向图的邻接矩阵是对称的. 有向图的邻接矩阵可能是不对称的. 2. 邻接矩阵法的头结点 记录定点的个数. 记录与顶点相关的