(Java版)Kruskal算法-----将森林合并成树

大致原理实现如下: 把所有的边放在一个集合里,每次都贪心的取出最短的边(权重最小),直到取出的边数为顶点数减一。当然取的时候有条件限制:每次取出来的边不能和之前取出来的边形成回路(这个可以使用并查集来实现)。

并查集(具体解析查看(Java版)并查集的实现_南柏良客的博客-CSDN博客),判断V和W是否属于同一颗集合树,如果是加上必然构成回路。

 最小堆的实现:只需要在最大堆(最大堆的实现)的基础上稍加改动,改动精髓点在于向下过滤

节点的步骤: 必须要把每一个自定义节点的每一个属性都向下过滤(正确代码查看图二),否则会出现错误(有什么好的解决办法还请大神们指点迷津)

 

正确向下过滤节点法 (每一个属性都向下过滤):

错误过滤法:

 

 

具体代码实现如下 :

最小边堆

public class EdgeData {
	public int weight;
	public int Node1;
	public int Node2;
}


public class MinEdgeHeap {

	public static final int MinData = -99999;
	EdgeData[] data;
	int size;
	int capacity;
	
	
	private MinEdgeHeap create(int MaxSize) {
		MinEdgeHeap minEdgeHeap = new MinEdgeHeap();
		minEdgeHeap.data = new EdgeData[MaxSize*MaxSize];
		minEdgeHeap.size = 0;
		minEdgeHeap.capacity = MaxSize;
		minEdgeHeap.data[0] = new EdgeData();
		minEdgeHeap.data[0].weight = MinData;    //建立哨兵,方便操作
		return minEdgeHeap;
	}

	public boolean IsFull(MinEdgeHeap H) {
		if(H.size == H.capacity) {
			return true;
		}
		return false;
	}
	
	public boolean IsEmpty(MinEdgeHeap H) {
		if(H.size == 0) {
			return true;
		}
		return false;
	}
	
	public void insert(MinEdgeHeap H, int weight,int Node1,int Node2) {
		if(IsFull(H)) {
			System.out.println("最大堆已满");
			return; 
		}
		// 因为邻接表形成的边是有方向的,下面的for循环去方向
		for(int i=1;i<=H.size;i++) {
			if((H.data[i].Node1==Node1||H.data[i].Node1==Node2)&&(H.data[i].Node2==Node1||H.data[i].Node2==Node2)) {
				return;
			}
		}
		int i = ++H.size;    //i指向插入元素后堆中最后一个元素的位置
		H.data[i] = new EdgeData();
		//这里利用堆(完全二叉树)的性质,每个子节点i/2必定得到父节点。称为向下过滤节点
		for( ; H.data[i/2].weight>weight; i/=2) {
			H.data[i].weight = H.data[i/2].weight;
			H.data[i].Node1 = H.data[i/2].Node1;
			H.data[i].Node2 = H.data[i/2].Node2;
		}
		H.data[i].weight = weight;
		H.data[i].Node1 = Node1;
		H.data[i].Node2 = Node2;
	}
	
	public EdgeData deleteMax(MinEdgeHeap H) {
		int parent,child;
		EdgeData MaxItem,temp;
		if(IsEmpty(H)) {
			System.out.println("最大堆已空");
			return null;
		}
		MaxItem = H.data[1];
		temp = H.data[H.size--];
		//parent*2<H.size说明有儿子(左右至少一个)
		for(parent = 1; parent*2<H.size; parent = child) {
			child = parent*2;   //假设左儿子为最大值
			//child != H.size说明有右儿子,H.data[child]<H.data[child+1]右儿子更大
			if((child != H.size)&&(H.data[child].weight>H.data[child+1].weight)) {
				child++;
			}
			if(temp.weight<=H.data[child].weight) {
				break;
			}
			else {
				H.data[parent] = H.data[child];
			}
		}
		H.data[parent] = temp;
		return MaxItem;
	}
	
	public MinEdgeHeap createEdgeHeap(Vertex[] vertexList) {
		MinEdgeHeap minEdgeHeap = new MinEdgeHeap();
		MinEdgeHeap heap = minEdgeHeap.create(vertexList.length*vertexList.length);
		for(int i=0;i<vertexList.length;i++) {
			EdgeNode p = vertexList[i].firstEdge;
			while(p != null) {
				minEdgeHeap.insert(heap, p.weight, i, p.adjvex);
				p = p.next;
			}
		}
		return heap;
	}
}

 并查集

//并查集
public class Assemble {

	public char data;
	public int parent;
	
	public int find(Assemble[] assemble,char data) {
		int i ;
		for(i = 0; i<assemble.length && assemble[i].data != data;i++);
		if(i >= assemble.length) return -1;
		for(; assemble[i].parent >=0 ;i = assemble[i].parent);
		return i;
	}
	
	public void union(Assemble[] assemble,char data1,char data2) {
		int Root1,Root2;
		Root1 = find(assemble, data1);
		Root2 = find(assemble, data2);
		if(Root1 != Root2) {   
			if(assemble[Root1].parent <= assemble[Root2].parent) {
				assemble[Root1].parent = assemble[Root1].parent+assemble[Root2].parent;
				assemble[Root2].parent = Root1;
			}
			if(assemble[Root1].parent > assemble[Root2].parent) {
				assemble[Root2].parent = assemble[Root1].parent+assemble[Root2].parent;
				assemble[Root1].parent = Root2;
			}
		}
	}
}

Kruskal算法如下: 

import maxHeap.Assemble;
import maxHeap.EdgeData;
import maxHeap.MinEdgeHeap;
import maxHeap.Vertex;

public class Kruskal {

	
	public void kruskal(Vertex[] vertexList) {
		EdgeData[] NodeList = new EdgeData[vertexList.length-1];
		Assemble[] asmb = new Assemble[vertexList.length];
		for(int i=0;i<vertexList.length;i++) {
			asmb[i] = new Assemble();
			asmb[i].data = vertexList[i].data;
			asmb[i].parent = -1;
		}
		MinEdgeHeap minEdgeHeap = new MinEdgeHeap();
		MinEdgeHeap heap = minEdgeHeap.createEdgeHeap(vertexList);
		int j=0;
		while((NodeList[vertexList.length-2] == null)&&(!minEdgeHeap.IsEmpty(heap))) {
			EdgeData data = minEdgeHeap.deleteMax(heap);
			Assemble assemble = new Assemble();
			if(assemble.find(asmb, vertexList[data.Node1].data)!=
					assemble.find(asmb, vertexList[data.Node2].data)) {
				NodeList[j++] = data;
				assemble.union(asmb, vertexList[data.Node1].data, vertexList[data.Node2].data);
			}
		}
		if(NodeList[vertexList.length-2] == null) {
			System.out.println("生成树不存在或图不连通");
		}
		for(int i = 0;i<NodeList.length;i++) {
			System.out.println(vertexList[NodeList[i].Node1].data+"  "+vertexList[NodeList[i].Node2].data);
		}
	}
	
}

简单写个测试类: 

import map.Kruskal;

public class Test2 {

	public static void main(String[] args) {
		char[] vexs = {'A','B','C','D','E','F','G'};
		char[][] edges = new char[][] {
			{'A','B',7},
			{'A','D',6},
			{'A','C',9},
			{'B','C',13},
			{'B','G',3},
			{'D','C',2},
			{'D','E',6},
			{'E','C',10},
			{'E','F',7},
			{'F','C',6},
			{'F','G',6},
			{'G','C',6},
		};
		CreateVertexList createVertexList = new CreateVertexList();
		Vertex[] vertexList = createVertexList.createListNDG(vexs, edges);
		Kruskal kruskal = new Kruskal();
		kruskal.kruskal(vertexList);
	}
}

传入的图: 

测试类输出结果如下: 

 

形象化,如下便是形成的最小生成树: 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值