C++ 数据结构-图相关操作的算法思路

20 篇文章 0 订阅

目录

1.回路的判断:

2.普利姆-最小生成树

3.克鲁斯特卡尔-最小生成树

4.迪杰斯特拉-最短路径

5.图的最长路径(不走重复路)

6.有向无环图的关键路径


1.回路的判断:

用深度优先遍历,在有向图中如果遍历过程中重复访问到已经访问过的点,那么这个有向图就是就是有回路;如果是无向图,重复访问到了祖先结点那么这个无向图就存在回路。

2.普利姆-最小生成树

需要输入一个开始结点,新建一个对象数组arr [ size ] (nodeIndex,lowcost)  ,其中nodeIndex指的是结点在邻接矩阵或者邻接表的数组下标,其中arr[ i ] 表示  nodeIndex 到 i 的 是最短路径,消耗是lowcost。

对新加入的结点进行遍历边,比对 arr[i] ,如果新的边比arr[i]更小那么就重新覆盖 arr[i]的值,然后再旋转lowcost最小的点,再进行进行加入。反复执行次操作。

 

1.假设刚开始输入是A ,那么遍历 A 的边 ,初始化最小值 ,得到最小的边是(A,C),.然后把C 加入到集合

2 遍历新结点C的所有边,其中(C,B)要比原来的(A,B)要小 ;(C,E),(C,F)要比原先的(A,E)  (A,F)要小,覆盖值,不断重复步骤2,直到遍历n次(结点总数)

次数\结点ABCDEF已加入的点最小结点备注
1(null)(A,6)(A,1)(A,5)(A,∞)(A,∞)(A)C把C加入到集合
2(null)(C,5)(null)(A,5)(C,6)(C,4)(A,C)F(C,B)比原来的(A,B)小,覆盖
3(null)(C,5)(null)(F,2)(C,6)(null)(A,C,F)D(F,D)比(A,D)小
4(null)(C,5)(null)(null)(C,6)(null)(A,C,F,D)BD的边没有原来的小
5(null)(null)(null)(null)(B,3)(null)(A,C,F,D,B)E(B,E)比(C,E)小
6(null)(null)(null)(null)(null)(null)(A,C,F,D,B,E)结束总共6个结点,共遍历6次

3.克鲁斯特卡尔-最小生成树

  刚开始,每个结点为各立为一组连通分量。连通分量之间选出最短的边,同通过最短的边,来合并连通分量,反复直到所有结点在同一个连通分量中,结束,或者无可以连接的边结束。当添加最短边时出现回路则选下一条边

对边进行从小到大排序:

(A,C,1)(D,F,2)(B,E,3)(C,F,4)(A,D,5)(B,C,5)(C,D,5)(A,B,6)(C,E,6)(E,F,6)

初始连通分量组ABCDEF
第1小边(A,C)(A,C)BDEF
第2小边(D,F)(A,C)B(D,F)E
第3小边(B,E)(A,C)(B,E)(D,F)
第4小边(C,F)(A,C,D,F)(B,E)
第5小边(A,D),已在同一集合中,形成回路(A,C,D,F)(B,E)
第6小边(B,C)(A,C,D,F,B,E)
全部结点在同一集合中,结束      

4.迪杰斯特拉-最短路径

    目标:输入一个起始结点,求起始结点到其他结点的最短路径和代价。需要提前初始化好邻接矩阵 adjacencyMatrix_。

假设输入起始点A,当前路径 A  (也是已访问的点),

对象数组的对象元素 时   (最小代价 lowcost_,和 最短路径  pathIndex_)

1.求到所有点的代价(A,C,10) (A,E,30) ,(A,F,100) ,选取最小代价的直接目标结点currentPathIndex(C)。加入到当前路径currentPath (A,C)  代价lowestCost为10.

2.即

currentPath= lowestPaths[currentPathIndex].pathIndex_  + currentPathIndex ;
lowestCost=lowestPaths[currentPathIndex].lowcost_

3.遍历LowestPaths[0....j...n]  (排除在CurrentPath的点)

if (lowestCost+ adjacencyMatrix_[currentPathIndex][j] <lowestPaths[j].lowcost_) {
    lowestPaths[j].lowcost_= lowestCost+ adjacencyMatrix_[currentPathIndex][j] ;
    lowestPaths[j].pathIndex_=currentPath;
}

  重复 2,3

求解步骤:

 


5.图的最长路径(不走重复路)

     不管是有向图或者无向图都适用的递归方法,建议使用邻接矩阵的数据结构,当图是有向无环图的时候,求的是关键路径。主要思想是:当已知源节点到目标结点的前继结点的最长路径时, 就可求得  源节点到目标结点的最长路径..

加入求 结点V0 到 Vn 的最长路径。那么首先要列出Vn的前驱结点集(Vxi,Vxi....) 

有递归函数fun(V0,Vn) 表示V0到Vn的最长路径 。其值  =Max(fun(V0,Vxi)+arc[Vxi][Vn]).通过次方法找到最长路径。找最短路径也可以参考此方法

函数格式      double fun( src , target , vector<int> & hasVisits)

提前初始化邻接矩阵 arc[][]。

0.如果源结点和目标结点相同则返回0。

1.已访问的结点集 hasVisits为引用形参,把目标结点target 加入进该集合。

2.寻找还未访问的目标结点的前继结点。

3.判断邻接矩阵arc[源结点][目标结点] 的是否是∞,如果为真初始化最大路径maxValue为最小浮点值,如果为假  maxValue为设置为arc[源结点][目标结点]。

4..拷贝hasVisits出一个副本,遍历前继结点集合,

value = fun(源结点,某个前继结点,hasVisits的副本引用) + arc[某个前继结点][目标结点]

,如果value大于maxvalue时,maxvalue赋值成value且 hasVisit赋值成hasVisits的副本引用。最后递归结束时hasVisits就是最大路径,返回值就是最大代价。

6.有向无环图的关键路径

主要思想就是 找出 最早开始时间和最晚结束时间相等的结点

起始结点的最早开始时间是 0 ,把代价当作时间。

每个结点最早开始时间 =   max(前继结点的最早开始时间+ arc[前继结点][当前结点])

终点结点的最晚结束时间=终点结点的最早开始时间。

每个结点最晚结束时间 =    min((后继结点的最晚结束时间   -  arc[当前结点][后继结点]) 

最早开始时间和最晚结束时间相等的结点就是关键结点,通路就是关键路径

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.深度优先遍历(Depth-First Traversal) 假设给定G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至中所有顶点均已被访问为止。 2.广度优先遍历 1)从中某个顶点V0出发,并访问此顶点; 2)从V0出发,访问V0的各个未曾访问的邻接点W1,W2,…,Wk;然后,依次从W1,W2,…,Wk出发访问各自未被访问的邻接点; 3)重复步骤2,直到全部顶点都被访问为止。 3. prim算法 假设V是中顶点的集合,E是中边的集合,TE为最小生成树中的边的集合,则prim算法通过以下步骤可以得到最小生成树: 1)初始化:U={u 0},TE={f}。此步骤设立一个只有结点u 0的结点集U和一个空的边集TE作为最小生成树的初始形态,在随后的算法执行中,这个形态会不断的发生变化,直到得到最小生成树为止。 2)在所有u∈U,v∈V-U的边(u,v)∈E中,找一条权最小的边(u 0,v 0),将此边加进集合TE中,并将此边的非U中顶点加入U中。此步骤的功能是在边集E中找一条边,要求这条边满足以下条件:首先边的两个顶点要分别在顶点集合U和V-U中,其次边的权要最小。找到这条边以后,把这条边放到边集TE中,并把这条边上不在U中的那个顶点加入到U中。这一步骤在算法中应执行多次,每执行一次,集合TE和U都将发生变化,分别增加一条边和一个顶点,因此,TE和U是两个动态的集合,这一点在理解算法时要密切注意。 3)如果U=V,则算法结束;否则重复步骤2。可以把本步骤看成循环终止条件。我们可以算出当U=V时,步骤2共执行了n-1次(设n为中顶点的数目),TE中也增加了n-1条边,这n-1条边就是需要求出的最小生成树的边。 4.Kruskal算法 假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子,若将该子中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子中含有 n-1条边为止。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值