您的位置:首页 > 产品设计 > UI/UE

利用优先队列PriorityQueue实现Prim算法

2017-12-10 20:45 609 查看

1.Prim算法介绍

1.Prim算法是贪婪技术的一种。

2.贪婪技术:

在每一步中,都‘贪婪’地选择最佳的操作,并希望通过一些列局部最优选择,能够产生一个整个问题(全局)的最优解。

3.Prim算法的用处:

通俗的讲就是求解最小生成树问题。

4.Prim算法思想(贪婪的体现):

Prim算法将顶点分为2个集合vt和v-vt,并总是找出边(a,b)使得a∈vt,b∈v-vt,且边的权重最小。

5.Prim算法的关键之处:

Prim算法的关键之处在于求出边(a,b)使得a∈vt,b∈v-vt,且边的权重最小。此处求权重最小的边可以用优先队列PriorityQueuen来求取。

2.代码实现

package algorithm.experiment6;

import java.util.Comparator;
import java.util.PriorityQueue;

public class Prim
{
//表示无穷大
final static Integer M = Integer.MAX_VALUE;
static int[][] G = {
{M,3,M,M,6,5},
{3,M,1,M,M,4},
{M,1,M,6,M,4},
{M,M,6,M,8,5},
{6,M,M,8,M,2},
{5,4,4,5,2,M}};
//全部顶点名称【对应数组的下标】
static char[] vName = {'a','b','c','d','e','f'};
//顶点是否被选【对应数组的下标】
static boolean[] vIsChoose = {true,false,false,false,false,false};

public static void main(String[] args)
{
prim(G);
}

public static void prim(int[][] G)
{

System.out.println("默认的点:a  集合vt:a");
while(true)
{
//判断是否生成了最小生成树
if(isOver()) break;

PriorityQueue<MyEdge> myPriorityQueue = myPriorityQueue(G,vIsChoose);

MyEdge edge = myPriorityQueue.poll();
changeG(edge);

//          System.out.print(edge+"    ");
System.out.print("选择的点:"+vName[edge.index2]+"  集合vt:");

for(int i=0;i<vIsChoose.length;i++)
if(vIsChoose[i])
System.out.print(vName[i]+" ");
System.out.println();
}
}

//判断是否找到了最小生成树(判断数组vIsChoose如果全为true则返回true)
public static boolean isOver()
{
for(Boolean b:vIsChoose){
if(!b) return false;
}
return true;
}

//改变图以及已经选择的标记数组
private static void changeG(MyEdge edge)
{
int x = edge.index1;
int y = edge.index2;

G[x][y] = M;
G[y][x] = M;
vIsChoose[x] = true;
vIsChoose[y] = true;
}

//构造一个myEdge的优先队列
public static PriorityQueue<MyEdge> myPriorityQueue(int[][] G,boolean[] vIsChoose)
{
PriorityQueue<MyEdge> myPriorityQueue = new PriorityQueue<MyEdge>(11,myEdgeComparator());

for(int i=0;i<vIsChoose.length;i++)
{
//如果顶点被选则找出相邻的顶点并组成边加入到优先队列中
if(vIsChoose[i])
{
//遍历相应的顶点
for(int j=0;j<G[i].length;j++)
{
//将相邻的顶点组成的边加入优先队列 且该边的连个顶点是包含于vt和v-vt的
if(G[i][j]!=M&&!vIsChoose[j])
{
MyEdge edge = new MyEdge(i, j, G[i][j]);
myPriorityQueue.offer(edge);
}
}
}
}
return myPriorityQueue;
}

//表示边 index1:表示顶点1的在字符数组中的下标
static class MyEdge
{
public int index1,index2;
public int weight;

public MyEdge(int v1,int v2,int weight){
this.index1 = v1;
this.index2 = v2;
this.weight = weight;
}

public String toString(){
return "("+vName[index1]+","+vName[index2]+","
b10f
+weight+")";
}
}

//myEdge比较器
public static Comparator<MyEdge> myEdgeComparator()
{
Comparator<MyEdge> comparator = new Comparator<MyEdge>(){
@Override
public int compare(MyEdge o1, MyEdge o2)
{
return o1.weight-o2.weight;
}
};
return comparator;
}

}


3.运行结果

默认的点:a  集合vt:a
选择的点:b  集合vt:a b
选择的点:c  集合vt:a b c
选择的点:f  集合vt:a b c f
选择的点:e  集合vt:a b c e f
选择的点:d  集合vt:a b c d e f


4.代码分析

首先是图的表示,我采用的是邻接矩阵的方式来表示图,用vName的字符数组表示顶点名称,用vIsChoose表示相应的坐标是否被选择。

内部类MyEdge用于表示边,在myPriorityQueue(int[][] G,boolean[] vIsChoose)方法中首先构建了一个优先队列,该队列通过自己实现的比较器(方法myEdgeComparator()实现)每次出队都可以得到一个满足条件的边(a,b)(权重最小,a∈vt,b∈v-vt)。依次循环直到找到最小生成树从而退出循环。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: