这一次作业运用了recursive来写。
public class KdTree {
private static class Node {
private Point2D point; // the point
private RectHV rect; // the axis-aligned rectangle corresponding to this node
private Node left; // the left/bottom subtree
private Node right; // the right/top subtree
private boolean vertical;
public Node(Point2D p,Node left,Node right,boolean v,RectHV rect){
this.point=p;
this.left=left;
this.right=right;
this.vertical=v;
this.rect=rect;
}
}
private Node root;
private int size;
public KdTree(){ // construct an empty set of points
root=null;
size=0;
}
public boolean isEmpty(){ // is the set empty?
return size()==0;
}
public int size(){ // number of points in the set
return size;
}
public void insert(Point2D p){ // add the point p to the set (if it is not already in the set)
root=insert(root,p,true,0,0,1,1);
}
private Node insert(Node node, Point2D p, boolean v, double xmin, double ymin, double xmax, double ymax){
// if new node, create it
if(node==null){
size++;
return new Node(p,null,null,v,new RectHV(xmin,ymin,xmax,ymax));
}
// if already in, return it
if (node.point.x() == p.x() && node.point.y() == p.y()) return node;
// else, insert it where corresponds (left - right recursive call)
if (node.vertical){ //if node is in vertical level or odd level
if(p.x() < node.point.x()){
node.left = insert(node.left, p, !node.vertical, node.rect.xmin(),node.rect.ymin(),node.point.x(),node.rect.ymax());
}else{
node.right = insert(node.right, p, !node.vertical, node.point.x(),node.rect.ymin(),node.rect.xmax(),node.rect.ymax());
}
}else{ //if node is in horizontal level or even level
if(p.y() < node.point.y()){
node.left = insert(node.left, p, !node.vertical, node.rect.xmin(),node.rect.ymin(),node.rect.xmax(),node.point.y());
}else{
node.right = insert(node.right, p, !node.vertical, node.rect.xmin(),node.point.y(),node.rect.xmax(),node.rect.ymax());
}
}
return node;
}
public boolean contains(Point2D p){ // does the set contain the point p?
return contains(root, p.x(),p.y());
}
private boolean contains(Node node, double x, double y)
{
if (node == null) return false;
if (node.point.x() == x && node.point.y() == y) return true;
if (node.vertical && x < node.point.x() || !node.vertical && y < node.point.y())
return contains(node.left, x, y);
else
return contains(node.right, x, y);
}
public void draw(){ // draw all of the points to standard draw
draw(root);
}
private void draw(Node node){
if(node==null) return;
// draw the point
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
node.point.draw();
Point2D min, max;
if (node.vertical) {
StdDraw.setPenColor(StdDraw.RED);
min = new Point2D(node.point.x(), node.rect.ymin());
max = new Point2D(node.point.x(), node.rect.ymax());
} else {
StdDraw.setPenColor(StdDraw.BLUE);
min = new Point2D(node.rect.xmin(), node.point.y());
max = new Point2D(node.rect.xmax(), node.point.y());
}
// draw that division line
StdDraw.setPenRadius();
min.drawTo(max);
// recursively draw children
draw(node.left);
draw(node.right);
}
public Iterable<Point2D> range(RectHV rect){ // all points in the set that are inside the rectangle
Stack<Point2D> s = new Stack<Point2D>();
range(rect, root, s);
return s;
}
private void range(RectHV rect, Node node, Stack<Point2D> s){
if(node==null) return;
if(node.rect.intersects(rect)){
if(rect.contains(node.point)){
s.push(node.point);
}
range(rect,node.left,s);
range(rect,node.right,s);
}
}
public Point2D nearest(Point2D p){ // a nearest neighbor in the set to p; null if set is empty
return nearest(root,p,null);
}
private Point2D nearest(Node x, Point2D p, Point2D candidate) {
if (x == null) return candidate; // if empty or the tree is searched over, return null or the presently nearest one
if(candidate==null){ // if x equals root, the nearest point is root
candidate=x.point;
}
double nearestD = candidate.distanceSquaredTo(p);
double distanceToPoint = x.point.distanceSquaredTo(p);
if(nearestD>x.rect.distanceSquaredTo(p)){ // judge whether this node and its subtree need to be processed
if(distanceToPoint<nearestD){
candidate=x.point;
}
if (x.left != null && x.right != null && x.left.rect.distanceSquaredTo(p) < x.right.rect.distanceSquaredTo(p)) {
candidate=nearest(x.left, p, candidate);
candidate=nearest(x.right, p, candidate);
}else{
candidate=nearest(x.right, p, candidate);
candidate=nearest(x.left, p, candidate);
}
}
return candidate;
}
}
有疑问可以看《Algorithms 4th Edition》399页的BST写法来加深理解,399页的get,由于方便,加上要递归,本来的get只有要get的参数,没有从哪里开始搜索,所以要加上root,所以分两个get写。
如果两个都是return value,那么直接return。如果像put这样,写的是void,那么就是root=put(root, key, val) 仔细看书上recursive的运用。这次的作业就是照着BST的写法写,也可以看github别人写的:https://gist.github.com/agjacome/5246693#file-kdtree-java-L85