-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKDTree.java
More file actions
189 lines (163 loc) · 4.66 KB
/
KDTree.java
File metadata and controls
189 lines (163 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package gfg.ds.advanced;
import java.util.Arrays;
/** @noinspection WeakerAccess */
public class KDTree {
public KDNode root;
public int degree;
public KDTree(int degree) {
this.degree = degree;
}
/** t=O(log n) */
public boolean search(KDNode node) {
assert node.degree == degree;
int depth = 0;
for (KDNode curr = root; curr != null; depth++) {
if (curr.equals(node)) {
return true;
}
curr = node.get(depth % degree) < curr.get(depth % degree) ? curr.left : curr.right;
}
return false;
}
/** t=O(log n) */
public KDTree insert(KDNode node) {
assert node.degree == degree;
if (isEmpty()) {
root = node.copy();
return this;
}
KDNode curr = root;
KDNode prev = null;
int depth = 0;
for (; curr != null; depth++) {
prev = curr;
curr = node.get(depth % degree) < curr.get(depth % degree) ? curr.left : curr.right;
}
// Prev is empty only if tree is empty but we are checking that before hand.
assert prev != null;
if (node.get((depth - 1) % degree) < prev.get((depth - 1) % degree)) {
prev.left = node.copy();
} else {
prev.right = node.copy();
}
return this;
}
public boolean isEmpty() {
return root == null;
}
/** todo time complexity */
public KDNode getMin(int dimension) {
return getMinUtil(root, 0, dimension);
}
private KDNode getMinUtil(KDNode root, int depth, int dimension) {
if (root == null) {
return null;
}
if (dimension == depth % degree) {
return min(root, getMinUtil(root.left, depth + 1, dimension), dimension);
}
return min(
root,
min(
getMinUtil(root.left, depth + 1, dimension),
getMinUtil(root.right, depth + 1, dimension),
dimension),
dimension);
}
private KDNode min(KDNode first, KDNode second, int dimension) {
if (first == null) {
return second;
}
if (second == null) {
return first;
}
return first.get(dimension) < second.get(dimension) ? first : second;
}
/** todo time complexity */
public KDTree delete(KDNode node) {
assert node.degree == degree;
assert !isEmpty() : "Empty tree";
KDNode curr = root;
KDNode prev = null;
int depth = 0;
for (; curr != null; depth++) {
if (curr.equals(node)) {
break;
}
prev = curr;
curr = node.get(depth % degree) < curr.get(depth % degree) ? curr.left : curr.right;
}
if (curr == null) {
throw new RuntimeException("Element not found");
}
if (curr.right == null && curr.left == null) {
if (prev == null) {
root = null;
} else {
if (prev.left == curr) {
prev.left = null;
} else {
prev.right = null;
}
}
} else {
KDNode min = getMinUtil(curr.right != null ? curr.right : curr.left, 0, depth % degree);
delete(min);
min.left = curr.left;
min.right = curr.right;
if (prev == null) {
root = min;
} else {
/* The case where we have both right and left subtrees or only right subtree we search for the minimum
* and replace it with the to-be-deleted node.
* The case where we have only left subtree we make it a right subtree. It could be better visualized
* when trying to draw this on paper and see what is happening.
*/
prev.right = min;
}
}
return this;
}
public static class KDNode {
public int degree;
private int data[];
public KDNode left, right;
public KDNode(int degree) {
this.degree = degree;
this.data = new int[degree];
}
public int get(int dimension) {
assert dimension < degree;
return data[dimension];
}
public static KDNode of(int degree, int... values) {
assert values.length == degree;
KDNode node = new KDNode(degree);
System.arraycopy(values, 0, node.data, 0, degree);
return node;
}
public KDNode copy() {
KDNode copy = new KDNode(degree);
System.arraycopy(data, 0, copy.data, 0, degree);
return copy;
}
@Override
public String toString() {
return "KDNode{" + "degree=" + degree + ", data=" + Arrays.toString(data) + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KDNode node = (KDNode) o;
if (degree != node.degree) return false;
return Arrays.equals(data, node.data);
}
@Override
public int hashCode() {
int result = degree;
result = 31 * result + Arrays.hashCode(data);
return result;
}
}
}