【C++学习笔记】:图论基础术语

413 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

1、写在前面

大家好,今天文章的内容是:

  • 图的若干概念

2、内容

2.1、什么是图?

图(grahpgrahp)是由顶点的非空集合VV和边或弧的集合EE组成的,表示为G=(V,E)G=(V, E)

一般的,我们用V(G)V(G)表示图GG的顶点集,用E(G)E(G)表示图GG的边集。

图结构是一种复杂的非线性结构,在图结构中,结点之间的关系是多对多的关系。因此图结构一般被用于描述各种复杂的数据关系,在计算机科学领域有着广泛的应用。

2.2、图的基础术语

下面记录图论的一些基本概念。

无向图

如果图中的结点对是无序的,也就是说结点之间的边是没有方向的。此时将这个图GG称为无向图。

边集 E(G)E(G) 为无向边的集合,以无序对 (uv)(u,v) 表示 uuvv 之间存在一条无向边。在无向图中边是对称的,(uv)(u,v)(vu)(v,u) 表示的是同一条边。

image.png

有向图

如果图中的顶点对是有序的,也就是说结点之间的边是有方向的,这时则称图GG为有向图。

边集 E(G)E(G) 为有向边的集合,此时习惯上会将结点的边称为弧,并且以有序对 <uv><u,v> 表示一条从顶点 uu 出发到达顶点 vv 的弧,其中:uu 称为弧尾或起点,vv 称为弧头或终点。在有向图中,<uv><u,v><vu><v,u> 不同的两条弧。

image.png

加权图

图中的边带有某种与之相关的数值,我们称之为权值

如果图中的边被赋予权值,那么这种图就被称为加权图。

如果图是有向的,称为加权有向图,如果是无向的,称为加权无向图。

image.png

无向完全图

如果在无向图中,任意两个顶点都有一条边直接相连,这时就称该图为无向完全图

备注:

  • 具有nn个顶点的无向完全图具有n(n1)/2n(n-1)/2条边。

image.png

有向完全图

如果在有向图中,任意顶点都有一条弧直接到达其他顶点,这时就称该图为有向完全图

备注:

  • 具有nn个顶点的有向完全图具有n(n1)n(n-1)条弧。

image.png

子图

给定两个图GGGG' ,且满足条件V(G)V(G')V(G)V(G)的子集,V(G)V(G)V(G')⊆V(G),且E(G)E(G')E(G)E(G)的子集,E(G)E(G)E(G')⊆E(G),则称GG'GG的子图。

image.png

在一个图GG中,与顶点vv相关联的边的数目被称为顶点vv的度。

注意:

  • 在无向图中,顶点vv的度指的是与该顶点相关联的边的数目。
  • 在有向图中,顶点vv的度分为入度和出度。因此有向图的度等于入度和出度相加。

清楚度的概念,我们不难得出一个结论:一个具有nn个顶点,ee条边或弧的图,其顶点的度数之和就等于边数的2倍。

连通图和连通分量

这里需要清楚连通的概念。在无向图G中,若从顶点uu到顶点vv存在一条路径(uvu≠v),也就是这两个顶点是可达的,此时就称uuvv是连通的。

明白什么是连通后,再看看什么是连通图。如果顶点集V(G)V(G)中的每一对不同的顶点uuvv都连通,则称GG连通图

另外,无向图GG中的极大连通子图称为图GG连通分量

image.png

强连通图和强连通分量

前面已经知道了什么是连通。那么,在有向图中,如果对于V(G)V(G)中的每一对不同的顶点uuvvuvu≠v)都存在从uuvv的一条路径以及从vvuu的一条路径,那么称该图GG为强连通图。

另外,有向图GG中极大的强连通子图称为图GG的强连通分量。

image.png

生成树

连通图的生成树是包含图中所有顶点的一个极小连通子图。

说明:

  • 生成树的特点是含有图中全部的n个顶点,并且只有n-1条边(n-1条边就足以构成一棵树)
  • 边尽可能的少,但又要保持连通。
  • 因此在生成树中任意地添加一条边,必然会构成一个回路或环。

image.png

需要注意,图的生成树并不是唯一的。

有向树

只有一个顶点的入度为0,其余顶点的入度为1的有向图,称为有向树

说明:

  • 有向树是弱连通图。
  • 将有向图的所有的有向边替换为无向边,所得到的图称原图的基图
  • 如果一个有向图的基图是连通图,则该有向图是弱连通图

2.3、图的抽象数据类型定义

代码如下,仅供参考:

template <class VType, class EType> 
class Graph {
public:
    // 返回图的顶点数
    int numOfVertex() const { return verNum; }
    // 返回图的边数
    int numOfEdge() const { return edgeNum; }
    // 创建图
    virtual void createGraph(const VType V[],const EType E[])=0;
    // 查找边
    virtual bool searchEdge(int from, int to) const = 0;
    // 插入权值为w的边
    virtual bool insertEdge(int from, int to, EType w) = 0;
    // 删除边
    virtual bool removeEdge(int from, int to) = 0;
    // 输出图
    virtual void printGraph()const=0;
    // 深度优先遍历
    virtual void dfsTraverse()const = 0;
    // 广度优先遍历
    virtual void bfsTraverse()const = 0;
    // 拓扑排序
    virtual bool topSort()const=0;
    // prim算法
    virtual void prim(EType noEdge) const=0;
    // kruskal算法
    virtual void kruskal() const=0;
    // 输出最小生成树
    virtual void printMst()const=0;

protected:
    int verNum, edgeNum; // 图的顶点数和边数
    bool *visited;      // 访问标志数组
    // 最小生成树的边结点类型
    struct mstEdge {
        // 边的三元组(始点,终点,权值)
        int vex1, vex2;
        EType weight;
        // 由于需要使用优先级队列,因此要重载 <
        bool operator<(const  mstEdge &e) const {
            return weight < e.weight;
        }
    } *TE;  // 最小生成树的边集
};

3、写在最后

好了,文章的内容就到这里,感谢观看。