第八章 图.ppt

上传人:jobexamine331 文档编号:388833 上传时间:2018-10-12 格式:PPT 页数:133 大小:1.74MB
下载 相关 举报
第八章 图.ppt_第1页
第1页 / 共133页
第八章 图.ppt_第2页
第2页 / 共133页
第八章 图.ppt_第3页
第3页 / 共133页
第八章 图.ppt_第4页
第4页 / 共133页
第八章 图.ppt_第5页
第5页 / 共133页
亲,该文档总共133页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

1、第八章 图,图的基本概念 图的存储结构 图的遍历与连通性 最小生成树 最短路径 活动网络,1,图的基本概念,图定义 图是由顶点(vertex)集合以及顶点之间的关系集合组成的一种数据结构:G( V, E ) 其中 V = x | x 某个数据对象 是顶点的有穷非空集合;E = (x, y) | x, y V 或 E = | x, y V & Path (x, y)是顶点之间关系的有穷集合,也叫做边(edge)集合。Path (x, y)表示从 x 到 y 的一条单向通路, 它是有方向的。,2,有向图与无向图 在有向图中,顶点对 是有序的。在无向图中,顶点对(x, y)是无序的。 完全图 若有

2、n 个顶点的无向图有 n(n-1)/2 条边, 则此图为无向完全图。若有 n 个顶点的有向图有n(n-1) 条边, 则此图为有向完全图。,3,0,0,0,0,1,1,1,1,2,2,2,2,6,5,4,3,3,邻接顶点 如果 (u, v) 是 E(G) 中的一条边,则称 u 与 v 互为邻接顶点。 子图 设有两个图G(V, E) 和G(V, E)。若V V 且EE, 则称图G是图G的子图。权或权重(weight) 在某些图中,边具有与它相关的数值, 称为权重。带权图也叫作网络(network)。,4,子图,顶点的度 (degree) 一个顶点v的度是与它相关联的边的条数, 记作deg(v)。在

3、有向图中, 顶点 v 的入度是以 v 为终点的有向边的条数, 记作 indeg(v); 顶点 v 的出度是以 v 为始点的有向边的条数, 记作 outdeg(v)。在有向图中, 顶点的度等于该顶点的入度与出度之和。路径 在图 G(V, E) 中, 若从顶点 vi 出发, 沿一些边经过若干顶点 vp1, vp2, , vpm,到达顶点vj,则称顶点序列 (vi , vp1 , vp2 , . , vpm , vj) 为从顶点vi 到顶点 vj 的一条路径。它经过的边(vi, vp1)、(vp1, vp2)、.、(vpm, vj) 都是来自于E的边。,5,路径长度 非带权图的路径长度是指此路径上边

4、的条数。带权图的路径长度是指路径上各边的权值之和。简单路径 若路径上各顶点 v1, v2, ., vm 均不互相重复, 则称这样的路径为简单路径。回路 若路径上第一个顶点 v1 与最后一个顶点vm 重合, 则称这样的路径为回路或环。,6,0,1,2,3,0,1,2,3,0,1,2,3,连通图与连通分量 在无向图中, 若从顶点v1到顶点v2有路径, 则称顶点v1与v2是连通的。如果图中任意一对顶点都是连通的, 则称此图是连通图。非连通图的极大连通子图叫做连通分量。强连通图与强连通分量 在有向图中, 若对于每一对顶点vi和vj, 都存在一条从vi到vj和从vj到vi的路径, 则称此图是强连通图。非

5、强连通图的极大强连通子图叫做强连通分量。生成树(spanning tree) 一个无向连通图的生成树是其极小连通子图,在 n 个顶点的情形下,有 n-1 条边。若是有向图,则可能得到它的由若干有向树组成的生成森林。,7,图的抽象数据类型,class Graph /对象: 由一个非空顶点集合和一个边集合构成 /每条边由一个顶点对来表示。 public:Graph(); /建立一个空的图void insertVertex (const T/在图中删除顶点v和所有关联到它的边,8,void removeEdge (int v1, int v2);/在图中删去边(v1,v2)bool IsEmpty(

6、);/若图中没有顶点, 则返回true, 否则返回falseT getWeight (int v1, int v2);/函数返回边 (v1,v2) 的权值int getFirstNeighbor (int v);/给出顶点 v 第一个邻接顶点的位置int getNextNeighbor (int v, int w);/给出顶点 v 的某邻接顶点 w 的下一个邻接顶点 ;,9,图的存储表示,图的模板基类 在模板类定义中的数据类型参数表 中,T是顶点数据的类型,E是边上所附数据的类型。这个模板基类是按照最复杂的情况(即带权无向图)来定义的,如果需要使用非带权图,可将数据类型参数表 改为 。如果使用

7、的是有向图,也可以对程序做相应的改动。,10,图的模板基类,const int maxWeight = ; /无穷大的值(=) const int DefaultVertices = 30; /最大顶点数(=n) template class Graph /图的类定义 protected:int maxVertices; /图中最大顶点数int numEdges; /当前边数int numVertices; /当前顶点数virtual int getVertexPos (T vertex); /给出顶点vertex在图中位置 public:,11,Graph (int sz = Default

8、Vertices); /构造函数Graph(); /析构函数bool GraphEmpty () const /判图空否 return numEdges = 0; int NumberOfVertices () return numVertices; /返回当前顶点数int NumberOfEdges () return numEdges; /返回当前边数virtual T getValue (int i); /取顶点 i 的值virtual E getWeight (int v1, int v2); /取边上权值virtual int getFirstNeighbor (int v);/取顶

9、点 v 的第一个邻接顶点,12,virtual int getNextNeighbor (int v, int w);/取邻接顶点 w 的下一邻接顶点virtual bool insertVertex (const T vertex);/插入一个顶点vertexvirtual bool insertEdge (int v1, int v2, E cost);/插入边(v1,v2), 权为costvirtual bool removeVertex (int v); /删去顶点 v 和所有与相关联边virtual bool removeEdge (int v1, int v2); /在图中删去边(

10、v1,v2) ;所有虚函数都与具体存储表示相关。,13,邻接矩阵 (Adjacency Matrix)表示,在图的邻接矩阵表示中,有一个记录各个顶点信息的顶点表,还有一个表示各个顶点之间关系的邻接矩阵。设图 A = (V, E) 是一个有 n 个顶点的图, 图的邻接矩阵是一个二维数组 A.Edgenn,定义:,14,15,在有向图中, 统计第 i 行 1 的个数可得顶点 i 的出度,统计第 j 列 1 的个数可得顶点 j 的入度。在无向图中, 统计第 i 行 (列) 1 的个数可得顶点i 的度。,16,无向图的邻接矩阵是对称的;有向图的邻接矩阵可能是不对称的。,17,网络(带权图)的邻接矩阵,

11、template class Graphmtx : public Graph friend istream,18,用邻接矩阵表示的图的类定义,public: Graphmtx (int sz = DefaultVertices); /构造函数Graphmtx () /析构函数 delete VerticesList; for (i = 0; i = 0 ,19,int getFirstNeighbor (int v);/取顶点 v 的第一个邻接顶点int getNextNeighbor (int v, int w); /取 v 的邻接顶点 w 的下一邻接顶点bool insertVertex

12、(const T vertex); /插入顶点vertexbool insertEdge (int v1, int v2, E cost);/插入边(v1, v2),权值为costbool removeVertex (int v);/删去顶点 v 和所有与它相关联的边bool removeEdge (int v1, int v2);/在图中删去边(v1,v2) ;,20,template Graphmtx:Graphmtx (int sz) /构造函数maxVertices = sz; numVertices = 0; numEdges = 0;int i, j;VerticesList =

13、new TmaxVertices; /创建顶点表Edge = (E *) new E*maxVertices;for (i = 0; i maxVertices; i+)Edgei = new EmaxVertices; /邻接矩阵 for (i = 0; i maxVertices; i+) /矩阵初始化for (j = 0; j maxVertices; j+)Edgeij = (i = j) ? 0 : maxWeight; ;,21,template int Graphmtx:getFirstNeighbor (int v) /给出顶点位置为v的第一个邻接顶点的位置, /如果找不到,

14、则函数返回-1if (v != -1) for (int col = 0; col 0 ,22,template int Graphmtx:getNextNeighbor (int v, int w) /给出顶点 v 的某邻接顶点 w 的下一个邻接顶点 if (v != -1 ,23,邻接表 (Adjacency List),以邻接矩阵表示图,当边数远远小于n2 的时候,大量元素是maxWeight,会造成空间浪费。邻接表是邻接矩阵的改进形式。为此需要把邻接矩阵的各行分别组织为一个单链表。在邻接表中,同一个顶点发出的边链接在同一个边链表中,每一个链表结点代表一条边(边结点),结点中有另一顶点的

15、标识 dest 和指针 link。对于带权图,边结点中还要保存该边的权值cost。顶点表的第 i 个顶点中保存该顶点的数据,以及它对应边链表的头指针adj。,24,无向图的邻接表,统计某顶点对应边链表中结点个数,可得该顶点的度。 某条边(vi, vj)在邻接表中有两个边结点,分别在第 i 个顶点和第 j 个顶点对应的边链表中。,25,有向图的邻接表和逆邻接表,26,网络 (带权图) 的邻接表,统计出边表中结点个数,得到该顶点的出度; 统计入边表中结点个数,得到该顶点的入度。,27,用邻接表表示的图的类定义,template struct Edge /边结点的定义int dest; /边的另一顶

16、点位置E cost; /边上的权值Edge *link; /下一条边链指针Edge () /构造函数Edge (int num, E c) /构造函数: dest (num), cost (c), link (NULL) bool operator != (Edge,28,template struct Vertex /顶点的定义T data; /顶点的名字Edge *adj; /边链表的头指针 ;template class Graphlnk : public Graph /图的类定义 friend istream /输出,29,private:Vertex *NodeTable;/顶点表

17、(各边链表的头结点)int getVertexPos (const T vertex) /给出顶点vertex在图中的位置for (int i = 0; i numVertices; i+)if (NodeTablei.data = vertex) return i;return -1; public:Graphlnk (int sz = DefaultVertices); /构造函数Graphlnk(); /析构函数,30,T getValue (int i) /取顶点 i 的值return (i = 0 ,31,template Graphlnk:Graphlnk (int sz) /构造

18、函数:建立一个空的邻接表maxVertices = sz;numVertices = 0; numEdges = 0;NodeTable = new VertexmaxVertices; /创建顶点表数组if (NodeTable = NULL) cerr “存储分配错!“ endl; exit(1); for (int i = 0; i maxVertices; i+) NodeTablei.adj = NULL; ;,32,template Graphlnk:Graphlnk() /析构函数:删除一个邻接表for (int i = 0; i *p = NodeTablei.adj;whil

19、e (p != NULL) NodeTablei.adj = p-link;delete p; p = NodeTablei.adj; delete NodeTable; /删除顶点表数组 ;,33,template int Graphlnk:getFirstNeighbor (int v) /给出顶点位置为 v 的第一个邻接顶点的位置, /如果找不到, 则函数返回-1if (v != -1) /顶点v存在Edge *p = NodeTablev.adj; /对应边链表第一个边结点if (p != NULL) return p-dest; /存在, 返回第一个邻接顶点return -1; /第

20、一个邻接顶点不存在 ;,34,template int Graphlnk:getNextNeighbor (int v, int w) /给出顶点v的邻接顶点w的下一个邻接顶点的位置, /若没有下一个邻接顶点, 则函数返回-1if (v != -1) /顶点v存在Edge *p = NodeTablev.adj;while (p != NULL ,35,邻接矩阵与邻接表对比,空间时间,邻接多重表 (Adjacency Multilist),无向图的邻接表表示中,每条边被存储了两遍,既浪费了空间,又造成为边做标记等有关边的处理的不方便在邻接多重表中, 每一条边只有一个边结点。为有关边的处理提供了

21、方便。,37,无向图,边结点的结构其中, mark 是记录是否处理过的标记; vertex1和vertex2是该边两顶点位置。path1域是链接指针, 指向下一条依附顶点vertex1的边;path2 是指向下一条依附顶点vertex2的边链接指针。 需要时还可设置一个存放与该边相关的权值的域 cost。,38,顶点结点的结构存储顶点信息的结点表以顺序表方式组织, 每个顶点结点有两个数据成员:其中,data 存放与该顶点相关的信息,firstout 是指向依附于该顶点的第一条边的指针。在邻接多重表中, 所有依附同一个顶点的边都链接在同一个单链表中。,39,无向图,邻接多重表的结构,从顶点 i

22、出发, 可以循链找到所有依附于该顶点的边,也可以找到它的所有邻接顶点。,40,无向图,在用邻接表表示有向图时, 有时需要同时使用邻接表和逆邻接表。用有向图的邻接多重表(十字链表)可把两个表结合起来表示。 边结点的结构其中,mark是处理标记;vertex1和vertex2指明该有向边始顶点和终顶点的位置。path1是链接指针,指向与该边有同一始顶点的下一条边(出边表);path2也是链接指针,指向与该边有同一终顶点的下一条边(入边表)。需要时还可有权值域cost。,41,有向图,顶点结点的结构每个顶点有一个结点,它相当于出边表和入边表的表头结点:其中,数据成员data存放与该顶点相关的信息,指

23、针firstout指向以该顶点为始顶点的出边表的第一条边, firstin 指向以该顶点为终顶点的入边表的第一条边。,42,有向图,43,有向图,图的遍历与连通性,从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次,就叫做图的遍历 (Graph Traversal)。图中可能存在回路,且图的任一顶点都可能与其它顶点相通,在访问完某个顶点之后可能会沿着某些边又回到了曾经访问过的顶点。,44,为了避免重复访问,可设置一个标志顶点是否被访问过的辅助数组 visited 。辅助数组visited 的初始状态为 0, 在图的遍历过程中, 一旦某一个顶点 i 被访问, 就

24、立即让visitedi为 1, 防止它被多次访问。,45,图的遍历的分类: 深度优先搜索 DFS (Depth First Search) 广度优先搜索 BFS (Breadth First Search),46,深度优先搜索DFS (Depth First Search),深度优先搜索的示例,47,前进,回退,深度优先搜索过程 深度优先生成树,DFS 在访问图中某一起始顶点 v 后, 由 v 出发, 访问它的任一邻接顶点 w1; 再从 w1 出发, 访问与 w1邻 接但还没有访问过的顶点 w2; 然后再从 w2 出发, 进行类似的访问, 如此进行下去, 直至到达所有的邻接顶点都被访问过的顶点

25、 u 为止。 接着, 退回一步, 退到前一次刚访问过的顶点, 看是否还有其它没有被访问的邻接顶点。如果有, 则访问此顶点, 之后再从此顶点出发, 进行与前述类似的访问; 如果没有, 就再退回一步进行搜索。 重复上述过程, 直到连通图中所有顶点都被访问过为止。,48,图的深度优先搜索算法,template void DFS (Graph,49,template void DFS (Graph,50,广度优先搜索BFS (Breadth First Search),广度优先搜索的示例,51,广度优先搜索过程 广度优先生成树,BFS在访问了起始顶点 v 之后, 由 v 出发, 依次访问 v 的各个未

26、被访问过的邻接顶点 w1, w2, , wt, 然后再顺序访问 w1, w2, , wt 的所有还未被访问过的邻接顶点。 再从这些访问过的顶点出发,再访问它们的所有还未被访问过的邻接顶点, 如此做下去,直到图中所有顶点都被访问到为止。 广度优先搜索是一种分层的搜索过程, 每向前走一步可能访问一批顶点, 不像深度优先搜索那样有往回退的情况。因此, 广度优先搜索不是一个递归的过程。,52,图的广度优先搜索算法,为了实现逐层访问, 算法中使用了一个队列, 以记忆正在访问的这一层和上一层的顶点, 以便于向下一层访问。 为避免重复访问, 需要一个辅助数组 visited ,给被访问过的顶点加标记。tem

27、plate void BFS (Graph /图中顶点个数,53,54,bool *visited = new booln; for (i = 0; i Q; Q.EnQueue (loc); /顶点进队列, 实现分层访问while (!Q.IsEmpty() ) /循环, 访问所有结点Q.DeQueue (loc);w = G.getFirstNeighbor (loc); /第一个邻接顶点while (w != -1) /若邻接顶点w存在if (!visitedw) /若未访问过,55,cout G.getValue (w) ; /访问visitedw = true; Q.EnQueue

28、(w); /顶点w进队列w = G.getNextNeighbor (loc, w); /找顶点loc的下一个邻接顶点 /外层循环,判队列空否delete visited; ;,连通分量 (Connected component),当无向图为非连通图时,从图中某一顶点出发,利用深度优先搜索算法或广度优先搜索算法不可能遍历到图中的所有顶点,只能访问到该顶点所在极大连通子图(连通分量)的所有顶点。若从无向图每一连通分量中的一个顶点出发进行遍历, 可求得无向图的所有连通分量。例如,对于非连通的无向图,所有连通分量的生成树组成了非连通图的生成森林。,56,57,确定连通分量的算法,template v

29、oid Components (Graph ,58,最小生成树 ( minimum cost spanning tree ),使用不同的遍历图的方法,可以得到不同的生成树;从不同的顶点出发,也可能得到不同的生成树。 按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1条边。 构造最小生成树 假设有一个网络,用以表示 n 个城市之间架设通信线路,边上的权值代表架设通信线路的成本。如何架设才能使线路架设的成本达到最小?,59,构造最小生成树的准则 必须使用且仅使用该网络中的 n-1 条边来连接网络中的 n 个顶点; 不能使用产生回路的边; 各边上的权值的总和达到最小。,60,61,

30、克鲁斯卡尔 (Kruskal) 算法,克鲁斯卡尔算法的基本思想:设有一个有 n 个顶点的连通网络 N = V, E , 最初先构造一个只有 n 个顶点、没有边的非连通图 T = V, , 图中每个顶点自成一个连通分量。当在 E 中选到一条具有最小权值的边时, 若该边的两个顶点落在不同的连通分量上,则将此边加入到 T 中; 否则将此边舍去,重新选择一条权值最小的边。如此重复下去, 直到所有顶点在同一个连通分量上为止。,62,Kruskal算法的伪代码描述,T = ; /T是最小生成树的边集合 /E是带权无向图的边集合while ( T 包含的边少于n-1 ,63,算法的框架 利用最小堆(MinH

31、eap)和并查集(UFSets)来实现克鲁斯卡尔算法。 首先, 利用最小堆来存放E中所有的边, 堆中每个结点的格式为在构造最小生成树过程中, 利用并查集的运算检查依附一条边的两顶点tail、head 是否在同一连通分量 (即并查集的同一个子集合) 上, 是则舍去这条边;否则将此边加入T, 同时将这两个顶点放在同一个连通分量上。,64,边的两个顶点位置 边的权值,构造最小生成树的过程,随着各边逐步加入到最小生成树的边集合中, 各连通分量也在逐步合并, 直到形成一个连通分量为止。,65,66,最小生成树类定义,const float maxValue = FLOAT_MAX /机器可表示的、问题中

32、不可能出现的大数 template struct MSTEdgeNode /树边结点的类定义int tail, head; /两顶点位置E cost; /边上的权值MSTEdgeNode() : tail(-1), head(-1), cost(0) /构造函数 ;,67,template class MinSpanTree /树的类定义 protected:MSTEdgeNode *edgevalue;/边值数组 int maxSize; /最大元素个数int currentSize; /当前元素个数 public:MinSpanTree (int sz = DefaultSize-1) :

33、 maxSize (sz), currentSize (0) edgevalue = new MSTEdgeNodesz; int Insert (MSTEdgeNode,68,Kruskal算法的实现,在求解最小生成树时,可以用邻接矩阵存储图,也可以用邻接表存储图。算法中使用图的抽象基类的操作,无需考虑图及其操作的具体实现。#include “heap.h“ #include “UFSets.h“ template void Kruskal (Graph& G, MinSpanTree& MST) ,69,70,MSTEdgeNode edge; /边结点辅助单元int u, v, coun

34、t; int n = G.NumberOfVertices(); /顶点数int m = G.NumberOfEdges(); /边数MinHeap H(m); /最小堆 UFSets F(n); /并查集for (u = 0; u n; u+)for (v = u+1; v n; v+)if (G.getWeight(u,v) != maxValue) /插入堆edge.tail = u; edge.head = v; edge.cost = G.getWeight (u, v);H.Insert(edge); ,71,count = 1; /最小生成树边数计数while (count n)

35、 /反复执行, 取n-1条边H.Remove(edge); /退出具最小权值的边u = F.Find(edge.tail); v = F.Find(edge.head); /取两顶点所在集合的根u与vif (u != v) /不是同一集合,不连通F.Union(u, v); /合并,连通它们 MST.Insert(edge); /该边存入MSTcount+; ;,72,出堆顺序 (0,5,10) 选中 (2,3,12) 选中(1,6,14) 选中 (1,2,16) 选中 (3,6,18) 舍弃(3,4,22) 选中 (4,6,24) 舍弃 (4,5,25) 选中,并查集,原图,-2,-2,-2

36、,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,2,-1,-1,-1,0,-2,2,0,0,0,0,0 1 2 3 4 5 6,-2,1,-1,1,-2,-1,-4,2,1,-2,-5,1,2,1,1,-7,1,1,2,1,1,F,(0,5,10),(2,3,12),(1,6,14),(1,2,16),(3,4,22),(4,5,25),普里姆(Prim)算法,普里姆算法的基本思想:从连通网络 N = V, E中的某一顶点 u0 出发, 选择与它关联的具有最小权值的边 (u0, v), 将其顶点加入到生成树顶点集合U中。以后每一步从一个顶点在集合U中, 而另

37、一个顶点不在集合U中的各条边中选择权值最小的边(u, v), 把它的顶点加入到集合U中。如此继续下去, 直到网络中的所有顶点都加入到生成树顶点集合U中为止。,73,普里姆(Prim)的伪代码描述,选定构造最小生成树的出发顶点u0;Vmst = u0,Emst = ; while (Vmst包含的顶点少于n ,74,75,例子,76,H = (0,5,10), (0,1,28) edge = (0, 5, 10) Vmst = t, f, f, f, f, f, fVmst = t, f, f, f, f, t, f,77,H = (5,4,25), (0,1,28) edge = (5, 4,

38、 25) Vmst = t, f, f, f, f, t, fVmst = t, f, f, f, t, t, f,H = (4,3,22), (4,6,24), (0,1,28) edge = (4, 3, 22) Vmst = t, f, f, f, t, t, fVmst = t, f, f, t, t, t, f,78,H = (3,2,12), (3,6,18), (4,6,24),(0,1,28) edge = (3, 2, 12) Vmst = t, f, f, t, t, t, fVmst = t, f, t, t, t, t, f,H = (2,1,16), (3,6,18)

39、, (4,6,24),(0,1,28) edge = (2, 1, 16) Vmst = t, f, t, t, t, t, fVmst = t, t, t, t, t, t, f,最小生成树中边集合里存入的各条边为:(0, 5, 10), (5, 4, 25), (4, 3, 22),(3, 2, 12), (2, 1, 16), (1, 6, 14),79,H = (1,6,14), (3,6,18), (4,6,24),(0,1,28) edge = (1, 6, 14) Vmst = t, t, t, t, t, t, fVmst = t, t, t, t, t, t, t,Prim算

40、法的实现,#include “heap.h“ template void Prim (Graph /最小堆,80,bool Vmst = new booln; /最小生成树顶点集合for (i = 0; i n; i+) Vmsti = false; Vmstu = true; /u 加入生成树count = 1;do /迭代v = G.getFirstNeighbor(u); while (v != -1) /检测u所有邻接顶点if (!Vmstv) /v不在mst中edge.tail = u; edge.head = v;edge.cost = G.getWeight(u, v);H.In

41、sert(edge); /(u,v)加入堆 /堆中存所有u在mst中, v不在mst中的边v = G.getNextNeighbor(u, v); ,81,while (!H.IsEmpty() ,82,Prim算法适用于边稠密的网络。 Kruskal算法适合于边稀疏的情形。 注意:当各边有相同权值时,由于选择的随意性,产生的生成树可能不唯一。,83,最短路径 (Shortest Path),最短路径问题:如果从图中某一顶点(称为源点)到另一顶点(称为终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边上的权值总和达到最小。 问题解法边上权值非负情形的单源最短路径问题 Dijkstra

42、算法边上权值为任意值的单源最短路径问题 Bellman和Ford算法 (不讲) 所有顶点之间的最短路径 Floyd算法,84,边上权值非负情形的 单源最短路径问题,问题的提法:给定一个带权有向图D与源点 v,求从v到D中其他顶点的最短路径。 限定各边上的权值大于或等于0。为求得这些最短路径, Dijkstra提出按路径长度的递增次序, 逐步产生最短路径的算法。首先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,依次类推,直到从顶点v到其它各顶点的最短路径全部求出为止。,85,86,Dijkstra逐步求解的过程,引入辅助数组dist。它的每一个分量disti表示当前找到的从源点

43、 v0 到终点 vi 的最短路径的长度。初始状态: 若从v0到顶点vi有边, 则disti为该边的权值; 若从v0到顶点vi无边, 则disti为 。 假设S是已求得的最短路径的终点的集合,则可证明:下一条最短路径必然是从v0 出发,中间只经过S中的顶点便可到达的那些顶点vx (vxV-S )的路径中的一条。 每次求得一条最短路径后, 其终点vk 加入集合S,然后对所有的vi V-S,修改其 disti值。,87,Dijkstra算法可描述如下:, 初始化: Sv0; distjEdge0j, j = 1, 2, , n-1;/ n为图中顶点个数 求出最短路径的长度:distumin dist

44、i, iV-S ; SSu; 修改: distkmindistk, distu+Edgeuk,对于每一个 kV-S ; 判断:若 S = V, 则算法结束,否则转。,88,计算从单个顶点到其他各顶点 最短路径的算法,void ShortestPath (Graph,89,Si = false;if (i != v /将顶点u加入集合S,90,for (k = 0; k n; k+) /修改w = G.GetWeight(u, k);if (!Sk ,91,92,Dijkstra算法中各辅助数组的最终结果,从表中读取源点0到终点v的最短路径的方法 : 举顶点4为例path4 = 2 path2

45、= 3 path3 = 0,反过来排列,得到路径 0, 3, 2, 4,这就是源点0到终点4的最短路径。,0,4,1,2,3,10,50,10,20,60,30,100,序号,顶点,1,顶点,2,顶点,3,顶点,4,Dist,10,50,30,60,path,0,3,0,2,93,求:源点1到所有点的最短路径,所有顶点之间的最短路径,问题的提法:已知一个各边权值均大于0的带权有向图,对每一对顶点 vi vj,要求求出vi 与vj之间的最短路径和最短路径长度。 Floyd算法的基本思想:定义一个n阶方阵序列:A(-1), A(0), , A(n-1).其中 A(-1) ij = Edgeij;A

46、(k) ij = min A(k-1)ij,A(k-1)ik + A(k-1)kj , k = 0,1, n-1,94,求各对顶点间最短路径的算法,A(0) ij是从顶点vi 到vj , 中间顶点是v0的最短路径长度; A(k) ij是从顶点vi 到vj , 中间顶点的序号不大于k的最短路径的长度; A(n-1)ij是从顶点vi 到vj 的最短路径长度。template void Floyd (Graph& G, E a, int path) /aij是顶点i和j之间的最短路径长度。pathij /是相应路径上顶点j的前一顶点的顶点号。,95,96,for (i = 0; i n; i+) /矩阵a与path初始化for (j = 0; j n; j+) aij = G.getWeight (i, j);if (i != j ,97,pathij = pathkj; /缩短路径长度, 绕过 k 到 j ;Floyd算法允许图中有带负权值的边,但不许有包含带负权值的边组成的回路。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 教学课件 > 大学教育

copyright@ 2008-2019 麦多课文库(www.mydoc123.com)网站版权所有
备案/许可证编号:苏ICP备17064731号-1