期末复习之数据结构 第7章 图

目录

一.课本知识点

1.图的定义和术语

2.图的存储结构

a.邻接矩阵(数组)表示

b. 邻接表表示

c. 十字链表​​

d. 邻接多重表​​

3.图的遍历

a.深度优先遍历(DFS)

 b.广度优先遍历​​

4.图的连通性问题

a.求图的生成树​​

b.求最小生成树​

5.有向无环图及其应用

a. AOV网—拓扑排序

b. AOE网—关键路径​​​

6.最短路径

 a.单源最短路径 (Dijkstra算法)​​

 b.Dijkstra(迪杰斯特拉)算法​

c.所有顶点之间的最短路径(Floyd算法)​​​​​​

二.练习题 

题组一:

题组二: 

题组三:


一.课本知识点

1.图的定义和术语

  • 图的定义:
  •  图的基本术语:
  •  不同结构中逻辑关系的对比
  •  顶点的度:在无向图中,顶点v的是指与该顶点相关联的边数,通常记为TD (v)。
  •  弧头和尾:
  • 无向完全图:在无向图中,如果任意两个顶点之间都存在边,则称该图为无向完全图。
  • 有向完全图:在有向图中,如果任意两个顶点之间都存在方向相反的两条弧,则称该图为有向完全图。  
  • 含有n个顶点的无向完全图有多少条边?  n×(n-1)/2条边
    含有n个顶点的有向完全图有多少条弧?  n×(n-1)条边
  • 稀疏图:称边数很少的图为稀疏图;通常边数<<n^2
  • 稠密图:称边数很多的图为稠密图。
  • :是指对边赋予的有意义的数值量。
  • :边上带权的图,也称网图。
  • 路径:在无向图G=(V, E)中,从顶点vp到顶点vq之间的路径是一个顶点序列(vp=vi0,vi1,vi2, …, vim=vq),其中,(vij-1,vij)∈E(1≤j≤m)。若G是有向图,则路径也是有方向的,顶点序列满足<vij-1,vij>∈E。
  • 路径长度:
  • 回路(环):第一个顶点和最后一个顶点相同的路径。
  • 简单路径:序列中顶点不重复出现的路径。
  • 简单回路(简单环):除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路。
  • 子图:若图G=(V,E),G'=(V',E'),如果V'V 且E'  E ,则称图G'是G的子图。
  • 连通图:在无向图中,如果从一个顶点vi到另一个顶点vj(i≠j)有路径,则称顶点vi和vj是连通的。如果图中任意两个顶点都是连通的,则称该图是连通图。
  • 连通分量:非连通图的极大连通子图称为连通分量。
  • 强连通图:有向图中,对图中任意一对顶点vi和vj (i≠j),若从顶点vi到顶点vj和从顶点vj到顶点vi均有路径,则称该有向图是强连通图。
  • 强连通分量:非强连通图的极大强连通子图。
  • 生成树:n个顶点的连通图G的生成树是包含G中全部顶点的一个极小连通子图。
  • 生成森林:非连通图中,由每个连通分量都可以得到一棵生成树,这些连通分量的生成树就组成了一个非连通图的生成森林。 
  • 图的抽象数据类型:
    ADT Graph {
    数据对象V:v是具有相同特性的数据元素的集合,称为顶点集。
    数据关系R:R={VR};VR={<v,w>|v,w∈V 且 P(v,w), 
                       <v,w>表示从v到w的弧,
                       谓词P(v,w)定义了弧<v,w>的意义或信息}
    基本操作P:
               CreatGraph ( &G, V,VR);
         初始条件:V是图的顶点集,VR是图中弧的集合。
         操作结果:按V和VR的定义构造图G。
              InsertVex ( &G, v);
         初始条件:图G存在,v和图中顶点有相同特征。
         操作结果:在图G中添加新顶点。
         ………………(参见P156-257)
    }
    
  • 图的基本操作:

    CreatGraph(&G, V, VR)  
    // 按定义(V, VR) 构造图
    
    DestroyGraph(&G)
      // 销毁图
    
    LocateVex(G, u);  
     // 若G中存在顶点u,则返回该顶点在图中位置,否则返回其它信息。
    
    GetVex(G, v);       // 返回 v 的值。
    
    PutVex(&G, v, value);   // 对 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中增添弧<v,w>,若G是无向的,
     //则还增添对称弧<w,v>。
    
    DeleteArc(&G, v, w);  
     //在G中删除弧<v,w>,若G是无向的,
     //则还删除对称弧<w,v>。
    
    DFSTraverse(G, v, Visit()); 
    //从顶点v起深度优先遍历图G,并对每
    //个顶点调用函数Visit一次且仅一次。
    
    BFSTraverse(G, v, Visit()); 
    //从顶点v起广度优先遍历图G,并对每
    //个顶点调用函数Visit一次且仅一次。

2.图的存储结构

a.邻接矩阵(数组)表示

  • 是否可以采用顺序存储结构存储图?
  •  邻接矩阵(数组)表示法
  •  代码
    Typedef   struct   ArcCell  {       //弧(边)结点的定义
         VRType     adj;    // VRType可以是int类型    
                      //顶点间关系,无权图取1或0;有权图取权值类型
        InfoType  *info;
    } ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    Typedef  enum {DG,DN,UDG,UDN} GraphKind
    
    
     Typedef struct {                             //图的定义
          VertexType   vexs [MAX_VERTEX_NUM ] ; //顶点表
    	// VertexType 可以是char类型
          AdjMatrix    arcs;                     //邻接矩阵
          int   Vernum,   arcnum;      //顶点总数,弧(边)总数
          GraphKind      kind;                //图的种类标志
    } Mgraph;       
    
  • 用邻接矩阵构造无向网的算法

    Status CreateUDN ( Mgraph &G ) 
    {   //无向网的构造,用邻接矩阵表示
      Scanf (&G.vexnum, &G.arcnum); 
                                                       //输入总顶点数,总弧数和信息
      for ( i=0;i<G.vexnum,;++i)  scanf (&G.vexs[i] );
                            //输入顶点值,存入一维向量中
    //对邻接矩阵n*n个单元初始化,adj=∞
      for( i=0; i<G. vexnum; ++i )  
          for ( j=0; j<G.vexnum; ++j )   
                G.arcs[i][j]={ INFINITY,NULL}; 
    //#include <limits.h>,#define INFINITY   INT_MAX
    
      for ( k=0; k<G.arcnum; ++k)
     {   //给邻接矩阵有关单元赋初值(循环次数=弧数)
        scanf(&v1, &v2, &w);     //输入弧的两顶点以及对应权值
        i=LocateVex(G,v1);    j=LocateVex(G,v2); 
                                                //找到两顶点在矩阵中的位置
        G.arcs[i][j].adj=w;        //输入对应权值
        G.arcs[j][i] = G.arcs [i] [j]; //无向网是对称矩阵
      } 
      return OK;
    } // CreateUDN 
    

    对于n个顶点e条弧的网, 建网时间效率 = O(n2+n+e*n)

b. 邻接表表示

  • 图的邻接表存储表示 
    Typedef   struct  VNode{                 //头结点结构-顶点结构
         VertexType   data;              //顶点信息
         ArcNode   * firstarc;         //指向依附该顶点的第一条弧的指针
    } VNode, AdjList[  MAX_VERTEX_NUM ];  
    
    Typedef  struct  ArcNode {             //表结点结构-边结构
          int  adjvex;                              //该弧所指向的顶点位置
          struct  ArcNode *nextarcs;   //指向下一条弧的指针
          InfoArc    *info;                     //该弧相关信息的指针
    } ArcNode;
    
    Typedef   struct {                 //图结构
         AdjList   vertics ;           //应包含邻接表
          int  vexnum, arcnum;  //应包含顶点总数和弧总数
          int  kind;                       //还应说明图的种类(用标志)
    }  ALGraph;             
    
  • 当邻接表的存储结构形成后,图便唯一确定!

  • 邻接表与邻接矩阵有什么异同之处?

c. 十字链表

  •  代码
    #define MAX_VERTEX_NUM 20
    
    Typedef  struct  ArcBox {               //弧结点结构
       int  tailvex , headvex ;
       struct  ArcBox * hlink , tlink;
       InfoType    *info;
    } ArcBox;
    
    Typedef   struct  VexNode{  //顶点结构
        VertexType   data;
         ArcBox   * firstin,*firstout;
    }VexNode;  
    
    Typedef   struct { 
          VexNode xlist[  MAX_VERTEX_NUM ];   //表头向量
          int  vexnum, arcnum;
    }OLGraph;    //图结构
    

d. 邻接多重表

3.图的遍历

  • 图的遍历操作要解决的关键问题 

a.深度优先遍历(DFS)

  • 基本思想 :
  •  深度优先搜索(遍历)步骤:
  •  计算机如何实现DFS?
  •  在图的邻接表中如何进行DFS?
  •  深度优先遍历图的算法:
    Boolean  visited [MAX];          // 访问标志数组
    Status (*VisitFunc) (int v);        //函数指针变量
    Void DFSTraverse( Graph  G, Status (*Visit) (int v))
    {         // 对图G做深度优先遍历
       VisitFunc = Visit;    
                      // 使用全局变量VisitFunc,使DFS不必设函数指针参数
        for (v=0; v<G.vexnum; ++v)  visited[v] = FALSE;
                                                                // 访问标志数组初始化
        for (v=0; v<G.vexnum; ++v) //对于连通图从某一个结点出发就可以访问到所有结点,如果是非连通图需要从多个结点出发才能访问所有结点。
             if (!visited[v])   DFS(G,v);  // 对尚未访问的顶点调用DFS
     }
    
    Void DFS (Graph G, int v)
    {  // 从第v个顶点出发递归地深度优先遍历图G
       visited [v] = TRUE;   VisitFunc (v); 
                                                //访问第v个顶点
       for ( w = FirstAdjVex (G, v);  w>=0;
               w = NextAdjVex (G, v, w) )
            if (!visited[w])   DFS(G,w);  
                                    // 对v的尚未访问的邻接点w递归调用DFS
     }
    
    Status FirstAdjVex(MGraph G,int v)
    {	int i;
    	for(i=0;i<G.vexnum;i++)
    		if(G.arcs[v][i].adj!=INFINITY)
    			return i;
    	return OVERFLOW;}
    
    Status NextAdjVex(MGraph G,int v,int w)
    {	int i;
    	for(i=w+1;i<G.vexnum;i++)
    		if(G.arcs[v][i].adj!=INFINITY)
    			return i;
    	return OVERFLOW;}
    
  • DFS 算法效率分析:

 b.广度优先遍历

  •  BFS算法如何编程?
    Void BFSTraverse ( Graph G, Status (* Visit) (int  v) )
    {   for ( v=0; v<G.vexnum; ++v )   visited[v] = FALSE ;
        InitQuene(Q);         // 置空的辅助队列Q
        for ( v=0; v<G.vexnum; ++v )
            if (!visited[v] )           // v尚未访问
          {  visited[v] = TRUE; Visit(v);
              EnQuene (Q,v);           // v入队列
              while (!QueneEmpty(Q))
            {  DeQuene (Q, u);            // 队头元素出队并置为u
                for (w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w))
                    if (! Visited [w] )         // w为u的尚未访问的邻接顶点
                 {  Visited [w] = TRUE;  Visit(w);
                     EnQuene (Q,w);
                  } //if 
              } //while
           } // if 
    }  // BFSTraverse
    
  • BFS 算法效率分析:

4.图的连通性问题

a.求图的生成树

b.求最小生成树

  • Kruskal(克鲁斯卡尔)算法
     
  • Prim(普里姆)算法
  •  计算机内怎样实现Prim(普里姆)算法?
void MiniSpanTree_P ( MGraph G, VertexType u) 
{  //用普里姆算法从顶点u出发构造网G的最小生成树
   k = LocateVex ( G, u ); 
   for ( j=0; j<G.vexnum; ++j )  // 辅助数组初始化
      if (j!=k)  
          closedge[j] = { u, G.arcs[k][j].adj };  
   closedge[k].lowcost = 0;      // 初始,U={u}
   for (i=0; i<G.vexnum; ++i) //选择其余G.vexnum-1个顶点
  {    k = minimum(closedge);  
                  // 求出T的下一个结点:第k顶点
    printf (closedge[k].adjvex, G.vexs[k]); 
                    // 输出生成树上一条边和对应的顶点
  closedge[k].lowcost = 0;    // 第k顶点并入U集
  for (j=0; j<G.vexnum; ++j)  //修改其它顶点的最小边
    if (G.arcs[k][j].adj < closedge[j].lowcost)
           //新顶点并入U后重新选择最小边
      closedge[j] = { G.vexs[k], G.arcs[k][j].adj }; 
  }//for
}// MiniSpanTree
  • 比较两种算法

5.有向无环图及其应用

a. AOV网—拓扑排序

 进行拓扑排序的方法:重复选择没有直接前驱的顶点。

b. AOE网—关键路径

  • 关键路径:在AOE网中,从始点终点具有最大路径长度(该路径上的各个活动所持续的时间之和)的路径称为关键路径。
  • 关键活动:关键路径上的活动称为关键活动。

  •  事件的最早发生时间Ve(j):
  •  事件的最迟发生时间Vl(i):
  •  活动as的最早开始时间e(s):
  •  活动as的最迟开始时间l(s):

6.最短路径

 a.单源最短路径 (Dijkstra算法)

 b.Dijkstra(迪杰斯特拉)算法

 

  • Dijkstra算法描述:
    (1)设A[n][n]为有向网的带权邻接矩阵,
        A[i][j]表示弧(vi,vj )的权值,
        S为已找到从源点v0出发的最短路径的终点集合,初始状态为{v0}.
           辅助数组dist[n]为各终点当前找到的最短路径的长度,初始值为: dist[i]=A[v0 ,i]  
                           //即邻接矩阵中第v0行的权值
    (2)选择u,使得
        dist[u]=min{ dist[w] | w∈V-S }   
          // w是S集之外的顶点,dist[u]是从源点v0到S集外所有顶点
            的弧中最短的一条
        S= S ∪{u}   //将u加入S集
    (3)对于所有不在S中的终点w,若
            dist[u]+ A[u,w]< dist[w]      
                           // 即(v0,u)+(u,w)<(v0,w)
        则修改dist[w]为: dist[w]= dist[u]+ A[u,w]
    (4)重复操作(2)、(3)共n-1次,由此求得从v0到各终点的最短路径。
    
    

    c.所有顶点之间的最短路径(Floyd算法)

二.练习题 

题组一:

题组二: 

一、单选题             

(  c )1. 在一个图中,所有顶点的度数之和等于图的边数的      倍。

             A.1/2            B.  1             C.  2             D.  4 

(  b  )2. 在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和的     倍。

             A.1/2            B.  1             C.  2             D.  4 

(  b  )3. 有8个结点的无向图最多有      条边。

             A.14            B.  28             C.  56             D.  112

(  c  )4. 有8个结点的无向连通图最少有      条边。

             A.5            B.  6             C.  7             D.  8

(  c  )5. 有8个结点的有向完全图有      条边。

             A.14            B.  28             C.  56             D.  112

(  b  )6. 用邻接表表示图进行广度优先遍历时,通常是采用         来实现算法的。

A.栈            B. 队列            C.               D.  

(  a  )7. 用邻接表表示图进行深度优先遍历时,通常是采用         来实现算法的。

A.栈            B. 队列            C.               D.  

( c  )8. 已知图的邻接矩阵,根据算法思想,则从顶点0出发按深度优先遍历的结点序列是

(  d  )9. 已知图的邻接矩阵同上题8,根据算法,则从顶点0出发,按深度优先遍历的结点序列是

A. 0 2 4 3 1 5 6      B.  0 1 3 5 6 4 2     C.  0 4 2 3 1 6 5   D.  0 1 3 4 2 5 6

b)10. 已知图的邻接矩阵同上题8,根据算法思想,则从顶点0出发,按广度优先遍历的结点序列是

A. 0 2 4 3 6 5 1      B.  0 1 3 6 4 2 5      C.  0 4 2 3 1 5 6   D.  0 1 3 4 2 5 6

(  c  )11. 已知图的邻接矩阵同上题8,根据算法,则从顶点0出发,按广度优先遍历的结点序列是

A. 0 2 4 3 1 6 5     B.  0 1 3 5 6 4 2     C.  0 1 2 3 4 6 5   D.  0 1 2 3 4 5 6

(  d  )12. 已知图的邻接表如下所示,根据算法,则从顶点0出发按深度优先遍历的结点序列是

 (  a )13.  已知图的邻接表如下所示,根据算法,则从顶点0出发按广度优先遍历的结点序列是

(  a  )14. 深度优先遍历类似于二叉树的

A.先序遍历      B.  中序遍历     C.  后序遍历    D.  层次遍历

(  d  )15. 广度优先遍历类似于二叉树的

A.先序遍历      B.  中序遍历     C.  后序遍历    D.  层次遍历

(  a  )16. 任何一个无向连通图的最小生成树

A.只有一棵     B.  一棵或多棵     C.  一定有多棵    D.  可能不存在

(注,生成树不唯一,但最小生成树唯一,即边权之和或树权最小的情况唯一)

二、填空题

1. 图有 邻接矩阵    邻接表  等存储结构,遍历图有 深度优先遍历   广度优先遍历   等方法。

2. 有向图G用邻接表矩阵存储,其第i行的所有元素之和等于顶点i   出度   

3. 如果n个顶点的图是一个环,则它有    n    棵生成树。  (以任意一顶点为起点,得到n-1条边)

4.  n个顶点e条边的图,若采用邻接矩阵存储,则空间复杂度为   O(n2)    

5.  n个顶点e条边的图,若采用邻接表存储,则空间复杂度为    O(n+e)    

6. 设有一稀疏图G,则G采用  邻接表   存储较省空间。

7. 设有一稠密图G,则G采用  邻接矩阵   存储较省空间。

8. 图的逆邻接表存储结构只适用于   有向  图。

9. 已知一个图的邻接矩阵表示,删除所有从第i个顶点出发的方法是 将邻接矩阵的第i行全部置0  

10. 图的深度优先遍历序列  不是  惟一的。

11.  n个顶点e条边的图采用邻接矩阵存储,深度优先遍历算法的时间复杂度为   O(n2) ;若采用邻接表存储时,该算法的时间复杂度为  O(n+e)    

12. n个顶点e条边的图采用邻接矩阵存储,广度优先遍历算法的时间复杂度为   O(n2)    ;若采用邻接表存储,该算法的时间复杂度为   O(n+e)    

13. 图的BFS生成树的树高比DFS生成树的树高 小或相等     

14. 用普里姆(Prim)算法求具有n个顶点e条边的图的最小生成树的时间复杂度为  O(n2)     ;用克鲁斯卡尔(Kruskal)算法的时间复杂度是   O(elog2e)     

15. 若要求一个稀疏图G的最小生成树,最好用  克鲁斯卡尔(Kruskal)  算法来求解。

16. 若要求一个稠密图G的最小生成树,最好用  普里姆(Prim)   算法来求解。

17. 用Dijkstra算法求某一顶点到其余各顶点间的最短路径是按路径长度   递增   的次序来得到最短路径的。

18.  拓扑排序算法是通过重复选择具有   0   个前驱顶点的过程来完成的。

三、分析求解题

 

 

题组三:

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值