码迷,mamicode.com
首页 > 编程语言 > 详细

图的基础算法(大话数据结构笔记)

时间:2015-11-18 19:26:12      阅读:302      评论:0      收藏:0      [点我收藏+]

标签:

概述

线性表的每个元素有线性关系,每个数据元素只有一个直接前去和一个直接后继。树的数据元素之间有着明细那的层次关系,并且每层上的数据元素可能和下一层中多个元素相关,但只能和上一层中一个元素相关。这和一对父母可以有很多孩子,但每个孩子却只能有一对父母是一个道理。可现实中,人与人之间关系复杂,不是简单一对一,一对多的关系。这种复杂关系更适合用图来表示。在图结构中,节点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。如下图所示:
技术分享
无向边:Edge (vi,vj)
有向边:也叫弧,Arc。 <vi,vj>
对于无向图G=(V,E),如果边(v,v)E,则称定点v和v‘互为邻接点(Adjacent),即v和v‘相临接。边(v,v‘)依附于顶点v,v‘,或者说(v,v‘)与定点v,v‘相关联.定点v的度(Degree)是和v相关联的变的数目,记为TD(v).
blabla.....我去,概念太多了,不写了,自己查书《大话数据结构》

图的存储结构

邻接矩阵

图的邻接矩阵(Adjacency Matrix)春初方式是用两个数组来表示图。一个以为数组存储定点,第二个存贮边或弧的信息

f(x)={1,0,if(vi,vj)Eor<vi,vj>Eother(1)

技术分享
上图是无向图邻接矩阵

技术分享
上图是有向图邻接矩阵
技术分享
上图是有向网络邻接矩阵

邻接表

对于边相对与定点较少的图,邻接矩阵表示很浪费空间
技术分享
稀疏边的邻接矩阵
我们把一种数组与链表想结合的存储方法称为邻接表(Adjacency List).
邻接表是这样子的:

  1. 图中顶点用一个一维数组存储,数组元素还需要存储指向第一个邻接点(vi,vj有边链接,vi,vj就互为邻接点)的指针,一边查询该定点的边信息。
  2. 图中每个顶点vi的所有邻接点构成一个线性表。

技术分享
上图是无向图的邻接表
技术分享
一个有向图的逆邻接表,就是对每个顶点vi都建议一个链接为vi为弧头的表。

十字链表

重新定义顶点表结点结构:
|data|firstin|firstout|
|-------|-------|-------|

其中firstin表示入边表头指针,指向该顶点的入边表中第一个节点。firstout表示出边表头指针,指向该顶点的出边表中的第一个节点。
重定义边表结点结构
|tailvex|headvex|headlink|taillink|
|-------|-------|-------|-------|

其中tailvex是指向弧起点在顶点表的下标,headvex是指弧终点在顶点表中的下标。headlink是指入边表指针域,指向终点相同的下一条边,taillink是指出边表指针域,指向起点相同的下一条边。如果是网,还可以增加一个weight域来存储权值。
如下图,顶点依然存入一个一维数组{v0,v1,v2,v3},实线箭头指针的图示完全与上面有向图邻接表相同。就以顶点v0来说,firstout指向的是出边表中的第一个节点v3.所以v0边表节点的headvex=3,而tailvex其实就是当前顶点v0的下标,由于v0只有一个出边顶点,所以headlink和taillink都是空。
技术分享
十字链表
我们重点需要解释虚线箭头的含义,它其实就是此图的逆邻接表的表示。对于v0来说,它有两个顶点v1和v2的入边。因此v0的firstin指向顶点v1的边表节点中headvex为0的节点,如上图中的 ①。接着由入边节点的headlink指向下一个边顶点v2,如上图的②。对于顶点v1,它有一个入边顶点v2,所以它的firstin指向顶点v2的边表节点中headvex为1的节点,如图中的③。顶点v2,v3也是同样有一个入边顶点,如图中④和⑤。
十字链表的好处是因为吧邻接表和逆邻接表整合在了一起,这样容易找到以vi为尾的弧,也容易找到以vi为头的弧,因而容易求得顶点的出度和入度。而且它除了结构复杂一点外,其实创建图算法的时间复杂度和邻接表示相同的。

邻接多重表

如果我们关注的重点是顶点,那么上面的邻接表是不错的存储结构。但如果我们关注边的操作,比如对边删除等操作,就意味着,我们需要找到这条边的两个边表节点进行操作。这其实还是比较麻烦的。比如下图中,如果要删除左图的(v0,v2)这条边,需要对邻接表结构中右边表的阴影两个结点进行删除操作技术分享
于是我们对便表接待你的结构进行一些改造,也许可以避免刚才的问题。
|ivex|ilink|jvex|jlink|
|-|

其中ivex和jvex是与某条边衣服的两个顶点再顶点表中下表。ilink指向依附顶点ivex的下一条边,jlink指向依附顶点jvex的下一条边。这就是邻接多重表结构。
我们来看看结构示意图的绘制过程,理解了它是怎么链接的,就理解了多重表构造原理了。如下图,作图告诉我们他有四个顶点和5条边,显然,我们就应该先将4个顶点和五条边的边表节点画出来。由于是无向图,所以ivex是0,jvex是1还是翻过来都是无所谓的,不过为了绘图方便,都将ivex值设置得与一旁的顶点下标相同。
技术分享
多重链接表绘图1
我们开始连线,如下图。首先连线的①②③④就是将顶点的firstedge指向一条边,顶点下标要与ivex的值相同,这样很好理解。接着,由于顶点v0的(v0,v1)边的邻边有(v0,v3)和(v0,v2)。因此⑤⑥的连线就是满足指向下一条依附于顶点v0的边的目标,注意ilink指向的结点的jvex一定要和它本身的ivex的值相同。同样的道理,连线⑦就是指(v1,v0)这条边,它是相当于顶点v1指向(v1,v2)边后的下一条。v2有三条边依附,所以在③之后就有了⑧⑨。连线⑩的就是顶点v3在连线④之后的下一条边。左图一共有五条边,所以右图有10条连线,完全符合预期。
技术分享
邻接多重表的绘图--连线
到这里大家应该看出来了,邻接多重表与邻接表的差别,仅仅是在于同一条边在邻接表中用两个结点表示,而在邻接多重表中只有一个节点。这样对边的操作就方便多了。如果要删除上图左边(v0,v2)这条边,只需要将右图的⑥⑨的链接指向改为^即可。

边集数组

一图胜千言:
技术分享

图的遍历

深度优先

深度优先(Depth First Search)
如下图,从顶点A开始要走遍所有的图顶点并作上标记,不重复不遗漏。
技术分享
有这样一个策略,我们从A开始,坐上标记后,前面有两条路,分别是B和F,我们给自己定一个原则,在没有碰到重复顶点的情况下,始终是向右手边走(假设我们在图中这样迷宫里),于是走到了B。整个过程,可以参见上面的右图,我们到达B节点,发现三条分支,分别通向顶点C,I,G,右手通行原则,使得我们走到了C顶点,。就这样,我们一直顺着右手通道走,一直走到了F顶点。当我们依然选择右手通道走过去后,发现走回到顶点了,因为我们做了标记,知道已经走过。此时我们退回到顶点F,走向从右数的第二条通道,到了G顶点,他有三条通道,发现B和D都已经是走过的,于是走到H,当我们面对通向H的两条通道D和E时,会发现已经走过了。此时还有很多分支没走,我们原路返回,继续寻找没有访问过的结点。直到返回顶点A,确认已经完成遍历任务,找到所有的九个节点。
其实,就是上面右图那棵树的前序遍历。
邻接矩阵的DFS代码:

  1. //代码没有运行过,纯粹为了记笔记用,如果疏漏,欢迎指正
  2. typdef int Boolean;
  3. Boolean visited[MAX];
  4. //邻接矩阵的深度优先递归算法
  5. void DFS(MGraph,int i){
  6. int j;
  7. visited[i] = TRUE;
  8. printf("%c",G.vexs[i]);
  9. for(j = 0;j < G.numVertexes;j++){
  10. //下一条边存在,且没有被访问,就向下搜索。
  11. if(G.arc[i][j]==1 && !visited[j])
  12. DFS(G,j);
  13. }
  14. }
  15. //邻接矩阵的深度遍历操作
  16. void DFSTraverse(MGraph G){
  17. int i;
  18. for(i = 0;i < G.numVertexes;i++){
  19. visited[i] = FALSE;
  20. }
  21. for(i = 0;i < G.numVertexes; i++){
  22. if(!visited[i])
  23. DFS(G,i)
  24. }
  25. }

图是邻接表结构:其中DFSTraverse函数的代码几乎是相同的,知识在递归函数中因为将数组换成了链表而有不同,代码如下。

  1. void DFS(GraphAdjList GL,int i){
  2. EdgeNode * p;
  3. visited[i] = TRUE;
  4. printf("%c",GL->adjList[i].data);
  5. p = GL->adjList[i].firstedge;
  6. while(p){
  7. if(!visited[p->adjvex])
  8. DFS(GL,p->adjvex);
  9. p = p->next;
  10. }
  11. }
  12. //邻接表的深度遍历操作
  13. void DFSTraverse(GraphAdjList GL){
  14. int i;
  15. for(i = 0;i<GL->numVertexes;i++)
  16. visited[i] = FALSE;
  17. for(i = 0;i<GL->numVertexes;i++){
  18. if(!visited[i])
  19. DFS(GL,i);
  20. }
  21. }

广度优先遍历

Breadth First Search,有点类似树的层序遍历。见下图:
技术分享

直接上代码:
邻接矩阵的BFS代码

  1. void BFSTraverse(MGraph G){
  2. int i,j;
  3. Queue Q;
  4. for (i=0;i < G.numVertexes;i++){
  5. visited[i] = FALSE;
  6. }
  7. InitQueue(&Q);
  8. for(i=0;i<G.numVertexes;i++){
  9. if(!visited[i]){
  10. visited[i] = TRUE;
  11. printf("%c",G.vexs[i]);
  12. EnQueue(&Q,i);
  13. while(!QueueEmpty(Q)){
  14. DeQueue(&Q,&i);
  15. for(j=0;j < G.numVertexes;j++){
  16. if(G.arc[i][j] == 1 && !visited[j]){
  17. visited[j] = TRUE;
  18. printf("%c",G.vexs[j]);
  19. EnQueue(&Q,j);
  20. }
  21. }
  22. }
  23. }
  24. }
  25. }

邻接表的BFS算法

  1. void BFSTraverse(GraphAdjList GL){
  2. int i;
  3. EdgeNode * p;
  4. Queue Q;
  5. for (i = 0;i < GL->numVertexes; i++)
  6. visited[i] = FALSE;
  7. InitQueue(&Q);
  8. for(i=0;i < GL->numVertexes; i++){
  9. visited[i] = TRUE;
  10. printf("%c",GL->adjList[i].data);
  11. EnQueue(&Q,i);
  12. while(!QueueEmpty(Q)){
  13. DeQueue(&Q,&i);
  14. p = GL->adjList[i].firstedge;
  15. while(p){
  16. if (!visited[p->adjvex]){
  17. visited[p->adjvex] = TRUE;
  18. printf("%c",GL->adjList[p->adjvex].data);
  19. EnQueue(&Q,p->adjvex);
  20. }
  21. p = p->next;
  22. }
  23. }
  24. }
  25. }

最小生成树

一个图的生成树,定义为包含图中全部的顶点,但只有足以构成一棵树的n-1条边(有n个结点)。我们把构造连通网的最小代价生成树称为最小生成树(Minimum Cost Spanning Tree)。

普里姆(Prim)算法

先构造如下图的邻接矩阵:
技术分享
现在,我们已经有了一个存储结构为MGrapgh的G。
于是Prim算法代码如下:

  1. typedef char VertexType;
  2. typedef int EdgeType;
  3. #define MAXVEX 100
  4. #define INFINITY 65535
  5. typedef struct{
  6. VertexType vexs[MAXVEX];
  7. EdgeType arc[MAXVEX][MAXVEX];
  8. int numVertexes, numEdges;
  9. }MGraph;
  10. int a[9][9] = {
  11. { 0, 1, 5,INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY },
  12. { 1, 0, 3, 7, 5, INFINITY, INFINITY, INFINITY ,INFINITY },
  13. { 5, 3, 0, INFINITY, 1, 7, INFINITY, INFINITY, INFINITY },
  14. { INFINITY, 7, INFINITY, 0, 2, INFINITY, 3, INFINITY, INFINITY },
  15. { INFINITY, 5, 1, 2, 0, 3, 6, 9, INFINITY },
  16. { INFINITY, INFINITY, 7, INFINITY, 3, 0, INFINITY, 5, INFINITY },
  17. {INFINITY, INFINITY, INFINITY, 3, 6, INFINITY, 0, 2, 7},
  18. { INFINITY, INFINITY, INFINITY, INFINITY ,9,5,2,0,4},
  19. { INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY ,7,4,0} };
  20. void CreateMGraph(MGraph *G){
  21. for (int i = 0; i < 8; i++){
  22. G->vexs[i] = ‘0‘ + i;
  23. }
  24. G->numEdges = 16;
  25. G->numVertexes = 9;
  26. for (int i = 0; i < G->numVertexes; i++){
  27. for (int j = 0; j < G->numVertexes; j++)
  28. G->arc[i][j] = a[i][j];
  29. }
  30. }
  31. void MiniSpanTree_Prim(MGraph *G){
  32. int min, i, j, k;
  33. //保存相关顶点下标
  34. int adjvex[MAXVEX];
  35. /*保存相关顶点间边的权值*/
  36. int lowcost[MAXVEX];
  37. lowcost[0] = 0; //初始化第一个权值为0,即v0加入生成树
  38. adjvex[0] = 0; //初始化第一个顶点下标
  39. //将v0以外的值放入lowcost
  40. for (int i = 0; i < G->numVertexes; i++){
  41. lowcost[i] = G->arc[0][i];
  42. adjvex[i] = 0;
  43. }
  44. //每个顶点依次加入生成树
  45. for (int i = 1; i < G->numVertexes; i++){
  46. min = INFINITY;
  47. j = 1; k = 0;
  48. //找到一个lowcost的最小值
  49. while (j < G->numVertexes){
  50. if (lowcost[j] != 0 &&lowcost[j] < min ){
  51. min = lowcost[j];
  52. k = j;
  53. }
  54. j++;
  55. }
  56. //得到最小距离,以及对应的下标k
  57. lowcost[k] = 0;//表示顶点k加入生成树合集
  58. printf("(%d,%d)\n", adjvex[k], k);//adjvex[k]是与顶点k相连的顶点
  59. //更新所有顶点到生成树顶点的距离。当有顶点到达生成树中多个顶点时候,只记录最近的一个
  60. //也就是其它节点到生成树中最近的那个结点的距离
  61. for (j = 1; j < G->numVertexes; j++){
  62. //找最近的那个节点
  63. if (lowcost[j] != 0 && G->arc[k][j] < lowcost[j]){
  64. lowcost[j] = G->arc[k][j];
  65. adjvex[j] = k;
  66. }
  67. }
  68. }
  69. }
  70. void main(void){
  71. MGraph g;
  72. CreateMGraph(&g);
  73. MiniSpanTree_Prim(&g);
  74. while(1);
  75. }

最后一个for循环
最后这个for循环是,找到顶点k,k成功加入到最小生成树顶点合集中(lowcost对应位置0)。然后,我们寻找其它顶点中, 离这个顶点合集最短的一个顶点。
由于k是新加入合集的,lowcost中还没有记录其它顶点到K的距离,所以我们更新lowcost,将其它顶点到k的距离添加进去。遇到集合之外的顶点同时到达集合内多个顶点的,我们选择最小的距离,并且在adjvex数组中记录下j的最近距离lowcost[j]是指向哪一个节点的(比如adjvex[j]=k,表示顶点j到集合内最短距离边为(j,k),最短距离为lowcost[j]。)这里为什么要记录最短距离呢?因为我们最终求的是集合外一个结点到集合内任意结点的最短距离,所以,当一个结点同时和最小生成树结点集合中多个结点链接时候,我们只保存最小的值,较大的距离值就被抛弃了,反正后面比较的时候较大的值也会被抛弃。
lowcost矩阵存储的都是集合外部节点到生成树节点集合中最近的距离。到底离哪个最近,则对应adjvex[j] = k,表示外部结点j离集合内部节点k最近。

总结一下Prim算法,假设N=(V,E)是连通网,TE是N上最小生成树中边的集合。算法从U=u0(u0V),TE={}开始。重复执行下述操作:在所有uU,vV?U的边(u,v)E找一条代价最小的边(u0,v0)并入集合TE,同时v0并入U,直到U=V为止。此时TE中必有n-1条边,则T=(v,{TE})为N的最小生成树。算法时间复杂度是O(n2)。具体参见算法导论的分析。

库鲁斯卡儿(Kruskal)

Prim算法是以某顶点为起点,逐步找各顶点最小权值的边来构建。但我们也可以直接以边为目标去构建,因为权值是在边上的,直接找最小权值的边来构建生成树也是很自然的,只不过构建时要考虑是否形成环路而已。此时我们就用到了图的存储结构中的边集数组结构。一下是edge边集数组结构的定义代码:

  1. typedef struct{
  2. int begin;
  3. int end;
  4. int weight;
  5. }

我们将图的邻接矩阵通过程序转化为下图的右图的边集数组,并且对它们按照权值从小到大排序。
技术分享
Kruskal代码

  1. void MiniSpanTree_Kruskal(MGraph G){
  2. int i,n,m;
  3. //定义边集数组
  4. Edge edges[MAXEDGE];
  5. //定义一组用来判断边与边是否行成环路
  6. int parent[MAXEDGE];
  7. /*此处省略邻接矩阵G转化为边集数组edges并按照权由小到大排序的代码*/
  8. for(i = 0;i < G.numVertexes; i++)
  9. parent[i] = 0;//初始化数组值为0
  10. for(i = 0;i < G.numEdges;i++){
  11. n = Find(parent,edges[i].begin);
  12. m = Find(parent,edges[i].end);
  13. if(n!=m){
  14. parent[n] = m;
  15. printf("(%d,%d) %d",edges[i].begin,edges[i].end,edges[i].weight);
  16. /*将此边的结尾顶点法国如下标为起点的parent中*/
  17. /*表示此顶点已经在生成树中*/
  18. }
  19. }
  20. }
  21. //返回这个连通分量的最后一个顶点的下标
  22. int Find(int * parent,int f){
  23. while(parent[f] > 0){
  24. f = parent[f];
  25. }
  26. return f;
  27. }

同一个连通分量中,不管从哪一个vex开始,由begin->end不断“行走”,最后终点都是相同的,由此判断是否在同一连通分量。在边集数据中选择代价最小的边(已经排好序,一次遍历就OK),若该边依附的顶点落在T中不同的连通分量上,则将此边加入到结果集parent中,并且还合并了两个连通分量。

最短路径

迪杰斯特拉(Dijkstra)算法

这是一个按路径长度递增的次序产生最短路径的算法。
如下图
技术分享
v0v1的最短距离,很明显就是v0直接连接到v1。由于v1还与v2,v3,v4连线,所以此时我们同时求得了v0->v1->v2 = 1+3 =4;v0->v1->v3 = 1+7 =8;v0->v1->v4 = 1+5 = 6;
现在,问题来了,从v0->v2的最短距离是多少?很明显不会是v0->v2的直接连线,而是v0->v1->v2 = 1+ 3 =4。由于V2还和v4 ,v5连线,所以此时我们同时得到了v0->v2->v4=4+1=5,v0->v2->v5=4+7=11.这里v0->v2我们用的是刚才计算出来的最短距离4。此时我们发现v0->v1->v2->v4=5比v0->v1->v4=6小。所以v0->v4最小的距离是5。
当我们求v0->v3的最短距离时,通向v3的三条边,除了v6外,v0->v1->v3=8;v0->v4->v3=7;因此v0->v3的最短距离是7.
好了,这就是大致Dijstra算法的基本步骤。它并不是一下子就求出了v0->8的最短路径,而是一步步求出它们之间顶点的最短路径,过程中都是基于已经求出的最短路径的基础上,求得最远顶点的最短路径,最终得到你想要的结果。

  1. typedef char VertexType;
  2. typedef int EdgeType;
  3. #define MAXVEX 100
  4. #define INFINITY 65535
  5. typedef struct{
  6. VertexType vexs[MAXVEX];
  7. EdgeType arc[MAXVEX][MAXVEX];
  8. int numVertexes, numEdges;
  9. }MGraph;
  10. int a[9][9] = {
  11. { 0, 1, 5,INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY },
  12. { 1, 0, 3, 7, 5, INFINITY, INFINITY, INFINITY ,INFINITY },
  13. { 5, 3, 0, INFINITY, 1, 7, INFINITY, INFINITY, INFINITY },
  14. { INFINITY, 7, INFINITY, 0, 2, INFINITY, 3, INFINITY, INFINITY },
  15. { INFINITY, 5, 1, 2, 0, 3, 6, 9, INFINITY },
  16. { INFINITY, INFINITY, 7, INFINITY, 3, 0, INFINITY, 5, INFINITY },
  17. {INFINITY, INFINITY, INFINITY, 3, 6, INFINITY, 0, 2, 7},
  18. { INFINITY, INFINITY, INFINITY, INFINITY ,9,5,2,0,4},
  19. { INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, INFINITY ,7,4,0} };
  20. void CreateMGraph(MGraph *G){
  21. for (int i = 0; i < 8; i++){
  22. G->vexs[i] = ‘0‘ + i;
  23. }
  24. G->numEdges = 16;
  25. G->numVertexes = 9;
  26. for (int i = 0; i < G->numVertexes; i++){
  27. for (int j = 0; j < G->numVertexes; j++)
  28. G->arc[i][j] = a[i][j];
  29. }
  30. }
  31. typedef int Patharc[MAXVEX];//用来存储最短路径的下标
  32. typedef int ShortPathTable[MAXVEX];//用于存储到各个点最短路径的权值和,Dijstra,
  33. /*Dijstra算法,求有向网G的v0顶点到其余顶点v最短路径P[v]以及带权长度D[v]*/
  34. /*P[v]的值为前驱顶点下标,D[v]表示v0到v的最短路径长度*/
  35. void ShortestPath_Dijkstra(MGraph G, int v0, Patharc * P,ShortPathTable* D ){
  36. int v, w, k, min;
  37. int final[MAXVEX];/*final[w]=1表示求得顶点v0到v_w的最短路径*/
  38. for (v = 0; v < G.numVertexes; v++){/*初始化数据*/
  39. final[v] = 0; /*全部顶点初始化为未知最短路径状态*/
  40. (*D)[v] = G.arc[0][v]; /*将与v0点有连线的顶点加上权值*/
  41. (*P)[v] = 0; /*初始化路径数组P为0*/
  42. }
  43. (*D)[0] = 0; /*v0-v0路径为0*/
  44. final[0] = 1; /*v0-v0不需要路径*/
  45. /*开始主循环,每次求得v0到某个v顶点的最短路径*/
  46. for (v = 1; v < G.numVertexes; v++){
  47. min = INFINITY;
  48. for (w = 0; w < G.numVertexes; w++){
  49. if (!final[w] && (*D)[w] < min){
  50. k = w;
  51. min = (*D)[w];/*w顶点离v0顶点更近*/
  52. }
  53. }
  54. final[k] = 1; /*将目前找到的最近的顶点置为1*/
  55. for (w = 0; w < G.numVertexes; w++){
  56. if (!final[w] && (min + G.arc[k][w] < (*D)[w])){
  57. /*说明找到了更短的路径,修改D[w]和P[w]*/
  58. (*D)[w] = min + G.arc[k][w]; /*修改当前路径长度*/
  59. (*P)[w] = k;
  60. }
  61. }
  62. }
  63. }
  64. void main(void){
  65. MGraph g;
  66. CreateMGraph(&g);
  67. ShortPathTable d;
  68. Patharc p;
  69. ShortestPath_Dijkstra(g,0,&p,&d);
  70. while (1);
  71. }

上面Dijstra和Prim代码很像,相似处就不说了,它们的区别如下:

  1. 前者是求最短路径,后者是求最小生成树
  2. 都有一步更新过程前者是 min+G.arc[k][w] < D[w]来判断,也就是新的最短路径+其它任意结点w的值是不是小于以前v0->w的路径长度D[w].是就更新v0到w的路径长度.P[w]记录下w的前驱k。
    后者是G.arc[k][j] < lowcost[j]来判断,也就是生成树加入了新成员k,然后其它结点到最小生成树结点集合的最近距离会改变,但有可能改变的只是与k相关的最近距离。我们遍历与k相关
    的其它节点的权值,然后这一判断其它结点到K的权值是不是小于以前到最小生成树合集的最近距离。是就更新这个结点到最小生成树的距离,并且在adjvex中记录下这个结点的前驱k。
    总结Dijkstra:
    Dijkstra算法解决了从某个源点到其余各顶点的最短路径问题。从循环嵌套中可知算法时间复杂度为O(n2)。可是我们如果需要知道每个顶点到其余节点的最短路径怎么办?最简单办法就是将每个结点选为源点运行一次DIjkstra算法。此时时间复杂度为O(n3)。但下面的Floyd算法,时间复杂度一样,但是代码特别简介。值得一学!

弗洛伊德(Floyd)算法

{未完待续}





图的基础算法(大话数据结构笔记)

标签:

原文地址:http://www.cnblogs.com/gavin-yue/p/4975531.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!