【算法设计与分析基础】15、最近对问题

1、由于Java中没有存放单个键值对的类型使用起来不是很方便

package cn.xf.util;

/**
 *
 * 功能:相当于一个key value
 * @author xiaofeng
 * @date 2017年6月18日
 * @fileName GenericPair.java
 *
 */
public class GenericPair<E extends Object, F extends Object> {

	private E first;
	private F second;

	public GenericPair() {
	}

	public GenericPair(E first, F second) {
		this.first = first;
		this.second = second;
	}

	@Override
	public String toString() {
		String result = "["+ this.first.toString() + ", " + this.second.toString() +"]";
		return result;
	}

	public E getFirst() {
		return first;
	}

	public void setFirst(E first) {
		this.first = first;
	}

	public F getSecond() {
		return second;
	}

	public void setSecond(F second) {
		this.second = second;
	}
}

  

求最近键值对问题

package cn.xf.algorithm.ch05;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

import cn.xf.util.GenericPair;

/**
 *
 * 功能:最近对问题
 * @author xiaofeng
 * @date 2017年6月18日
 * @fileName MinPath.java
 *
 */
public class MinPath {

	/**
	 *
	 * @param points 数组points中存储了平面上的n >= 2个点,并且按照这些点的x轴坐标升序排序  seqXList  seqYList
	 * @param qpoints 数据qpoint存储了与points相同的点,只是它是按照这点的Y轴坐标升序排序
	 * 输出:最近点对之间的欧几里得距离
	 */
	public double efficientClosestPair(List<GenericPair<Double, Double>> points, List<GenericPair<Double, Double>> qpoints) {
	    if(points.size() <= 3) {
	        //如果少于3个直接蛮力比较,求几点的最近距离
	    	double countMin = Double.MAX_VALUE;
	    	for(int i = 0; i < points.size(); ++i) {
	    		for(int j = 0; j < points.size(); ++j) {
	    			if(i == j) {
	    				continue;
	    			}
	    			double temp = dist(points.get(i), points.get(j));
	    			if(temp < countMin) {
	    				countMin = temp;
	    			}
	    		}
	    	}
	        return countMin;
	    } else {
	    	int midIndex = points.size() / 2;
	    	//吧points前面一半提取出来pointsl
	    	List<GenericPair<Double, Double>> pointsl = new ArrayList<GenericPair<Double,Double>>();
	    	for(int i = 0; i < midIndex; ++i) {
	    		pointsl.add(points.get(i));
	    	}
	    	//把qpoints前面一半提取出来qpointsl
//	    	List<GenericPair<Double, Double>> qpointsl = new ArrayList<GenericPair<Double,Double>>();
//	    	for(int i = 0; i < midIndex; ++i) {
//	    		qpointsl.add(qpoints.get(i));
//	    	}
	    	//pointsl 的Y排序版本作为新的qpointsl
	    	List<GenericPair<Double, Double>> qpointsl = new ArrayList<GenericPair<Double,Double>>();
	    	for(int i = 0; i < midIndex; ++i) {
	    		qpointsl.add(points.get(i));
	    	}

	    	seqYList(qpointsl, 0, qpointsl.size() - 1);

	    	//把points后面一半提取出来pointsr
	    	List<GenericPair<Double, Double>> pointsr = new ArrayList<GenericPair<Double,Double>>();
	    	for(int i = midIndex; i < points.size(); ++i) {
	    		pointsr.add(points.get(i));
	    	}
	    	//吧qpoints后面一半提取出来qpointsr
//	    	List<GenericPair<Double, Double>> qpointsr = new ArrayList<GenericPair<Double,Double>>();
//	    	for(int i = midIndex; i < qpoints.size(); ++i) {
//	    		qpointsr.add(qpoints.get(i));
//	    	}

	    	List<GenericPair<Double, Double>> qpointsr = new ArrayList<GenericPair<Double,Double>>();
	    	for(int i = midIndex; i < points.size(); ++i) {
	    		qpointsr.add(points.get(i));
	    	}

	    	seqYList(qpointsr, 0, qpointsr.size() - 1);

	    	//用新的集合点进入递归
	    	double dl = efficientClosestPair(pointsl, qpointsl);
	    	double dr = efficientClosestPair(pointsr, qpointsr);

	    	//两个距离取小的
	    	double dmin = minValue(dl, dr);
	    	double dminDist = Math.pow(dmin, 2);
	    	//取X值得中间分段
	    	double midPointX = points.get(midIndex).getFirst();
	    	//吧所有这些点中X-midPointX的距离比dmin小的提取出来
	    	List<GenericPair<Double, Double>> pointsDmin = new ArrayList<GenericPair<Double,Double>>();
	    	for(int i = 0; i < qpoints.size(); ++i) {
	    		//绝对值比最小的距离还小
	    		if(Math.abs(qpoints.get(i).getFirst() - midPointX) < dmin) {
	    			//比两边最小距离,横向更小的值,这个是按照Y升序的数据
	    			pointsDmin.add(qpoints.get(i));
	    		}
	    	}

	    	//遍历这个集合中的所有数据,获取最小距离
	    	for(int i = 0; i < pointsDmin.size(); ++i) {
	    		//如果K超出范围,就不用算了
	    		int k = i + 1;
	    		if(k >= pointsDmin.size()) {
	    			break;
	    		}
	    		//求平方差
	    		double minY2 = Math.pow(pointsDmin.get(k).getSecond() - pointsDmin.get(i).getSecond(), 2);
	    		while(k < pointsDmin.size() && minY2 < dminDist) {
	    			//在数据范围内,然后Y的平方差比最小的还小,那么就可以进行比较了
	    			double tempMin = Math.pow(pointsDmin.get(k).getFirst() - pointsDmin.get(i).getFirst(), 2) + Math.pow(pointsDmin.get(k).getSecond() - pointsDmin.get(i).getSecond(), 2);
	    			dminDist = minValue(tempMin, dminDist);
	    			++k;
	    		}
	    	}

	    	return Math.sqrt(dminDist);
	    }
	}

	public double minValue(double dl, double dr) {
		if(dl < dr) {
			return dl;
		} else {
			return dr;
		}
	}

	public static double dist(GenericPair<Double, Double> point1, GenericPair<Double, Double> point2) {
	    //求出两点之间的距离
	    //求平方差
	    double distx = Math.abs(point1.getFirst() - point2.getFirst());
	    double disty = Math.abs(point1.getSecond() - point2.getSecond());
	    //求平方差的和的平方根
	    return Math.sqrt(distx * distx + disty * disty);
	}

	@Test
	public void quikSortTest() {
		List<GenericPair<Double, Double>> points = new ArrayList<GenericPair<Double,Double>>();
		List<GenericPair<Double, Double>> qpoints = new ArrayList<GenericPair<Double,Double>>();
		//5,3,1,9,8,2,4,7,8
		//4,1,8,2,11,9,7,15,11
		GenericPair<Double, Double> el1 = new GenericPair<Double, Double>(5d, 4d);
		GenericPair<Double, Double> el2 = new GenericPair<Double, Double>(3d, 1d);
		GenericPair<Double, Double> el3 = new GenericPair<Double, Double>(1d, 8d);
		GenericPair<Double, Double> el4 = new GenericPair<Double, Double>(9d, 2d);
		GenericPair<Double, Double> el5 = new GenericPair<Double, Double>(8d, 11d);
		GenericPair<Double, Double> el6 = new GenericPair<Double, Double>(2d, 9d);
		GenericPair<Double, Double> el7 = new GenericPair<Double, Double>(4d, 7d);
		GenericPair<Double, Double> el8 = new GenericPair<Double, Double>(7d, 15d);
//		GenericPair<Double, Double> el9 = new GenericPair<Double, Double>(8d, 11d);
		points.add(el1);points.add(el2);points.add(el3);points.add(el4);points.add(el5);
		points.add(el6);points.add(el7);points.add(el8);//points.add(el9);

		qpoints.add(el1);qpoints.add(el2);qpoints.add(el3);qpoints.add(el4);qpoints.add(el5);
		qpoints.add(el6);qpoints.add(el7);qpoints.add(el8);//qpoints.add(el9);

		MinPath mp = new MinPath();
		mp.seqXList(points, 0, points.size() - 1);
		mp.seqYList(qpoints, 0, qpoints.size() - 1);

//		for(GenericPair<Double, Double> temp : points){
//			System.out.print(temp.toString() + "\t");
//		}

		double result = mp.efficientClosestPair(points, qpoints);
		System.out.println(result);
	}

	/**
	 * 按照X升序
	 * @param points
	 * @return
	 */
	public static void seqXList(List<GenericPair<Double, Double>> points, int start, int end) {
		//获取中间点位置,然后一分为二,进行遍历递归
		if(start < end) {
			int mid = hoarePartition(points, false, start, end);
			seqXList(points, start, mid - 1);
			seqXList(points, mid + 1, end);
		}
	}

	/**
	 * 按照Y升序
	 * @param points
	 * @return
	 */
	public static void seqYList(List<GenericPair<Double, Double>> points, int start, int end) {
		// 获取中间点位置,然后一分为二,进行遍历递归
		if (start < end) {
			int mid = hoarePartition(points, true, start, end);
			seqYList(points, start, mid - 1);
			seqYList(points, mid + 1, end);
		}
	}

	/**
	 * 寻找分裂点,并规整数据,xOry是用来判定两边是用x-false排序还是用y-true排序
	 * @param points
	 * @return
	 */
	public static int hoarePartition(List<GenericPair<Double, Double>> points, boolean xOry, int start, int end) {
		if(start >= end) {
			return start;
		}
		//以第一个数为准对进行分裂
		double temp = getValue(points.get(start), xOry);

		//两边进行遍历,直到两个错开,或者相等
		int leftIndex = start + 1;
		int rightIndex = end;
		while(leftIndex < rightIndex) {
			//如果遍历到左边的比第一个大,右边比第一个数小,交换数据,为了避免多余的一次交换
			while(getValue(points.get(leftIndex), xOry) < temp) {
				++leftIndex;
			}

			while(getValue(points.get(rightIndex), xOry) > temp) {
				--rightIndex;
			}
			//如果是到了最后一步,错位了,然后交换了,避免多余的一次交换
		    swap(points, leftIndex, rightIndex);
		}
		//从新吧最后一对错位的数据交换回来,但是如果这个循环根本没有进去过,那么就不应该有这个交换
		swap(points, leftIndex, rightIndex);
		//最后把j对应的数据地方交换到开始作为中间点的数据位置
		//如果本身比要排列的中间值还小,那么不用换,换了就打乱了排序
		if(getValue(points.get(start), xOry) > getValue(points.get(rightIndex), xOry))
		    swap(points, start, rightIndex);

		return rightIndex;
	}

	//交换数据
	public static void swap(List<GenericPair<Double, Double>> points, int i, int j) {
		//取出i位置的数据,吧i数据修改为j,temp为i的数据,吧j替换为temp
		GenericPair tempi = points.get(i);
		GenericPair tempj = points.get(j);
		points.set(i, tempj);
		points.set(j, tempi);
	}

	/**
	 * xOry是用来判定两边是用x-false排序还是用y-true排序
	 * @param pair
	 * @param xOry
	 * @return
	 */
	public static double getValue(GenericPair<Double, Double> pair, boolean xOry) {
		double temp = 0;
		if(!xOry) {
			//如果是true,那么就是判断y
			//否则是第一个x
			temp = pair.getFirst();
		} else {
			temp = pair.getSecond();
		}

		return temp;
	}
}

  

最近点距离

疑问,求解答,网上什么  “鸽巢原理”  不是很懂,求通俗点的解释。。。

时间: 2024-10-09 22:41:07

【算法设计与分析基础】15、最近对问题的相关文章

算法设计与分析基础(第3版)读书笔记(及几处翻译上的错误~~)

算法设计与分析基础(第3版) p16 in-place翻译为'在位'?'就地'更合适点 p38 amortized应翻译为'均摊','摊销'这个词简直莫名其妙(可能因为翻译是做算法交易导致的?) p64 迭代优于递归(迭代始终是增量式的,而递归就没办法增量了,除非能够dump整个运行时栈) p73 通过算法可视化得到一个更好的非递归算法(人的图像认知直觉思维?) p79 验证一个拓扑是环.星.还是团?(这个地方有点意思,因为我想到了动态的Verify) p87 凸包问题:从数据结构上讲,Set<

【算法设计与分析基础】大整数乘法

#include<iostream> #include<string> #include<time.h> #include<stdlib.h> #include<sstream> using namespace std; class BigDecimal{ private: int max(int a,int b){//获取两数中的最大值 return a^((a^b) & -(a<b)); } public: string n;

【算法设计与分析基础】关灯游戏

① R.java  用于存储一些全局变量 package lightoff; public class R { /* public static int lightCondition[][] = { {1,0,0,1,1}, {1,0,0,1,1}, {1,0,0,1,1}, {1,0,0,1,1}, }; */ public static int lightCondition[][] = { {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, {1,1,1,1}, }; //灯面

【算法设计与分析基础】19、字符串匹配算法

package cn.xf.algorithm.ch07inputEnhancement; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; /** * * 功能:字符串匹配算法,(还有一种叫KMP算法的,也是很经典的算法,就是比较复杂) * * 第一步:对于给定的长度为m的模式和在模式文本中用到的字母表,按照上面的描述构造移动表 * 第二步:将模式与文本的开

【算法设计与分析基础】16、高斯消元法

package cn.xf.algorithm.ch06ChangeRule; import java.util.ArrayList; import java.util.List; import org.junit.Test; import cn.xf.util.GenericPair; /** * * 功能:高斯消元法,也就是多元数据矩阵,依次吧每列的其他行数据消去为0,然后求出一个元的解,然后就可以根据这个数据来递推出其他元的解 * @author xiaofeng * @date 2017

【算法设计与分析基础】20、动态规划-硬币搜集问题

题目: 在n*m格木板中放有一些硬币,每格的硬币数目最多为一个.在木板左上方的一个机器人需要搜集尽可能多的硬币并把他们带到右下方的单元格,每一步,机器人可以从当前的位置向右移动一格 或者向下移动一格,当机器人遇到一个有硬币的单元格的时,就会将这枚硬币搜集起来 解题: 硬币收集的时候,我们 从结果状态开始看,当搜集当前硬币的时候,只有两种方式,从上往下搜集,或者从左向右搜集 也就是当前f[i,j] = max{f[i, j - 1], f[i - 1, j]},初始化第一行和第一列,从第二行和列开

【算法设计与分析基础】17、堆

以数组来存放堆数据 package cn.xf.algorithm.ch06ChangeRule; import java.util.ArrayList; import java.util.List; import org.junit.Test; /** * * 功能:堆的构造 * 1.堆可以定义为一颗二叉树,树的节点包含键,并且满足一下条件 * 1) 树的形状要求:这棵二叉树是基本完备的(完全二叉树),树的每一层都是满的,除了最后一层最右边的元素可能缺位 * 2) 父母优势,堆特性,每一个节点

【算法设计与分析基础】18、霍纳法则

产生随机数 package cn.xf.algorithm.ch02; import java.util.ArrayList; import java.util.List; /** * 生产随机数 * @author xiaof * */ public class Random { /** * 生产一个随机数的数列 * @param n 生成n个数列 * @param m 数据在0和m-1之间 * @param seed 随机初始种子 * @param a 参数 * @param b 参数 *

【算法设计与分析基础】22、最优二叉查找树

package cn.xf.algorithm.ch08DynamicProgramming; import java.util.Arrays; import org.junit.Test; import cn.xf.algorithm.ch08DynamicProgramming.vo.ResultVo; /** * 最优二叉树问题 * * 思路:根据最优二叉树的问题就是查找对应的节点的比较次数的期望值保持最小 * 最优二叉查找树的期望搜索代价保持最小 * 例如:一颗树有节点{k0,k1,k2