凸包问题(包含蛮力算法和快速凸包算法)+最优二叉查找树详解

凸包问题+最优二叉查找树 都利用javafx生成可视乎界面

凸包问题

1.蛮力算法

解法:任意选取两个点,然后判断这两个点连接的直线是否为凸边,依次判断所有点。说的通俗一点就是任取两个点,其他的点是否在“这两个点连接的直线”的同一侧。
可以利用for循环依次判断,代码如下。

//判断是否为凸包的边
    public boolean isValidSide(Point p1, Point p2) {
        int right = 0;//凸边右边的点
        int left = 0;//凸边左边的点
        if (points.length < 3) {//平面点的数量小于3,无法组成凸包
            return false;
        }
        for (int i = 0; i < points.length; i++) {
            if (points[i].equals(p1) || points[i].equals(p2)) {
                continue;
            }
            if (leftOrRight(p1, p2, points[i]) > 0) {
                left++;
            } else if (leftOrRight(p1, p2, points[i]) < 0){
                right++;
            }
        }
        if (right > 0 && left > 0) {//直线两边都有点时,该边不为凸边
            return false;
        }
        return true;
    }

    //判断p3在 p1和p2 所在直线的哪一边
    public int leftOrRight(Point p1, Point p2, Point p3) {
        int x1 = p1.x;
        int y1 = p1.y;
        int x2 = p2.x;
        int y2 = p2.y;
        int x3 = p3.x;
        int y3 = p3.y;
        return (y1-y2)*x3+(x2-x1)*y3+x1*y2-y1*x2;
    }
2.快速凸包算法

解法:首先选取一个最左边和最右边的点,然后再找出离这条直线最远的点,将该点连接那个两个点,同时该点即为凸包边上的点。然后依次根据三角形的边寻找最远的点。最后结果即为凸包。
步骤图
下面是该解法的核心代码。

 //找凸包边界的点
    public void findPoint() {
        if (points.length < 3) {
            return;
        }
        Point left = points[0], right = points[0], maxfarP = points[0];//最左边和最右边的点,离这两点直线最远的点
        for (int i = 0; i < points.length; i++) {
            if (points[i].x < left.x) {
                left = points[i];
            } else if (points[i].x > right.x) {
                right = points[i];
            }
        }
        int far = 0;
        for (int i = 0; i < points.length; i++) {
            if (Math.abs(distance(left, right, points[i])) > far) {
                far = Math.abs(distance(left, right, points[i]));
                maxfarP = points[i];
            }
        }
        list.add(left);
        list.add(right);
        list.add(maxfarP);
        findEndPoint(outPoint(left, right, maxfarP, points), left, right);
        findEndPoint(outPoint(maxfarP, right, left, points), maxfarP, right);
        findEndPoint(outPoint(left, maxfarP, right, points), left, maxfarP);
    }

    public void findEndPoint(Point[] points, Point p1, Point p2) {
        if (points.length == 0) {//凸边无其他点
            return;
        }
        //寻找离直线最远的点
        Point maxfarP = points[0];
        int far = 0;
        for (int i = 0; i < points.length; i++) {
            if (far < Math.abs(distance(p1, p2, points[i]))) {
                maxfarP = points[i];
                far = Math.abs(distance(p1, p2, points[i]));
            }
        }
        list.add(maxfarP);
        //形成新的三角形凸包后,继续重复步骤。
        //判断两条边是否为凸边,若不是继续执行
        findEndPoint(outPoint(p1, maxfarP, p2, points), p1, maxfarP);
        findEndPoint(outPoint(p2, maxfarP, p1, points), p2, maxfarP);
    }

以下是凸包问题的截图
在这里插入图片描述

最优二叉查找树

题目:产生 20 个随机小数,其和为 1,分别表示 20 个结点的查找概率,构造一颗最优二叉查找树。
解法:根据动态规划求出平均查找时间,同时确定相应的顶点。
伪代码:
算法 OptimalBST(P[1…n])
//动态规划算法求最优二叉树
//输入:一个n个键的有序列表的查找概率数组P[1…n]
//输出:在最优BST中成功查找的平均比较次数,以及最优BST中树的根表R

for i ← 1 to n do
    C[i,i-1]0
    C[i,j]P[i]
    R[i,j] ← i
C[n+1,n]0
for d←1 to n-1 do //对角线计数
    for i←1 to n-1 do
        j ← i+d
minval ← ∞
for k ← i to j do
     if C[i,k-1]+C[k+1,j]<minval
         minval ← C[i,k-1]+C[k+1,j];kmin ← k
R[i,j] ← kmin
sum ← P[i];
for s ← i+1 to j do
    sum ← sum + P[s]
C[i,j] ← minval +sum
    return C[1,n],R

实现核心代码如下

/**
     * 生成主表和根表
     */
    public void OptimalBST(){
        c = new double[p.length + 1][p.length];
        r = new int[p.length + 1][p.length];
        int n = p.length-1;
        for (int i = 1; i <= n; i++) {
            c[i][i-1] = 0;
            c[i][i] = p[i];
            r[i][i] = i;
        }
        c[n+1][n] = 0;
        for (int d = 1; d <= n-1; d++) {
            for (int i = 1; i <= n-d; i++) {
                int j = i+d;
                double minval = Double.MAX_VALUE;
                int kmin = 0;
                for (int k = i; k <= j; k++) {
                    if (c[i][k - 1] + c[k + 1][j] < minval) {
                        minval = c[i][k-1] + c[k+1][j];
                        kmin = k;
                    }
                }
                r[i][j] = kmin;
                double sum = p[i];
                for (int s = i+1; s <= j; s++) {
                    sum = sum + p[s];
                }
                c[i][j] = minval + sum;
            }
        }
    }

    //根据根表生成最优二叉查找树
    public void getOBST(int x, int y, int val, Node node){
        int leftLoc = r[x][val - 1];
        if (leftLoc != 0) {
            double lNum = p[leftLoc];
            Node lnode = new Node(lNum);
            node.setlNode(lnode);
            getOBST(x, val-1, leftLoc, lnode);
        }

        int rightLoc = r[val+1][y];
        if (rightLoc != 0) {
            double rNum = p[rightLoc];
            Node rnode = new Node(rNum);
            node.setrNode(rnode);
            getOBST(val + 1, y, rightLoc, rnode);
        }
    }

实现截图
图1
图2
若想修改生成节点数可在代码中修改。

各位小伙伴有什么问题评论区留言o((>ω< ))o

源码

具体源码地址:https://download.csdn.net/download/qq_49143427/85524497

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追风少年浪子彦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值