i'm trying to make a 11 x 11 matrix of nodes doubly linked nodes in Java but i have a problem, i linked the nodes to right, left and down node but when i try to link to the up node i just can't and when i try to get node.up for example, i got a null instead of getting an int(which i should get).
Anyway, here is my code hoping someone can help me. I guess the error may be in void linkUp().
public class CazadorPresa {
// node of linked list
static class Node {
int no;
Node right;
Node down;
Node left;
Node up;
int xpos,ypos;
public boolean hunter,prey,crossed,blocked;
};
// returns head pointer of linked list
// constructed from 2D matrix
static Node construct(int arr[][], int i, int j, int m, int n) {
// return if i or j is out of bounds
if (i > n - 1 || j > m - 1)
return null;
// create a new node for current i and j
// and recursively allocate its down and
// right pointers
Node temp = new Node();
temp.no = arr[i][j];
temp.xpos = j;
temp.ypos = i;
temp.blocked = false;
temp.crossed = false;
temp.hunter = false;
temp.prey = false;
temp.right = construct(arr, i, j + 1, m, n);
temp.down = construct(arr, i + 1, j, m, n);
return temp;
}
// utility function for displaying
// linked list data
static void display(Node head) {
// pointer to move right
Node Rp;
// pointer to move down
Node Dp = head;
// loop till node->down is not NULL
while (Dp != null) {
Rp = Dp;
// loop till node->right is not NULL
while (Rp != null) {
System.out.print(Rp.no + " ");
Rp = Rp.right;
}
System.out.println();
Dp = Dp.down;
}
}
// link left
static void linkLeft(Node head) {
Node Rp;
Node Dp = head;
Node auxL= head;
// loop till node->down is not NULL
while (Dp != null) {
Rp = Dp;
// loop till node->right is not NULL
while (Rp != null) {
if(Rp==Dp){
}else{
Rp.left = auxL;
auxL = Rp;
}
Rp = Rp.right;
}
Dp = Dp.down;
}
}
// link UP
static void linkUp(Node head) {
// pointer to move right
Node Rp;
// pointer to move down
Node Dp = head;
Node aux;
// loop till node->down is not NULL
while (Dp != null) {
Rp = Dp;
// loop till node->right is not NULL
while (Rp != null) {
aux = Rp.down;
if(aux==null){
}else{
aux.up = Rp;
}
Rp = Rp.right;
}
Dp = Dp.down;
}
}
static void hunter(Node head,int x, int y) {
Node arr,aba,izq,der;
boolean out = false;
// pointer to move right
Node Rp;
// pointer to move down
Node Dp = head;
// loop till node->down is not NULL
while (Dp != null) {
Rp = Dp;
// loop till node->right is not NULL
while (Rp != null) {
if(Rp.xpos==x-1 && Rp.ypos==y-1){
Rp.hunter = true;
arr=Rp.up;
if(arr==null){
System.out.println("No link up");
}else{
System.out.println(arr.no);
}
aba=Rp.down;
izq=Rp.left;
der=Rp.right;
System.out.println(" "+izq.no+" "+aba.no+" "+der.no);
out=true;
}
if(out==true){
break;
}
Rp = Rp.right;
}
if(out==true){
break;
}
Dp = Dp.down;
}
}
// driver program
public static void main(String args[]) {
// 2D matrix
int arr[][]= new int[11][11];
int no=1;
for(int i=0;i<11;i++){
for(int j=0;j<11;j++){
arr[i][j] = no;
no=no+1;
}
}
int m = 11, n = 11;
Node head = construct(arr, 0, 0, m, n);
linkUp(head);
linkLeft(head);
display(head);
System.out.println("I should get: 38 48 60 50 but i get: ");
hunter(head,5,5);
}
}
The problem is in the use of recursion to construct the grid of Nodes. When you do:
temp.right = construct(arr, i, j + 1, m, n);
temp.down = construct(arr, i + 1, j, m, n);
You're actually creating multiple versions of the grid, each one overwriting right and down linked Nodes that have already been created. For example, it should be the case that after construction, for a given node:
node.right.down == node.down.right
but given how the grid is constructed this will not be the case, which then causes problems when you come to try to link them up. You can see how bad the problem is by considering that for an 11x11 grid you should be creating 121 Nodes, but I checked and you're actually creating 705,431!
Fortunately the fix is fairly straightforward. Create a 2d array of Nodes and hook up them up directly:
public static void main(String args[]) {
// 2D matrix
Node arr[][]= new Node[11][11];
int m = 11, n = 11;
int no=1;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
arr[i][j] = new Node();
arr[i][j].no = no;
arr[i][j].xpos = j;
arr[i][j].ypos = i;
no=no+1;
}
}
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
arr[i][j].up = (i>0) ? arr[i-1][j] : null;
arr[i][j].left = (j>0) ? arr[i][j-1] : null;
arr[i][j].down = (i+1<m) ? arr[i+1][j] : null;
arr[i][j].right = (j+1<n) ? arr[i][j+1] : null;
}
}
Node head = arr[0][0];
display(head);
hunter(head,5,5);
}
}
Which produces:
38
48 60 50
Which I believe is the output you were expecting.
I am trying to write this code to print the given user inputs in a tree structure that follows
x
x x
x x
but it does not output that way.
I am getting the output as
x
x
x
This is the function I have written that gets and prints:
private void inOrder(Node n)
{
if(n == null) // recursion ends when node is null
return;
{
inOrder(n.left);
System.out.println(n.data);
inOrder(n.right);
}
}
public void printInorder()
{
inOrder(root);
}
This approach runs into trouble because any calls to println() preclude printing further nodes on a line. Using a level order traversal/BFS will enable you to call println() to move to the next line only when all nodes on a given tree level have already been printed.
The bigger difficulty lies in keeping track of the horizontal placement of each node in a level. Doing this properly involves considering the depth, length of the node data and any empty children. If you can, consider printing your tree with depth increasing from left to right, similar to the unix command tree, rather than top-down, which simplifies the algorithm.
Here's a proof-of-concept for a top-down print. Spacing formulas are from this excellent post on this very topic. The strategy I used is to run a BFS using a queue, storing nodes (and null placeholders) in a list per level. Once the end of a level is reached, spacing is determined based on the number of nodes on a level, which is 2n-1, and printed. A simplifying assumption is that node data width is 1.
import java.util.*;
import static java.lang.System.out;
public class Main {
static void printLevelOrder(Node root) {
LinkedList<QItem> queue = new LinkedList<>();
ArrayList<Node> level = new ArrayList<>();
int depth = height(root);
queue.add(new QItem(root, depth));
for (;;) {
QItem curr = queue.poll();
if (curr.depth < depth) {
depth = curr.depth;
for (int i = (int)Math.pow(2, depth) - 1; i > 0; i--) {
out.print(" ");
}
for (Node n : level) {
out.print(n == null ? " " : n.val);
for (int i = (int)Math.pow(2, depth + 1); i > 1; i--) {
out.print(" ");
}
}
out.println();
level.clear();
if (curr.depth <= 0) {
break;
}
}
level.add(curr.node);
if (curr.node == null) {
queue.add(new QItem(null, depth - 1));
queue.add(new QItem(null, depth - 1));
}
else {
queue.add(new QItem(curr.node.left, depth - 1));
queue.add(new QItem(curr.node.right, depth - 1));
}
}
}
static int height(Node root) {
return root == null ? 0 : 1 + Math.max(
height(root.left), height(root.right)
);
}
public static void main(String[] args) {
printLevelOrder(
new Node<Integer>(
1,
new Node<Integer>(
2,
new Node<Integer>(
4,
new Node<Integer>(7, null, null),
new Node<Integer>(8, null, null)
),
null
),
new Node<Integer>(
3,
new Node<Integer>(
5,
new Node<Integer>(9, null, null),
null
),
new Node<Integer>(
6,
null,
new Node<Character>('a', null, null)
)
)
)
);
}
}
class Node<T> {
Node left;
Node right;
T val;
public Node(T val, Node left, Node right) {
this.left = left;
this.right = right;
this.val = val;
}
}
class QItem {
Node node;
int depth;
public QItem(Node node, int depth) {
this.node = node;
this.depth = depth;
}
}
Output:
1
2 3
4 5 6
7 8 9 a
Try it!
You have a problem to print the way you want.
An In order will print left, current and right. These are in different levels in the tree. As soon you print a down level you can't print the current one above because it was already printed.
Also don't forget the println will print that string and give a new line after.
To have a fancy design, you probably need to do some fancy engineering to align them perfectly, something like this:
You need a Queue for the nodes to visit.
printNode(Node root, queueWithNodesAndStartAndEnd, start, end)
print me at the middle of start and end
put my left child in the queue with start = myStart and end = middle of my start and my end
put my right child in the queue with start = middle of my start and my end and end = my end
pop (get and remove) first element from queue
if not empty print popped node with start and end provided
I know this is pseudo-code but you should be able to implement it.
This is the nicest solution I've seen: https://stackoverflow.com/a/42449385/9319615
Here is my code snippet leveraging it. This class will run as is.
class Node {
final int value;
Node left;
Node right;
Node(int value) {
this.value = value;
right = null;
left = null;
}
public void print() {
print("", this, false);
}
private void print(String prefix, Node n, boolean isLeft) {
if (n != null) {
System.out.println(prefix + (isLeft ? "|-- " : "\\-- ") + n.value);
print(prefix + (isLeft ? "| " : " "), n.left, true);
print(prefix + (isLeft ? "| " : " "), n.right, false);
}
}
}
class BinaryTree {
Node root;
private Node addRecursive(Node current, int value) {
if (current == null) {
return new Node(value);
}
if (value < current.value) {
current.left = addRecursive(current.left, value);
} else if (value > current.value) {
current.right = addRecursive(current.right, value);
} else {
// value already exists
return current;
}
return current;
}
public void add(int value) {
root = addRecursive(root, value);
}
public void traverseInOrder(Node node) {
if (node != null) {
traverseInOrder(node.left);
System.out.print(" " + node.value);
traverseInOrder(node.right);
}
}
}
public class Main {
public static void main(String[] args) {
BinaryTree bt = new BinaryTree();
bt.add(6);
bt.add(4);
bt.add(8);
bt.add(3);
bt.add(5);
bt.add(7);
bt.add(9);
System.out.println("Print in order->");
bt.traverseInOrder(bt.root);
System.out.println("\n\nPrint Tree Structure");
bt.root.print();
}
}
Output example
I'm looking for a KDTree implementation in Java.
I've done a google search and the results seem pretty haphazard. There are actually lots of results, but they're mostly just little one-off implementations, and I'd rather find something with a little more "production value". Something like apache collections or the excellent C5 collection library for .NET. Something where I can see the public bug tracker and check to see when the last SVN commit happened. Also, in an ideal world, I'd find a nice well-designed API for spatial data structures, and the KDTree would be just one class in that library.
For this project, I'll only be working in either 2 or 3 dimensions, and I'm mostly just interested in a good nearest-neighbors implementation.
In the book Algorithms in a Nutshell there is a kd tree implementation in java along with a few variations. All of the code is on oreilly.com and the book itself also walk you through the algorithm so you could build one yourself.
for future seekers. Java-ml library has a kd-tree implementation that work fine.
http://java-ml.sourceforge.net/
I've had success with Professor Levy's implementation found here. I realize you're looking for a more production-certified implementation so this is probably not a good fit.
However note to any passers-by, I've been using it for a while now in my photomosaic project with no issues. No guarantee but better than nothing :)
I created a KD-Tree implementation as part of an offline reverse geocoding library
https://github.com/AReallyGoodName/OfflineReverseGeocode
Maybe Nearest Neighbor Search and KD-trees from the Stony-Brook algorithm repository can help.
This is a full implementation for KD-Tree, I have used some libraries to store point and rectangle. These libraries are freely available. It is possible to do with these classes my making your own classes to store point and rectangle. Please share your feedback.
import java.util.ArrayList;
import java.util.List;
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.Point2D;
import edu.princeton.cs.algs4.RectHV;
import edu.princeton.cs.algs4.StdDraw;
public class KdTree {
private static class Node {
public Point2D point; // the point
public RectHV rect; // the axis-aligned rectangle corresponding to this
public Node lb; // the left/bottom subtree
public Node rt; // the right/top subtree
public int size;
public double x = 0;
public double y = 0;
public Node(Point2D p, RectHV rect, Node lb, Node rt) {
super();
this.point = p;
this.rect = rect;
this.lb = lb;
this.rt = rt;
x = p.x();
y = p.y();
}
}
private Node root = null;;
public KdTree() {
}
public boolean isEmpty() {
return root == null;
}
public int size() {
return rechnenSize(root);
}
private int rechnenSize(Node node) {
if (node == null) {
return 0;
} else {
return node.size;
}
}
public void insert(Point2D p) {
if (p == null) {
throw new NullPointerException();
}
if (isEmpty()) {
root = insertInternal(p, root, 0);
root.rect = new RectHV(0, 0, 1, 1);
} else {
root = insertInternal(p, root, 1);
}
}
// at odd level we will compare x coordinate, and at even level we will
// compare y coordinate
private Node insertInternal(Point2D pointToInsert, Node node, int level) {
if (node == null) {
Node newNode = new Node(pointToInsert, null, null, null);
newNode.size = 1;
return newNode;
}
if (level % 2 == 0) {//Horizontal partition line
if (pointToInsert.y() < node.y) {//Traverse in bottom area of partition
node.lb = insertInternal(pointToInsert, node.lb, level + 1);
if(node.lb.rect == null){
node.lb.rect = new RectHV(node.rect.xmin(), node.rect.ymin(),
node.rect.xmax(), node.y);
}
} else {//Traverse in top area of partition
if (!node.point.equals(pointToInsert)) {
node.rt = insertInternal(pointToInsert, node.rt, level + 1);
if(node.rt.rect == null){
node.rt.rect = new RectHV(node.rect.xmin(), node.y,
node.rect.xmax(), node.rect.ymax());
}
}
}
} else if (level % 2 != 0) {//Vertical partition line
if (pointToInsert.x() < node.x) {//Traverse in left area of partition
node.lb = insertInternal(pointToInsert, node.lb, level + 1);
if(node.lb.rect == null){
node.lb.rect = new RectHV(node.rect.xmin(), node.rect.ymin(),
node.x, node.rect.ymax());
}
} else {//Traverse in right area of partition
if (!node.point.equals(pointToInsert)) {
node.rt = insertInternal(pointToInsert, node.rt, level + 1);
if(node.rt.rect == null){
node.rt.rect = new RectHV(node.x, node.rect.ymin(),
node.rect.xmax(), node.rect.ymax());
}
}
}
}
node.size = 1 + rechnenSize(node.lb) + rechnenSize(node.rt);
return node;
}
public boolean contains(Point2D p) {
return containsInternal(p, root, 1);
}
private boolean containsInternal(Point2D pointToSearch, Node node, int level) {
if (node == null) {
return false;
}
if (level % 2 == 0) {//Horizontal partition line
if (pointToSearch.y() < node.y) {
return containsInternal(pointToSearch, node.lb, level + 1);
} else {
if (node.point.equals(pointToSearch)) {
return true;
}
return containsInternal(pointToSearch, node.rt, level + 1);
}
} else {//Vertical partition line
if (pointToSearch.x() < node.x) {
return containsInternal(pointToSearch, node.lb, level + 1);
} else {
if (node.point.equals(pointToSearch)) {
return true;
}
return containsInternal(pointToSearch, node.rt, level + 1);
}
}
}
public void draw() {
StdDraw.clear();
drawInternal(root, 1);
}
private void drawInternal(Node node, int level) {
if (node == null) {
return;
}
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius(0.02);
node.point.draw();
double sx = node.rect.xmin();
double ex = node.rect.xmax();
double sy = node.rect.ymin();
double ey = node.rect.ymax();
StdDraw.setPenRadius(0.01);
if (level % 2 == 0) {
StdDraw.setPenColor(StdDraw.BLUE);
sy = ey = node.y;
} else {
StdDraw.setPenColor(StdDraw.RED);
sx = ex = node.x;
}
StdDraw.line(sx, sy, ex, ey);
drawInternal(node.lb, level + 1);
drawInternal(node.rt, level + 1);
}
/**
* Find the points which lies in the rectangle as parameter
* #param rect
* #return
*/
public Iterable<Point2D> range(RectHV rect) {
List<Point2D> resultList = new ArrayList<Point2D>();
rangeInternal(root, rect, resultList);
return resultList;
}
private void rangeInternal(Node node, RectHV rect, List<Point2D> resultList) {
if (node == null) {
return;
}
if (node.rect.intersects(rect)) {
if (rect.contains(node.point)) {
resultList.add(node.point);
}
rangeInternal(node.lb, rect, resultList);
rangeInternal(node.rt, rect, resultList);
}
}
public Point2D nearest(Point2D p) {
if(root == null){
return null;
}
Champion champion = new Champion(root.point,Double.MAX_VALUE);
return nearestInternal(p, root, champion, 1).champion;
}
private Champion nearestInternal(Point2D targetPoint, Node node,
Champion champion, int level) {
if (node == null) {
return champion;
}
double dist = targetPoint.distanceSquaredTo(node.point);
int newLevel = level + 1;
if (dist < champion.championDist) {
champion.champion = node.point;
champion.championDist = dist;
}
boolean goLeftOrBottom = false;
//We will decide which part to be visited first, based upon in which part point lies.
//If point is towards left or bottom part, we traverse in that area first, and later on decide
//if we need to search in other part too.
if(level % 2 == 0){
if(targetPoint.y() < node.y){
goLeftOrBottom = true;
}
} else {
if(targetPoint.x() < node.x){
goLeftOrBottom = true;
}
}
if(goLeftOrBottom){
nearestInternal(targetPoint, node.lb, champion, newLevel);
Point2D orientationPoint = createOrientationPoint(node.x,node.y,targetPoint,level);
double orientationDist = orientationPoint.distanceSquaredTo(targetPoint);
//We will search on the other part only, if the point is very near to partitioned line
//and champion point found so far is far away from the partitioned line.
if(orientationDist < champion.championDist){
nearestInternal(targetPoint, node.rt, champion, newLevel);
}
} else {
nearestInternal(targetPoint, node.rt, champion, newLevel);
Point2D orientationPoint = createOrientationPoint(node.x,node.y,targetPoint,level);
//We will search on the other part only, if the point is very near to partitioned line
//and champion point found so far is far away from the partitioned line.
double orientationDist = orientationPoint.distanceSquaredTo(targetPoint);
if(orientationDist < champion.championDist){
nearestInternal(targetPoint, node.lb, champion, newLevel);
}
}
return champion;
}
/**
* Returns the point from a partitioned line, which can be directly used to calculate
* distance between partitioned line and the target point for which neighbours are to be searched.
* #param linePointX
* #param linePointY
* #param targetPoint
* #param level
* #return
*/
private Point2D createOrientationPoint(double linePointX, double linePointY, Point2D targetPoint, int level){
if(level % 2 == 0){
return new Point2D(targetPoint.x(),linePointY);
} else {
return new Point2D(linePointX,targetPoint.y());
}
}
private static class Champion{
public Point2D champion;
public double championDist;
public Champion(Point2D c, double d){
champion = c;
championDist = d;
}
}
public static void main(String[] args) {
String filename = "/home/raman/Downloads/kdtree/circle100.txt";
In in = new In(filename);
KdTree kdTree = new KdTree();
while (!in.isEmpty()) {
double x = in.readDouble();
double y = in.readDouble();
Point2D p = new Point2D(x, y);
kdTree.insert(p);
}
// kdTree.print();
System.out.println(kdTree.size());
kdTree.draw();
System.out.println(kdTree.nearest(new Point2D(0.4, 0.5)));
System.out.println(new Point2D(0.7, 0.4).distanceSquaredTo(new Point2D(0.9,0.5)));
System.out.println(new Point2D(0.7, 0.4).distanceSquaredTo(new Point2D(0.9,0.4)));
}
}
There is also JTS Topology Suite
The KdTree implementation only provides range search (no nearest-neighbors).
If nearest-neighbor is your thing look at STRtree
You are correct, there are not that many sites with kd implementation for java! anyways, kd tree is basically a binary search tree which a median value typically is calculated each time for that dimension. Here is simple KDNode and in terms of nearest neighbor method or full implementation take a look at this github project. It was the best one I could find for you. Hope this helps you.
private class KDNode {
KDNode left;
KDNode right;
E val;
int depth;
private KDNode(E e, int depth){
this.left = null;
this.right = null;
this.val = e;
this.depth = depth;
}
May be it will be interest for someone. Please see my nearest() (and KD Tree class) implementation for 2D tree in java:
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; // the point
private RectHV rect; // the axis-aligned rectangle corresponding to this node
private Node lb; // the left/bottom subtree
private Node rt; // the right/top subtree
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; // a base case for recursive call
if (node.p.equals(p)) return true;
if (level % 2 == 0) { // search by y coordinate (node with horizontal partition line)
if (p.y() < node.p.y())
return contains(node.lb, p, level + 1);
else
return contains(node.rt, p, level + 1);
}
else { // search by x coordinate (node with vertical partition line)
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 we try to insert existed point just return its node
if (level % 2 == 0) { // search by y coordinate (node with horizontal partition line)
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 { // search by x coordinate (node with vertical partition line)
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<>(); // create an Iterable object with all points we found
range(root, rect, points); // call helper method with rects intersects comparing
return points; // return an Iterable object (It could be any type - Queue, LinkedList etc)
}
private void range(Node node, RectHV rect, List<Point2D> points) {
if (node == null || !node.rect.intersects(rect)) return; // a base case for recursive call
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");
// set the start distance from root to query point
double best = root.p.distanceSquaredTo(query);
// StdDraw.setPenColor(StdDraw.BLACK); // just for debugging
// StdDraw.setPenRadius(0.01);
// query.draw();
return nearest(root, query, root.p, best, 1); // call a helper method
}
private Point2D nearest(Node node, Point2D query, Point2D champ, double best, int level) {
// a base case for the recursive call
if (node == null || best < node.rect.distanceSquaredTo(query)) return champ;
// we'll need to set an actual best distance when we recur
best = champ.distanceSquaredTo(query);
// check whether a distance from query point to the traversed node less than
// distance from current champion to query point
double temp = node.p.distanceSquaredTo(query);
if (temp < best) {
best = temp;
champ = node.p;
}
if (level % 2 == 0) { // search by y coordinate (node with horizontal partition line)
// we compare y coordinate and decide go up or down
if (node.p.y() < query.y()) { // if true go up
champ = nearest(node.rt, query, champ, best, level + 1);
// important case - when we traverse node and go back up through the tree
// we need to decide whether we need to go down(left) in this node or not
// we just check our bottom (left) node on null && compare distance
// from query point to the nearest point of the node's rectangle and
// the distance from current champ point to thr query point
if (node.lb != null && node.lb.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query)) {
champ = nearest(node.lb, query, champ, best, level + 1);
}
}
else { // if false go down
champ = nearest(node.lb, query, champ, best, level + 1);
if (node.rt != null && node.rt.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query))
// when we traverse node and go back up through the tree
// we need to decide whether we need to go up(right) in this node or not
// we just check our top (right) node on null && compare distance
// from query point to the nearest point of the node's rectangle and
// the distance from current champ point to thr query point
champ = nearest(node.rt, query, champ, best, level + 1);
}
}
else {
// search by x coordinate (node with vertical partition line)
if (node.p.x() < query.x()) { // if true go right
champ = nearest(node.rt, query, champ, best, level + 1);
// the same check as mentioned above when we search by y coordinate
if (node.lb != null && node.lb.rect.distanceSquaredTo(query) < champ.distanceSquaredTo(query))
champ = nearest(node.lb, query, champ, best, level + 1);
}
else { // if false go left
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) {
// unit tests
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 query = new Point2D(0.676, 0.736);
Point2D query1 = new Point2D(0.972, 0.887);
// RectHV test = new RectHV(0, 0, 0.7, 0.4);
// Point2D query = new Point2D(0.331, 0.762);
// Point2D p6 = new Point2D(0.4, 0.4);
// Point2D p7 = new Point2D(0.1, 0.6);
// RectHV rect = new RectHV(0.05, 0.1, 0.15, 0.6);
kd.insert(p1);
kd.insert(p2);
kd.insert(p3);
kd.insert(p4);
kd.insert(p5);
System.out.println(kd.nearest(query1));
// System.out.println("Dist query to 0.4,0.7= " + query.distanceSquaredTo(p4));
// System.out.println("Dist query to RectHV 0.2,0,3= " + test.distanceSquaredTo(p4));
// kd.insert(p6);
// kd.insert(p7);
// System.out.println(kd.size);
// System.out.println(kd.contains(p3));
// // System.out.println(kd.range(rect));
kd.draw();
}
}
Thanks to theosem, really!
Based on his posted library (http://java-ml.sourceforge.net/) I made this code example:
package kdtreeexample; //place your package name here
import net.sf.javaml.core.kdtree.KDTree; //import library
public class KDTreeExample {
public static void main(String[] args) {
KDTree kdTree = new KDTree(2); //2 dimensions (x, y)
// point insertion:
kdTree.insert(new double[]{4, 3}, 0); //insert points (x=4,y=3), index = 0
kdTree.insert(new double[]{1, 10}, 1); //insert points (x=1,y=10), index = 1
kdTree.insert(new double[]{10, 10}, 2); //insert points (x=10,y=10), index = 2
kdTree.insert(new double[]{5, 1}, 3); //insert points (x=5,y=1), index = 3
// nearest index to point in coordinates x, y:
int x = 0; //x coordinate for target point
int y = 11; //y coordinate for target point
int nearestIndex = (int) kdTree.nearest(new double[]{x, y}); //doing calculation here
// result:
System.out.println("Nearest point value index to point(" + x + ", " + y + ") = " + nearestIndex);
System.out.println(kdTree.toString()); //check the data
}
}
package kdtree;
class KDNode{
KDNode left;
KDNode right;
int []data;
public KDNode(){
left=null;
right=null;
}
public KDNode(int []x){
left=null;
right=null;
data = new int[2];
for (int k = 0; k < 2; k++)
data[k]=x[k];
}
}
class KDTreeImpl{
KDNode root;
int cd=0;
int DIM=2;
public KDTreeImpl() {
root=null;
}
public boolean isEmpty(){
return root == null;
}
public void insert(int []x){
root = insert(x,root,cd);
}
private KDNode insert(int []x,KDNode t,int cd){
if (t == null)
t = new KDNode(x);
else if (x[cd] < t.data[cd])
t.left = insert(x, t.left, (cd+1)%DIM);
else
t.right = insert(x, t.right, (cd+1)%DIM);
return t;
}
public boolean search(int []data){
return search(data,root,0);
}
private boolean search(int []x,KDNode t,int cd){
boolean found=false;
if(t==null){
return false;
}
else {
if(x[cd]==t.data[cd]){
if(x[0]==t.data[0] && x[1]==t.data[1])
return true;
}else if(x[cd]<t.data[cd]){
found = search(x,t.left,(cd+1)%DIM);
}else if(x[cd]>t.data[cd]){
found = search(x,t.right,(cd+1)%DIM);
}
return found;
}
}
public void inorder(){
inorder(root);
}
private void inorder(KDNode r){
if (r != null){
inorder(r.left);
System.out.print("("+r.data[0]+","+r.data[1] +") ");
inorder(r.right);
}
}
public void preorder() {
preorder(root);
}
private void preorder(KDNode r){
if (r != null){
System.out.print("("+r.data[0]+","+r.data[1] +") ");
preorder(r.left);
preorder(r.right);
}
}
/* Function for postorder traversal */
public void postorder() {
postorder(root);
}
private void postorder(KDNode r) {
if (r != null){
postorder(r.left);
postorder(r.right);
System.out.print("("+r.data[0]+","+r.data[1] +") ");
}
}
}
public class KDTree {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
KDTreeImpl kdt = new KDTreeImpl();
int x[] = new int[2];
x[0] = 30;
x[1] = 40;
kdt.insert(x);
x[0] = 5;
x[1] = 25;
kdt.insert(x);
x[0] = 10;
x[1] = 12;
kdt.insert(x);
x[0] = 70;
x[1] = 70;
kdt.insert(x);
x[0] = 50;
x[1] = 30;
kdt.insert(x);
System.out.println("Input Elements");
System.out.println("(30,40) (5,25) (10,12) (70,70) (50,30)\n\n");
System.out.println("Printing KD Tree in Inorder");
kdt.inorder();
System.out.println("\nPrinting KD Tree in PreOder");
kdt.preorder();
System.out.println("\nPrinting KD Tree in PostOrder");
kdt.postorder();
System.out.println("\nsearching...............");
x[0]=40;x[1]=40;
System.out.println(kdt.search(x));
}
}