之前都是看的书,大部分也是c++的实现,但是搞前端不能忘了JS啊,所以JS实现一遍这两个经典的最小生成树算法。
<强>一、权重图和最小生成树
强>
权重图:图的边带权重
最小生成树:在连通图的所有生成树中,所有边的权重和最小的生成树
本文使用的图如下:
它的最小生成树如下:
<强>二,邻接矩阵
强>
邻接矩阵:用来表示图的矩阵就是邻接矩阵,其中下标表示顶点,矩阵中的值表示边的权重(或者有无边,方向等)。
本文在构建邻接矩阵时,默认表示两个节点之间没有边,表示当前节点没有自环。
代码如下:
/* * *邻接矩阵 *值为顶点与顶点之间边的权值,0表示无自环,一个大数表示无边(比如10000) * */const MAX_INTEGER=Number.MAX_SAFE_INTEGER;//没有的边 const MIN_INTEGER=Number.MIN_SAFE_INTEGER;//没有自环 const矩阵=[ [MIN_INTEGER 9 2 MAX_INTEGER 6), MAX_INTEGER MIN_INTEGER[9日,3日,MAX_INTEGER), (2、3、MIN_INTEGER 5 MAX_INTEGER), [MAX_INTEGER MAX_INTEGER 5, MIN_INTEGER, 1], (6 MAX_INTEGER MAX_INTEGER 1 MIN_INTEGER]);
这个邻接矩阵表示的图如下:
<强>三,边的表示
强>
一个边具有权重,起点,重点三个属性,所以可以创建一个类(对象),实现如下:
/* * *边对象 * */函数边缘(开始、结束、重量){ 这一点。开始=开始; 这一点。结束=结束; 这一点。重量=重量; } Edge.prototype。getBegin=function () { 返回this.begin; }; Edge.prototype。getEnd=function () { 返回this.end; }; Edge.prototype。getWeight=function () { 返回this.weight; }; {/*类边缘 构造函数(开始、结束、重量){ 这一点。开始=开始; 这一点。结束=结束; 这一点。重量=重量; } getBegin () { 返回this.begin; } getEnd () { 返回this.end; } getWeight () { 返回this.weight; } }*/
, PS: JS这门语言没有私有变量的说法,这里写得到方法纯粹是模拟一下私有变量。可以不用这么写,可以直接通过属性访问到属性值。
<强>四,拘谨的算法
强>
将这个算法的文章数不胜数,这里就不细说了。
其大体思路就是:以某顶点为起点,逐步找各顶点上最小权值的相邻边构建最小生成树,同时其邻接点纳入生成树的顶点中,只要保证顶点不重复添加即可。
实现代码如下:
/* * *拘谨的算法 *以某顶点为起点,逐步找各顶点上最小权值的边构建最小生成树,同时其邻接点纳入生成树的顶点中,只要保证顶点不重复添加即可 *使用邻接矩阵即可 *优点:适合点少边多的情况 * @param矩阵邻接矩阵 * @return数组最小生成树的边集数组 * */函数的(矩阵){=matrix.length const行, 关口=行, 结果=[], savedNode=[0];//已选择的节点 让minVex=1, minWeight=MAX_INTEGER; (让我=0;我& lt;行;我+ +){ 让行=savedNode[我], edgeArr=矩阵(行); (让j=0;j & lt;关口;j + +) { 如果(edgeArr [j] & lt;minWeight,,edgeArr [j]。==MIN_INTEGER) { minWeight=edgeArr [j]; minVex=j; } }//保证所有已保存节点的相邻边都遍历到 如果(savedNode.indexOf (minVex)===1,,我===savedNode。长度- 1){ savedNode.push (minVex); 结果。推动(新边缘(行,minVex, minWeight));//重新在已加入的节点集中找权值最小的边的外部边 i=1; minWeight=MAX_INTEGER;//已加入的边,去掉,下次就不会选这条边了 矩阵[行][minVex]=MAX_INTEGER; 矩阵[minVex](行)=MAX_INTEGER; } } 返回结果; }
<强>五,Kruskal算法强>
介绍这个算法的文章也很多,这里不细说。
其主要的思路就是:遍历所有的边,按权值从小到大排的序,每次选取当前权值最小的边,只要不构成回环,则加入生成树。