克鲁斯卡尔算法思想的应用,普里姆算法和克鲁斯卡尔算法比较

首页 > 教育 > 作者:YD1662024-05-17 21:23:02

克鲁斯卡尔算法思想的应用,普里姆算法和克鲁斯卡尔算法比较(5)

第1步:将边<E,F>加入R中。 边<E,F>的权值最小,因此将它加入到最小生成树结果R中。

第2步:将边<C,D>加入R中。 上一步操作之后,边<C,D>的权值最小,因此将它加入到最小生成树结果R中。

第3步:将边<D,E>加入R中。 上一步操作之后,边<D,E>的权值最小,因此将它加入到最小生成树结果R中。

第4步:将边<B,F>加入R中。 上一步操作之后,边<C,E>的权值最小,但<C,E>会和已有的边构成回路;因此,跳过边<C,E>。同理,跳过边<C,F>。将边<B,F>加入到最小生成树结果R中。

第5步:将边<E,G>加入R中。上一步操作之后,边<E,G>的权值最小,因此将它加入到最小生成树结果R中。

第6步:将边<A,B>加入R中。 上一步操作之后,边<F,G>的权值最小,但<F,G>会和已有的边构成回路;因此,跳过边<F,G>。同理,跳过边<B,C>。将边<A,B>加入到最小生成树结果R中。

此时,最小生成树构造完成!它包括的边依次是:<E,F> <C,D> <D,E> <B,F> <E,G> <A,B>。

五、克鲁斯卡尔(Kruskal)算法分析

根据前面介绍的克鲁斯卡尔算法的基本思想和做法,我们能够了解到,克鲁斯卡尔算法重点需要解决的以下两个问题:

问题一:对图的所有边按照权值大小进行排序。

问题二 将边添加到最小生成树中时,怎么样判断是否形成了回路。

问题一很好解决,采用排序算法进行排序即可。

问题二,处理方式是:记录顶点在"最小生成树"中的终点,顶点的终点是"在最小生成树中与它连通的最大顶点"。然后每次需要将一条边添加到最小生存树时,判断该边的两个顶点的终点是否重合,重合的话则会构成回路。

六、如何判断是否构成回路——示例说明

克鲁斯卡尔算法思想的应用,普里姆算法和克鲁斯卡尔算法比较(6)

在将<E,F> <C,D> <D,E>加入到最小生成树R中之后,这几条边的顶点就都有了终点:

1)、C的终点是F。

2)、D的终点是F。

3)、E的终点是F。

4)、F的终点是F。

关于终点的说明:

1)、就是将所有顶点按照从小到大的顺序排列好之后;某个顶点的终点就是"与它连通的最大顶点"。

2)、因此,接下来,虽然<C,E>是权值最小的边。但是C和E的终点都是F,即它们的终点相同,因此,将<C,E>加入最小生成树的话,会形成回路。这就是判断回路的方式。也就是说,我们加入的边的两个顶点不能都指向同一个终点,否则将构成回路。

七、克鲁斯卡尔(Kruskal)算法——代码实现

package com.rf.data_structure_algorithm.algorithm.kruskal;

import java.util.Arrays;

/**

* @description: 克鲁斯卡尔算法

* @author: xiaozhi

* @create: 2020-11-16 20:55

*/

public class KruskalAlgorithm {

int edgeNum; //边的个数

char[] vertexs;//顶点数组

int[][] matrix; //邻接矩阵

static final int INF = Integer.MAX_VALUE;//使用 INF 表示两个顶点不能连通

//构造器

public KruskalAlgorithm(char[] vertexs, int[][] matrix) {

//初始化顶点, 复制拷贝的方式

this.vertexs = new char[vertexs.length];

for (int i = 0; i < vertexs.length; i ) {

this.vertexs[i] = vertexs[i];

}

//初始化边, 使用的是复制拷贝的方式

this.matrix = new int[vertexs.length][vertexs.length];

for (int i = 0; i < vertexs.length; i ) {

for (int j = 0; j < vertexs.length; j ) {

this.matrix[i][j] = matrix[i][j];

}

}

//统计边的条数

for (int i = 0; i < vertexs.length; i ) {

for (int j = i 1; j < vertexs.length; j ) {

if (this.matrix[i][j] != INF) {//可以连通,边的个数 1

edgeNum ;

}

}

}

}

/**

* @Description: 打印邻接矩阵

* @Author: xz

* @Date: 2020/11/16 21:11

*/

public void print() {

for (int i = 0; i < vertexs.length; i ) {

for (int j = 0; j < vertexs.length; j ) {

System.out.printf("d", matrix[i][j]);

}

System.out.println();//换行

}

}

/**

* @Description: 对边进行排序(冒泡排序)

* @Param: edges 边的集合

* @Author: xz

* @Date: 2020/11/16 21:28

*/

public void sortEdges(KData[] edges){

for(int i=0;i<edges.length-1;i ){

for(int j=0;j<edges.length-1-i;j ){

if(edges[j].weight >edges[j 1].weight){

KData temp =edges[j];

edges[j]=edges[j 1];

edges[j 1]=temp;

}

}

}

}

/**

* @Description:

* @Param: c 表示顶点的值,比如‘A’,‘B’...

* @Author: xz

* @return: 返回c 顶点的下标,如果找不到返回-1

* @Date: 2020/11/16 21:35

*/

public int getPosition(char c){

for(int i=0;i<vertexs.length;i ){

if(vertexs[i] ==c){

return i;

}

}

//找不到返回-1

return -1;

}

/**

* @Description: 获取图中的边放到KData[] 数组中,通过 matrix 邻接矩阵获取

* KData[] 的形式如: [[<A, B>= 12], [<A, F>= 16],...]

* @Author: xz

* @Date: 2020/11/16 21:41

*/

public KData[] getEdges(){

int index=0;

KData[] edges=new KData[edgeNum];

for(int i=0;i<vertexs.length;i ){

for(int j=i 1;j<vertexs.length;j ){

if(matrix[i][j] != INF){

edges[index ] =new KData(vertexs[i],vertexs[j],matrix[i][j]);

}

}

}

return edges;

}

/**

* 功能: 获取下标为i的顶点的终点(), 用于后面判断两个顶点的终点是否相同

* @param ends : 数组就是记录了各个顶点对应的终点是哪个,ends 数组是在遍历过程中,逐步形成

* @param i : 表示传入的顶点对应的下标

* @Author: xz

* @return 返回的就是 下标为i的这个顶点对应的终点的下标

* @Date: 2020/11/16 21:49

*/

private int getEnd(int[] ends, int i) {

while(ends[i] != 0) {

i = ends[i];

}

return i;

}

/**

* @Description: 克鲁斯卡尔方法

* @Author: xz

* @Date: 2020/11/16 21:52

*/

public void kruskal() {

int index = 0; //表示最后结果数组的索引

int[] ends = new int[edgeNum]; //用于保存"已有最小生成树" 中的每个顶点在最小生成树中的终点

//创建结果数组, 保存最后的最小生成树

KData[] rets = new KData[edgeNum];

//获取图中 所有的边的集合 , 一共有12边

KData[] edges = getEdges();

System.out.println("图的边的集合=" Arrays.toString(edges) " 共" edges.length); //12

//按照边的权值大小进行排序(从小到大)

sortEdges(edges);

//遍历edges 数组,将边添加到最小生成树中时,判断是准备加入的边否形成了回路,如果没有,就加入 rets, 否则不能加入

for(int i=0; i < edgeNum; i ) {

//获取到第i条边的第一个顶点(起点)

int p1 = getPosition(edges[i].start); //p1=4

//获取到第i条边的第2个顶点

int p2 = getPosition(edges[i].end); //p2 = 5

//获取p1这个顶点在已有最小生成树中的终点

int m = getEnd(ends, p1); //m = 4

//获取p2这个顶点在已有最小生成树中的终点

int n = getEnd(ends, p2); // n = 5

//是否构成回路

if(m != n) { //没有构成回路

ends[m] = n; // 设置m 在"已有最小生成树"中的终点 <E,F> [0,0,0,0,5,0,0,0,0,0,0,0]

rets[index ] = edges[i]; //有一条边加入到rets数组

}

}

//<E,F> <C,D> <D,E> <B,F> <E,G> <A,B>。

//统计并打印 "最小生成树", 输出 rets

System.out.println("最小生成树为=================");

for(int i = 0; i < index; i ) {

System.out.println(rets[i]);

}

}

/**

* @Description: 测试方法

* @Author: xz

* @Date: 2020/11/16 21:15

*/

public static void main(String[] args) {

//定义7个顶点

char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

//定义克鲁斯卡尔算法的邻接矩阵 INF:表示两个顶点不能连通,0:表示顶点自己和顶点自己相连

int matrix[][] = {

/*A*//*B*//*C*//*D*//*E*//*F*//*G*/

/*A*/ {0, 12, INF, INF, INF, 16, 14},

/*B*/ {12, 0, 10, INF, INF, 7, INF},

/*C*/ {INF, 10, 0, 3, 5, 6, INF},

/*D*/ {INF, INF, 3, 0, 4, INF, INF},

/*E*/ {INF, INF, 5, 4, 0, 2, 8},

/*F*/ {16, 7, 6, INF, 2, 0, 9},

/*G*/ {14, INF, INF, INF, 8, 9, 0}

};

//创建KruskalAlgorithm 对象实例

KruskalAlgorithm kruskalAlgorithm = new KruskalAlgorithm(vertexs, matrix);

//输出构建的邻接矩阵

System.out.println("邻接矩阵============== \n");

kruskalAlgorithm.print();

System.out.println();

System.out.println("图中的边及权值-------------------------");

KData[] edges = kruskalAlgorithm.getEdges();

System.out.println("排序前=" Arrays.toString(edges));

kruskalAlgorithm.sortEdges(edges);

System.out.println("排序后=" Arrays.toString(edges));

System.out.println();

kruskalAlgorithm.kruskal();

}

}

/**

* @Description: 创建一个类KData,它的对象实例就表示一条边

* @Author: xz

* @Date: 2020/11/16 21:22

*/

class KData {

char start; //边的一个点

char end; //边的另外一个点

int weight; //边的权值

//构造器

public KData(char start, char end, int weight) {

this.start = start;

this.end = end;

this.weight = weight;

}

//重写toString, 便于输出边信息

@Override

public String toString() {

return "KData [<" start ", " end ">= " weight "]";

}

}

运行:

克鲁斯卡尔算法思想的应用,普里姆算法和克鲁斯卡尔算法比较(7)

克鲁斯卡尔算法思想的应用,普里姆算法和克鲁斯卡尔算法比较(8)

上一页123下一页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.