关于Kd树啊,可能很多人没听说过。
Kd树是 K-dimension tree 的缩写,是对数据点在 K维空间(如二维(x,y),三维(x,y,z),K维(x,y,z, …))中划分的一种高维索引树形数据结构。Kd树是一种空间划分树,说白了,就是把整个空间划分为特定的几个部分,然后在特定空间的部分内进行相关搜索操作。
Kd树从BST(Binary search tree)发展而来,在划分好的特定空间的部分内进行相关搜索操作。Kd树也是一种平衡二叉树。
Kd树主要应用于多维空间关键数据的搜索,常用于大规模高维数据密集的查找比对的使用场景中,主要是最近邻查找(Nearest Neighbor)以及近似最近邻查找(Approximate Nearest Neighbor)。在计算机视觉(CV)中主要是图像检索和识别中的高维特征向量的查找和比对。 (本段文字参考自下面的这篇文章)
这里我们简单地实现一个二维划分的Kd树,二维的呦~。
二维Kd树实现代码
/**
* Quick illustration of a two-dimensional tree.
*/
public class KdTree<T extends Comparable<? super T>> {
private static class KdNode<T> {
T[] data;
KdNode<T> left;
KdNode<T> right;
@SuppressWarnings("unchecked")
KdNode(T[] item) {
data = (T[]) new Comparable[2];
data[0] = item[0];
data[1] = item[1];
left = right = null;
}
}
private KdNode<T> root;
public KdTree() {
root = null;
}
public void insert(T[] x) {
root = insert(x, root, 0);
}
private KdNode<T> insert(T[] x, KdNode<T> t, int level) {
if(t == null) {
t = new KdNode<>(x);
} else if( x[level].compareTo(t.data[level] ) < 0) {
t.left = insert(x, t.left, 1 - level);
} else {
t.right = insert(x, t.right, 1 - level);
}
return t;
}
/**
* Print items satisfying
* low[0] <= x[0] <= high[0] and
* low[1] <= x[1] <= high[1].
*/
public void printRange(T[] low, T[] high) {
printRange(low, high, root, 0);
}
private void printRange(T[] low, T[] high, KdNode<T> t, int level) {
if(t != null) {
if(low[0].compareTo(t.data[0]) <= 0 && low[1].compareTo(t.data[1] ) <= 0 &&
high[0].compareTo(t.data[0]) >= 0 && high[1].compareTo(t.data[1]) >= 0) {
System.out.println("(" + t.data[ 0 ] + "," + t.data[ 1 ] + ")");
}
if(low[level].compareTo(t.data[level]) <= 0) {
printRange(low, high, t.left, 1-level);
}
if(high[level].compareTo(t.data[level]) >= 0) {
printRange(low, high, t.right, 1-level);
}
}
}
}
测试
public class KdTreeTest {
public static void main(String [] args) {
KdTree<Integer> t = new KdTree<>();
System.out.println("Starting program");
for(int i = 300; i < 370; i++) {
Integer [] it = new Integer[2];
it[0] = i;
it[1] = 2500-i;
t.insert(it);
}
Integer [] low = {70, 2186};
Integer [] high = {1200, 2200};
t.printRange(low, high);
}
}
测试结果:
Starting program
(300,2200)
(301,2199)
(302,2198)
(303,2197)
(304,2196)
(305,2195)
(306,2194)
(307,2193)
(308,2192)
(309,2191)
(310,2190)
(311,2189)
(312,2188)
(313,2187)
(314,2186)