首先定义一个Point类,代表样本点
<!--[endif]--> package com.sunzhenxing; public class Point { private int x; private int y; private boolean isKey; private boolean isClassed; public boolean isKey() { return isKey; } public void setKey(boolean isKey) { this.isKey = isKey; this.isClassed=true; } public boolean isClassed() { return isClassed; } public void setClassed(boolean isClassed) { this.isClassed = isClassed; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public Point(){ x=0; y=0; } public Point(int x,int y){ this.x=x; this.y=y; } public Point(String str){ String[] p=str.split(","); this.x=Integer.parseInt(p[0]); this.y=Integer.parseInt(p[1]); } public String print(){ return "<"+this.x+","+this.y+">"; } }
然后定义一个工具类,为算法的实现服务:
package com.sunzhenxing; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.*; public class Utility { /** * 测试两个点之间的距离 * @param p 点 * @param q 点 * @return 返回两个点之间的距离 */ public static double getDistance(Point p,Point q){ int dx=p.getX()-q.getX(); int dy=p.getY()-q.getY(); double distance=Math.sqrt(dx*dx+dy*dy); return distance; }
/** * 检查给定点是不是核心点 * @param lst 存放点的链表 * @param p 待测试的点 * @param e e半径 * @param minp 密度阈值 * @return 暂时存放访问过的点 */ public static List<Point> isKeyPoint(List<Point> lst,Point p,int e,int minp){ int count=0; List<Point> tmpLst=new ArrayList<Point>(); for(Iterator<Point> it=lst.iterator();it.hasNext();){ Point q=it.next(); if(getDistance(p,q)<=e){ ++count; if(!tmpLst.contains(q)){ tmpLst.add(q); } } } if(count>=minp){ p.setKey(true); return tmpLst; } return null; } public static void setListClassed(List<Point> lst){ for(Iterator<Point> it=lst.iterator();it.hasNext();){ Point p=it.next(); if(!p.isClassed()){ p.setClassed(true); } } } /** * 如果b中含有a中包含的元素,则把两个集合合并 * @param a * @param b * @return a */ public static boolean mergeList(List<Point> a,List<Point> b){ boolean merge=false; for(int index=0;index<b.size();++index){ if(a.contains(b.get(index))){ merge=true; break; } } if(merge){ for(int index=0;index<b.size();++index){ if(!a.contains(b.get(index))){ a.add(b.get(index)); } } } return merge; } /** * 返回文本中的点集合 * @return 返回文本中点的集合 * @throws IOException */ public static List<Point> getPointsList() throws IOException{ List<Point> lst=new ArrayList<Point>(); String txtPath="src\\com\\sunzhenxing\\points.txt"; BufferedReader br=new BufferedReader(new FileReader(txtPath)); String str=""; while((str=br.readLine())!=null && str!=""){ lst.add(new Point(str)); } br.close(); return lst; } }
最后在主程序中实现算法,如下所示:
package com.sunzhenxing; import java.io.*; import java.util.*; public class Dbscan { private static List<Point> pointsList=new ArrayList<Point>();//存储所有点的集合 private static List<List<Point>> resultList=new ArrayList<List<Point>>();//存储DBSCAN算法返回的结果集 private static int e=2;//e半径 private static int minp=3;//密度阈值 /** * 提取文本中的的所有点并存储在pointsList中 * @throws IOException */ private static void display(){ int index=1; for(Iterator<List<Point>> it=resultList.iterator();it.hasNext();){ List<Point> lst=it.next(); if(lst.isEmpty()){ continue; } System.out.println("-----第"+index+"个聚类-----"); for(Iterator<Point> it1=lst.iterator();it1.hasNext();){ Point p=it1.next(); System.out.println(p.print()); } index++; } } //找出所有可以直达的聚类 private static void applyDbscan(){ try { pointsList=Utility.getPointsList(); for(Iterator<Point> it=pointsList.iterator();it.hasNext();){ Point p=it.next(); if(!p.isClassed()){ List<Point> tmpLst=new ArrayList<Point>(); if((tmpLst=Utility.isKeyPoint(pointsList, p, e, minp)) != null){ //为所有聚类完毕的点做标示 Utility.setListClassed(tmpLst); resultList.add(tmpLst); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //对所有可以直达的聚类进行合并,即找出间接可达的点并进行合并 private static List<List<Point>> getResult(){ applyDbscan();//找到所有直达的聚类 int length=resultList.size(); for(int i=0;i<length;++i){ for(int j=i+1;j<length;++j){ if(Utility.mergeList(resultList.get(i), resultList.get(j))){ resultList.get(j).clear(); } } } return resultList; } /** * 程序主函数 * @param args */ public static void main(String[] args) { getResult(); display(); //System.out.println(Utility.getDistance(new Point(0,0), new Point(0,2))); } }
下边是一个小测试, 即使用src\\com\\sunzhenxing\\points.txt文件的内容进行测试,points.txt的文件内容是:0,0
0,1
0,2
0,3
0,4
0,5
12,1
12,2
12,3
12,4
12,5
12,6
0,6
0,7
12,7
0,8
0,9
1,1
最后算法的结果是:
-----第1个聚类-----
<0,0>
<0,1>
<0,2>
<1,1>
<0,3>
<0,4>
<0,5>
<0,6>
<0,7>
<0,8>
<0,9>
-----第2个聚类-----
<12,1>
<12,2>
<12,3>
<12,4>
<12,5>
<12,6>
<12,7>
大家画一下坐标就可以理解实验的结论了。