大话数据结构学习笔记 - 图

大话数据结构学习笔记 - 图

图的定义

图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为: G(V,E) G ( V , E ) ​ , 其中G表示一个图, V是图G中顶点的集合,E是图G中边的集合

  • 数据元素在线性表中被称为元素,在树中被称为结点,而在图中被称为顶点(Vertext)
  • 顶点集合V有穷非空
  • 图中顶点之间的逻辑关系用边来表示,边集可以为空

各种图定义

  • 无向边:若顶点 vi v i vj v j 之间的边没有方向,则称这条边为无向边(Edge), 用无序偶对( vi,vj v i , v j )来表示
  • 无向图:若图中任意两个顶点之间的边都是无向边,则为无向图(Undirected graphs)
  • 有向边:若从顶点 vi v i vj v j 之间的边有方向,则称这条边为有向边,也成为弧(Arc),用有序偶 <vi,vj> < v i , v j > 表示, vi v i 称为弧尾, vj v j 称为弧头
  • 有向边:如果图中任意两个顶点之间的边都是有向边,则称该图为有向图(Directed graphs)
  • 无向边用小括号()表示,有向边用尖括号<>
  • 简单图:不存在顶点到其自身的边,且同一条边不重复出现,这样的图为简单图
  • 无向完全图:任意两个顶点都存在边的无向图。 含有n个顶点的无向完全图有 n(n1)2 n ( n − 1 ) 2 条边
  • 有向完全图:任意两个顶点之间存在互为相反的两条弧的有向图。含有n个顶点的有向完全图有 n(n1) n ( n − 1 ) 条边
  • 稀疏图:有很少条边或弧的图称为稀疏图,反之为稠密图
  • 权(Weight):与图的边或弧相关的数叫做权
  • 网(Network):带权的图统称为网
  • 子图(Subgraph):假设有两个图 G=(V,{E}) G = ( V , { E } ) G=(V,{E}) G ′ = ( V ′ , { E ′ } ) , 如果 VV V ′ ⊆ V EE E ′ ⊆ E , 则称 G G ′ G G 的子图

图的顶点与边间关系

  • 无向图的邻接点(Adjacent):对于无向图 G=(V,{E}) G = ( V , { E } ) , 如果边 (v,v)E ( v , v ′ ) ∈ E , 则称顶点 v v v v ′ 互为邻接点。即 v v v v ′ 相邻接。边 (v,v) ( v , v ′ ) 依附于顶点 v v v v ′ ,或者说 (v,v) ( v , v ′ ) 与顶点 v v v v ′ 相关联
  • 无向图的度(Degree):顶点v的度是和v相关联的边的数目, 记为 TD(v) T D ( v )

  • 有向图的邻接: 对于有向图 G=(V,{E}) G = ( V , { E } ) ,如果弧 <v,v>E < v , v ′ >∈ E , 则称顶点v邻接到顶点 v v ′ , 顶点 v v ′ 邻接自顶点 v v 。弧 <v,v> < v , v ′ > 和顶点 v,v v , v ′ 相关联.

  • 有向图的入度(InDegree):以顶点v为头的弧的数目称为v的入度, 记为 ID(v) I D ( v )
  • 有向图的出度(OutDegree):以顶点v为尾的弧的数目称为v的出度 , 记为 OD(v) O D ( v )
  • 有向图的度: 顶点v的度为 TD(v)=ID(v)+OD(v) T D ( v ) = I D ( v ) + O D ( v )
  • 回路或环(Cycle):第一个顶点到最后一个顶点相同的路径称为回路或环
  • 简单路径:序列中顶点不重复出现的路径称为简单路径
  • 简单回路或简单环:除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环

连通图相关术语

  • 连通图(Connected Graph):在无向图 G G 中,如果从顶点 v v 到顶点 v v ′ 有路径,则称 v v v v ′ 是连通的。如果对于图中任意两个顶点 vi,vjE v i , v j ∈ E vi v i vj v j 都是连通的, 则称 G G 是连通图
  • 连通分量:无向图中的极大连通子图称为连通分量
  • 强连通图: 在有向图 G G 中,如果对于每一对 vi,vjV,vivj v i , v j ∈ V , v i ≠ v j , 从 vi v i vj v j 和从 vj v j vi v i 都存在路径,则称 G G 是强连通图。
  • 强连通分量:有向图中的极大强连通子图称作有向图的强连通分量
  • 生成树:一个连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n - 1条边
  • 有向树:如果一个有向图恰有一个顶点的入度为0, 其余顶点的入度均为1, 则是一棵有向树

图的抽象类型

ADT 图(Graph)
Data
    顶点的有穷非空集合和边的集合
Operation
    CreateGraph(*G, V, VR):按照顶点集 V 和边弧集 VR 的定义构造图 G
    DestroyGraph(*G):图 G 存在则销毁
    LocateVex(G, u):若图 G 中存在顶点 u, 则返回图中的位置
    GetVex(G, v):返回图 G 中顶点 v 的值
    PutVex(G, v, value):将图 G 中顶点 v 赋值 value
    FirstAdjVex(G, *v):返回顶点 v 的一个邻接顶点, 若顶点在 G 中无邻接顶点返回空
    NextAdjVex(G, v, *w):返回顶点 v 相对于顶点 w 的下一个邻接顶点,若 w 是 v 的最后一个邻接点则返                            回空
    InsertVex(*G, v):在图 G 中增添新节点 v
    DeleteVex(*G, v):删除图 G 中顶点 v 及其相关的弧
    InsertArc(*G, v, w):在图 G 中增点弧 , 若 G 是无向图,还需要增添对称弧 。
    DeleteArc(*G, v, w):在图 G 中删除弧 ,若 G 是无向图,则还需要删除对称弧 。
    DFSTraverse(G):对图 G 中进行深度优先遍历,在遍历过程对每个顶点调用
    HFSTraverse(G):对图 G 中进行广度优先遍历,在遍历过程对每个顶点调用
endADT

图的存储结构

对于图的存储结构,简单的顺序存储结构以及多重链表都无法使用,最常用的是 邻接矩阵邻接表

邻接矩阵

图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息

设图中Gn个顶点,则邻接矩阵是一个 nn n ∗ n 的方阵,定义为

Graph_adjacement_matrix_function

  • 无向图邻接矩阵示意图

    大话数据结构学习笔记 - 图_第1张图片

  • 有向图邻接矩阵示意图

    大话数据结构学习笔记 - 图_第2张图片

邻接矩阵的缺点是对于边数相对顶点较少的图,比较浪费存储空间

  • 图的邻接矩阵存储结构

    typedef char VertexType;  /* 顶点类型 */
    typedef int EdgeType;     /* 边上的权值类型 */
    
    #define MAXVEX 100        /* 最大顶点数 */
    
    
    #define INFINITY 65535    /* 65535 代表无限大 */
    
    typedef struct
    {
      VertexType vexs[MAXVEX];  /* 顶点表 */
        EdgeType arc[MAXVEX][MAXVEX];  /* 邻接矩阵, 可看做边表 */
        int numVertexes, numEdges;     /* 图中当前的顶点数和边数 */
    }MGraph;
  • 无向网图的邻接矩阵表示建立

    /* 无向网图的邻接矩阵表示 */
    void CreateMGraph(MGraph *G)
    {
      int i, j, k, w;
        printf("输入顶点数和边数:\n");
        scanf("%d,%d", &G->numVertexes, &G->numEdges);  /* 输入顶点数和边数 */
        for(i = 0; i < G->numVertexes; i++)  /* 输入顶点信息,建立顶点表 */
            scanf("%d", &G->vecs[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 条边,建立邻接矩阵 */
      {
          printf("输入边(vi, vj)上的下标i, 下标j 和权 w:\n");
            scanf("%d,%d,%d", &i, &j, &w);  /* 输入变(vi, vj)上的权 w */
            G->arc[i][j] = w;
            G->arc[j][i] = G->arc[i][j];  /* 因为是无向图,矩阵对称 */
      }
    }

链接表

邻接表(Adjacencty List)是图的一种链式存储,并且将数组与链表相结合的表示方法。即图中顶点用一维数组存储,每个顶点的所有邻接点用链表存储

  • 无向图的邻接表结构示意图

    • 方便查找某个顶点的度,只需要查找顶点的边表中结点的个数
    • 判断两定点是否存在边,只需要测试一顶点的边表中是否存在另一节点的下标即可
    • 求某顶点的所有邻接点,只需要遍历边表即可

    大话数据结构学习笔记 - 图_第3张图片

  • 有向图的邻接表结构示意图

    • 方便得到每个顶点的出度,若想得到入度,可建立逆邻接表。

    大话数据结构学习笔记 - 图_第4张图片

  • 图的邻接表存储结构

    typedef char VertexType;  /* 顶点类型 */
    typedef int EdgeType;  /* 边上的权值类型 */
    
    typedef struct EdgeNode
    {
      int adjtex;  /* 邻接点域,存储该顶点对应的下标 */
        EdgeType weight;  /* 用于存储权值,对于非网图可以不需要 */
        struct EdgeNode *next;  /* 链域,指向下一个邻接点 */
    }EdgeNode;
    
    typedef struct VertexNode
    {
      VertexType data;
        EdgeNode *firstedge;
    }VertexNode, AdjList[MAXTEX];
    
    typedef struct
    {
      AdjList adjList;
        int numVertexes, numEdges;
    }GraphAdjList;
  • 建立图的邻接表结构

    /* 建立图的邻接表结构 */
    void CreateALGraph(GraphAdjList *G)
    {
      int i, j, k;
        EdgeNode *e;
        printf("输入顶点数和边数:\n");
        scanf("%d,%d", &G->numVertexes, &G->numEdges);  /* 输入顶点数和边数 */
        for(i = 0; i < G->numVertexes; i++)  /* 输入顶点信息,建立顶点表 */
      {
          scanf(&G->adjList[i].data);  /* 输入顶点信息 */
            G->adjList[i].firstedge = NULL;  /* 将边表置为空表 */
      }
        for(k = 0; k < G->numEdges; k++)  /* 建立边表 */
      {
            printf("输入边(vi,vj)上的顶点序号:\n");
            scanf("%d,%d", &i, &j);  /* 输入边(vi,vj)上的顶点序号 */
          e = (EdgeNode *)malloc(sizeof(EdgeNode));  /* 向内存申请空间,生成边表结点 */
            e->adjtex = j;  /* 邻接序号为 j */
            e.next = G->adjList[i].firstedge;  /* 将 e 指针指向当前顶点指向的结点 */
            G->adjList[i].firstedge = e;  /* 将当前顶点的指针指向 e */
    
            e = (EdgeNode *)malloc(sizeof(EdgeNode));  * 向内存申请空间,生成边表结点 */
            e->adjnext = i;  /* 邻接序号为 i */
            e->next = G->adjList[j].firstedge;  /* 将 e 指针指向当前顶点指向的结点 */
            G->adjList[j].firstedge = e;  /* 将当前顶点的指针指向 e */
      } 
    }

结语

后续会继续整理图的相关知识,本文章的代码code

你可能感兴趣的:(数据结构,C)