C++(数据结构与算法):54---图的总体概述、图的各种术语、特性

  • 接下来的几篇文章会介绍如下的内容:
    • 图的术语:顶点、边、邻接、关联、度、回路、路径、连通构件、生成树
    • 图的类型:无向图、有向图、加权图
    • 图的常用描述方法:邻接矩阵、矩阵邻接表、邻接链表
    • 图的标准搜索方法:广度优先搜索、深度优先搜索
    • 图的算法:寻找图的路径、寻找无向图的连通构件、寻找连通无向图的生成树

一、顶点、边、有向边、无向边、有向图、无向图

  • 简单地说,图(Graph)是一个用线或边连接在一起的顶点或节点的集合、严格地说,图是有限集V和E的有序对,即G=(V,E),其中V的元素称为顶点(也称节点或点),E的元素称为(也称弧或线)。每一条边连接两个不同的顶点,而且用元组(i,j)来表示,其中i和j是边所连接的两个顶点
  • 下图中,有些边是带方向的(带箭头),而有些边是不带方向的。带方向的边叫有向边,而不带方向的边叫无向边
  • 如果图的所有边都是无向边,那么该图叫做无向图(下图a和b都是)。如果图的所有边都是有向边,那么该图叫做有向图(下图c是)

二、邻接、关联

  • 当且仅当(i,j)是图的边,称顶点i和j是邻接的。边(i,j)关联于顶点i和j。例如下图中顶点1和顶点2是邻接的,顶点1和3,1和4,2和3,3和4也是邻接的;边(1,2)关联于顶点1和2,边(2,3)关联与顶点2和3

“至”和“于”的概念

  • 对有向图的邻接和关联的概念做更精确的定义非常有用
  • 有向边(i,j)是关联至顶点j和关联于顶点i。顶点i邻接至顶点j,顶点j邻接于顶点i

三、集合表示法

  • 如果使用集合表示方法,上图中的3个图可以用如下方法表示:
    • G1=(V1,E1),G2=(V2,E2),G1=(V3,E3)

四、图没有自连边/环

  • 一个图不能有重复的边。在无向图的任意两个顶点之间,最多只有一条边。在有向图的任意两个顶点i和i之间,从顶点i到顶点j最多只有一条边,从顶点j到顶点i页最多只有一条边。一个图不可能包含自连边,即(i,i)形式的边。自连边也叫做

五、权、加权图、加权无向图、加权有向图、网/网络

  • 在图的一些应用中,我们可能要为每条边赋予一个表示成本的值,我们称之为。这时的图称为加权图
  • 带有权的无向图称为加权无向图,带有权的有向图称为加权有向图
  • 一个网/网络经常指一个加权有向图或加权无向图。实际上,所有的图都可以看作是特殊的网络——一个无向(有向)图可以看作是一个所有边上的权都相同的无向(有向)网络

六、稀疏图、稠密图

  • 稀疏图:有很少边或弧的图(n<nlogn)
  • 稠密图:有较多边或弧的图

七、图应用之路径问题(路径、简单路径、路径长度)

  • 城市有许多街道,每一个路口都可以看做有向图的一个顶点,邻接的两个路口之间的街道,如果是双行线,就可以看做两条有向边,如果是单行线,就可以看做一条有向边。下图的假象的街道地图和响应的有向图。它有三条街道:街道1,街道2,街道3。有两条大街:大街1和大街2。路口用数字1到6编号。响应的有向图如下图b所示,其顶点标号和下图a的路口标号相同

  • 一个顶点序列P=i1,i2,...,ik是图或有向图G=(V,E)的一条从i1到ik的路径,当且仅当对于每个j(1<=j<k),边都在E中。从路口i到j存在一条路径,当且仅当在响应的有向图中,从顶点i到j有一条路径。在上图b的有向图中,5,2,1是从5到1的一条路径。在这个有向图中,从5到4之间没有路径
  • 一条路径,如果除第一个和最后一个顶点之外,其余所有顶点均不同,那么该路径称为一条简单路径。路径5,2,1是简单路径,而2,5,2,1不是,其只是路径
  • 图或有向图的每一条边都可以有长度。一条路径的长度是该路径的所有边长度之和

八、图应用之生成树(连通图、子图、环路、树、生成树、连通分量)

连通图(强连通图)

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

连通分量(强连通分量)

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

子图、环路(回路)、树、生成树、生成森林

  • 如果H的顶点和边的集合分别是G的顶点和边的集合的子集,那么称图H是图G的子集(子图)
  • 极小连通子图:该子图是G的连通子图,在该子图中删除任何一条边后子图不再连通
  • 一条始点和终点相同的简单路径称为环路。例如,1,2,3,1是下图的一条环路

  • 没有环路的连通无向图是一棵
  • 生成树:包含无向图G所有顶点的极小连通子图。也可以理解为是一个G的子图,如果包含G的所有顶点,且是一棵树,则称为G的生成树。例如下面的每一个都是上图的生成树

  • 生成森林:对非连通图,由各个连通分量的生成树的集合

九、图应用之翻译人员(二分图)

  • 假设你正在策划一次国际会议。所有发言人都只会说英语,而其他的参与会议的人员所懂得语言是L1,L2,....Ln中的一种。翻译小组可以在英语和其他语言之间互译。现在的任务是如何使翻译小组的人数最少
  • 我们可以把这个问题准确地表示为一个图的问题。在这个图中有两组顶点:一组与翻译人员对应,另一组和语言对应。在翻译人员i和语言Lj之间存在一条边,当且仅当翻译人员i能够将英文和语言Lj互译。翻译人员i覆盖语言Li,当且仅当有一条边连接翻译人员i和语言Li。我们需要找到能够翻译所有语言顶点的最小翻译人员顶点集
  • 下图的顶点被分为两个子集:A(翻译人员顶点)和B(语言顶点)。每条边都有一个顶点在A,另一个顶点在B中。具有这种特征的图叫做二分图

十、度、完全图、入度、出度

  • 在一个无向图中,与一个顶点i相关联的边数称为该顶点的(degree)。在下图中,d1=3,d2=2,d3=3,d4=2

  • 一个具有n个顶点和n(n-1)/2条边的无向图是一个完全图。下面的都是完全图

  • 设G是一个有向图。顶点i的入度是指是指关联至该顶点的边数。顶点i的出度是指关联于该顶点的边数。例如对于下图来说,其中

  • 在无向图中,入度和出度可以看作是度的同义词

十一、图的特性

特性①

  • 设G=(V,E)是一个无向图。令n=|V|,e=|E|,则有如下特性:

  • 证明如下:
    • 1)的证明:在无向图中,每一条边都与两个顶点相关联,因此顶点的度之和是边数的2倍
    • 2)的证明:一个顶点的度在0到n-1之间,因此度的和在0到n(n-1)之间。但再结合1)可知,e是在0到n(n-1)/2之间

特性②

  • 设G=(V,E)是一个无=有向图。令n=|V|,e=|E|,则有如下特性:

特性③

  • 一个具有n个顶点的完全有向图恰好包含n(n-1)条有向边
  • 下图给出了n=1,2,3,4时的完全有向图

十二、图的抽象数据类型(ADT)

  • 我们使用抽象数据类型graph来表示图,该类型适用于各种图:有向图、无向图、加权图、无权图
  • 下面是图操作的一小部分,随着学习的深入,还会加入一些其他操作

十三、图的抽象类实现

  • 与前面文章中链表、树介绍的抽象类不同,图的抽象类定义除了包含一些纯虚方法之外,还包含一些在抽象类中实现的方法:
    • 后者将利用迭代器从一个给定的顶点开始,根据相邻的关系,依次访问所有的顶点
    • 一些方法还需要知道它所操作的图是否有向以及是否加权
  • 因此我们定义的下面的抽象类
    • 对加权图,T是边上的权的数据类型
    • 对于无权图,T是布尔类型
template<typename T>
class graph
{
public:
    virtual ~graph() {}

    //ADT方法
    virtual int numberOfVertices()const = 0;      //返回图的顶点数
    virtual int numberOfEdges()const = 0;         //返回图的边数
    virtual bool existsEdge(int i,int j)const = 0;//如果边(i,j)存在返回true;否则返回false
    virtual void insertEdge(edge<T>*) = 0;        //删除边(i,j)
    virtual void eraseEdge(int i, int j) = 0;     //删除边
    virtual int degree(int i)const = 0;           //返回顶点i的度,只适用于无向图
    virtual int inDegree(int i)const = 0;         //返回顶点i的入度
    virtual int outDegree(int i)const = 0;        //返回顶点i的出度

    //其他方法
    virtual bool directed()const = 0; //当且仅当是有向图时,返回true
    virtual bool weighted()const = 0; //当且仅当是加权图时,返回true
    virtual vertexIterator<T>* iterator(int) = 0;//访问指定顶点的相邻顶点
};


template <class T>
class edge
{
public:
    virtual ~edge() {};
    virtual int vertex1() const = 0; //返回一个边的第一个顶点
    virtual int vertex2() const = 0; //返回一个边的第二个顶点
    virtual T weight() const = 0;    //返回一个边的权
};

//给定一个顶点,用来访问该顶点的相邻顶点
template<class T>
class vertexIterator
{
public:
    virtual ~vertexIterator() {}
    virtual int next() = 0;  //如果相邻顶点,此函数返回相邻顶点(如果没有返回0)
    virtual int next(T&) = 0;//如果是一个加权图,那么参数用来保存两个顶点之间的权值,函数返回值为相邻顶点
};
  • 方法insertEdge的输入数据类型是模板类edge。模板edge是一个抽象类,用来返回一个边的第一个顶点和第二个顶点以及权
  • 抽象类中还用到了模板类vertexIterator,用法如下:
  • 令g是指向一个图的一个指针。我们可以用下面的语句创建顶点5的一个迭代器
vertexIterator<T>* vertex5Iterator=iterator(5);
  • 接下来调用下面的语句可以返回一个与顶点5相邻的顶点
vertex5Iterator->next();
  • 如果图是一个加权图,那么调用下面的语句就可以返回其相邻订单,并用参数w来保存两个顶点之间边的权值
vertex5Iterator->next(w);
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

董哥的黑板报

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

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

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

打赏作者

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

抵扣说明:

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

余额充值