也许对某些人来说会很有兴趣。请查看我在Java中实现的nearest()函数(以及KD Tree类)用于2D树的实现:
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.StdDraw;
import java.util.ArrayList;
import java.util.List;
public class KdTree {
private Node root;
private int size;
private static class Node {
private Point2D p;
private RectHV rect;
private Node lb;
private Node rt;
public Node(Point2D p, RectHV rect) {
this.p = p;
this.rect = rect;
}
}
public KdTree() {
}
public boolean isEmpty() {
return size == 0;
}
public int size() {
return size;
}
public boolean contains(Point2D p) {
if (p == null) throw new IllegalArgumentException("argument to contains() is null");
return contains(root, p, 1);
}
private boolean contains(Node node, Point2D p, int level) {
if (node == null) return false;
if (node.p.equals(p)) return true;
if (level % 2 == 0) {
if (p.y() < node.p.y())
return contains(node.lb, p, level + 1);
else
return contains(node.rt, p, level + 1);
}
else {
if (p.x() < node.p.x())
return contains(node.lb, p, level + 1);
else
return contains(node.rt, p, level + 1);
}
}
public void insert(Point2D p) {
if (p == null) throw new IllegalArgumentException("calls insert() with a null point");
root = insert(root, p, 1);
}
private Node insert(Node x, Point2D p, int level) {
if (x == null) {
size++;
return new Node(p, new RectHV(0, 0, 1, 1));
}
if (x.p.equals(p)) return x;
if (level % 2 == 0) {
if (p.y() < x.p.y()) {
x.lb = insert(x.lb, p, level + 1);
if (x.lb.rect.equals(root.rect))
x.lb.rect = new RectHV(x.rect.xmin(), x.rect.ymin(), x.rect.xmax(), x.p.y());
}
else {
x.rt = insert(x.rt, p, level + 1);
if (x.rt.rect.equals(root.rect))
x.rt.rect = new RectHV(x.rect.xmin(), x.p.y(), x.rect.xmax(), x.rect.ymax());
}
}
else {
if (p.x() < x.p.x()) {
x.lb = insert(x.lb, p, level + 1);
if (x.lb.rect.equals(root.rect))
x.lb.rect = new RectHV(x.rect.xmin(), x.rect.ymin(), x.p.x(), x.rect.ymax());
}
else {
x.rt = insert(x.rt, p, level + 1);
if (x.rt.rect.equals(root.rect))
x.rt.rect = new RectHV(x.p.x(), x.rect.ymin(), x.rect.xmax(), x.rect.ymax());
}
}
return x;
}
public void draw() {
draw(root, 1);
}
private void draw(Node node, int level) {
if (node == null) return;
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.01);
node.p.draw();
StdDraw.setPenRadius();
if (level % 2 == 0) {
StdDraw.setPenColor(StdDraw.BLUE);
StdDraw.line(node.rect.xmin(), node.p.y(), node.rect.xmax(), node.p.y());
}
else {
StdDraw.setPenColor(StdDraw.RED);
StdDraw.line(node.p.x(), node.rect.ymin(), node.p.x(), node.rect.ymax());
}
draw(node.lb, level + 1);
draw(node.rt, level + 1);
}
public Iterable<Point2D> range(RectHV rect) {
if (rect == null) throw new IllegalArgumentException("calls range() with a null rect");
List<Point2D> points = new ArrayList<>();
range(root, rect, points);
return points;
}
private void range(Node node, RectHV rect, List<Point2D> points) {
if (node == null || !node.rect.intersects(rect)) return;
if (rect.contains(node.p))
points.add(node.p);
range(node.lb, rect, points);
range(node.rt, rect, points);
}
public Point2D nearest(Point2D query) {
if (isEmpty()) return null;
if (query == null) throw new IllegalArgumentException("calls nearest() with a null point");
double best = root.p.distanceSquaredTo(query);
return nearest(root, query, root.p, best, 1);
}
private Point2D nearest(Node node, Point2D query, Point2D champ, double best, int level) {
if (node == null || best < node.rect.distanceSquaredTo(query)) return champ;
best = champ.distanceSquaredTo(query);
double temp = node.p.distanceSquaredTo(query);
if (temp < best) {
best = temp;
champ = node.p;
}
if (level % 2 == 0) {
if (node.p.y() < query.y()) {
champ = nearest(node.rt, query, champ, best, level + 1);
if (node.lb != null && node.lb.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query)) {
champ = nearest(node.lb, query, champ, best, level + 1);
}
}
else {
champ = nearest(node.lb, query, champ, best, level + 1);
if (node.rt != null && node.rt.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query))
champ = nearest(node.rt, query, champ, best, level + 1);
}
}
else {
if (node.p.x() < query.x()) {
champ = nearest(node.rt, query, champ, best, level + 1);
if (node.lb != null && node.lb.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query))
champ = nearest(node.lb, query, champ, best, level + 1);
}
else {
champ = nearest(node.lb, query, champ, best, level + 1);
if (node.rt != null && node.rt.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query))
champ = nearest(node.rt, query, champ, best, level + 1);
}
}
return champ;
}
public static void main(String[] args) {
KdTree kd = new KdTree();
Point2D p1 = new Point2D(0.7, 0.2);
Point2D p2 = new Point2D(0.5, 0.4);
Point2D p3 = new Point2D(0.2, 0.3);
Point2D p4 = new Point2D(0.4, 0.7);
Point2D p5 = new Point2D(0.9, 0.6);
Point2D query1 = new Point2D(0.972, 0.887);
kd.insert(p1);
kd.insert(p2);
kd.insert(p3);
kd.insert(p4);
kd.insert(p5);
System.out.println(kd.nearest(query1));
kd.draw();
}
}