聚类算法之MST算法
在介绍最小生成树算法(MST)之前,简单说一下平均链接算法(average-link)的实现过程,平均链接聚类算法和单链接类似,多了计算聚类之间距离矩阵的步骤
实现步骤如下:
1,将元素各成一组,把这些组放入容器H
2,循环元素距离数组,根据两层下标得到将要比较的两个元素A,B
3,在H中分别查找含有A,B的组AH,BH。假如AH不等于BH(也就是A,B不同组), AH和BH的距离累加A,B的距离。
4,得到组间距离数组后,循环比较组间距离与阀值,小于阀值,则此两组合并成一组,合并之前把H中的两个作为比较的原始组删除。
MST算法比较有意思点,不仅用于聚类,还可以解决最短铺路成本这类问题。
我们假设一个场景:现在想在多个城市之间铺网络,怎样才是最短距离?每个城市当作一个数据点,每个点间的距离称为一个边,最短距离实际上就是求得每个点都能连成边,但是又不会回路的情况。
实现过程如下:
1,首先建立城市类和边类,如下
01
/**
02
* 城市
03
*
04
* <a href="http://my.oschina.net/arthor" class="referer" target="_blank">@author</a> duyf
05
*
06
*/
07
class City {
08
09
private String name;
10
// 经度
11
private double x;
12
13
// 纬度
14
private double y;
15
16
public double getX() {
17
return x;
18
}
19
20
public void setX(double x) {
21
this.x = x;
22
}
23
24
public double getY() {
25
return y;
26
}
27
28
public void setY(double y) {
29
this.y = y;
30
}
31
32
public String getName() {
33
return name;
34
}
35
36
public void setName(String name) {
37
this.name = name;
38
}
39
40
public boolean equals(Object obj) {
41
if (obj == null) {
42
return false;
43
}
44
if (this == obj) {
45
return true;
46
}
47
City other = (City) obj;
48
if (this.getX() == other.getX() && this.getY() == other.getY()) {
49
return true;
50
}
51
return false;
52
}
53
}
54
55
/**
56
* 边距 包含两端数据点(城市)的索引
57
* <a href="http://my.oschina.net/arthor" class="referer" target="_blank">@author</a> duyf
58
*
59
*/
60
class Edge {
61
62
private int i;
63
private int j;
64
private double w;
65
66
Edge(int i, int j, double w) {
67
this.i = i;
68
this.j = j;
69
this.w = w;
70
}
71
72
public int getI() {
73
return i;
74
}
75
76
public int getJ() {
77
return j;
78
}
79
80
public double getW() {
81
return w;
82
}
83
84
}
2,MST核心类,Edge类表示一个边的两点和距离,
找最短距离的边的过程是:不断的纳入最短边,并且再根据这些已知的最短边的两端寻找最短边(md 这句话我也感觉绕口 但应该是最通俗的了)
01
public class MST {
02
03
private List<City> data;
04
05
private double[][] ds;
06
07
public MST(List<City> data){
08
this.data=data;
09
}
10
11
public List<Edge> compute(){
12
// 距离矩阵
13
ds = new double[data.size()][data.size()];
14
15
for (int i = 0; i < data.size(); i++) {
16
City city1 = data.get(i);
17
for (int j = i + 1; j < data.size(); j++) {
18
City city2 = data.get(j);
19
ds[i][j] = getDistance(city1, city2);
20
// 矩阵 对称性
21
ds[j][i] = ds[i][j];
22
}
23
ds[i][i] = 0.0;
24
}
25
26
boolean[] isMst=new boolean[data.size()];
27
isMst[0]=true;
28
Edge edge=null;
29
List<Edge> edges=new ArrayList<Edge>();
30
while((edge=findMinEdge(isMst))!=null){
31
edges.add(edge);
32
33
//标记为已知MST数据点
34
isMst[edge.getJ()]=true;
35
}
36
return edges;
37
38
}
39
40
//找出 和 已知的MST数据点 最小距离的点
41
private Edge findMinEdge(boolean[] isMst){
42
//初始化无限大
43
double minds = Double.POSITIVE_INFINITY;
44
int minI=-1;
45
int minJ=-1;
46
Edge edge=null;
47
for(int i=0;i<ds.length;i++){
48
if(isMst[i]==true){
49
for(int j=0;j<ds.length;j++){
50
if(isMst[j]==false){
51
if(minds>ds[i][j]){
52
minds=ds[i][j];
53
minI=i;
54
minJ=j;
55
}
56
}
57
}
58
}
59
}
60
if(minI>-1){
61
edge=new Edge(minI,minJ,minds);
62
}
63
return edge;
64
}
65
66
// 计算空间距离
67
private double getDistance(City city1, City city2) {
68
double distance=Math.pow(city1.getX()-city2.getX(),2)+Math.pow(city1.getY()-city2.getY(),2);
69
return Math.sqrt(distance);
70
71
}
72
73
74
}
第一步肯定是算出临近距离矩阵
3,测试一下
01
public static void main(String[] args) {
02
List<City> citys = new ArrayList<City>();
03
04
City city0 = new City();
05
city0.setName("北 京");
06
city0.setX(116.28);
07
city0.setY(39.54);
08
citys.add(city0);
09
10
City city1 = new City();
11
city1.setName("上 海");
12
city1.setX(121.29);
13
city1.setY(31.14);
14
citys.add(city1);
15
16
City city2 = new City();
17
city2.setName("天 津");
18
city2.setX(117.11);
19
city2.setY(39.09);
20
citys.add(city2);
21
22
City city3 = new City();
23
city3.setName("重 庆");
24
city3.setX(106.32);
25
city3.setY(29.32);
26
citys.add(city3);
27
28
City city4 = new City();
29
city4.setName("哈尔滨");
30
city4.setX(126.41);
31
city4.setY(45.45);
32
citys.add(city4);
33
34
City city5 = new City();
35
city5.setName("长 春");
36
city5.setX(125.19);
37
city5.setY(43.52);
38
citys.add(city5);
39
40
City city6 = new City();
41
city6.setName("南 京");
42
city6.setX(118.50);
43
city6.setY(32.02);
44
citys.add(city6);
45
46
City city7 = new City();
47
city7.setName("武 汉");
48
city7.setX(114.21);
49
city7.setY(30.37);
50
citys.add(city7);
51
52
City city8 = new City();
53
city8.setName("台 北");
54
city8.setX(121.31);
55
city8.setY(25.03);
56
citys.add(city8);
57
58
City city9 = new City();
59
city9.setName("香 港");
60
city9.setX(114.10);
61
city9.setY(22.18);
62
citys.add(city9);
63
64
MST mst=new MST(citys);
65
List<Edge> edges=mst.compute();
66
67
System.out.println("------------------线路最佳方案如下------------------");
68
for(Edge edge:edges){
69
City from=citys.get(edge.getI());
70
City to=citys.get(edge.getJ());
71
double length=edge.getW();
72
System.out.println(edge.getI()+"========>"+edge.getJ());
73
System.out.println(from.getName()+"到"+to.getName()+",全长"+length);
74
}
75
76
}