聚类算法之MST算法 java实现版本

在介绍最小生成树算法(MST)之前,简单说一下平均链接算法(average-link)的实现过程,平均链接聚类算法和单链接类似,多了计算聚类之间距离矩阵的步骤
实现步骤如下:
[list]
[*]1,将元素各成一组,把这些组放入容器H
[*]2,循环元素距离数组,根据两层下标得到将要比较的两个元素A,B
[*]3,在H中分别查找含有A,B的组AH,BH。假如AH不等于BH(也就是A,B不同组), AH和BH的距离累加A,B的距离。
[*]4,得到组间距离数组后,循环比较组间距离与阀值,小于阀值,则此两组合并成一组,合并之前把H中的两个作为比较的原始组删除。
[/list]

MST算法比较有意思点,不仅用于聚类,还可以解决最短铺路成本这类问题。
我们假设一个场景:现在想在多个城市之间铺网络,怎样才是最短距离?每个城市当作一个数据点,每个点间的距离称为一个边,最短距离实际上就是求得每个点都能连成边,但是又不会回路的情况。
实现过程如下:
1,首先建立城市类和边类,如下

/**
* 城市
*
* @author duyf
*
*/
class City {

private String name;
// 经度
private double x;

// 纬度
private double y;

public double getX() {
return x;
}

public void setX(double x) {
this.x = x;
}

public double getY() {
return y;
}

public void setY(double y) {
this.y = y;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
City other = (City) obj;
if (this.getX() == other.getX() && this.getY() == other.getY()) {
return true;
}
return false;
}
}

/**
* 边距 包含两端数据点(城市)的索引
* @author duyf
*
*/
class Edge {

private int i;
private int j;
private double w;

Edge(int i, int j, double w) {
this.i = i;
this.j = j;
this.w = w;
}

public int getI() {
return i;
}

public int getJ() {
return j;
}

public double getW() {
return w;
}

}


2,MST核心类,Edge类表示一个边的两点和距离,
找最短距离的边的过程是:不断的纳入最短边,并且再根据这些已知的最短边的两端寻找最短边(md 这句话我也感觉绕口 但应该是最通俗的了)



public class MST {

private List<City> data;

private double[][] ds;

public MST(List<City> data){
this.data=data;
}

public List<Edge> compute(){
// 距离矩阵
ds = new double[data.size()][data.size()];

for (int i = 0; i < data.size(); i++) {
City city1 = data.get(i);
for (int j = i + 1; j < data.size(); j++) {
City city2 = data.get(j);
ds[i][j] = getDistance(city1, city2);
// 矩阵 对称性
ds[j][i] = ds[i][j];
}
ds[i][i] = 0.0;
}

boolean[] isMst=new boolean[data.size()];
isMst[0]=true;
Edge edge=null;
List<Edge> edges=new ArrayList<Edge>();
while((edge=findMinEdge(isMst))!=null){
edges.add(edge);

//标记为已知MST数据点
isMst[edge.getJ()]=true;
}
return edges;

}

//找出 和 已知的MST数据点 最小距离的点
private Edge findMinEdge(boolean[] isMst){
//初始化无限大
double minds = Double.POSITIVE_INFINITY;
int minI=-1;
int minJ=-1;
Edge edge=null;
for(int i=0;i<ds.length;i++){
if(isMst[i]==true){
for(int j=0;j<ds.length;j++){
if(isMst[j]==false){
if(minds>ds[i][j]){
minds=ds[i][j];
minI=i;
minJ=j;
}
}
}
}
}
if(minI>-1){
edge=new Edge(minI,minJ,minds);
}
return edge;
}

// 计算空间距离
private double getDistance(City city1, City city2) {
double distance=Math.pow(city1.getX()-city2.getX(),2)+Math.pow(city1.getY()-city2.getY(),2);
return Math.sqrt(distance);

}


}


第一步肯定是算出临近距离矩阵

3,测试一下

public static void main(String[] args) {
List<City> citys = new ArrayList<City>();

City city0 = new City();
city0.setName("北 京");
city0.setX(116.28);
city0.setY(39.54);
citys.add(city0);

City city1 = new City();
city1.setName("上 海");
city1.setX(121.29);
city1.setY(31.14);
citys.add(city1);

City city2 = new City();
city2.setName("天 津");
city2.setX(117.11);
city2.setY(39.09);
citys.add(city2);

City city3 = new City();
city3.setName("重 庆");
city3.setX(106.32);
city3.setY(29.32);
citys.add(city3);

City city4 = new City();
city4.setName("哈尔滨");
city4.setX(126.41);
city4.setY(45.45);
citys.add(city4);

City city5 = new City();
city5.setName("长 春");
city5.setX(125.19);
city5.setY(43.52);
citys.add(city5);

City city6 = new City();
city6.setName("南 京");
city6.setX(118.50);
city6.setY(32.02);
citys.add(city6);

City city7 = new City();
city7.setName("武 汉");
city7.setX(114.21);
city7.setY(30.37);
citys.add(city7);

City city8 = new City();
city8.setName("台 北");
city8.setX(121.31);
city8.setY(25.03);
citys.add(city8);

City city9 = new City();
city9.setName("香 港");
city9.setX(114.10);
city9.setY(22.18);
citys.add(city9);

MST mst=new MST(citys);
List<Edge> edges=mst.compute();

System.out.println("------------------线路最佳方案如下------------------");
for(Edge edge:edges){
City from=citys.get(edge.getI());
City to=citys.get(edge.getJ());
double length=edge.getW();
System.out.println(edge.getI()+"========>"+edge.getJ());
System.out.println(from.getName()+"到"+to.getName()+",全长"+length);
}

}


[img]http://dl.iteye.com/upload/picture/pic/115534/3b0e5176-38f2-3678-b1ca-13254830a242.jpg[/img]

By 阿飞哥 转载请说明
腾讯微博:[url]http://t.qq.com/duyunfeiRoom[/url]
新浪微博:[url]http://weibo.com/u/1766094735[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值