Coursera Algorithms Programming Assignment 5: Kd-Trees (98分)
题目地址:http://coursera.cs.princeton.edu/algs4/assignments/kdtree.html
分析:
Brute-force implementation. 蛮力实现的方法比较简单,就是逐个遍历每个point进行比较,实现下述API就可以了,没有什么难度。

import java.util.ArrayList;
import java.util.TreeSet;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.StdDraw;
/**
* @author evasean www.cnblogs.com/evasean/
*/
public class PointSET {
private TreeSet<Point2D> points;
public PointSET() {
// construct an empty set of points
points = new TreeSet<Point2D>();
} public boolean isEmpty() {
// is the set empty?
return points.isEmpty();
} public int size() {
// number of points in the set
return points.size();
} public void insert(Point2D p) {
// add the point to the set (if it is not already in the set)
if(p==null)
throw new IllegalArgumentException("Point2D p is not illegal!");
if(!points.contains(p))
points.add(p);
} public boolean contains(Point2D p) {
// does the set contain point p?
if(p==null)
throw new IllegalArgumentException("Point2D p is not illegal!");
return points.contains(p);
} public void draw() {
// draw all points to standard draw
for (Point2D p : points) {
p.draw();
}
StdDraw.show();
} public Iterable<Point2D> range(RectHV rect) {
// all points that are inside the rectangle (or on the boundary)
if(rect==null)
throw new IllegalArgumentException("RectHV rect is not illegal!");
ArrayList<Point2D> list = new ArrayList<Point2D>();
for(Point2D point : points){
if(rect.contains(point)) list.add(point);
}
return list;
} public Point2D nearest(Point2D p) {
// a nearest neighbor in the set to point p; null if the set is empty
if(p==null)
throw new IllegalArgumentException("Point2D p is not illegal!");
if(points.size() == 0) return null;
double neareatDistance = Double.POSITIVE_INFINITY;
Point2D nearest = null;
for(Point2D point : points){
double tmp = p.distanceTo(point);
if(Double.compare(neareatDistance, tmp) == 1){
neareatDistance = tmp;
nearest = point;
} }
return nearest;
} public static void main(String[] args) {
// unit testing of the methods (optional)
}
}
2d-tree implementation.
kd-tree插入时要交替以x坐标和y坐标作为判断依据,比如root节点处比较依据为x坐标,那么当要查找或插入一个新节点point时,比较root节点的x坐标和point的x坐标,如果后者比前者小,那么下一次要比较的就是root->left, 相反下一次要比较的就是root->right。进入下一层级之后,就要使用y坐标作为比较依据。示例如下图:

区域搜索:查找落在给定矩阵区域范围内的所有points。从root开始递归查找,如果给定的矩阵不与当前节点的相关矩阵相交,那么就没有必要继续查找该节点及其子树了。
最近节点搜索:查找与给定point距离最近的节点。从root开始递归查找其左右子树,如果给定节点point和已经查找到的最近节点的距离比该point与当前遍历节点的相关矩阵距离还近,那么就没必要遍历这个当前节点及其子树了。
import java.util.ArrayList;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.StdDraw;
/**
* @author evasean www.cnblogs.com/evasean/
*/
public class KdTree {
private Node root;
private class Node {
private Point2D p;
/*
* 节点的value就是包含该节点的矩形空间 其左右子树的矩形空间,就是通过该节点进行水平切分或垂直切分的两个子空间
*/
private RectHV rect;
private Node left, right;
private int size;
private boolean xCoordinate; // 标识该节点是否是以x坐标垂直切分 public Node(Point2D point, RectHV rect, int size, boolean xCoordinate) {
this.p = point;
this.rect = rect;
this.size = size;
this.xCoordinate = xCoordinate;
}
} public KdTree() {
// construct an empty set of points
} public boolean isEmpty() {
// is the set empty?
return size() == 0;
} public int size() {
// number of points in the set
return size(root);
} private int size(Node x) {
if (x == null)
return 0;
else
return x.size;
} public void insert(Point2D p) {
// add the point to the set (if it is not already in the set)
if (p == null)
throw new IllegalArgumentException("Point2D p is not illegal!");
if (root == null)
root = new Node(p, new RectHV(0.0, 0.0, 1.0, 1.0), 1, true);
else
insert(root, p);
// System.out.println("size="+root.size);
} private void insert(Node x, Point2D p) {
if (x.xCoordinate == true) { // x的切分标志是x坐标
int cmp = Double.compare(p.x(), x.p.x());
if (cmp == -1) {
if (x.left != null)
insert(x.left, p);
else {
RectHV parent = x.rect;
// 将节点x的矩形空间进行垂直切分后的左侧部分
double newXmin = parent.xmin();
double newYmin = parent.ymin();
double newXmax = x.p.x();
double newYmax = parent.ymax();
x.left = new Node(p, new RectHV(newXmin, newYmin, newXmax, newYmax), 1, false);
}
} else if (cmp == 1) {
if (x.right != null)
insert(x.right, p);
else {
RectHV parent = x.rect;
// 将节点x的矩形空间进行垂直切分后的右侧部分
double newXmin = x.p.x();
double newYmin = parent.ymin();
double newXmax = parent.xmax();
double newYmax = parent.ymax();
x.right = new Node(p, new RectHV(newXmin, newYmin, newXmax, newYmax), 1, false);
}
} else { // x.key.x() 与 p.x() 相等
int cmp2 = Double.compare(p.y(), x.p.y());
if (cmp2 == -1) {
if (x.left != null)
insert(x.left, p);
else {
x.left = new Node(p, x.rect, 1, false);
}
} else if (cmp2 == 1) {
if (x.right != null)
insert(x.right, p);
else {
x.right = new Node(p, x.rect, 1, false);
}
}
}
} else { // x的切分标志是y坐标
int cmp = Double.compare(p.y(), x.p.y());
if (cmp == -1) {
if (x.left != null)
insert(x.left, p);
else {
RectHV parent = x.rect;
// 将节点x的矩形空间进行垂直切分后的左侧部分
double newXmin = parent.xmin();
double newYmin = parent.ymin();
double newXmax = parent.xmax();
double newYmax = x.p.y();
x.left = new Node(p, new RectHV(newXmin, newYmin, newXmax, newYmax), 1, true);
}
} else if (cmp == 1) {
if (x.right != null)
insert(x.right, p);
else {
RectHV parent = x.rect;
// 将节点x的矩形空间进行垂直切分后的左侧部分
double newXmin = parent.xmin();
double newYmin = x.p.y();
double newXmax = parent.xmax();
double newYmax = parent.ymax();
x.right = new Node(p, new RectHV(newXmin, newYmin, newXmax, newYmax), 1, true);
}
} else { // x.key.y() 与 p.y()相等
int cmp2 = Double.compare(p.x(), x.p.x());
if (cmp2 == -1) {
if (x.left != null)
insert(x.left, p);
else {
x.left = new Node(p, x.rect, 1, true);
}
} else if (cmp2 == 1) {
if (x.right != null)
insert(x.right, p);
else {
x.right = new Node(p, x.rect, 1, true);
}
}
}
}
x.size = 1 + size(x.left) + size(x.right);
} public boolean contains(Point2D p) {
// does the set contain point p?
if (p == null)
throw new IllegalArgumentException("Point2D p is not illegal!");
return contains(root, p);
} private boolean contains(Node x, Point2D p) {
if(x == null ) return false;
if (x.p.equals(p))
return true;
else {
if(x.xCoordinate == true){
int cmp = Double.compare(p.x(), x.p.x());
if(cmp == -1) return contains(x.left,p);
else if(cmp == 1 ) return contains(x.right,p);
else{
int cmp2 = Double.compare(p.y(), x.p.y());
if(cmp2 == -1) return contains(x.left,p);
else if(cmp2 == 1 ) return contains(x.right,p);
else return true;
}
}else{
int cmp = Double.compare(p.y(), x.p.y());
if(cmp == -1) return contains(x.left,p);
else if(cmp == 1 ) return contains(x.right,p);
else{
int cmp2 = Double.compare(p.x(), x.p.x());
if(cmp2 == -1) return contains(x.left,p);
else if(cmp2 == 1 ) return contains(x.right,p);
else return true;
}
}
}
} public void draw() {
// draw all points to standard draw
StdDraw.setXscale(0, 1);
StdDraw.setYscale(0, 1);
draw(root);
} private void draw(Node x) {
if (x == null)
return;
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
x.p.draw();
if (x.xCoordinate == true) {
StdDraw.setPenColor(StdDraw.RED);
StdDraw.setPenRadius();
Point2D start = new Point2D(x.p.x(), x.rect.ymin());
Point2D end = new Point2D(x.p.x(), x.rect.ymax());
start.drawTo(end);
} else {
StdDraw.setPenColor(StdDraw.BLUE);
StdDraw.setPenRadius();
Point2D start = new Point2D(x.rect.xmin(), x.p.y());
Point2D end = new Point2D(x.rect.xmax(), x.p.y());
start.drawTo(end);
}
draw(x.left);
draw(x.right);
} public Iterable<Point2D> range(RectHV rect) {
// all points that are inside the rectangle (or on the boundary)
if (rect == null)
throw new IllegalArgumentException("RectHV rect is not illegal!");
if (root != null)
return range(root, rect);
else
return new ArrayList<Point2D>();
} private ArrayList<Point2D> range(Node x, RectHV rect) {
ArrayList<Point2D> points = new ArrayList<Point2D>();
if (x.rect.intersects(rect)) {
if (rect.contains(x.p))
points.add(x.p);
if (x.left != null)
points.addAll(range(x.left, rect));
if (x.right != null)
points.addAll(range(x.right, rect));
}
return points;
} public Point2D nearest(Point2D p) {
// a nearest neighbor in the set to point p; null if the set is empty
if (p == null)
throw new IllegalArgumentException("Point2D p is not illegal!");
if (root != null)
return nearest(root, p, root.p);
return null;
} /**
* 作业提交提示nearest的时间复杂度偏高,导致作业只有98分,我觉得这样写比较清晰明了,就懒得继续优化
* @param x
* @param p
* @param currNearPoint
* @return
*/
private Point2D nearest(Node x, Point2D p, Point2D currNearPoint) {
if(x.p.equals(p)) return x.p;
double currMinDistance = currNearPoint.distanceTo(p);
if (Double.compare(x.rect.distanceTo(p), currMinDistance) >= 0)
return currNearPoint;
else {
double distance = x.p.distanceTo(p);
if (Double.compare(x.p.distanceTo(p), currMinDistance) == -1) {
currNearPoint = x.p;
currMinDistance = distance;
}
if (x.left != null)
currNearPoint = nearest(x.left, p, currNearPoint);
if (x.right != null)
currNearPoint = nearest(x.right, p, currNearPoint);
}
return currNearPoint;
} public static void main(String[] args) {
// unit testing of the methods (optional)
}
}
Coursera Algorithms Programming Assignment 5: Kd-Trees (98分)的更多相关文章
- Coursera Algorithms Programming Assignment 1: Percolation(100分)
题目来源http://coursera.cs.princeton.edu/algs4/assignments/percolation.html 作业分为两部分:建立模型和仿真实验. 最关键的部分就是建 ...
- Coursera Algorithms Programming Assignment 3: Pattern Recognition (100分)
题目原文详见http://coursera.cs.princeton.edu/algs4/assignments/collinear.html 程序的主要目的是寻找n个points中的line seg ...
- Coursera Algorithms Programming Assignment 4: 8 Puzzle (100分)
题目原文:http://coursera.cs.princeton.edu/algs4/assignments/8puzzle.html 题目要求:设计一个程序解决8 puzzle问题以及该问题的推广 ...
- Coursera Algorithms Programming Assignment 2: Deque and Randomized Queue (100分)
作业原文:http://coursera.cs.princeton.edu/algs4/assignments/queues.html 这次作业与第一周作业相比,稍微简单一些.有三个编程练习:双端队列 ...
- Algorithms : Programming Assignment 3: Pattern Recognition
Programming Assignment 3: Pattern Recognition 1.题目重述 原题目:Programming Assignment 3: Pattern Recogniti ...
- Algorithms: Design and Analysis, Part 1 - Programming Assignment #1
自我总结: 1.编程的思维不够,虽然分析有哪些需要的函数,但是不能比较好的汇总整合 2.写代码能力,容易挫败感,经常有bug,很烦心,耐心不够好 题目: In this programming ass ...
- Coursera课程 Programming Languages, Part A 总结
Coursera CSE341: Programming Languages 感谢华盛顿大学 Dan Grossman 老师 以及 Coursera . 碎言碎语 这只是 Programming La ...
- 课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 3.Programming Assignment : Planar data classification with a hidden layer
Planar data classification with a hidden layer Welcome to the second programming exercise of the dee ...
- Programming Assignment 4: Boggle
编程作业四 作业链接:Boggle & Checklist 我的代码:BoggleSolver.java 问题简介 Boggle 是一个文字游戏,有 16 个每面都有字母的骰子,开始随机将它们 ...
随机推荐
- 第四次作业——项目Alpha测试
这个作业属于哪个课程 <课程链接> 这个作业要求在哪里 <作业要求> 团队名称 飞猪们 这个作业的目标 发布项目α版本,对项目进行用例测试,以及项目情况总结 一.团队成员学号列 ...
- MONO Design创建电信3D机房
前面我们简单介绍了下一分钟创建3D机房,实则mono Design的功能远远不止这些,试想一下,如果我们花上10分钟来创建一个电信机房,那么MONO design又会给我们带来什么样的惊喜呢? 我们从 ...
- POJ P2096 Collecting Bugs
思路 分类讨论,不妨先设$DP[i][j]$表示已经发现$i$种子系统中有$n$种$bug$无非只有四种情况 发现的$bug$在旧的系统旧的分类,概率$p1$是$(i/s)*(j/n)$. 发现的$b ...
- Python学习-比较运算符和逻辑运算符
比较运算符 == 等于 - 比较对象是否相等 print(3 == 4); //False != 不等于 - 比较两个对象是否不相等 print(3 != 4); // True <> ...
- Java 数组中寻找最大子数组
程序设计思想: 依次将数组划分开,先判断一个元素的单个数组大小,接下来两个,依次上升,最后将所得结果进行比较赋值,输出最大结果. 1 package ketangTest; //张生辉,康治家 201 ...
- Leetcode 89.格雷编码
格雷编码 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.格雷编码序列必须以 0 开头. 示例 1: 输入: 2 ...
- select节点clone全解析
select节点clone全解析 2009-12-18 在开发ns-log项目中,统计分类有复制的功能.由于之前的统计分类中的数据是通过JS赋值进去的,之后用户可能又进行了修改,发现进行节点克隆时,出 ...
- 使用C#执行PowerShell命令
按照网上的教程配置会发生SSL链接错误 该文章的最后使用了SSL来保证账户在连接服务器的时候不发生账户认证错误,但是我经过测试发现这个是不可行的,有一种更为简单的方法 首先要对服务器进行winrm设置 ...
- [bzoj1597][USACO2008]土地购买(DP斜率优化/四边形优化)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1597 分析: 1.先可以把被包含的土地可以去掉,这些土地的长宽肯定都是不会用的,具体先 ...
- Sping框架的IOC特性
IOC(Inversion of Control):控制反转 以下以课程与老师的安排来介绍控制反转. 一个合理的课程编排系统应该围绕培训的内容为核心,而不应该以具体的培训老师为核心,这样才能在正常授课 ...