编程之美2.11寻找最近的点对Java版二

二维的分治思想
  public static void main(String[] args) {
        double[][] arry2 = new double[][]{{10, 10}, {8, 2}, {5, 6}, {3, 3}, {12, 8}, {9, 10}};
        List<double[]> list2 = Arrays.asList(arry2);
        //解法三 分治思想 二维
        List<double[]> num4 = searchLength4(list2);
        System.out.println("距离最近的两个点:(" + num4.get(0)[0] + "," + num4.get(0)[1] + ")、(" + num4.get(1)[0] + "," + num4.get(1)[1] + ")距离为:" + num4.get(2)[0]);
    }
  /*
     用double[]表示一个点
     x坐标:double[0]
     y坐标:double[1]
     返回结果List<double[]>result,其中前两个节点是两个点,第三个节点下标为0的位表示距离
     */
    private static List<double[]> searchLength4(List<double[]> list) {
        List<double[]> result = new ArrayList();
        if (list.size() <= 2) {
            if (list.size() == 2) {//只有两个点,计算两点间距离
                double des = pointsDes(list.get(0), list.get(1));
                result.add(list.get(0));
                result.add(list.get(1));
                double[] d = new double[1];
                d[0] = des;
                result.add(d);
            } else {
                result.add(list.get(0));
                result.add(list.get(0));
                double[] d = new double[1];
                d[0] = 0;
                result.add(d);
            }
            return result;
        }
        //*************************把点分成左右两部分***********************************************
        //具体分法:a.把list按照x升序排列 
        //          b.选出位于中间的点 point
        list.sort(new Comparator<double[]>() {
            public int compare(double[] o1, double[] o2) {
                return (int) (o1[0] - o2[0]);
            }

        });
        int mid = list.size() / 2;
        double[] point = list.get(mid);//位于中间的点

        List<double[]> list_left = new ArrayList();
        List<double[]> list_right = new ArrayList();

        for (int i = 0; i < list.size(); i++) {
            if (list.get(i)[0] < point[0]) {
                list_left.add(list.get(i));
            } else if (list.get(i)[0] > point[0]) {
                list_right.add(list.get(i));
            }
        }

        if (list_left.size()
                < list_right.size()) {
            list_left.add(point);
        } else {
            list_right.add(point);
        }

//***************************获取了left和right两部分的点********************************************        
        List<double[]> result_left = searchLength4(list_left);
        List<double[]> result_right = searchLength4(list_right);
        System.out.println("result_left:(" + result_left.get(0)[0] + "," + result_left.get(0)[1] + ")、(" + result_left.get(1)[0] + "," + result_left.get(1)[1] + ")距离为:" + result_left.get(2)[0]);
        System.out.println("result_right:(" + result_right.get(0)[0] + "," + result_right.get(0)[1] + ")、(" + result_right.get(1)[0] + "," + result_right.get(1)[1] + ")距离为:" + result_right.get(2)[0]);
//*****************************寻找left、rignt两部分中各取一个点的组合是否距离更小**********************************
        //不用计算left.right部分全部的点的距离。只需要在有可能出现更小距离的有效区域内选取点,然后计算
        //有效区域的范围:x的取值范围(point[0]-m,point[0]+m)
        //下面开始计算有效区域并找出有效区域内的点
        //a.先判断两部分目前更小距离,来确定M的值
        double m = 0;//最小距离
        if (result_left.get(2)[0] == 0 && result_right.get(2)[0] == 0) {
            double des = pointsDes(result_left.get(0), result_right.get(1));
            result.add(result_left.get(0));
            result.add(result_right.get(1));
            double[] d = new double[1];
            d[0] = des;
            result.add(d);
            return result;

        } else {
            if (result_left.get(2)[0] == 0 && result_right.get(2)[0] > 0) {
                result.add(result_right.get(0));
                result.add(result_right.get(1));
                m = result_right.get(2)[0];
                result.add(result_right.get(2));
            } else if (result_right.get(2)[0] == 0 && result_left.get(2)[0] > 0) {
                result.add(result_left.get(0));
                result.add(result_left.get(1));
                m = result_left.get(2)[0];
                result.add(result_left.get(2));
            } else {
                if (result_left.get(2)[0] < result_right.get(2)[0]) {
                    result.add(result_left.get(0));
                    result.add(result_left.get(1));
                    m = result_left.get(2)[0];
                    result.add(result_left.get(2));
                } else {
                    result.add(result_right.get(0));
                    result.add(result_right.get(1));
                    m = result_right.get(2)[0];
                    result.add(result_right.get(2));
                }
            }
            //b.有效区域范围。计算方法:x(point[0]-m,point[0]+m)
            double x_min = point[0] - m;
            double x_max = point[0] + m;
            //c.找出有效区域内的点
            //寻找left部分x坐标在区域内的点
            List<double[]> may_list_left = new ArrayList();
            List<double[]> may_list_right = new ArrayList();
            for (int i = 0; i < list_left.size(); i++) {
                if (list_left.get(i)[0] > x_min) {
                    may_list_left.add(list_left.get(i));
                }
            }
            //寻找right部分x坐标在区域内的点
            for (int i = 0; i < list_right.size(); i++) {
                if (list_right.get(i)[0] < x_max) {
                    may_list_right.add(list_right.get(i));
                }
            }
            //****************************x坐标符合的点已经找出来了,准备开始计算,计算前还有一个筛选条件****************************
            //从left部分选出一个点pl,需要与pr进行计算的right部分的点要满足条件:pr的y坐标取值范围(pl[1]-m,pl[1]+m)
            //如果pr的y坐标超出这个范围,则pr与pl的距离大于m,则没有必要计算
            double tmp = 0;
            double[] tmp_pl = new double[2];
            double[] tmp_pr = new double[2];
            if (!may_list_left.isEmpty() && !may_list_right.isEmpty()) {
                for (int i = 0; i < may_list_left.size(); i++) {
                    double[] pl = may_list_left.get(i);
                    for (int j = 0; j < may_list_right.size(); j++) {
                        double[] pr = may_list_right.get(j);
                        if (pr[1] > (pl[1] - m) && pr[1] < (pl[1] + m)) {//只计算y坐标在可能区域内的right部分的点
                            double des = pointsDes(pl, pr);
                            if (tmp == 0 || des < tmp) {
                                tmp = des;
                                tmp_pl = pl;
                                tmp_pr = pr;
                            }
                        }
                    }
                }
            }
            //如果计算出来的距离比m小,则返回
            if (tmp > 0 && tmp < m) {
                result.set(0, tmp_pl);
                result.set(1, tmp_pr);
                result.set(2, new double[]{tmp});
            }
            return result;
        }

    }

    private static double pointsDes(double[] p1, double[] p2) {
        double des = 0;
        double x = Math.pow(Math.abs(p1[0] - p2[0]), 2);
        double y = Math.pow(Math.abs(p1[1] - p2[1]), 2);
        des = Math.sqrt(x + y);
        return des;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值