凸包问题+最优二叉查找树 都利用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);
}
}
实现截图
若想修改生成节点数可在代码中修改。
各位小伙伴有什么问题评论区留言o((>ω< ))o
源码
具体源码地址:https://download.csdn.net/download/qq_49143427/85524497