【算法設計與分析基礎】15、最近對問題
阿新 • • 發佈:2017-06-25
filename com 算法設計 2個 junit 開始 替換 lis 之間
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; } }
最近點距離
疑問,求解答,網上什麽 “鴿巢原理” 不是很懂,求通俗點的解釋。。。
【算法設計與分析基礎】15、最近對問題