/**
* 功能:在二维平面上,有一些点,请找出经过点数最多的那条线。
/**
* 思路:在任意两点之间画一条无线长的直线,用散列表追踪那条直线出现的次数最多。时间复杂度O(N*N)
* 注意:
* 1)用斜率和y轴截距来确定是否是同一条直线。
* 2)浮点数不一定能用二进制数准确表示,因此检查两个浮点数的差值是否在某个极小值(epsilon)内。
* 3)对于散列表而言,斜率相等,未必散列值相同。因此,将斜率减去一个极小值,并以得到的结果flooredSlope作为散列键。
* 4)取得所有可能相等的直线,搜索三个位置:flooredSlope,flooredSlope-epsilon,flooredSlope+epsilon。
* @param points
* @return
*/
public static MyLine1 findBestLine(GraphPoint[] points){
MyLine1 bestLine=null;
int bestCount=0;
HashMap<Double,ArrayList<MyLine1>> lineBySlope=new HashMap<Double, ArrayList<MyLine1>>();
for(int i=0;i<points.length-1;i++){
for(int j=i+1;j<points.length;j++){
MyLine1 line=new MyLine1(points[i],points[j]);
insertLine(lineBySlope,line);
int count=countEquivalentLines(lineBySlope,line);
if(count>bestCount){
bestCount=count;
bestLine=line;
}
}
}
return bestLine;
}
private static int countEquivalentLines(HashMap<Double, ArrayList<MyLine1>> lineBySlope, MyLine1 line) {
double key=line.floorToNearestEpsilon(line.slope);
double eps=line.epsilon;
int count=countEquivalentLines(lineBySlope.get(key), line)+countEquivalentLines(lineBySlope.get(key-eps), line)+
countEquivalentLines(lineBySlope.get(key+eps), line);
return count;
}
public static int countEquivalentLines(ArrayList<MyLine1> lines,MyLine1 line){
if(lines==null)
return 0;
int count=0;
for(MyLine1 paralleLine:lines){
if(paralleLine==line)
count++;
}
return count;
}
private static void insertLine(HashMap<Double, ArrayList<MyLine1>> lineBySlope, MyLine1 line) {
ArrayList<MyLine1> lines=null;
double key=line.floorToNearestEpsilon(line.slope);
if(!lineBySlope.containsKey(key)){
lines=new ArrayList<MyLine1>();
lineBySlope.put(key, lines);
}else{
lines=lineBySlope.get(key);
}
lines.add(line);//注意此处添加的用法
}
class MyLine1{
public static double epsilon=0.0001;
public double slope,intercept;
public boolean infiniteSlope=false;
public MyLine1(GraphPoint p,GraphPoint q){
if(Math.abs(p.x-q.x)>epsilon){//两个点的x坐标不同
slope=(p.y-q.y)/(p.x-q.x);//斜率
intercept=p.y-slope*p.x;//y轴截距
}else{
infiniteSlope=true;
intercept=p.x;//x轴截距
}
}
public double floorToNearestEpsilon(double d){
int r=(int) (d/epsilon);//使原d保留小数位后的4位(epsilon=0.0001)
return ((double)r)*epsilon;
}
public boolean isEquivalent(MyLine1 line){
if((slope==line.slope)&&(intercept==line.intercept)&&(infiniteSlope==line.infiniteSlope))
return true;
return false;
}
public boolean isEquivalent(double a,double b){
return Math.abs(a-b)<epsilon;
}
}
class GraphPoint{
int x;
int y;
public GraphPoint(int x,int y){
this.x=x;
this.y=y;
}
}
*/