图的基本概念和存储结构

图的基本概念和存储结构

回顾:
在这里插入图片描述

图的基本概念

  • 图的定义和术语

图:G=(V,E)
  V:顶点(数据元素)的有穷非空集合
  E:边的有穷集合

无向图——每条边都是无方向的
有向图——每条边都是有方向的

完全图——任意两个点都有一条边相连
无向完全图——n个顶点,有 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2条边
有向完全图——n个顶点,有 n ( n − 1 ) n(n-1) n(n1)条边

稀疏图——有很少边的弧的图(e<nlogn)
稠密图——有较多边或弧的图
网——边/弧带权的图
邻接——有边/弧相连的两个顶点之间的关系。存在 ( v i , v j ) (v_i,v_j) (vi,vj),则称 v i v_i vi v j v_j vj互为邻接点;存在 < v i , v j > <v_i,v_j> <vi,vj>,则称 v i v_i vi邻接到 v j v_j vj, v j v_j vj邻接于 v i v_i vi.
关联(依附)——边/弧与顶点之间的关系。存在 ( v i , v j ) / < v i , v j > (v_i,v_j)/<v_i,v_j> (vi,vj)/<vi,vj>,则称该边/弧关联于 v i v_i vi v j v_j vj.

顶点的度——与该点相关联的边的数目,记为TD(v)
在有向图中,顶点的度等于该顶点的入度与出度之和。
顶点v的入度是以v为终点的有向边的条数,记作ID(v)
顶点v的出度是以v为始点的有向边的条数,记作OD(v)

在这里插入图片描述


路径——接续的边构成的顶点序列
路径长度——路径上边或弧的数目/权值之和。
回路(环)——第一个顶点和最后一个顶点相同的路径
简单路径——除路径起点和终点可以相同外,其余顶点均不相同的路径
简单回路(简单环)——除路径起点和终点相同外,其余顶点均不相同的路径。

在这里插入图片描述

连通图(强连通图)——在无(有)向图G=(V,{E})中,若对任何两个顶点v,u都存在从v到u的路径,则称G是连通图(强连通图)。


权与网——图中边或所具有的相关数称为权。表明从一个顶点到另一个顶点的距离或耗费。带权的图称为网。
子图——设有两个G=(V,{E})、G1=(V1,{E1}),若V1 ⊆ \subseteq V,E1 ⊆ \subseteq E,则称G1是G的子图。

连通分量(强联通分量)

  • 无向图G的极大连通子图称为G的连通分量。
    极大连通子图意思是:该子图是G连通子图,将G的任何不在该子图中的顶点加入,子图不在连通。
  • 有向图G的极大强连通子图称为G的强连通分量
    极大强连通子图意思是:该子图是G的强连通子图,将D的任何不在该子图中的顶点加入,子图不在是强连通的

极小连通子图——该子图是G的连通子图,在该子图中删除任何一条边的子图不在连通。
生成树——包含无向图G所有顶点的极小连通子图。
生成森林——对非连通图,由各个连通分量的生成树的集合。

图的存储结构

图的逻辑关系——多对多

图没有顺序存储结构,但可以借助二维数组来表示元素间的关系——邻接矩阵
链式存储结构——多重链表(邻接表、邻接多重表、十字链表)

邻接矩阵的存储方法

  • 建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间的关系)。

设图A=(V,E)有n个顶点,则顶点表Vexs[n]

i012n-1
Vexs[i] v 1 v_1 v1 v 2 v_2 v2 v 3 v_3 v3 V n V_n Vn

图的邻接矩阵是一个二维数组A.arcs[n][n],定义为:

A . a r c s [ i ] [ j ] = { 1 , 如 果 < i , j > ∈ E 或 者 ( i , j ) ∈ E 0 , 否 则 A.arcs[i][j] = \begin{cases} 1, & 如果 < i,j> \in E 或者 (i,j) \in E \\ 0, & 否则 \\ \end{cases} A.arcs[i][j]={1,0,<i,j>E(i,j)E


  • 例子:

无向图的邻接矩阵:

在这里插入图片描述

有向图的邻接矩阵

在这里插入图片描述

网的邻接矩阵

A . a r c s [ i ] [ j ] = { W i , j , 如 果 < i , j > 或 者 ( i , j ) ∈ V R ∞ , 无 边 ( 弧 ) A.arcs[i][j] = \begin{cases} W_{i,j}, & 如果 <i,j> 或者 (i,j) \in VR \\ \infty, & 无边(弧) \\ \end{cases} A.arcs[i][j]={Wi,j,,<i,j>(i,j)VR

在这里插入图片描述


  • 邻接矩阵的存储表示——用两个数组分别存储顶点表和邻接矩阵
#define MaxInt 32767 //表示极大值 
#define MVNum 100 //最大顶点数
typedef char VerTexType; //顶点的数据类型定义
typedef int ArcType; //权值数据类型定义
typedef struct {
    VerTexType vexs[MVNum]; //顶点表
    ArcType arc[MVNum][MVNum]; //邻接矩阵
    int vexnum,arcnum; //图的当前点数和边数
}AMGraph; 

  • 采用邻接矩阵表示法创建无向网

无 向 网 { 无 向 图 有 向 图 有 向 网 无向网 \begin{cases} 无向图 \\ 有向图 \\ 有向网 \\ \end{cases}

算法思想:
1.输入总顶点数和总边数。
2.依次输入点的信息存入顶点表中。——vexs[i]
3.初始化邻接矩阵,使每个权值初始化为极大值。
4.构造邻接矩阵。

//在图中查找顶点
int LocateVex(AMGraph G,VertexType u){
    //在图中查找顶点u,存在则返回顶点表中的下标;否则返回-1
    int i;
    for(i=0;i<G.vexnum;++i) 
        if(u==G.vexs[i]) return i;
    return -1;
}
//采用邻接矩阵表示法,创建无向网
Status CreateUDN(AMGraph &G){ 
    cin>>G.vexnum>>G.arcnum;  //输入总顶点数,总边数
    for(int i=0;i<G.vexnum;i++)cin>>G.vexs[i]; //依次输入点的信息
    for(int i=0;i<G.vexnum;i++) // 初始化邻接矩阵
        for(int j=0;j<G.arcnum;j++)
            G.arcs[i][j]=MaxInt; //边的权值均置为最大值

    for(int k=0;k<G.arcnum;++k){ 
        cin>>v1>>v2>>w;    //输入一条边所依附的顶点以及边的权值
        i=LocateVex(G,v1);  
        j=LocateVex(G,v2);  //确定v1和v2在G中的位置
        G.arcs[i][j]=w;  //边<v1,v2>的权值置为w
        G.arcs[j][i]=G.arcs[i][j]; //置<v1,v2>的对称边<v2,v1>的权值为w
    }
    return OK;
} //CreateUDN

  • 邻接矩阵的优缺点

  • 优点:
    1.直观、简单、好理解
    2.方便检查任意一对顶点间是否存在边
    3.方便找任一顶点的所有“邻接点”(有边直接相连的顶点)
    4.方便计算任一顶点的“度”(从该点发出的边数为“出度”,指向该点的边数为入度)

    • 无向图:对应行(或列)非0元素的个数树“出度”
    • 有向图:对应行非0元素的个数是“出度”;对应列非0元素的个数是“入度”
  • 缺点:
    1.不便于增加和删除顶点
    2.浪费空间——存稀疏图时有大量的无效元素
    3.浪费时间——统计稀疏图中一共有多少条边

邻接表的存储方法

  • 邻接表的表示方法(链式)

在这里插入图片描述

  • 顶点——按编号顺序将1顶点数据存储在一维数组中;
  • 关联同一顶点的边(以顶点为尾的弧):
    用线性链表存储

  • 无向图的邻接表

在这里插入图片描述

  • 特点
    1.邻接表不唯一
    2.若无向图中有n个顶点、e条边,则其邻接表需n个头结点和2e个表结点。适宜存储稀疏图
    3.无向图中顶点 v i v_i vi的度为第 i i i个单链表中的结点数

  • 有向图的邻接表

在这里插入图片描述

  • 特点
    1.顶点 v i v_i vi的出度为第 i i i个单链表中的结点个数
    2.顶点 v i v_i vi的入度为整个单链表中邻接点域值时 i − 1 i-1 i1的结点个数

邻接表:——存储出度边

找出度易,找入度难

逆邻接表:——储存入度边

找入度易,找出度难


  • 图的邻接表存储表示:

  • 图的结点类型定义

  • 顶点结点结构

∣ d a t a ∣ f i r s t a r c ∣ |data|firstarc| datafirstarc

typedef struct VNode{
    VerTexType data; //顶点信息
    ArcNode *firstarc;  //指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];  //AdjList表示邻接表类型
  • 弧(边)结点结构

∣ a d j v e x ∣ n e x t a r c ∣ i n f o ∣ |adjvex|nextarc|info| adjvexnextarcinfo

#define MVNum 100    //最大顶点个数
typedef struct ArcNode{  //边结点
    int adjvex;   //该边所指向的顶点的位置
    struct ArcNode *nextarc; //指向下一条边的指针
    OtherInfo info;  //和边相关的信息
}ArcNode;
  • 图的结构定义

∣ 顶 点 ∣ 弧 ( 边 ) ∣ |顶点|弧(边)|

typedef struct {
    AdjList vertices; // vertices--vertex的复数
    int vexnum,arcnum; // 图的当前顶点数和弧度数
}ALGraph;
  • 采用邻接表表示法创建无向网

  • 算法思想
    1.输入总顶点数和总边数
    2.建立顶点表
      依次输入点的信息存入顶点表中,使每个表头结点的指针域初始化为NULL
    3.创建邻接表

    • 依次输入每条边依附的两个顶点;
    • 确定两个顶点的序号i和j,建立边结点;
    • 将此边结点分别插入到 v i v_i vi v j v_j vj对应的两个边链表的头部
//采用邻接表表示法,创建无向图
Status CreateUDG(ALGraph &G){
    cin>>G.vexnum>>G.arcnum; //输入总顶点数、总边数
    for(int i=0;i<G.vexnum;++i){ //输入各点,构造表头结点表
        cin>>G.vexnum[i].data; //输入顶点数
        G.vertices[i].firstarc=NULL; //初始化表头结点的指针域
    }
    for(int k=0;k<G.arcnum;++k){ //输入各边,构造邻接表
        cin>>v1>>v2;   // 输入一条边依附的两个顶点
        i=LocateVex(G,v1);  
        j=LocateVex(G,v2);
        //出度边
        p1=new ArcNode; //生成一个新结点*p1   
        p1->adjvex=j;  //邻接点序号为j
        p1->nextarc=G.vertices[i].firstarc; //
        G.vertices[i].firstarc=p1; //将新结点*p1插入顶点vi的边表头部
        //入度边
        p2=new ArcNode; //生成另一个对称的新的边结点*p
        p2->adjvex=i;   //邻接点序号为i
        p2->nextarc=G.vertices[j].firstarc; 
        G.vertices[j].fistarc=p2; //将新结点*p2插入顶点vj的边表头部
    }
    return OK;
}

  • 邻接表特点
    1.方便找任意顶点的所有“邻接点”
    2.节约稀疏图的空间
    3.对于无向图方便计算出度和入度,无向图分情况讨论(邻接表:方便计算出度;逆邻接表方便计算入度)
    4.不方便检查任意一对顶点间是否存在边

邻接矩阵和邻接表的关系

  • 联系——邻接表中每个链表对应于邻接矩阵中的一行,链表中结点个数等于一行中非零元素的个数。

  • 区别:
    1.对于任一确定的无向图,邻接矩阵是唯一确定的(行列号与顶点编号一致),但邻接表不唯一(链接次序与顶点编号无关)。
    2.邻接矩阵的空间复杂度为 O ( n 2 ) O(n^2) O(n2);而邻接表的空间复杂度为 O ( n + e ) O(n+e) O(n+e)

  • 用途——邻接矩阵多用于稠密图;而邻接表多用于稀疏图。



在这里插入图片描述

十字链表

邻接表和逆邻接表的结合

例子:

在这里插入图片描述

邻接多重表

无向图只存储一条边

例子:

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Galactus_hao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值