【数据结构(C语言)】数据结构-图

在这里插入图片描述

一、基本概念

1.图的定义

图(Graph):由两个集合V(G)和E(G)组成的,记为G=(V,{E})
其中:V是顶点的有穷非空集;E是边(弧)的有限集

2.约定符号

  • V

    顶点有穷非空集合

  • VR

    顶点关系的集合

  • E

    边或弧的集合

  • n

    图中顶点数目

  • e

    边或弧的数目

  • G

  • N

3.分类

  • 有向图

    • 术语

      • 顶点

        图中的数据元素

        • 入度

          顶点v的入度:以v为头的弧的数目,记为ID(v)

        • 出度

          顶点v的出度:以v为尾的弧的数目,记为OD(v)

        • 顶点v的度TD(v)= ID(v)+ OD(v)

      • 弧,弧头,胡尾

        <v,w>表示从v到w的一条弧,w称作弧头,v称作弧尾

      • 邻接关系

        如果弧<v,w> ∈E,称v邻接到w或w邻接自v

      • 有向完全图

        n个顶点、有n(n-1)条弧的有向图

    • 定义

      有向图G1 =(V1,{A}) 其中,V1 = {v1,v2,v3,v4} A = {<v1,v2>, <v1,v3>,
      <v3,v4>, <v4,v1>}

    • 有向图的连通性

      • v到w的路径

        在有向图G=(V,{E})中由顶点v经有向弧至w的顶点序列

      • v和w是连通的

        顶点v到w以及w到v都有路径存在

      • 强连通图

        有向图 G 的任意两点之间都连通

      • 强连通分量

        有向图的极大强连通子图

    • 有向树

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

    • 有向图的生成森林

      由若干有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧。

  • 无向图

    • 术语

      • 顶点

        图中的数据元素

        • 顶点的度

          顶点v相关联的边的数目即v的度,记为TD(v)

      • 邻接点

        如果边(v,w)∈E,v和w互为邻接点,或v和w相邻接
        边(v,w)依附于顶点v和w,或边(v,w)与v和w相关联

      • (v,w)表示v,w之间的一条边

      • 无向完全图

        n个顶点、有n(n-1)/2 条边的无向图

    • 定义

      无向图G2 =(V2,{E}) 其中,V2 = {v1,v2,v3,v4,v5} E = {(v1,v2),
      (v1,v3),(v2,v4), (v2,v5), (v3,v5),(v4,v5)}

    • 无向图的连通性

      • v到w的路径

        在无向图G=(V,{E})中由顶点v经无向边至w的顶点序列

      • v和w是连通的

        顶点v和w之间有路径存在

      • 连通图

        无向图的任意两点之间都连通

      • 连通分量

        无向图的极大连通子图

    • 无向连通图的生成树

      无向连通图的极小连通子图。包含图的全部n个顶点和足以构成一棵树的n-1条边。在生成树中添加一条边之后,必定会形成回路或环

4.子图

G=(V,{E}),G’= (V’,{E’}),若V’属于 V,E’属于 E,则G’是G的子图

5.路

  • 简单路径

    路径序列中顶点不重复出现

  • 回路或环

    第一个顶点和最后一个顶点相同的路径

  • 简单回路或简单环

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

6.其他术语

  • 稀疏图

    很少条边或弧(e<nlog2n)的图

  • 稠密图

    有很多条边或弧的图

  • 边或弧的权值

    与弧或边相关的数。可以表示从一个顶点到另一个顶点的距离、花费的代价、所需的时间等

  • 边或弧上带权的图

7.ADT

ADT Graph {
数据对象V: V是具有相同特性的数据元素的集合,即顶点集
数据关系R: R={VR} VR={<v,w>|……}
基本操作P:
CreateGraph(&G,V,VR); DestroyGraph (&G);
GetVex (G,v); PutVex (&G,v,value);
LocateVex(G,u);
FirstAdjVex (G,v);
NextAdjVex(G,v,w);
InsertVex (&G,v); DeleteVex (&G,v);
InsertArc (&G,v,w); DeleteArc (&G,v,w);
DFSTraverse (G,Visit());
BFSTraverse (G,Visit());
} ADT Graph

二、存储结构

1.邻接矩阵(数组)

用一个1-D数组存放顶点的元素信息
用一个二维数组存储顶点之间的关系,其中:
A[i][j]=1,i到j有弧且i≠j;
A[i][j]=0,其他情况
网的邻接矩阵:
A[i][j]= wi,j,若<vi,vj>或(vi,vj)∈E
A[i][j]= ∞,反之

  • 存储类型的定义

    typedef enum { DG, DN, UDG, UDN } GraphKind;
    typedef struct ArcCell
    {
    VRType adj;
    infoType *info;
    }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    typedef struct 
    {
    VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
    AdjMatrix arcs;
    int vexnum,arcnum;
    GraphKind kind;
    }MGraph;
    
  • 建图

    Status CreateGraph(MGraph& G)
    {//在邻接矩阵存储结构上根据图的种类调用具体构造算法
    printf("please input the kind of graph\n");
    printf("0构造有向图 1构造有向网 2构造无向图 3构造无向网\n");
    scanf("%d",&G.kind);
    switch (G.kind)
    {
    case DG:return CreateDG(G);//构造有向图
    case DN:return CreateDN(G);//构造有向网
    case UDG:return CreateUDG(G);//构造无向图
    case UDN:return CreateUDN(G);//构造无向网
    default:return ERROR;
    }
    }
    
    • 算法

      • 构造有向图

        Status CreateDG(MGraph &G) //在邻接矩阵存储结构上,构造有向图G
        {	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;i<G.vexnum;i++)	scanf(&G.vexs[i]);//构造顶点向量
        for(i=0;i<G.vexnum;i++) //邻接矩阵初始化
          for(j=0;j<G.vexnum;j++)
         	G.arcs[i][j]=0;
        for(k=0;k<G.arcnum;k++)//构造邻接矩阵
        {	scanf(&v1,&v2,);//读入一条边依附的顶点
        	i=LocateVex(G,v1);j=LocateVex(G,v2);//确定v1、v2在图中的位置
        	G.arcs[i][j]=1;//边<v1,v2>
        } 	
        return OK;
        }//CreateDG
        
      • 构造有向网

        Status CreateDN(MGraph &G) //在邻接矩阵存储结构上,构造有向网G
        {	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;i<G.vexnum;i++)	scanf(&G.vexs[i]);//构造顶点向量
        for(i=0;i<G.vexnum;i++) //邻接矩阵初始化
          for(j=0;j<G.vexnum;j++)
         	G.arcs[i][j]=INFINITY;
        for(k=0;k<G.arcnum;k++)//构造邻接矩阵
        {	scanf(&v1,&v2,&w);//读入一条弧依附的顶点及权值
        	i=LocateVex(G,v1);j=LocateVex(G,v2);//确定v1、v2在图中的位置
        	G.arcs[i][j]=w;//边<v1,v2>的权值
        } 	
        return OK;
        }//CreateDN
        
      • 构造无向图

        Status CreateUDG(MGraph &G) //在邻接矩阵存储结构上,构造无向图G
        {	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;i<G.vexnum;i++)	scanf(&G.vexs[i]);//构造顶点向量
        for(i=0;i<G.vexnum;i++) //邻接矩阵初始化
          for(j=0;j<G.vexnum;j++)
         	G.arcs[i][j]=0;
        for(k=0;k<G.arcnum;k++)//构造邻接矩阵
        {	scanf(&v1,&v2,);//读入一条边依附的顶点
        	i=LocateVex(G,v1);j=LocateVex(G,v2);//确定v1、v2在图中的位置
        	G.arcs[i][j]=1;//边<v1,v2>
        	G.arcs[j][i]=G.arcs[i][j];//置<v1,v2>的对称弧<v2,v1 >
        } 	
        return OK;
        }//CreateUDG
        
      • 构造无向网

        Status CreateUDN(MGraph &G) //在邻接矩阵存储结构上,构造无向网G
        {	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;i<G.vexnum;i++)	scanf(&G.vexs[i]);//构造顶点向量
        for(i=0;i<G.vexnum;i++) //邻接矩阵初始化
          for(j=0;j<G.vexnum;j++)
         	G.arcs[i][j]=INFINITY;
        for(k=0;k<G.arcnum;k++)//构造邻接矩阵
        {	scanf(&v1,&v2,&w);//读入一条边依附的顶点及权值
        	i=LocateVex(G,v1);j=LocateVex(G,v2);//确定v1、v2在图中的位置
        	G.arcs[i][j]=w;//边<v1,v2>的权值
        	G.arcs[j][i]=G.arcs[i][j];//置<v1,v2>的对称弧<v2,v1 >
        } 	
        return OK;
        }//CreateUDN
        
    • 算法分析

      • 优缺点

        优点
        易判定任两个顶点之间是否有边或弧存在。
        适合存储有向图、无向图、有向网、无向网
        缺点:在边稀疏(e<<n(n-1)/2)时,浪费存储空间

      • 时间复杂度讨论

        有n个顶点和e条边的图
        邻接矩阵初始化的时间复杂度为O(n2)
        输入顶点编号,建立邻接矩阵的时间复杂度为O(e)
        输入顶点值,建立邻接矩阵的时间复杂度为O(ne)
        总的时间复杂度为:O(n2+n
        e)

  • 定位顶点

    • 算法分析

      遍历顶点向量,定位顶点,失败则返回-1

    • 代码实现

      int LocateVex(MGraph G, VertexType v)
      {
      int i;
      for (i = 0; i < G.vexnum; i++)
      	if (G.vexs[i] == v)   
      		return i;
      return -1;
      }//定位顶点坐标
      	```
      
      

2.邻接表

图的一种链式存储结构,适用于有向图和无向图。对图中每个顶点建立一个单链表,单链表中的结点表示依附于该顶点的边(对有向图来说是以该顶点为弧尾的弧)

  • 存储类型定义

    typedef struct ArcNode//表结点
    {
    int adjvex;//弧指向顶点的位置
    struct ArcNode* nextarc;//指向下一弧的指针
    }ArcNode;
    typedef struct Vnode//头结点
    {
    VertexType data;//顶点信息
    ArcNode* firstarc;//指向第一条弧的指针
    }VNode, AdjList[MAX_VERTEX_NUM];
    typedef struct
    {
    AdjList vertices;//头节点向量
    int vexnum, arcnum; //图的当前顶点数和弧数
    int kind;      //图的种类
    }ALGraph;
    
  • 建图

    • 算法

      • 构造有向图
      • 构造有向网
      • 构造无向图
      • 构造无向网
    • 算法分析

      • 优缺点

        优点:易找到任一顶点的第一个邻接点和下一个邻接点
        适合存储有向图(网)、无向图(网)
        缺点:难以直接判定任意两个顶点之间是否有边或弧相连。需搜索第i和第j个单链表。不及邻接矩阵方便。

      • 时间复杂度讨论

        时间复杂度的讨论:
        邻接表头结点初始化的时间复杂度为O(n)
        输入顶点编号,建立邻接点链表的时间复杂度为O(e)
        输入顶点值,建立邻接点链表的时间复杂度为O(ne)
        总的时间复杂度为:O(n+n
        e)

三、基本算法

1.遍历

  • 定义

    从图中某个顶点出发遍访图中其余顶点,且使每个顶点仅被访问一次的过程.

  • 意义

    对非线性结构线性化。遍历算法是求解图的连通性、拓扑排序、求关键路径等算法的基础。

  • 两种遍历方式

    • 深度优先搜索DFS (Depth First Search)

      • 算法思想

        深度优先遍历:类似于树的先序遍历,是其推广
        ①从图中某个顶点v出发,访问此顶点;
        ②依次从v的各个未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到
        ③若图中还有顶点未被访问(非连通图),则另选图中一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

      • 算法代码

        Boolean visited[MAX_VERTEX_NUM]; 
        Status (*VisitFunc)(int v); //全局函数指针变量
        void DFSTraverse( Graph G, Status (*Visit)(int v))
        { //对图G进行深度优先遍历  
        VisitFunc=Visit;
        for ( v=0; v <G.vexnum; ++v ) visited[v] = FALSE;
        for ( v=0; v <G.vexnum; ++v )
         if ( !visited[v] ) DFS(G,v); 
        }//DFSTraverse
        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)} //DFS
        
      • 算法分析

        在遍历图时,对每个顶点至多调用一次DFS函数,因为一旦某个顶点被标志成已被访问,就不再从它出发进行搜索。
        遍历图的实质上是对每个顶点查找其邻接点的过程。其耗费的时间取决于所采用的存储结构。
        用邻接矩阵存储图时,查找所有顶点的邻接点需要O(n2);
        用邻接表存储图时,查找所有顶点的邻接点需要O(e);
        深度优先遍历图的算法的时间复杂度与采用的存储结构有关
        以邻接矩阵做图的存储结构时,深度优先遍历的时间复杂度为O(n2)
        以邻接表做图的存储结构时,深度优先遍历的时间复杂度为O(n+e)。

    • 广度优先搜索BFS (Breadth First Search)

      • 算法思想

        类似于树的层序遍历,是其推广。
        广度优先遍历的实质是以v为起点,由近及远,依次访问和v有路径相通且路径长度为1、2、……的顶点。
        步骤:
        ①从图中的某个顶点v出发,访问此顶点;
        ②依次访问v的所有未被访问过的邻接点,之后按这些邻接点被访问的先后次序依次访问它们的邻接点,直至图中所有和v有路径相通的顶点都被访问到;
        ③若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。

      • 算法代码

        void BFSTraverse(Graph G,Status(*Visit)(int v)) 
        { //对图G进行广度优先遍历
        for(v=0;v<G.vexnum;++v) visited[v] = FALSE;  
        InitQueue(Q);
        for( v=0;v<G.vexnum;++v )
        if(!visited[v]) //v没有被访问 
        { visited[v]=TRUE; 	Visit(v);   //访问v
         EnQueue(Q,v);  //v入队列
         while(!QueueEmpty(Q))
         { DeQueue(Q,u); //队头元素u出队列
           for(w=FirstAdjVex(G,u); w>=0; w=NextAdjVex(G,u,w)) 
        	if(!Visited[w])  
        	{ visited[w]=TRUE; Visit(w); //访问w
        	  EnQueue(Q,w); //w入队列
        	} //if
         } //while
         } //if
        } //BFSTraverse
        
  • 辅助向量visited[]的使用

    • 使用原因

      因为图中任意顶点都可能和其余顶点相邻接,所以在访问了某顶点后,可能沿另外的某条路径搜索,而后又回到此顶点上,为了避免同一顶点被多次访问,在遍历图的过程中,必须记下每个已访问过的顶点。

    • 使用方法

      设置一个辅助数组visited[0…n-1],它的初始值置为“假”,表示顶点未被访问过,一旦访问了顶点i,就置visited[i]的值为“真”或者被访问时的次序号。

2.求无向图的连通分量

  • 算法思想

    利用图的遍历算法来判定一个无向图是否是连通图
    对于无向连通图,从任一顶点出发,进行深度/广度优先遍历,就可访遍图中所有顶点;
    对于非连通图,它有几个连通分量,就需要从几个顶点出发进行遍历。
    修改DFSTraverse和BFSTraverse中的语句,可以判断无向图的连通分量个数。如:
    sum=0;
    for ( v=0; v <G.vexnum; ++v )
    if ( ! visited[v] )
    { sum++;

    }

3.生成树或生成森林

  • 深度优先生成树

    由深度优先遍历得到的为深度优先生成树

  • 广度优先生成树

    由广度优先遍历得到的为广度优先生成树

4.最小生成树

  • 定义

    生成树中各边权值(代价)之和最小的树。

  • 最小生成树的应用

    在n个城市之间选取n-1条线路架设连通的通信网使总费用最低问题 在n个顶点的连通网上构造最小生成树

  • MST性质

    设N=(V,{E})是连通网,U是V的一个非空子集。若(u,v)是所有满足u∈U, v∈V-U的边中代价最小的边,则必存在一棵包括边(u, v)的最小生成树。 (可用反证法证明)

    • Prim算法(点)

      • Prim算法步骤

        设N=(V,{E})是连通网,T=(V,{TE})表示N的最小生成树,TE为最小生成树边的集合,初始为空集。则Prim算法的执行过程:
        Step1:令U={u},u∈V(u是网中任意一个顶点),TE={};
        Step2:在u∈U,v∈V-U的边(u,v)∈E中寻找一条代价最小的边(u,v)并入TE,同时将顶点v并入U;
        Step3:重复Step2,直至U=V,此时TE中必有n-1条边,而T={V,{TE}}是N的一棵最小生成树。

      • 时间复杂度

        只与顶点数有关, 与网中的边数无关
        适用于求边稠密的网的最小生成树

    • Kruscal算法(边)

      • Kruskal算法步骤

        步骤:
        假设连通网N=(V,{E}),T=(V,{TE})表示N的最小生成树,TE为最小生成树上边的集合。初始时令TE为空集。
        Step1:令最小生成树T的初态为只有n个顶点的非连通图T=(V,{TE}),TE={}。
        Step2:从权值最小的边(u,v)开始,若该边依附的两个顶点落在T的不同连通分量上,则将此边加入到TE中,即TE=TE∪(u,v),否则舍弃此边,选择下一条代价最小的边。
        Step3:重复Step2,直至TE所有顶点在同一连通分量上。此时T=(V,{TE})就是N的一棵最小生成树。

      • 时间复杂度

        O(e*loge),只与边数有关, 与网中的顶点数无关
        适合于求边稀疏的网的最小生成树

5.拓扑排序

  • 概念和术语

    • DAG图

      • 有向无环图(DAG图)

        无环的有向图

      • 应用

        • 描述有公共因子的表达式
        • 描述工程和系统的进行过程
      • 有向图中检测是否存在环

        • 拓扑排序

          对有向图进行拓扑排序,若网中所有顶点都在它的拓扑有序序列中,则不存在环。

        • 深度优先遍历

          利用深度优先遍历判断有向图是否存在环的方法:

          由图中某点出发进行深度优先搜索遍历,遇到回边时,判断该回边指向顶点的深度优先遍历过程是否已结束,若发现回边时弧头顶点的深度优先遍历过程还未退出,则图中有环。

    • AOV网

      • AOV(Activity On Vertex)网

        有向图可用来描述一项工程或系统的完成过程。在这种图中,顶点表示活动,有向弧表示活动之间的优先关系,如
        <vi,vj>表示活动vi必须先于活动vj进行。其中vi是vj的直接前驱,vj是vi的直接后继。若从顶点vi到vk有一条路径,则vi是vk的前驱、vk是vi的后继;

      • 用途:描述工程项目或系统进行的次序

    • 偏序

      若集合 X 上的关系R是传递的、自反的、反对称的,则称R是集合X上的偏序关系。可指集合中部分成员之间可比较。

    • 全序

      若关系R 是集合 X 上的偏序关系,如果对于属于X的每个x,y,必有xRy 或yRx
      ,则称R是集合X上的全序关系。可指集合中全部成员之间可比较。

    • 拓扑排序

      由集合上的偏序得到该集合上的全序的操作。这个全序被称为拓扑有序。

  • 拓扑排序步骤

    • Step1:

      在有向图中选一个无前驱的顶点输出之;

    • Step2:

      从有向图中删去此顶点及所有以它为尾的弧;

    • Step3:

      重复前2步,直到图中顶点全部输出,此时图中无环;或图不空但找不到无前驱的顶点,此时图中有环。

  • 算法

    • 算法思想

      基于邻接表存储结构的图的拓扑排序算法:
      辅助数组Indegree[]:记录每个顶点的入度
      辅助结构:暂存入度为零的顶点以避免重复检测

    • 算法代码

      Status TopologicalSort(ALGraph G)   
      { FindIndegree(G,indegree);  
      InitStack(S); //用到第3章中栈的基本操作 
      for(i=0;i<G.vexnum;++i)  if (!indegree[i]) Push(S,i); 
      count=0;    //对输出顶点计数 
      while(!StackEmpty(S))
      { Pop(S,i);  printf(i,G.vertices[i].data); 
       ++count;         //输出顶点数加1
       for(p=G.vertices[i].firstarc; p; p=p->nextarc)
       { k=p->adjvex; if(!(--indegree[k])) Push(S,k); }
      }//while 
      if(count<G.vexnum) return ERROR;  
      else return OK;      //无回路   
      }// TopologicalSort
      

6.关键路径

  • 术语

    • AOE-网

      • AOE-网(Activity On Edge

        AOE-网(Activity On Edge):一个有向无环网,顶点表示事件,弧表示活动,弧上权值表示活动持续的时间。

      • 通常用来估算工程完成时间

      • 源点

        入度为0

      • 汇点

        出度为0

      • 路径长度

        AOE网中路径上各活动持续时间之和。

      • 关键路径

        从源点到汇点路径长度最长的路径。

    • 活动ai的最早开始时间e(i)

      活动ai的最早开始时间e(i):是从源点v0到vj的最长路径长度。

    • 活动ai的最迟开始时间l(i)

      是不推迟工程完成的前提下,该活动允许的最迟开始时间。

    • 活动ai时间余量

      l(i)-e(i)

    • 关键活动

      l(i)=e(i)的活动。 关键路径上的活动都是关键活动

    • 事件vk的最早发生时间Ve(k)

      事件vk的最早发生时间Ve(k)=从源点v0到vk的最长路径长度 Ve(0)=0;
      Ve(k)=Max{Ve(j)+dut(<j,k>), <j,k>∈T,所有j}

    • 事件vj的最迟开始时间Vl(j)

      保证汇点vn-1在Ve(n-1)时刻完成的前提下,事件vj最迟允许开始的时间。 Vl(n-1) =
      Ve(n-1)=从源点到汇点的最长路径长度; Vl(j)=Min{Vl(k)-dut(<j,k>), <j,k>∈T,所有k}

  • 求关键活动

    • 从Ve(0)=0向汇点方向递推

      从Ve(0)=0向汇点方向递推,顶点vk的最早开始时间ve(k)=Max{Ve(j)+dut(<j,k>)},在拓扑有序的前提下进行

    • 从vl(n-1)=ve(n-1)向源点方向推

      从vl(n-1)=ve(n-1)向源点方向推,顶点vj的最迟开始时间vl(j)=Min{vl(k)-dut(<i,j>)},在逆拓扑有序前提下进行

7.最短路径

  • 最短路径问题

    从图中某一顶点到达另一顶点的路径可能不止一条,求其中一条路径使得沿此路径上各弧上的权值总和最小。称路径的第一个顶点为源点,最后一个顶点为终点。

  • 算法

    • Dijkstra算法

      迪杰斯特拉提出了一个按路径长度递增次序产生最短路径的算法——迪杰斯特拉算法
      一般情况下,假设S为已求得最短路径终点的集合,可以证明:下一条最短路径(设其终点为vk)可能是弧<v0,vk>或者是中间只经过S中的顶点到达顶点vk的路径(反证法)

      • 步骤

        • Step1:置final[i] 为FALSE,从源点v0出发到图上其余各顶点vi (vi∈V)可能的最短路径长度的初值为:
          D[i]= G.arcs[LocateVex(G,v0)][i];
        • Step2:选择vj ,使得D[j]={D[i]|vi∈V-S}, 则vj就是当前求得的一条从v0出发的最短路径的终点,令final[j]为TRUE,即S=S∪{vj};
        • Step3:修改从v0出发到集合V-S上任一顶点vk可达的最短路径长度:如果D[j] +arcs[j][k]<D[k],则更新D[k]为D[k]=D[j]+arcs[j][k];
        • Step4:重复Step2、Step3共n-1次,由此求得从v0到其余各顶点的n-1条最短路径,并且它们是按路径长度递增的。
      • 代码

        Status ShortestPath_DIJ(MGraph G, int v0, 
        int P[MAX_VERTEX_NUM][ MAX_VERTEX_NUM], VRType D[MAX_VERTEX_NUM])
        {//求邻接矩阵表示的图的最短路径的Dijkstra算法
        初始化D[],P[][],final[]数组; 
         D[v0]=0;	 final[v0]=TRUE;  //v0并入S
        for(i=1;i<G.vexnum;i++) //对于其余G.vexnum-1个顶点
         { select(D,final,min,v);
        final[v]=TRUE;  //找到一条从v0到v的最短路径
          for(w=0; w<G.vexnum;w++) //更新当前最短路径和距离
        	{ if(!final[w]&& (min+G.arcs[v][w]<D[w]))
        	  { D[w]=min+G.arcs[v][w];  
        	   P[w]=P[v];
             P[w][w]=TRUE; //w是从v0到w的最短路径上的顶点
        	  }//if
        	}//for
         }//for
        }//ShortestPath_DIJ
        
    • Floyd算法

      • (1)在vi和vj之间加入顶点v0,若<vi,v0>和<v0,vj>存在,则(vi,v0,vj)存在,比较<vi,vj>和(vi,v0,vj)的路径长度,取较短者为从vi到vj的中间顶点序号不大于0的最短路径。

      • (2)在vi和vj之间加入顶点v1,若(vi,…,v1)和(v1,…,vj)分别是当前找到的中间顶点序号不大于0的最短路径,则路径(vi,…,v1,…vj)存在,和上一步求出的vi和vj的中间顶点序号不大于0的最短路径比较后,取较短者为从vi到vj的中间顶点序号不大于1的最短路径。

      • (3)以此类推,在vi和vj之间加入顶点vk,若(vi,…,vk)和(vk,…,vj)分别是当前找到的中间顶点序号不大于k-1的最短路径,则将路径(vi,…,vk,…vj)和已经求得的vi和vj的中间顶点序号不大于k-1的最短路径比较后,取较短者为从vi到vj的中间顶点序号不大于k的最短路径。

      • 经过n次比较后,最后求得的必是vi到vj的最短路径。按此方法可以同时求得每一对顶点之间的最短路径。

文章索引

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BkbK-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值