图的定义与存储结构

图的定义与基本术语

图的定义

图(Graph)是一种网状数据结构。
形式化定义如下:

Graph=(V,R)
V={x∣x ∈ DataObject}
R={VR}
VR={<x,y>∣P(x,y)∧(x,y∈V)} 

DataObject为具有相同特性元素的集合。
V中的数据元素通常称为顶点
VR是两个顶点之间的关系的集合
P(x,y)表示x和y之间有特定的关联属性P;
若<x,y>∈VR,则<x,y>表示从顶点x到顶点y的一条
并称x为弧尾或起始点,称y为弧头或终端点。
若图中的边是有方向的,称这样的图为有向图
若<x,y>∈VR,必有<y,x>∈VR,即VR是对称关系,这时以无序对(x,y)来代替两个有序对,表示x和y之间的一条,此时的图称为无向图

在这里插入图片描述
顶点位置:
可以将任一顶点看成是图的第一个顶点,同理,对于任一顶点而言,它的邻接点之间也不存在顺序关系。顶点在这个人为的随意排列中的位置序号称为顶点在图中的位置。

基本术语

1、完全图,稀疏图与稠密图

设用n表示图中顶点的个数,用 e表示图中边或弧的数目,不考虑图中每个顶点到其自身的边或弧。
无向完全图
图中每个顶点和其余n-1个顶点都有边相连(边数:n(n-1)/2)的无向图。
有向完全图
图中每个顶点和其余n-1个顶点都有弧相连(弧数:n(n-1))的有向图。
稀疏图
对于有很少条边的图(e < n log n)称为稀疏图,反之称为稠密图

2、子图:
设有两个图G=(V,{E})和图G’=(V’,{E`}),若V’⊆V且E’ ⊆ E,则称图G’为G的子图。

在这里插入图片描述
3、邻接点
对于无向图 G=(V,{E}),如果边(v,v’)∈E,则称顶点v,v’互为邻接点,即v,v’ 相邻接。边(v,v’)依附于顶点v和v’,或者说边(v,v’)与顶点v和v’ 相关联
对于有向图G=(V,{A})而言,若弧<v,v’>∈A,则称顶点v邻接到顶点v’,顶点v’ 邻接自顶点v,或者说弧<v,v’>与顶点v,v’相关联。

4、度、入度和出度
对于无向图而言,顶点v的度是指和v相关联边的数目,记作TD(v)
对于有向图而言,顶点v的度有入度出度两部分,其中以顶点v为弧头的弧的数目称为该顶点的入度,记作ID(v),以顶点v为弧尾的弧的数目称为该顶点的出度,记作OD(v),顶点v的度为TD(v)=ID(v)+OD(v)
一般的,若图G中有n个顶点,e条边或弧,则图中顶点的度与边的关系如下:
e = ( ∑ i = 1 n T D ( v i ) ) / 2 e=(\displaystyle\sum_{i=1}^{n} TD(v_i))/2 e=(i=1nTD(vi))/2.

5、权与网
在实际应用中,图的边或弧上往往与具有一定意义的数有关,即每一条边都有与它相关的数,称为,将带权的图叫做赋权图

在这里插入图片描述
6、路径与回路
路径
无向图G =(V,{E})中从顶点v到v’的路径是一个顶点序列vi0,vi1,vi2,…,vin,其中(vij-1,vij)∈E,1≤j≤n。
如果图G是有向图,则路径也是有向的,顶点序列应满足<vij-1,vij>∈A,1≤j≤n。
路径长度
路径上经过的弧或边的数目。
回路
一个路径中,若第一个顶点和最后一个顶点相同,即v =v’。
简单路径
路径的顶点序列中的顶点各不相同。
简单回路
除了第一个和最后一个顶点外,其余各顶点均不重复出现的回路。

7、连通图
连通图
无向图G =(V, {E})中,若从vi到vj有路径相通,则称顶点vi与vj是连通的。如果图中任意两个顶点vi、vj∈V,vi,vj都是连通的,则称该无向图G为连通图。
连通分量
无向图中的极大连通子图。
强连通图
在有向图G=(V,{A})中,对于每对顶点vi、vj∈V且vi ≠ vj,从vi到vj和vj到vi都有路径。
强连通分量
有向图的极大强连通子图称作有向图的强连通分量。
生成树
一个连通图的生成树是指一个极小连通子图,它含有图中的全部顶点,但只有足已构成一棵树的n-1条边。两顶点间有且仅有一条路径。

在这里插入图片描述
在这里插入图片描述

图的存储结构

1、邻接矩阵表示法

也称作数组表示法。采用两个数组来表示图:
一维数组:存储顶点信息;
二维数组(邻接矩阵):存储图中顶点之间关联关系。

无权图邻接矩阵:
A [ i , j ] = { 1 , 若<Vi,Vj>或(Vi,Vj)∈VR 0 , 反之 A[i,j] = \begin{cases} 1, & \text{若<Vi,Vj>或(Vi,Vj)∈VR} \\ 0, & \text{反之} \end{cases} A[i,j]={1,0,<Vi,Vj>(Vi,Vj)∈VR反之
在这里插入图片描述
在这里插入图片描述
无向图的邻接矩阵是对称的。

网的邻接矩阵:

A [ i , j ] = { W i j , 若<Vi,Vj>或(Vi,Vj)∈VR ∞ , 反之 A[i,j] = \begin{cases} Wij, & \text{若<Vi,Vj>或(Vi,Vj)∈VR} \\ ∞, & \text{反之} \end{cases} A[i,j]={Wij,,<Vi,Vj>(Vi,Vj)∈VR反之

在这里插入图片描述

描述:

#define MAX_VERTEX_NUM 10      /*最多顶点个数*/
#define INFINITY 32768         /*表示极大值,即∞*/

//图的种类:DG:有向图, DN:向网, UDG表示无向图, UDN表示无向网
typedef enum{DG, DN, UDG, UDN}  GraphKind;
typedef char VertexData;    /*假设顶点数据为字符型*/
typedef struct ArcNode{
 	AdjType adj; /*无权图用1、0表示邻接;带权图则为权值类型*/
	OtherInfo info;
} ArcNode;

typedef struct
{  	VertexData vexs[MAX_VERTEX_NUM];   /*顶点向量*/
   	ArcNode arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  /*邻接矩阵*/
   	int vexnum, arcnum;          /*图的顶点数和弧数*/
   	GraphKind kind;                /*图的种类标志*/
} AdjMatrix;  

存储特点:

  1. 存储空间:
    无向图:邻接矩阵对称,可采用压缩存储法(下三角),其存储空间只需n(n-1)/2;
    有向图:弧有方向,邻接矩阵不一定是对称矩阵,需要 n 2 n^2 n2个存储空间。
  2. 便于运算:
    根据 Aij = 0/1 判定图中任意两个顶点之间是否有边;
    便于求得各个顶点的度。

顶点的度:
无向图:
第i个顶点的度 = 第i行元素之和, T D ( v i ) = ∑ j = 1 n A i j TD(v_i)=\displaystyle\sum_{j=1}^{n}A_{ij} TD(vi)=j=1nAij.
有向图:
第i个顶点的出度 = 第i行元素之和, O D ( v i ) = ∑ j = 1 n A i j OD(v_i)=\displaystyle\sum_{j=1}^{n}A_{ij} OD(vi)=j=1nAij.
第i个顶点的入度 = 第i列元素之和, I D ( v i ) = ∑ j = 1 n A i j ID(v_i)=\displaystyle\sum_{j=1}^{n}A_{ij} ID(vi)=j=1nAij.

基本操作:
采用邻接矩阵存储法,很便于实现图的一些基本操作,如 FirstAdjVertex(G,v):
1)由LocateVertex(G,v)找到 v 在图中的位置,即 v 在一维数组 vexs 中的序号i。
2)二维数组 arcs 中第i行上第一个 adj 域非零的分量所在的列号j,便是 v 的第一个邻接点在图 G 中的位置。
3)取出一维数组vexs[j]中的数据信息。
注意:稀疏图不适于用邻接矩阵来存储,会造成存储空间的浪费。

创建有向图:

int LocateVertex(AdjMatrix * G, VertexData v)  /*求顶点位置函数*/
{
	int j=Error,k;
	for(k=0;k<G->vexnum;k++)
		if(G->vertex[k]==v)
		{  j=k; break;  }
	return j;
}

int CreateDN(AdjMatrix *G) 
{  /*创建一个有向网*/
   int i, j, k, weight; VertexData v1, v2;
   scanf("%d,%d",&G->arcnum, &G->vexnum);       		/*输入顶点数和弧数*/
   for(i = 0; i < G->vexnum; i++)
      for(j = 0; j < G->vexnum; j++)
          G->arcs[i][j].adj=INFINITY;	/*邻接矩阵初始化*/
   for(i = 0; i < G->vexnum; i++)
      scanf("%c", &G->vexs[i]);  	/* 输入图的顶点*/
   for(k = 0; k < G->arcnum; k++)
   {
    	scanf("%c,%c,%d", &v1, &v2, &weight);   	/*输入一条弧的两个顶点及权值*/
    	i = LocateVex_M(G, v1);	
	    j = LocateVex_M(G, v2); 
	    G->arcs[i][j].adj = weight;  	/*建立弧*/
    } 
   return(Ok);
} 

时间复杂度为O( n 2 n^2 n2+e×n);
O( n 2 n^2 n2)为二维数组arcs初始化。O(e×n)为边权赋值。

2、邻接表表示法

稀疏图用邻接矩阵表示法会造成空间浪费。
邻接表表示法是图的一种链式存储结构,基本思想是只存有关联的信息,一个n个顶点的图的邻接表表示由表头结点表边表两部分构成。

表头结点表:

所有表头结点以顺序结构(向量)的形式存储,以便可以随机访问任一顶点的单链表。
数据域(vexdata):存储顶点的名或其它有关信息;
链域(firstarc):指向链表中第一个顶点(即与顶点vi邻接的第一个邻接点)。

在这里插入图片描述

边表:
由表示图中顶点间邻接关系的n个边链表组成。
邻接点域(adjvex):存放与顶点vi相邻接的顶点在图中的位置;
链域(nextarc):指向与顶点vi相关联的下一条边或弧的结点;
数据域(info):存放与边或弧相关的信息(如赋权图中每条边或弧的权值等)。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
类似树的孩子表示法。

定义:

#define MAX_VERTEX_NUM 10            /*最多顶点个数*/
typedef enum{DG, DN, UDG, UDN} GraphKind; /*图种类*/
typedef struct ArcNode{
	int adjvex;     		/*该弧指向顶点的位置*/
    struct ArcNode *nextarc; /*指向下一条弧的指针*/
    OtherInfo info;       	/*与该弧相关的信息*/
} ArcNode; 

typedef struct VertexNode{
  	VertexData data;        /*顶点数据*/
    ArcNode *firstarc;    	/*指向该顶点第一条弧的指针*/
} VertexNode; 

typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];   
    int vexnum, arcnum;       /*图的顶点数和弧数*/
    GraphKind kind;          /*图的种类标志*/
}AdjList;           /*基于邻接表的图(Adjacency List Graph)*/ 

存储空间:
n个顶点,e条边的无向图,需要n个表头结点和2e个表结点。
无向图的度:
顶点vi的度恰好就是第i个边链表上结点的个数。
有向图的度:
第i个边链表上顶点的个数是顶点的出度。
要求顶点vi的入度,则必须遍历整个邻接表。在所有单链表中查找邻接点域的值为i的结点并计数求和。

逆邻接表法:(解决求入度不方便的问题)
可对图中的每一顶点vi建立一个逆邻接表;
对每个顶点vi建立一个所有以顶点vi为弧头的弧的表;
顶点vi的入度是逆邻接表中第i个顶点的边链表中结点个数。
在这里插入图片描述

在这里插入图片描述
3、十字链表

十字链表(Orthogonal List)是有向图的另一种链式存储结构,可以看成将有向图的邻接表逆邻接表结合起来形成的一种链表。
① 每条弧对应一个弧结点;
② 每个顶点对应一个顶点结点,顺序存储。

在这里插入图片描述
有向图G1的十字链表:

在这里插入图片描述
建立有向图的十字链表算法:

void  CrtOrthList(OrthList g)
{/*输入n个顶点和e条弧信息,建立有向图十字链表*/
   scanf(%d,%d”, &n, &e);/*键盘输入图的顶点个数和弧的个数*/
   for(i = 0; i < n; i++)
    {//结点顺序表初始化
    	scanf(%c”, g.vertex[i].data);   
    	g.vertex[i].firstin = g.vertex[i].firsout = NULL}
   for (k = 0; k < e; k++)
    {//建弧链表
	    scanf(%c,%c”, &vt, &vh);    
	    i = LocateVertex(g,vt);
	    j = LocateVertex(g,vh);
    	p = (ArcNode *)malloc(sizeof(ArcNode));  
    	p->tailvex=i;p->headvex=j;//确定弧头尾
    	p->tlink = g.vertex[i].firstout;
    	g.vertex[i].firstout =p;//头插法
    	p->hlink = g.vertex[j].firstin;
    	g.vertex[j].firstin =p;
    }
}/* CrtOrthList */ 

采用十字链表作为存储结构,很容易求出顶点的度。
既容易找到以顶点为尾的弧,也容易找到以顶点为头的弧。

4、邻接多重表

能够提供更为方便的边处理信息。
将图中关于一条边的信息用一个结点来表示;
提供标志域标记边是否被搜索过。

结构类型说明:

typedef struct EdgeNode {
	int mark, ivex, jvex;
	struct EdgeNode *ilink, *jlink;
}EdgeNode;

typedef struct {
    VertexData data;
    EdgeNode *firstedge;
}VertexNode;

typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];   
   	int vexnum, arcnum;      /*图的顶点数和弧数*/
    GraphKind kind;          /*图的种类*/
} AdjMultiList; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值