首页 > 编程语言 >Java实现:分治法求最近点对

Java实现:分治法求最近点对

时间:2023-04-13 17:31:57浏览次数:48  
标签:Java Point int 分治 getX getY new Math 法求

/*
 问题1:如何解决 cannot be cast to java.lang.Comparable问题?
 产生原因:TreeSet的特点是可排序、不重复,即TreeSet要求存放的对象必须是可排序的。如果对象之间不可排序,就会抛出这个异常。
 解决:实现Comparable接口 
 问题2:Java ArrayList toArray() 方法
 解决:https://www.runoob.com/java/java-arraylist-toarray.html
 问题3:TreeSet有重复元?
 解决:注意比较器comareTo的写法
 问题4:堆栈溢出java.lang.StackOverflowError(当点的数量很多,但集中在一块区域的时候)
 解决:因为解决了问题3这个问题也解决了
 */
import java.util.ArrayList;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

/*
 * 建立自己的类Point,建立在主函数外面
 */
class Point implements Comparable<Point>{
	private int x;
	private int y;
	public Point() {
		x=0;
		y=0;
	}
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	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;
	}
	//问题1的解决:
	public int compareTo(Point o) {
		//x是比较的主要条件,y是比较的次要条件
		return this.x-o.getX()== 0 ? this.y-o.getY():this.x-o.getX();
	}
}
public class 最近点对 {
	public static void main(String[] args) {
		Set<Point> testData=new TreeSet<Point>();
		Random random=new Random();
		int x=0;
		int y=0;
		for (int i = 0; i < 10000; i++) {
			//()里面是返回的随机数的界限,必须是正数
			//返回一个伪随机、均匀分布的int值,介于0(包括)和n(不包括)之间
			x=random.nextInt(10000);
			y=random.nextInt(10000);
			System.out.println("x:"+x+" y:"+y);
			testData.add(new Point(x,y));
		}
		Point[] S=new Point[testData.size()];
		S=(Point[])testData.toArray(S);
		for (int i = 0; i < S.length; i++) {
			System.out.println("("+S[i].getX()+","+S[i].getY()+")");
		}
		System.out.println(testData.size());
		//mergeSort(S,"x"); treeSet生成的结果本身就是有序的
		Point[] ans=new Point[2];
		ans=closestPoint(S);
		System.out.println("最近的两点分别为是("+ans[0].getX()+","+ans[0].getY()+")和("
							+ans[1].getX()+","+ans[1].getY()+"),最近距离为:"+
							Math.sqrt(Math.pow(ans[0].getX()-ans[1].getX(), 2)+
									  Math.pow(ans[0].getY()-ans[1].getY(), 2)));
    }

	private static Point[] closestPoint(Point[] S) {
		// TODO Auto-generated method stub
		Point[] res=new Point[2];
		/**
		 * 0.首先,解决该问题的边界,当数组长度在一定范围内时直接求出最近点,蛮力求解
		 */
		double dmin=Double.POSITIVE_INFINITY;//正无穷
		double tmpmin=0;
		if(S.length<=20) {
			for (int i = 0; i < S.length; i++) {
				for (int j = i+1; j < S.length; j++) {
					tmpmin=Math.sqrt(Math.pow(S[i].getX()-S[j].getX(), 2)+Math.pow(S[i].getY()-S[j].getY(), 2));
					if(tmpmin<dmin) {
						dmin=tmpmin;
						res[0]=S[i];
						res[1]=S[j];
					}
				}
			}
			return res;
		}
		
		
		/**
		 * 1.求所有点在X坐标中的中位数
		 */
//		int minX=(int)Double.POSITIVE_INFINITY;//保证假设的初始最小值
//		int maxX=(int)Double.NEGATIVE_INFINITY;//保证假设的初始最大值
//		for(int i=0;i<S.length;i++) {
//			if(S[i].getX()<minX)
//				minX=S[i].getX();
//			if(S[i].getX()>maxX)
//				maxX=S[i].getX();
//		}
		int midX=(S[0].getX()+S[S.length-1].getX())/2;
		
		/**
		 * 2.以midX为界将所有点分成两组分别存放在两个表中
		 */
		ArrayList T1=new ArrayList();
		ArrayList T2=new ArrayList();
		for (int i = 0; i < S.length; i++) {
			if(S[i].getX()<=midX)      //是否要=号?
				T1.add(S[i]);
			if(S[i].getX()>midX)
				T2.add(S[i]);
		}
		
		/**
		 * 3.将两张表转化为数组类型,并分别按X坐标升序排序
		 */
		Point[] S1=new Point[T1.size()];
		Point[] S2=new Point[T2.size()];
		
		T1.toArray(S1);
		T2.toArray(S2);
		
		//mergeSort(S1,"x");//按X坐标升序排列
		//mergeSort(S2,"x");//按X坐标升序排列
		
		/**
		 * 4.求S1中的最近距离的两个点
		 */
		Point[] res1=new Point[2];
		res1=closestPoint(S1);
		
		/**
		 * 5.求S2中的最近距离的两个点
		 */
		Point[] res2=new Point[2];
		res2=closestPoint(S2);
		
		/**
		 * 6.求两个最近距离的最小值
		 */
		double d1=Math.sqrt(Math.min(Math.pow(res1[0].getX()-res1[1].getX(), 2)+Math.pow(res1[0].getY()-res1[1].getY(), 2), 
									Math.pow(res2[0].getX()-res2[1].getX(), 2)+Math.pow(res2[0].getY()-res2[1].getY(), 2)));
		if(Math.pow(res1[0].getX()-res1[1].getX(), 2)+Math.pow(res1[0].getY()-res1[1].getY(), 2)<
		   Math.pow(res2[0].getX()-res2[1].getX(), 2)+Math.pow(res2[0].getY()-res2[1].getY(), 2))
			res=res1;
		else
			res=res2;
		
		/**
		 * 7.在S1、S2中收集距离中线小于d1的点,分别存放在两个表中
		 */
		ArrayList T3=new ArrayList();
		//ArrayList T4=new ArrayList();
		for (int i = 0; i < S1.length; i++) {
			if(midX-S1[i].getX()<d1)
				T3.add(S1[i]);
		}
		for (int i = 0; i < S2.length; i++) {
			if(S2[i].getX()-midX<d1)
				//T4.add(S2[i]);
				T3.add(S2[i]);
		}
		
		/**
		 * 8.分别将表T3、T4转化为数组类型的S3、S4,并将其分别按Y坐标升序排列
		 */
		Point[] S3=new Point[T3.size()];
		//Point[] S4=new Point[T4.size()];
		T3.toArray(S3);
		//T4.toArray(S4);
		
		mergeSort(S3,"y");
		//mergeSort(S4,"y");
		
		
		/**
		 * 求解S3、S4两者之间可能的更近(相比于d1)距离,以及构成该距离的点
		 */
		double tmp=Double.POSITIVE_INFINITY;
		for (int i = 0; i < S3.length; i++) {
			for (int j = i+1; j < S3.length; j++) {
				if(S3[j].getY()-S3[j].getY()>d1) 
					continue;
				else {
					tmp=Math.sqrt(Math.pow(S3[i].getX()-S3[j].getX(),2)+Math.pow(S3[i].getY()-S3[j].getY(),2));
					if(tmp<d1) {
						res[0]=S3[i];
						res[1]=S3[j];
						d1=tmp;
					}
				}
			}
		}
//		double d=Double.POSITIVE_INFINITY;
//		for (int i = 0; i < S3.length; i++) {
//			for (int j = 0; j < S4.length; j++) {
//				if(Math.abs(S3[i].getY()-S[4].getY())<d1) {
//					double tmp=Math.sqrt(Math.pow(S3[i].getX()-S4[j].getX(),2)+Math.pow(S3[i].getY()-S4[j].getY(),2));
//					if(tmp<d) {
//						d=tmp;
//						res[0]=S3[i];
//						res[1]=S4[j];
//					}
//				}
//			}
//		}
		return res;
	}

	private static void mergeSort(Point[] a, String s) {
		// TODO Auto-generated method stub
		Point[] tmpArray=new Point[a.length];
		mergeSort(a,tmpArray,0,a.length-1,s);
	}

	private static void mergeSort(Point[] a, Point[] tmpArray, int left, int right, String s) {
		// TODO Auto-generated method stub
		if(left<right) {
			int mid=left+((right-left)>>1);
			//分治
			mergeSort(a,tmpArray,left,mid,s);
			mergeSort(a,tmpArray,mid+1,right,s);
			//合并
			merge(a,tmpArray,left,mid,right,s);
		}
	}

	private static void merge(Point[] a, Point[] tmpArray, int left, int mid, int right, String s) {
		// TODO Auto-generated method stub
		System.arraycopy(a, left, tmpArray, left, right-left+1);
		int l=left,r=mid+1;
		int current=left;
		while(l<=mid&&r<=right) {
			if(s.equals("x")) {
				if(tmpArray[l].getX()<=tmpArray[r].getX()) {
					a[current++]=tmpArray[l++];
				}else {
					a[current++]=tmpArray[r++];
				}
			}else if(s.equals("y")) {
				if(tmpArray[l].getY()<=tmpArray[r].getY()) {
					a[current++]=tmpArray[l++];
				}else {
					a[current++]=tmpArray[r++];
				}
			}else {
				throw new RuntimeException();
			}
		}
		while(l<=mid) {
			a[current++]=tmpArray[l++];
		}
	}
}

注:本篇博客做了部分修改和优化

源码参考:(8条消息) 分治法-最近距离问题Java实现_过顶擒龙的博客-CSDN博客

标签:Java,Point,int,分治,getX,getY,new,Math,法求
From: https://blog.51cto.com/u_15470952/6188278

相关文章

  • Java集成工作流审批机制,多个项目实际运用优化版本(干货)
    前言activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,一套完整并且实际运用在多套项目中的案例,满足日常业务流程审批需求。一、项目形式springboot+vue+activiti集成了activiti在线编辑器,流行的前后端分离部署开发模式,快速开发平台,可插拔工作流服务。工作......
  • java.io.Serializable(序列化)接口
     一、概念Java对象序列化的意思就是将对象的状态转化成字节流,以后可以通过这些值再生成相同状态的对象。对象序列化是对象持久化的一种实现方法,它是将对象的属性和方法转化为一种序列化的形式用于存储和传输。反序列化就是根据这些保存的信息重建对象的过程。序......
  • Java常用实体类介绍:POJO、Domain、DO、DTO、VO
    POJOPOJO是PlainOldJavaObject的简称,它指的是一个没有限制或要求下的纯平对象。POJO用于表示没有任何框架或技术限制的纯数据对象。在Java开发中,POJO通常用于简化复杂对象和降低对象的耦合度,是面向对象编程中"高内聚、低耦合"设计思想的体现。示例代码:@Datapublic......
  • JavaScript黑科技:变量监听
    作者:JShaman团队,转载请保留功能目标实时监视一个变量的值,当值发生改变时,马上给出提示。实现方法一直观且朴素的方法,可以用setInterval,循环检测变量的值,示例代码:<html><body><script>//要监视的变量vartest_value=1;setInterval(function(){......
  • java故障处理(三)远程debug
    转载:https://blog.51cto.com/u_11554106/4930697一、remotedebug何为远程debug呢?通常我们在开发过程中,都会将代码部署到服务中,这个时候QA提出了一个bug,通过查看代码的逻辑发现问题十分的困难?一般情况下都是想着本地能不能复现一下,本地debug调试一下;或者通过arthas进行相关......
  • Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not fi
    用idea使用mybatis时<mappers><mapperresource="com/mybatis/mapper/UserMapper.xml"></mapper></mappers>遇到吐下错误时ErrorparsingSQLMapperConfiguration.Cause:java.io.IOException:Couldnotfindresourcecom/my......
  • java故障处理(二)可视化工具
    一、JConsole:Java监视与管理控制台命令行:jconsoleJConsole是一款基于JMX的可视化监视、管理工具。它的主要功能是通过JMX的MBean(ManagedBean)对系统进行信息收集和参数动态调整。JMX是一种开放性的技术,不仅可以用在虚拟机本身的管理上,还可以运行于虚拟机之上的软件中,......
  • Java里的数据类型都有哪些
    相关面试题我们从学习Java开始,很快就会遇到Java中的数据类型这个问题。关于数据类型,对于初学者来说,很容易记混,因为Java中的数据类型划分的有点多。所以在招聘初级程序员时,面试官就会经常在这一块出一些题目,对求职者进行基础语法方面的考核。常见的数据类型相关的面试题如下:请说一......
  • java故障处理(一)基础命令行工具
     一、基础命令行工具1.jps:虚拟机进程状况工具可以列出本机正在运行的虚拟机进程,并显示主类1.1.选项:选项作用-q省略主类,只显示id-l显示主类全名,或jar包路径-m显示传递给主类main方法的参数-v输出jvm启动时所有参数2.jstat:虚拟机统计信息监控用于监......
  • JAVA返回前端时候bean转json时首字母、第二个字母大写会自动变成小写的问题
      后台bean是privateStringuName;但是前端生成的json是uname会自动变成小写 如果我们只是个别的几个的话,只需要加个注解@JsonProperty("uName")privateStringuName; 这样就可以了......