• 1、完全无向图有n(n-1)/2条边,完全有向图有n(n-1)条边。

    2、网络=带权图

    3、图中任意一对顶点都是连通的(连通,即有路径),称为连通图。非连通图的极大连通子图叫做连通分量。

    4、有向图的每一对顶点都连通(vi到vj,vj到vi都有路径)则称为强连通图。非强连通图的极大连通子图叫做强连通分量。

    5、生成树:是一个极小连通子图,它含有图中全部n个顶点,但只有n-1条边。(连通图)

    深度优先搜索得到的是深度优先生成树,广度优先搜索得到的是广度优先生成树。

    (1)如果在生成树上添加1条边,必定构成一个环;(2)若图中有n个顶点,却少于n-1条边,必为非连通图。

    注:如果一个图n个顶点和小于n-1条边,则是非连通图;如果它多于n-1条边,则一定有环;但是n-1条边,则不一定是生成树。

    6、生成森林:各个连通分量的生成树构成非连通图的生成森林。(非连通图)也分为深度优先生成森林和广度优先生成森林。

    7、如果一个有向图恰有一个顶点的入度为0,其余顶点的入度均为1,则是一棵有向树。

    一、图的存储结构

    1、邻接矩阵(数组):空间复杂度O(n2),多用于稠密图,具有唯一性;

      注:网(带权图)的邻接矩阵对角线为inf(无穷大),普通图的邻接矩阵对角线为0。

    2、邻接表(链式):空间复杂度O(n+e),多用于稀疏图,邻接表不唯一。

    二、图的遍历

    设置一辅助数组visited[n]用来标记每个被访问过得顶点,访问过标记为1,否则为0。

    1、深度优先搜索DFS

    (1)在访问图中某一起始顶点v后,由v出发,访问它的任一邻接顶点w1;

    (2)再从w1出发,访问与w邻接但还未被访问过得顶点w2;

    (3)否则回退。直到所有顶点都被访问。

    时间复杂度分析:邻接矩阵存储结构时,遍历图中每个顶点都要从头扫描该顶点所在行,因此遍历全部n个顶点的时间复杂度为O(n^2);(适合稠密图)

    以邻接表存储结构时,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,加上访问n个头结点的时间,因此时间复杂度为O(n+e),其中e为无向图中边的个数或有向图中弧的个数。(适合稀疏图)

    2、广度优先搜索BFS

    (1)在访问了起点v之后,依次访问v的邻接点;

    (2)然后再依次访问这些顶点中未被访问过的邻接点;

    (3)直到所有顶点都被访问过为止。

    时间复杂度分析:使用邻接矩阵,则对于每个被访问的顶点,都要循环检测矩阵中的一整行,所以时间复杂度为O(n2);

    使用邻接表,则总时间复杂度为各个顶点的总度,加上访问n个头结点的时间,即O(n+e)。

    DFS和BFS比较:时间复杂度只与存储结构有关,而与搜索路径无关。空间复杂度相同,都是O(n)(DFS是递归的,使用堆栈;BFS不是递归,使用队列)。

    三、图的连通性、生成树

    1、无向图:利用深度优先搜索或广度优先搜索可以判断图的连通性,并可以得到生成树或生成森林。时间复杂度与图的遍历相同。

    2、有向图:利用深度优先搜索求有向图的强连通分量。时间复杂度也与遍历相同。

    3、最小生成树应用:求n个城市之间建立网络的问题,选取n(n-1)/2条总路径数中的(n-1)条,使总耗费最小。

    (1)普里姆算法Prim:归并顶点,O(n2)

    假设N=(V,{E})是连通网,TE是N上最小生成树边的集合。算法从U={u0}(u0€V),TE={}开始,重复执行下述操作:

    在所有u€V,v€V-U的边(u,v)€E中找一条代价最小的边(u0 ,v0)并入集合TE,同时v0 并入U,直至U=V为止。

    此时TE中必有n-1条边,则T={V,{TE}}为N的最小生成树。

    (2)克鲁斯卡尔算法Kruskal:归并边,O(eloge)

    假设N=(V,{E})是连通网,则令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),图中每个顶点自成一个连通分量。

    在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。依次类推,直至T中所有顶点都在同一连通分量上为止。

     4、关节点和重连通分量

    (1)概念

    关节点(割点):假若删去顶点v以及v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则v是一个关节点。

    重连通图:没有关节点的连通图。

    连通度:在连通图上至少删去k个顶点才能破坏其连通性,则此图的连通度为k。

    (2)利用深度优先搜索可求图的关节点,并由此判别图是否是重连通图。

    a.根有两棵或两棵以上的子树,则根顶点必为关节点;

    b.生成树中某非叶子顶点v,v的某棵子树的根和子树中的其他结点均没有指有向v的祖先的回边,则v为关节点。

    注:v的孩子结点是在它之后搜索到的邻接点,双亲结点和由回边连结的祖先结点是在它之前搜索到的邻接点。

    四、有向无环图(DAG)

    1、有向无环图是描述含有公共子式的表达式的有效工具。

    2、检查一个有向图是否存在环,要比无向图更复杂。

    无向图中,若深度优先搜索过程中遇到回边(即指向已访问过的顶点的边),则必定存在环;(有向图中,该回边可能是指向深度优先生成森林中另一棵生成树顶点的弧)

    有向图中,如果从某顶点v出发遍历,在DFS(v)结束之前出现一条从顶点u到顶点v的回边,由于u在生成树上是v的子孙,则有向图中必定存在包含v和u的环。

     3、对整个工程和系统,人们关心的两方面问题:工程能否顺利进行(AOV的拓扑排序);估算整个工程完成所必须的最短时间(AOE的关键路径)

    (1)AOV-网:顶点表示活动,弧表示活动间的优先关系。(有向无环、无权)

    AOV中不应该出现有向环,因为环意味着以自己为先决条件。因此,对于给定的AOV应首先判断是否有环,方法是拓扑排序(Topological Sort)。

    若AOV中所有顶点都在它的拓扑有序序列中,则不存在环。方法如下:

    a.在有向图中选一个没有前驱的顶点且输出;

    b.从图中删除该顶点和所有以它为尾的弧;

    c.重复上述过程,直至全部顶点均输出(无环),或当前图中不存在无前驱的顶点为止(存在环)。

    以邻接表存储时,时间复杂度为O(n+e)。

    (2)AOE-网:弧表示活动,顶点表示事件。(有向无环、有权,权表示活动持续时间)

     AOE中待解决的问题是:完成整项工程至少需要多少时间?哪些活动是影响工程进度的关键?

    关键路径:因为AOE中有些活动可以并行进行,所以完成工程的最短时间是从开始点到完成点的最长路径的长度,即关键路径(Critical Path)。

    关键活动:时间余量为0的活动。关键路径上所有活动都是关键活动。

    时间余量的计算:弧表示活动,那么时间余量=弧尾的最迟开始时间-弧尾的最早开始时间。

    注:只有在不改变网的关键路径的情况下,提高关键活动的速度才有效。如果网中有几条关键路径,那么必须同时提高这几条关键路径上关键活动的速度。

    五、最短路径

    1、从某个源点到其余各顶点的最短路径(迪杰斯特拉算法Dijkstra)时间复杂度O(n2)

      思想:按路径长度递增的次序产生最短路径。

      首先,引进一个辅助向量D,它的每个分量D[i]表示当前所找到的从始点v到每个终点vi的最短路径的长度。它的初态为:若从v到vi有弧,则D[i]为弧上的权值;否则置D[i]为无穷大。

      例如:已知有向图、对应的邻接矩阵为:

    终点 从v0到各终点的D值和最短路径的求解过程
    i=1(初始数组D) i=2 i=3 i=4 i=5
    v1 无穷大 无穷大 无穷大 无穷大 无穷大
    v2 10        
    v3 无穷大 10+50 30+20    
    v4 30 30      
    v5 100 100 30+60 50+10  
    vi v2 v4 v3 v5  
    S {v0,v2} {v0,v2,v4} {v0,v2,v3,v4} {v0,v2,v3,v4,v5}  

      S是以求得最短路径的终点的集合。下一条最短路径(设其终点为x)或者是弧(v,x),或者是中间只经过S中的顶点而最后到达顶点x的路径。 

    2、每一对顶点之间的最短路径(弗洛伊德算法Floyd)时间复杂度O(n3);也可重复执行Dijkstra算法,也是O(n3)

      思想:假设求从vi到vj的最短路径。如果从vi到vj有弧,则从vi到vj存在一条长度为该弧权值的路径,但该路径不一定最短,尚需进行n次试探。

      首先考虑路径(vi,v0,vj)是否存在,即判别弧(vi,v0)和(v0,vj)是否存在。如果存在,则比较(vi,vj)和(vi,v0,vj),取长度较短者作为vi到vj的中间顶点序号不大于0的最短路径。

      路径上继续添加一点v1,如果(vi,…,v1)和(v1,…,vj)分别是当前找到的中间顶点的序号不大于0的最短路径,则将(vi,…,v1,…,vj)和之前得到的中间顶点序号不大于0的最短路径比较,取较短者作为中间顶点序号不大于1的最短路径。

      再增加v2继续试探,以此类推。这样n次比较之后,即可同时求得各对顶点间最短路径。

      例如:

      定义一个n*n的数组D。D-1--V0-->D0--V1-->D1--V2-->D2。(上图中A,B,C分别代表V0,V1,V2)

    D D-1(初始状态) D0(在前面基础上加入A) D1(在前面基础上加入B) D2(在前面基础上加入C)
    A B C A B C A B C A B C
    A 0 4 11 0 4 11 0 4  11>4+2  0  4<6+7  6
    B 6 0 2 6 0 2<6+11 6 0  2  6>2+3  0  2
    C 3 inf 0 3 inf>3+4 0  3<7+6  7 0  3  7  0
    P        
    A B C A B C  A  B  C  A  B  C
    A   AB AC   AB AC    AB  ABC    AB  ABC
    B BA   BC BA   BC  BA    BC  BCA    BC
    C CA     CA CAB    CA  CAB    CA  CAB  
  • 相关阅读:
    mybatis动态sql中的两个内置参数(_parameter和_databaseId)
    Vue.js项目部署在Tomcat服务器上
    Vue2.0 + ElementUI的+ PageHelper实现的表格分页
    mybatis中使用mysql的模糊查询字符串拼接(like)
    C++循环链表解决约瑟夫环问题
    Nginx源码分析-ngx_module_s结构体
    设计模式(一)工厂模式Factory(创建型)(转)
    网络编程--套接字选项(一)
    Linux阵列 RAID详解 (转)
    HDFS RAID实现方案(转)
  • 原文地址:https://www.cnblogs.com/seven7seven/p/3633190.html
Copyright © 2020-2023  润新知