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