数据机构之图

一、图的概念

通常图表示为偶对,是顶点和边的集合

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

1.图的分类

1.通常根据边有无方向分为:又向图和无向图。

2.根据任意两个顶点之间是否有边相连称为:完全图
其中:无向完全图中  n个顶点有 n(n-1)/2 条边
          有向完全图中  n个顶点有 n(n-1) 条边

3.稀疏图:有很少边或弧的图(e<n logn)
   稠密图:有较多边或弧的图
   网:边/弧带权的图
   邻接:有边/弧相连的两个顶点之间的关系
             存在(Vi,Vj),则称Vi,Vj互为邻接点(无向图)
             存在<Vi,Vj>,则称Vi,Vj互为邻接点(有向图)

4.关联/依附:边与顶点之间的关系。
                    存在(Vi,Vj)/<Vi,Vj>,则称该边/弧关联于Vi,Vj

5.顶点的度:与该顶点相关的边的数目,记作TD(v)
                    在有向图中,顶点的度等于该顶点的入度与出度之和。
                    入度:以当前顶点为终点,出度:以当前顶点为始点。

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

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

8.权与网
         图中边或弧所具有的相关数称为权,表明从一个顶点到另一个顶点的距离或者花费。

9.子图
         设有两个图G=(v,{E})、G1=(V1,{E1}),若V1∈V,E1∈E,则称G1是G的子图

10.连通分量(强连通分量)
          无向图G的极大连通子图称为G的连通分量。(强连通分量是有向图)
          极大连通子图意思是:该子图是G连通子图,将G的任何不在该子图的顶点加入,子图不再连通。
           极小连通子图:该子图是G的连通子图,在该子图中删除任何一条边,子图不再连通
11.生成树:包含了无向图G所有项点的极小连通子图。
            生成森林:对非连通图,由各个连通分量的生成树的集合

2.图的代码定义

1.图的抽象数据类型定义

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>的信息
}

2.图的存储结构(数组/邻接矩阵  表示法):

逻辑关系:多对多,图没有顺序存储结构,但可以借助二维数组来表示元素间的关系——邻接矩阵(数组表示法)

                 用链式存储结构表示——(因为前驱和后继都不确定,不能使用多重链表)常用——邻接表、邻接多重表,十字链表表示

(1)数组(邻接矩阵)表示法

 

(2)无向图的连接矩阵

对角线上都为0,因为是自身不会相连接,且关于对角线对称

顶点i的度 = 第i行(列)中1的个数(相关联的个数)

在完全图(每个元素都直接相连)的邻接矩阵中,对角元素为0,其余为1

 

(3)有向图的连接矩阵

有向图的邻接矩阵可能是不对称的(因为连接是有方向的)

顶点的出度 = 第i行元素之和
顶点的入度 = 第i列元素之和
顶点的度 = 第i行元素之和+第i列元素之和

 

(4)网(有权图)的邻接矩阵表示法

邻接矩阵的表示
// 分别有两个数组来存储顶点表和邻接矩阵
#define MaxInt 32767         // 表示极大值,即∞
#define MVNum 100            // 最大顶点数
typedef char VerTexType      // 设顶点的数据类型为字符型
typedef int ArcType          // 假设边的权值类型为整型
typedef struct {
    VerTexType vexs[MVNum]         // 顶点表
    ArcType arcs [MVNum][MVNum]    // 邻接矩阵
    int vexnum,arcnum             // 图的当前结点数和边数
} AMGraph
(5) 采用邻接矩阵表示法创建无向网(无向图,有向图,有向网)

1.输入总顶点数和总边数
2.依次输入点的信息存入顶点表中
3.初始化邻接矩阵,使每个权值初始化为极大值,
4.构造邻接矩阵

Status CreateUDN(AMGraph &G) {
 // 采用邻接矩阵表示法,创建无向网G
    cin >> G.vexnum >> G.arcnum     // 输入总顶点数,总边数
    for(i = 0;i<G.vexnum;i++) {
        cin >> G.vexs[i]            // 依次输入点的信息
        for(i = 0;i<G.vexnum;++i)    // 初始化邻接矩阵
            for(j = 0;j<G.vexnum;++j ) 
                G.arcs[i][j] = MaxInt    // 初始化权值置为极大值
                    for(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
    }
}

 

// 查找算法
int LocateVex(AMGraph G,VertexType u) {
// 查找图G中顶点u,存在则返回顶点表在的下标,否则返回-1
    int i
    for(i = 0; i<G.vexnum; i++)
        if(u == G.vexs[i]) return i
    return -1
}

邻接矩阵的好处:方便找任何一顶点的所有“邻接点”,直观,简单,好理解

缺点:不便于增加或者删除顶点,浪费空间(有大量的0)

3.图的存储结构(邻接表  表示法):

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

用一个一维数组存储无向图。其中每个结点有两个数据域,其中一个数据域存放当前结点在数组中的位置,另一个数据域存放下一个结点的地址。如果当前结点还有权值灯,还可以增加一个域info,用来存放权值

(1) 无向图

邻接表不唯一,结点位置可以互换
若无向表中有n个顶点、e条边,则其邻接表需要n个头结点和2e个表结点,适宜存储稀疏表。

 无向表中:结点的相邻结点个数就是单链表中结点数
顶点Vi的度为低i个单链表中的结点数

邻接多重表

邻接表的优点:容易求的顶点和边的信息,缺点是某些操作不方便(删除一条边需找表示此边的两个结点,每一条边会存储两次)

边结点有六个数据域用于存放数据,第一个是标志域,用于表示是否被搜索过,不需要可以尾空。第二个是边的尾结点,第四个是边的头结点,第三个相当于是出度的下一个边的地址。第五个相当于是入度的下一个地址。第六个数据域用于存放网中边的权值。

因为出度和入度合并了,可以减少一半的结点。

(2)有向图

有向图的邻接表是由当前弧尾的结点表示表头表头 

顶点Vi的出度为低i个单链表中的结点个数

顶点Vi的入度为整个单链表在邻接点域值是i-1的结点数 。(找V1的九尾域值为0的结点个数)

当邻接表的存储结构形成后,图便唯一确定。

十字链表

用十字链表来存储有向图,是有向图的邻接表和逆邻接表集合起来形成的一种链表
有向图中的每一条弧对应十字链表中的一个弧结点,同时有向图中的每个顶点在十字链表中对应有一个结点,叫做顶点结点。

表头结点有三个数据域 ,一个存储顶点,一个存储该顶点的入度弧,一个存储顶点的出度弧。

 弧结点有四个数据域,第一个存储弧的尾结点,第二个存储弧的头结点,第三个存储下一个入度地址,第四个存储下一个出度地址。

(2)图的邻接表存储表示
// 顶点的结点结构
typedef struct VNode() {
    VerTexType data            // 顶点信息
        ArcNode* firstarc      // 指向第一条依附该顶点的边的指针
} VNode,AdjList[MVNum]        // AdjList表示邻接表的类型
// 弧的结点结构
#define MVNum 100              // 最大顶点数
typedef struct ArcNode{        // 边结点
    int adjvex                 // 该边所指向的顶点的位置
    struct ArchNode* nextarc   // 指向下一条边的指针
    OtherInfo info             // 和边相关的信息
}ArchNode
// 图的结构定义
typedef struct{
    AdjList vertices            // vertices--vertex的复数
    int vexnum,arcnum          // 图的当前顶点数和弧数
}ALGraph
(3)采用邻接表表示法创建无向图

1.输入总顶点数和总变数
2.建立顶点表
          依次输入点的信息存入顶点表中
          使每个表头结点的指针域初始化为NULL
3.创建邻接表
           依次输入每条边依附的两个顶点
           确定两个顶点的序号i和j,建立边结点
           将此边结点分别插入到Vi和Vj对应的两个边链表的头部

 

Status CreateUDG(ALGraph &G) {        // 采用邻接表表示法,创建无向图G
    cin >> G.vexnum >>G.arcnum        // 输入总顶点数,总边数
    for(i=0;i< G.vexnum;++i) {        // 输入各点,构造表头结点表
        cin >> G.vertices[i].data        // 输入顶点值
        G.vertices[i].firstarc = NULL     // 初始化表头结点的指针域为空 
    }
    for(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                        // 生成另一个对称的新的边结点p2(因为无向网是双向的,有向网可以省略)
    P2 -> adjvex = i                        // 邻接点序号为i
    P2 -> nextarc = G.vertices[j].firstarc  
    G.vertices[i].firstarc = P2             // 将新结点p2插入顶点Vj的边表头部
}
(4)邻接表的特点

1.方便找任一顶点的所有邻接点
2.节约稀疏图的空间
          需要n个头指针+2e个结点(每个结点至少两个域)
3.方便计算无向图的度,有向图只能计算出度,需要构造逆邻接表来计算入度

(5)邻接表和邻接矩阵的关系

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

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

用途:1.邻接矩阵多用于稠密图,邻接表多用于稀疏图

 

posted @   铜须的编程生活  阅读(221)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示