Expm 3_2 寻找最邻近的点对
【问题描述】
设p1=(x1,y1), p2=(x2,y2), … , pn=(xn,yn) 是平面上n个点构成的集合S,设计和实现找出集合S中距离最近点对的算法。


每一个格子最多只能存在一个点,三行最多存在12个顶点,因此对于上图中的第(i=27)个顶点来说,最多只需要比较第27个顶点与之后的11个顶点,对于i之后或之前的11个顶点之外的顶点j,即|i-j|>=12,i与j之间的距离一定大于d,因为i和j已经相隔了至少两行。两个顶点若相隔大于等于两行或两列,则他们之间的距离一定大于等于d

package org.xiu68.exp.exp3; import java.util.ArrayList;
import java.util.List;
import java.util.Random; public class Exp3_2 { //设p1=(x1,y1), p2=(x2,y2), … , pn=(xn,yn)
//是平面上n个点构成的集合S,设计和实现找出集合S中距离最近点对的算法。
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<20;i++){
System.out.println("***************************");
List<Point> pointList=new ArrayList<>();
for(int j=0;j<50;j++){
Point p=new Point(new Random().nextInt(100),new Random().nextInt(100));
pointList.add(p);
}
System.out.println(bruteforce(pointList)); //蛮力法
System.out.println(closestPair(pointList)); //分治法 System.out.println("****************************");
}
} //寻找最近点对
public static double closestPair(List<Point> pointList){
//对pointList中的点按横坐标和纵坐标进行升序排序 List<Point> sortedListX=new ArrayList<>();
List<Point> sortedListY=new ArrayList<>(); //按横坐标对数组进行升序排序
pointList.sort((Point a,Point b)->{
if(a.getX()<b.getX())
return -1;
else
return 1;
});
sortedListX.addAll(pointList); //按纵坐标对数组进行升序排序
pointList.sort((Point a,Point b)->{
if(a.getY()<b.getY())
return -1;
else
return 1;
});
sortedListY.addAll(pointList); /* for(int i=0;i<pointList.size();i++)
System.out.println(sortedListX.get(i));
System.out.println("*********************");
for(int i=0;i<pointList.size();i++)
System.out.println(sortedListY.get(i)); System.out.println("*********************");
System.out.println(divide(sortedListX,sortedListY));*/ return divide(sortedListX,sortedListY); } /*
* 原问题的分解
* sortedListX:横坐标升序排序的数组
* sortedListY:纵坐标升序排序的数组
*/
public static double divide(List<Point> sortedListX,List<Point> sortedListY){
if(sortedListX.size()==1) //如果只有一个元素
return Double.MAX_VALUE;
else if(sortedListX.size()==2) //如果只有两个元素
return dist(sortedListX.get(0),sortedListX.get(1)); else{ //大于2个元素
int mid=sortedListX.size()/2; //在第mid个点处把点分成左右相等的两部分
double L=sortedListX.get(mid).getX(); //把点分成左右相等的两部分的直线的横坐标,设这条直线为L //L左边的点的横坐标升序排序的数组
List<Point> sortedListXL=sortedListX.subList(0, mid); //L右边的点的横坐标升序排序的数组
List<Point> sortedListXR=sortedListX.subList(mid, sortedListX.size()); List<Point> sortedListYL=new ArrayList<>(); //L左边的点的纵坐标升序排序的数组
List<Point> sortedListYR=new ArrayList<>(); //L右边的点的纵坐标升序排序的数组 //求sortedListYL与sortedListYR
for(int i=0;i<sortedListY.size();i++){
Point p=sortedListY.get(i);
if(sortedListY.get(i).getX()<L){
sortedListYL.add(p);
}else{
sortedListYR.add(p);
}
} double dL=divide(sortedListXL,sortedListYL); //L左边两个点之间的最短距离
double dR=divide(sortedListXR,sortedListYR); //L右边两个点之间的最短距离 //比较L左边最短距离、L右边最短距离以及跨越L的顶点对之间的最短距离
return conquer(sortedListY,L,Math.min(dL, dR));
}//else
} //子问题解的合并
public static double conquer(List<Point> sortedListY,double L,double d){
//求在L-d以及L+d之间的顶点(2d-strip)
List<Point> inside2DList=new ArrayList<>();
for(int i=0;i<sortedListY.size();i++){
Point p=sortedListY.get(i);
if(p.getX()>L-d || p.getX()<L+d){
inside2DList.add(p);
}
} //求2d-strip之间顶点对的最短距离、与L左边和右边的最短距离比较,最小者为最终结果
double minDistance=d;
for(int i=0;i<inside2DList.size()-1;i++){
//i只需与i之后的11个顶点比较,i与大于11个顶点之后的顶点的距离一定大于等于d
for(int j=i+1;j<=i+11 && j<inside2DList.size();j++){
double temp=dist(inside2DList.get(i),inside2DList.get(j));
if(temp<minDistance)
minDistance=temp;
}
}
return minDistance;
} //计算两点之间的距离
public static double dist(Point a,Point b){
return Math.sqrt(Math.pow(a.getX()-b.getX(), 2)+Math.pow(a.getY()-b.getY(), 2));
} //蛮力法
public static double bruteforce(List<Point> pointList){
double minDistance=Double.MAX_VALUE;
//依次比较每个顶点对
for(int i=0;i<pointList.size();i++){
for(int j=i+1;j<pointList.size();j++){
double temp=dist(pointList.get(i),pointList.get(j));
if(temp<minDistance)
minDistance=temp;
}
}
return minDistance;
}
} class Point{
private double x; //横坐标
private double y; //纵坐标 public Point(int x,int y){
this.x=x;
this.y=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 toString(){
return x+","+y;
}
}
Expm 3_2 寻找最邻近的点对的更多相关文章
- 机器学习 第4篇:sklearn 最邻近算法概述
sklearn.neighbors 提供了针对无监督和受监督的基于邻居的学习方法的功能.监督的基于最邻近的机器学习算法是值:对带标签的数据的分类和对连续数据的预测(回归). 无监督的最近算法是许多其他 ...
- 机器学习 第5篇:knn回归
基于最邻近算法的分类,本质上是对离散的数据标签进行预测,实际上,最邻近算法也可以用于对连续的数据标签进行预测,这种方法叫做基于最邻近数据的回归,预测的值(即数据的标签)是连续值,通过计算数据点最临近数 ...
- [Elasticsearch] 邻近匹配 (三) - 性能,关联单词查询以及Shingles
提高性能 短语和邻近度查询比简单的match查询在性能上更昂贵.match查询仅仅是查看词条是否存在于倒排索引(Inverted Index)中,而match_phrase查询则须要计算和比較多个可能 ...
- [Elasticsearch] 邻近匹配 (一) - 短语匹配以及slop參数
本文翻译自Elasticsearch官方指南的Proximity Matching一章. 邻近匹配(Proximity Matching) 使用了TF/IDF的标准全文搜索将文档,或者至少文档中的每一 ...
- [LeetCode] Find the Celebrity 寻找名人
Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist o ...
- [LeetCode] Find Minimum in Rotated Sorted Array II 寻找旋转有序数组的最小值之二
Follow up for "Find Minimum in Rotated Sorted Array":What if duplicates are allowed? Would ...
- [LeetCode] Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- C语言 · 寻找数组中的最大值
问题描述 对于给定整数数组a[],寻找其中最大值,并返回下标. 输入格式 整数数组a[],数组元素个数小于1等于100.输出数据分作两行:第一行只有一个数,表示数组元素个数:第二行为数组的各个元素. ...
- 【跟着子迟品 underscore】如何优雅地写一个『在数组中寻找指定元素』的方法
Why underscore (觉得这部分眼熟的可以直接跳到下一段了...) 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中. ...
随机推荐
- A1073. Scientific Notation
Scientific notation is the way that scientists easily handle very large numbers or very small number ...
- random模块(十九)
1 ).random() 返回0<=n<1之间的随机实数n: 2 ).choice(seq) 从序列seq中返回随机的元素: 3 ).getrandbits(n) 以长整型形式返回n个随机 ...
- c输出格式
#include <stdio.h> #include <stdlib.h> #include <math.h> int main() { //取整 printf( ...
- 窗体监听事件WindowListener
EXIT_ON_CLOSE:结束窗口所在的应用程序.在窗口被关闭的时候会退出JVM. DISPOSE_ON_CLOSE:隐藏当前窗口,并释放此窗体占有的资源.如果程序没有其他线程在运行,当所有窗口都被 ...
- 化工pdf下载
Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...
- Kafka 0.10问题点滴
15.如何消费内部topic: __consumer_offsets 主要是要让它来格式化:GroupMetadataManager.OffsetsMessageFormatter 最后用看了它的源码 ...
- 内联函数 —— C 中关键字 inline 用法解析
一.什么是内联函数 在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗. 为了解决这个问题,特别的引入了inline修饰符,表示为内联函数. 栈空间就是指放 ...
- C#星夜拾遗之delegate示例
概念 delegate即委托.如果你使用过C++或者js中的回调函数,你会更容易明白一些.在异步操作中常常使用回调函数,例如在Ajax中,当HttpRequest执行异步请求时,就需要有一个状态改变时 ...
- golang数组声明
格式 初始化数组 {}中的元素数不能大于[]中的数字,并且长度在初始化后不能改变,定义数组时需指定长度 ... var arrName [num]type = [num]type{value, val ...
- python学习笔记8--面向对象编程
一.面向对象编程 面向对象--Object Oriented Programming,简称oop,是一种程序设计思想.在说面向对象之前,先说一下什么是编程范式,编程范式你按照什么方式来去编程,去实现一 ...