最小生成树-普里姆(Prim)和克鲁斯卡尔(Kruskal)算法JS实现

JavaScript实现prime(普里姆)算法和kruskal(克鲁斯卡尔)算法 prime算法 prime算法生成最小生成树(Minimum Cost Spanning Tree)的一种算法。 prime算法是从指定的顶点开始构建最小生成树。 prime算法思想如下: 从连通图(V,E)中找最小生成树(U,TE): (1)假设从顶点V0出发开始构造,U={V0},TE={}; (2)先找权值最小的边(u,v),u属于U,v属于V-U,并且子图不构成环,则U=U并{... 阅读详情

如何在n个顶点,n*(n-1)/2条边中,筛选出具有n-1条边的,且具有最小代价的连通网呢?这就是最小生成树问题,下面介绍两种算法:

1 普里姆(Prim)算法

首先建立图的邻接矩阵存储:

class Graph{
	constructor(v,vr){
		let len = v.length
		this.vexs = [].slice.apply(v);
		let arcs = [];
		for (let i=0;i<len;i++){
			arcs[i] = new Array(len);
			for (let j=0;j<len;j++){
				arcs[i][j] = i===j ? 0 : 65535;
			}
		}
		for (let arc of vr){
			let v1 = v.indexOf(arc[0]);
			let v2 = v.indexOf(arc[1]);
			arcs[v1][v2] = arcs[v2][v1] = arc[2] || 1;
		}
		this.arcs = arcs;
	}

}

let a = new Graph(['v0','v1','v2','v3','v4','v5','v6','v7','v8'],[['v0','v1',10],['v0','v5',11],['v1','v6',16],['v1','v2',18],['v1','v8',12],['v6','v7',19],['v5','v6',17],['v4','v5',26],['v3','v4',20],['v3','v7',16],['v2','v8',8],['v3','v8',21],['v4','v7',7],['v2','v3',22],['v3','v6',24]]);
console.log(a);

在这里插入图片描述
在这里插入图片描述
算法思路:
假设N=(P,{E})是连通网,TE是N上最小生成树中边的集合。算法从U={u0} (u0∈V),TE={ }开始。重复执行下述操作:在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0),并入集合TE,同时v0并入U,直至U=V为止。此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。

为实现该算法,需要设置一个辅助数组closeEdge(长度与图的顶点数相同)用于记录从顶点集U到V-U的代价最小的边。该数组每个元素有两个域,分别为adjvex和lowcost,用于表示一条边。以下图为例:

lowcost001865535260166553512
adjvex001050101

此时表示,边(v0,v1)和(v0,v5)已经入选最小生成树,用边的权值lowcost值等于0标识。边(v1,v2)这条边权值为18,(v5,v4)这条边权值为26,(v1,v6)这条边权值为16,(v1,v8)这条边权值为12,其余顶点对应的边权值为65535(不存在)。整个算法过程就是一步一步填补这个辅助数组的过程,当lowcost中所有顶点的值都为0时,表示已经找到n-1条边,完成了算法。
在这里插入图片描述
可以根据算法,思考这个问题:

class MiniEdge{   //定义辅助数组的元素
	constructor(adjvex,lowcost){
		this.adjvex = adjvex;   //用于表示边
		this.lowcost = lowcost;   //用于存储边的权值
	}
}

function Prim(G){
	let closeEdge = new Array(G.vexs.length);
	closeEdge[0] = new MiniEdge(0,0);     //将顶点v0加入最小生成树
	for (let i=1;i<G.vexs.length;i++){      //初始化数组,此时数组保存着顶点v0到各个顶点的边及权值
		closeEdge[i] = new MiniEdge(0,G.arcs[0][i]);
	}

	var j;
	var miniVex;   //用于存储具有最小权值的边顶点下标
	var miniCost;   //用于存储最小的权值
	for (let i=1;i<G.vexs.length;i++){
		j = 1;
		miniVex = 0;   //初始化
		miniCost = 65535;
		while(j<G.vexs.length){   //找寻最小权值的边,并存储相应的顶点
			if (closeEdge[j].lowcost !==0 && closeEdge[j].lowcost < miniCost){  //注意lowcost等于0代表该节点已经入选生成树,应跳过
				miniCost = closeEdge[j].lowcost;
				miniVex = j;
			}
			j++;
		}

		console.log(G.vexs[closeEdge[miniVex].adjvex],G.vexs[miniVex],miniCost);  //打印最小权值的边及权值

		closeEdge[miniVex].lowcost = 0;    //将当前顶点加入最小生成树
		for (j = 1;j<G.vexs.length;j++){   //更新辅助数组,此时数组保存着最小生成树中顶点到图中其余各顶点权值最小的边
			if (closeEdge[j].lowcost !==0 && G.arcs[miniVex][j] < closeEdge[j].lowcost){
				closeEdge[j].lowcost = G.arcs[miniVex][j];
				closeEdge[j].adjvex = miniVex;
			}
		}
	}
}

在这里插入图片描述
由此可见,两个嵌套的循环,Prim算法复杂度为O(n2)

2 克鲁斯卡尔(Kruskal)算法

Prim算法以顶点为起点,逐步寻找各顶点上最小权值的边来构建最小生成树,而Kruskal算法直接就以边为目标去构造最小生成树。
首先需要构建一个边集数组:

class edge{
	constructor(begin,end,weight){
		this.begin = begin;
		this.end = end;
		this.weight = weight;
	}
}

class Graph{
	constructor(v,vr){
		let len = v.length;
		this.vexs = [].slice.apply(v);
		let edges = [];
		let v1=0,v2=0;
		for (let arc of vr){
			v1 = v.indexOf(arc[0]);
			v2 = v.indexOf(arc[1]);
			edges.push(new edge(v1,v2,arc[2]));
		}
		edges.sort(function(a,b){
			return a.weight - b.weight;
		})
		this.edges = edges;
	}
}

let a = new Graph(['v0','v1','v2','v3','v4','v5','v6','v7','v8'],[['v0','v1',10],['v0','v5',11],['v1','v6',16],['v1','v2',18],['v1','v8',12],['v6','v7',19],['v5','v6',17],['v4','v5',26],['v3','v4',20],['v3','v7',16],['v2','v8',8],['v3','v8',21],['v4','v7',7],['v2','v3',22],['v3','v6',24]]);
console.log(a);

在这里插入图片描述
在这里插入图片描述

算法思路:
假设N={V,{E}}是连通网,则令最小生成树的初始状态为只有n个顶点而无边的非连通图T={V,{ }},图中每个顶点自成一个连通分量,在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。依次类推,直至T中所有顶点都在同一连通分量上为止。

由此可见该算法的关键在于如何判定一条边依附的顶点是否落在T中不同的连通分量上,换句话说,就是如果加入了这条边,则判断T中是否形成了环路,若形成了环路,则必须舍弃这条边。因此需要一个辅助数组parents来帮助判断,如图:
在这里插入图片描述
边(V0,V1)和(V0,V2)已经入选最小生成树,对应的数组为:

1200

其中,parents[0] = 1, parents[1] = 2, parents[2] = 0,代表此时最小生成树中已包含v0,v1,v2顶点。此时还需添加一条边,由于边(V1,V2)权值较小,因此先试试添加这条边,将这条边的一个顶点序号1代入下列代码,返回2,再将该边的另一个顶点2代入,返回2,我们发现头尾顶点的返回值相等,这表明此时形成了环路,应该舍弃这条边。接着,我们代入边(V1,V3)的两个顶点序号,返回2≠3,因此没有将其纳入最小生成树中。

function(i){
	while (parents[i] >0) i = parents[i];
	return i;
}

算法代码很短,很容易理解

function Kruskal(G){
	let parents = new Array(G.vexs.length);
	for (let i=0;i<G.vexs;i++){   //初始化辅助数组
		parents[i] = 0;
	}
	let v1=0,v2=0;
	for (let edge of G.edges){   //遍历所有边
		v1 = find(edge.begin);
		v2 = find(edge.end);
		if (v1 !== v2){        //若不形成环路,则将这条边加入生成树
			parents[v1] = v2;
			console.log(G.vexs[edge.begin],G.vexs[edge.end],edge.weight);
		}
	}

	function find(i){        //辅助函数
		while(parents[i] > 0) 
			i = parents[i];
		return i;
	}
}

在这里插入图片描述
由此可见,在Kruskal算法中,若以堆来存放边,则find函数复杂度为O(loge),而外部有一个for循环e次,因此总算法为O(eloge)

JS实现最小生成树(普里姆算法) JS实现最小生成树(prim算法) 图中有五个节点ABCDE,该算法实现在这张图中找到最短的路径将ABCDE串联在一起。 核心就是先拿到图中的一个点,然后判断它的邻居中离谁最近,就前往它的邻居中,然后再递归判断邻居的邻居。 例如从A开始,它有BCD三个邻居,到D的距离最近,然后到达D ... 阅读详情

相关推荐

javascript:实现使用Prim算法确定图的最小生成树算法(附完整源码)

javascript:实现使用Prim算法确定图的最小生成树算法(附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 365

JS实现最小生成树之克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔算法打印最小生成树:   构造出所有边的集合 edges,从小到大,依次选出筛选边打印,遇到闭环(形成回路)时跳过。 JS代码: 1 //定义邻接矩阵 2 let Arr2 = [ 3 [0, 10, 65535, 65535, 65535, 11, 65535, 65535, 65535], 4 [10, 0, 18,...

408

【信息科学与工程学】【数据科学】数据科学领域 第六篇 算法设计 07 堆、栈、表、矩阵、集合、队列、数组、字符串、树、图、动态规划、结构体、元组的算法01

当前段必须包含所有字符的最后出现位置。1. 字符串分割成最多片段2. 基因序列功能域划分3. 文本段落划分4. 音频声道分离5. 图像色彩分区6. 社交网络社群划分7. 蛋白质结构域8. 音乐乐章分段9. 代码模块划分10. 章节划分特征:一次扫描,贪心确定边界。

weixin_49199313的博客 1272

最小生成树算法——Prim算法和Kruskal算法的JS实现

之前都是看书,大部分也是c++的实现,但是搞前端不能忘了JS啊,所以JS实现一遍这两个经典的最小生成树算法。 一、权重图和最小生成树 权重图:图的边带权重 最小生成树:在连通图的所有生成树中,所有边的权重和最小的生成树 本文使用的图如下: 它的最小生成树如下: 二、邻接矩阵 邻接矩阵:用来表示图的矩阵就是邻接矩阵,其中下标表示顶点,矩阵中的值表示边的权重(或者有无边,方向等)...

随风丶逆风的博客 6997

JavaScript实现kruskal克鲁斯卡尔算法(附完整源码)

JavaScript实现kruskal克鲁斯卡尔算法(附完整源码)DisjointSetItem.js完整源代码DisjointSet.js完整源代码Comparator.js完整源代码Sort.js完整源代码QuickSort.js完整源代码Graph.js完整源代码kruskal.js完整源代码 DisjointSetItem.js完整源代码 export default class DisjointSetItem { constructor(value, keyCallback) { th

希望我的博客,能帮上你解决学习中工作中所遇到的问题 638

【数据结构】克鲁斯卡尔(Kruskal)算法 —PK— 普里姆(Prim)算法

求图的最小生成树的典型算法:克鲁斯卡尔(Kruskal)算法;普里姆(Prim)算法。考虑问题的出发点相同:为使生成树上边的权值之和达到最小,则应使生成树中每一条边的权值尽可能的小。

四季轮换叶,一路招摇胜 1万+

数据结构のJavaScript 实现之最小生成树MST( Kruskal算法和Prim算法)

先感谢查阅博客时给予我启发的一些博主: https://www.cnblogs.com/skywang12345/p/3711496.html 这篇问题说得比较清楚,kruskal算法的重点在于怎么判断是否形成了回路,而判断是否形成回路要用到并查集的概念。 https://www.cnblogs.com/zhangming-blog/p/5414514.html 这篇例子很好,prim算法讲的...

等时钟成长 392

JavaScript中的最小生成树库:MST2使用详解

本文还有配套的精品资源,点击获取 简介:MST2可能与JavaScript中的最小生成树算法相关,或是实现这一算法的项目或库。最小生成树用于连接图中所有节点,使得边的总权重最小,常应用于网络设计和物流规划。MST2作为一个库,可能提供Prim和Kruskal等算法的实现,通过API如 addVertex 、 addEdge 和 calcu...

weixin_42462474的博客 1581

c语言实现克鲁斯卡尔算法,连通图求解最小生成树的普林姆(prim)算法和克鲁斯卡尔(kruskal)算法之JavaScript实现...

最近在看《大话数据结构》,图的算法。书中用C语言讲解的,下面用JavaScript实现普林姆(prim)算法和克鲁斯卡尔(kruskal)算法求解连通网的最小生成树普林姆(prim)算法// 普林姆算法寻找连通网的最小生成树const _ = require('lodash')// 图的邻接矩阵const G_0 = [[0, 10, Infinity, Infinity, Infinity, 1...

weixin_42365898的博客 224

【H5JS】游戏常用算法-路径搜索算法-随机迷宫算法(普里姆算法).pdf

【H5JS】游戏常用算法-路径搜索算法-随机迷宫算法(普里姆算法).pdf

JS使用Prim算法和Kruskal算法实现最小生成树

主要为大家详细介绍了JS使用Prim算法和Kruskal算法实现最小生成树,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

破圈法求最小生成树_JavaScript 实现 最小生成树

一 : 了解最小生成树最小生成树(MST)问题是网络设计中常见的问题。想象一下,你的公司有几间办公室,要 以最低的成本实现办公室电话线路相互连通,以节省资金,最好的办法是什么?这也可以应用于岛桥问题。设想你要在 n 个岛屿之间建造桥梁,想用最低的成本实现所有岛 屿相互连通。这两个问题都可以用 MST 算法来解决,其中的办公室或者岛屿可以表示为图中的一个顶点, 边代表成本。下面有一个图的例子,其中...

weixin_40005795的博客 807

OB4.X集群状态running但是oceanbase-ce is not running

自 V3.2.0 起,若 obd 设置了加密密钥,执行 display 命令输出的集群信息中,密码相关内容为加密状态。若需输出明文密码,可在命令中添加 --epk/–encryption-passkey 指定密钥用于验证。obd 运维的数据库,启停需要使用obd进行操作,停机时候没有使用obd会导致集群状态running但是oceanbase-ce is not running。查看集群中的租户时无租户反馈,警告oceanbase-ce is not running,但是查询集群状态明明是running。

qq961573863的博客 1213

Kruskal算法js实现

const graph = [ /** * A, B, C, D, E, F * 0, 1, 2, 3, 4 ,5 **/ [0, 2, 4, 0, 0, 0],//0 A [2, 0, 2, 4, 2, 0],//1 B [4, 2, 0, 0, 3, 0],//2 C [0, 4, 0, 0, 3, 2],//3 D [0, 2, 3, 3, 0, 2],//4 E [0, 0, 0, 2, 2, 0] //5 F ] .

nishiweiyj的博客 876

Android 12高通thermal-engine调试实战:如何快速开启debug日志并解决CPU降频问题

本文详细介绍了Android 12高通thermal-engine的调试实战,包括如何快速开启debug日志、解读关键日志信息以及解决CPU降频问题。通过优化配置文件和调整温控策略,开发者可以有效提升设备性能,避免因温度管理导致的性能瓶颈。

i3j4k5的博客 307

DC-DC电源PCB布局实战:从EMI优化到热管理

本文深入探讨了DC-DC电源PCB布局的核心实战技巧。文章从分析电流环路入手,强调通过优化“黄金三角”布局以最小化环路面积,从而有效抑制EMI并提升效率。详细阐述了功率器件摆放、地线分割、敏感信号布线、电感下方铺铜策略以及热管理设计等关键步骤,为工程师提供了一套从理论到实践的完整布局指南。

z5a6b的博客 721

js实现克鲁斯卡尔算法

克鲁斯卡尔算法是一种用于构造最小生成树的算法。下面是一种在 JavaScript 中实现克鲁斯卡尔算法的方法: function kruskal(edges, nodes) { // 将边排序,从小到大 edges.sort((a, b) => a.weight - b.weight); let mst = []; let parent = []; // 初始化每个结...

weixin_35756690的博客 197

SAP Group Reporting入门指南(11)--配置

这里选择的是FS项目目标属性,FS项目有四个目标属性,比如上图配置的是抵消目标属性,所以就去找触发FS项目的抵消目标属性配置的是哪个FS项目,就以这个FS项目作为贷方。这里选择的是FS项目目标属性,FS项目有四个目标属性,比如上图配置的是抵消目标属性,所以就去找源FS项目的抵消目标属性配置的是哪个FS项目,就以这个FS项目作为借方。例如,添加一个包含用于存储百分比的 FS 项的选项。这里选择的是FS项目的角色属性值,如果这里定义了,那么就从FS项目中找到FS项目角色属性值与之匹配的FS项目作为贷方。

bflyfish的博客 568

JS实现最小生成树之普里姆(Prim)算法

最小生成树:   我们把构造连通网的最小代价生成树称为最小生成树。经典的算法有两种,普利姆算法和克鲁斯卡尔算法。 普里姆算法打印最小生成树:   先选择一个点,把该顶点的边加入数组,再按照权值最小的原则选边,选完最小权值的边,把在所选边的另一顶点的边加入数组,再选权值最小的边,如此循环(有多少顶点循环多少次) ∞ 我们代码中用65535表示 //定义邻接矩阵 let ...

289

YOLO26改进策略【YOLO和Mamba】| 替换骨干 Mamba-YOLO26-L !!! 最新的发文热点

Vision Clue Merge模块在Mamba - YOLO模型中同样重要,主要负责在模型的下采样过程中处理特征图,为后续的特征融合和目标检测任务提供更有效的信息。

Limiiiing的博客 472

⭐️VMwareWorkstation17.0虚拟机搭建WindowsXP虚拟机(完整安装步骤详细图文教程)

Windows XP是微软公司研发的计算机操作系统,于2001年10月25日正式发布。其名字中“XP”的意思来自英文中的“体验”(Experience)。Windows XP使用了Luna图形用户界面和双列开始菜单,提升了系统的安全性和工作性能,提供了WiFi支持,简化了软件的安装和运行,并增加了远程桌面功能。

Python老吕的博客 1万+

javascript手撕prim算法

prim算法是求求最小生成树的一种贪心算法,而且代码与dijkstra算法非常类似,不同的地方是dijkstra算法每次寻找和更新是所有已知点的距离到源点的最小距离, 而prim算法每次寻找的是现有最小生成树的所有的不在生成树上的临近点的最小距离。 const INF = Number.MAX_SAFE_INTEGER; const minKey = (key, visited) => { let min = INF; let minIndex = -1; for (let i = 0;

qq_21522331的博客 274

流体动力学仿真软件:SU2_(1).SU2简介与安装

SU2 是一个开源的计算流体动力学(CFD)和计算结构动力学(CSD)仿真软件,由斯坦福大学的航空航天系开发。它主要用于解决流体动力学问题,包括但不限于空气动力学、热力学、化学反应流等。SU2 的特点在于其高度的灵活性和可扩展性,使其成为科研和工业领域中非常受欢迎的工具。SU2 采用有限体积法(FVM)和有限元法(FEM)进行数值求解,支持多种物理模型和求解器,如 Euler 方程、Navier-Stokes 方程、RANS 方程等。

kkchenjj的博客 1313
上一篇: JS实现图的深度优先遍历(DFS)和广度优先遍历(BFS)
下一篇: 最短路径-迪杰斯特拉(Dijkstra)和弗洛伊德(Floyd)算法JS实现
PAT-python-zjw
博客等级 码龄10年 381粉丝 408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值