数据结构-图


文章目录

    • 基本概念
      • 图的定义
      • 约定符号
      • 分类
      • 子图
      • 其他术语
      • ADT
    • 存储结构
      • 邻接矩阵(数组)
      • 邻接表
    • 基本算法
      • 遍历
      • 求无向图的连通分量
      • 生成树或生成森林
      • 最小生成树
      • 拓扑排序
      • 关键路径
      • 最短路径

基本概念

图的定义

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

约定符号

  • V

    顶点有穷非空集合

  • VR

    顶点关系的集合

  • E

    边或弧的集合

  • n

    图中顶点数目

  • e

    边或弧的数目

  • G

  • N

分类

  • 有向图

    • 术语

      • 顶点

        图中的数据元素

        • 入度

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

        • 出度

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

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

      • 弧,弧头,胡尾

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

      • 邻接关系

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

      • 有向完全图

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

    • 定义

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

    • 有向图的连通性

      • 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条边。在生成树中添加一条边之后,必定会形成回路或环

子图

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

  • 简单路径

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

  • 回路或环

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

  • 简单回路或简单环

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

其他术语

  • 稀疏图

    很少条边或弧(e

  • 稠密图

    有很多条边或弧的图

  • 边或弧的权值

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

  • 边或弧上带权的图

ADT

ADT Graph {
数据对象V: V是具有相同特性的数据元素的集合,即顶点集
数据关系R: R={VR} VR={|……}
基本操作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-D数组存放顶点的元素信息
用一个二维数组存储顶点之间的关系,其中:
A[i][j]=1,i到j有弧且i≠j;
A[i][j]=0,其他情况
网的邻接矩阵:
A[i][j]= wi,j,若或(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
		  	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;//边
		  	} 	
		    return OK;
		  }//CreateDG
	- 构造有向网
		  Status CreateDN(MGraph &G) //在邻接矩阵存储结构上,构造有向网G
		  {
     	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;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;//边的权值
		  	} 	
		    return OK;
		  }//CreateDN
	- 构造无向图
		  Status CreateUDG(MGraph &G) //在邻接矩阵存储结构上,构造无向图G
		  {
     	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;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;//边
		  		G.arcs[j][i]=G.arcs[i][j];//置的对称弧
		  	} 	
		    return OK;
		  }//CreateUDG
	- 构造无向网
		  Status CreateUDN(MGraph &G) //在邻接矩阵存储结构上,构造无向网G
		  {
     	scanf(&G.vexnum,&G.arcnum);//读入顶点数和边数目for(i=0;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;//边的权值
		  		G.arcs[j][i]=G.arcs[i][j];//置的对称弧
		  	} 	
		    return OK;
		  }//CreateUDN
- 算法分析

	- 优缺点

	  优点
	  易判定任两个顶点之间是否有边或弧存在。
	  适合存储有向图、无向图、有向网、无向网
	  缺点:在边稀疏(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;
	  }//定位顶点坐标

邻接表

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

  • 存储类型定义
  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)

基本算法

遍历

  • 定义

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

  • 意义

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

  • 两种遍历方式

    • 深度优先搜索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]的值为“真”或者被访问时的次序号。

求无向图的连通分量

  • 算法思想

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

    }

生成树或生成森林

  • 深度优先生成树

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

  • 广度优先生成树

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

最小生成树

  • 定义

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

  • 最小生成树的应用

    在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),只与边数有关, 与网中的顶点数无关
	  适合于求边稀疏的网的最小生成树

拓扑排序

  • 概念和术语

    • DAG图

      • 有向无环图(DAG图)

        无环的有向图

      • 应用

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

        • 拓扑排序

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

        • 深度优先遍历

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

    • AOV网

      • AOV(Activity On Vertex)网

        有向图可用来描述一项工程或系统的完成过程。在这种图中,顶点表示活动,有向弧表示活动之间的优先关系,如 表示活动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

关键路径

  • 术语

    • 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(), ∈T,所有j}

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

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

  • 求关键活动

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

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

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

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

最短路径

  • 最短路径问题

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

  • 算法

    • Dijkstra算法

      迪杰斯特拉提出了一个按路径长度递增次序产生最短路径的算法——迪杰斯特拉算法
      一般情况下,假设S为已求得最短路径终点的集合,可以证明:下一条最短路径(设其终点为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] 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,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的最短路径。按此方法可以同时求得每一对顶点之间的最短路径。

你可能感兴趣的:(#,数据结构c,学习笔记,数据结构,算法,图论)