第六章 图

1.图的定义

  图的定义:图G由顶点集V和边集E组成,记为G =(V,E),其中V(G)表示图G中顶点的有限非空集,E(G)表示图G中顶尖之间的关系(边)集合,|V|表示图中顶点的个数,也称为图的阶,|E|表示图中边的条数。

  简单图:不存在重复边;不存在顶点到自身的边;

  完全图:无向图:边数 = n(n-1)/2

      有向图:边数 = n(n-1)

  强连通图:从顶点v到顶点w有路径和从顶点w到顶点v有路径,则顶点v和顶点w是强连通的。若 任意一对结点都是强连通的,则称此图为强连通图。

  稀疏图:|E| < |V| log |V|

  简单路径:顶点不重复出现的路径称为简单路径。

  简单回路:除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。

2.图的实现(包括邻接矩阵和邻接表)和基本操作

  (1)邻接矩阵:

    所谓邻接矩阵存储,是指用一个一位数组存储图中顶点的信息,用一个二维数组存储图中边的信息,存储顶点之间邻接关系的二维数组称为邻接矩阵。

    A[i][j] = 1表示从顶点i到顶点j有边。

    特点:

      ①无线图的邻接矩阵是对称矩阵,因此在存储邻接矩阵时只需存储上(或下)三角矩阵的元素。

      ②第i行非零元素的个数表示第i个结点的出度;第j列非零元素的个数表示第j个结点的入度。

      ③稠密图适合用邻接矩阵存储

      ④设图G的邻接矩阵为A,An的元素An[i][j]表示从顶点i到顶点j的长度为n的路径的数目。

      ⑤空间复杂度为O(n2)

  (2)邻接表法

  

    特点:

      ①若G为无向图,则所需的存储空间为O(|V|+2|E|)。

         若G为有向图,则所需的存储空间为O(|V|+|E|)。

      ②对于稀疏图,采用邻接表法可以极大的节省存储空间。

      ③对于一个有向图,求一个顶点的出度只需要计算其邻接表中的结点个数;但求其入度则需要遍历全部邻接表。

      ④图的邻接表表示法不唯一。

3.图的两种遍历

  (1)深度优先遍历

    借助栈

伪代码如下:

 1 bool visited[MAX_VERTEX_NUM]
 2 void DFSTraverse(Graph G){
 3     for(v=0; v<G.vernum; ++v){    //访问标记数组初始化 
 4         visited[v] = FALSE;
 5     }
 6     for(v=0; v<G.vexnum; ++v){    //从0号开始遍历 
 7         if(!visited[v]){
 8             DFS(G,v);
 9         }
10     }
11 } 
12 void DFS(Graph G, int v){        //从顶点v出发,广度优先遍历图 
13     visit(v);
14     visited[v] = TRUE;
15     for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w)){
16         if(!visited[w]){
17             DFS(G,w);
18         }//if
19     }//for
20 } 

  空间复杂度:O(|V|)

  邻接矩阵的时间复杂度:O(|V|2)

  邻接表的时间复杂度:O(|V|+|E|)

  (2)广度优先遍历

    借助一个辅助队列

伪代码如下:

 1 bool visited[MAX_VERTEX_NUM]
 2 void BFSTraverse(Graph G){
 3     for(i=0; i<G.vernum; ++i){    //访问标记数组初始化 
 4         visited[i] = FALSE;
 5     }
 6     InitQueue(Q);
 7     for(i=0; i<G.vexnum; ++i){    //从0号开始遍历 
 8         if(!visited[i]){
 9             BFS(G,i);
10         }
11     }
12 } 
13 void BFS(Graph G, int v){        //从顶点v出发,广度优先遍历图 
14     visit(v);
15     visited[v] = TRUE;
16     EnQueue(Q,v);
17     while(!isEmpty(Q)){
18         DeQueue(Q,v);
19         for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w)){
20             if(!visited[w]){
21                 visit(w);
22                 visited[w] = TRUE;
23                 EnQueue(Q,w);
24             }//if
25         }//for
26     }//while
27 } 

    采用邻接矩阵存储:时间复杂度O(|V|2),空间复杂度O(|V|)。

    采用邻接表存储:时间复杂度O(|V|+|E|),空间复杂度O(|V|)。

4.图的基本应用,包括最小支撑树、最短路径、拓扑排序和关键路径。

   (1)最小支撑树(也称为最小生成树MST)

    性质:

      最小支撑树不是唯一的,即最小生成树的树形不唯一。若图G中各边权值均不相同,则最小生成树唯一。

      最小生成树的权值之和是唯一的。

      最小生成树的顶点数 = 边数 + 1

    Prim算法与Kruskal算法均是基于贪心算法。

    ①Prim算法

      思路:从一个顶点出发,一直沿着这个子图扩张,直到构造出最小生成树。

      时间复杂度:O(|V|2),适用于边稠密的图的最小生成树。

    ②Kruskal

      思路:按边的权值递减排序,每次找出未连通的权值最小的边加入其中。

      时间复杂度:O(|E|+log|E|),适用于边稀疏而顶点较多的图  

  (2)最短路径

    单元最短路径:Dijkstra算法,求图中某一个顶点到其他顶点的最短路径。

    最短路径:Floyd算法,求每对顶点间的最短路径。

    ①Dijkstra算法求单元最短路径问题

      

      时间复杂度:O(|V|2)

      特点:不允许有负值的权值。

     ②Floyd算法求各顶点之间的最短路径问题

  

      思路:

        (1)初始化方阵

        (2)将V0作为中间顶点更新方阵

        (3)将V1作为中间结点更新方阵

        (4)将V2作为中间节点更新方阵

      时间复杂度:O(|V|3)

      特点:允许有负值的权值,但是不允许有负值的权值构成的回路。

  (3)拓扑排序

      DAG图:有向无环图

      AOV网:若用DAG图表示一个工程,其顶点表示活动,用有向边<Vi,Vj>表示活动Vi必须优先于活动Vj进行的一种关系,则将这种有向图称为顶点表示活动的网络,记为AOV网

      拓扑排序:由一个有向无环图的顶点组成的序列。

        条件:每个顶点只出现一次;若顶点A在序列中排在顶点B的前面,则不存在从B到A的路径。

        算法:每次选择一个没有前驱的结点输出,删除该顶点和所有以它为结点的有向边,重复此过程,知道输出所有的顶点。

        时间复杂度:O(|V|+|E|)

  (4)关键路径

     AOE网:在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动所需要的开销,简称AOE网。

       性质:

        只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始。

        只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。

      参考量的定义:ve(k):事件vk最早发生时间;

            vl(k):事件vk最晚发生时间;

            e(i):活动a(i)最早开始时间;

            l(i):活动a(i)最晚开始的时间;

            d(i)=l(i)-e(i):活动最早开始时间和最晚时间之差

      关键路径是时间最长的路径。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

空梦♡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值