文章

KD-Tree

KD树

KD树 KD-Tree(k-dimensional tree的简称), 可以实现k近邻搜索, 构造kd树相当于不断地用垂直于坐标轴的超平面将k维空间切分 k-d树每个结点都是k维的点二叉树, 所有非叶子节点可以看作用超平面把空间分成两个部分, 节点左子树代表超平面左边的点, 右子树代表右边的点
适合需要进行相邻区间和查询的情况, 比如需要找到一个点附近的一些点, 维护这些点之间的状态, 就可以用八叉树 适用KD树的情况:数据量大,且点位更新不频繁

建树

建树流程: 取任意维度, 然后取该维度中位点, 由该点按该维度将树划分成左右两部分, 对划分后的部分依次重复次操作,直到划分后没有子树 如以下6个点:(5,4) (2,3) (9,6) (7,2) (8,1) (4,7) , 建树结果如下:
Desktop View

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
public class KDTreeNode
{
    public KDTreeNode lchild;
    public KDTreeNode rchild;
    public Vector2 pos;
    public KDTreeNode(Vector2 position)
    {
        pos = position;
    }
}

public class CompareVector : IComparer<Vector2>
{
    int m_dimension;
    public CompareVector(int dimension)
    {
        m_dimension = dimension;
    }
    public int Compare(Vector2 x, Vector2 y)
    {
        return x[m_dimension].CompareTo(y[m_dimension]);
    }
}

public class KDTree
{
    //KD树根节点
    public KDTreeNode rootNode;
    public KDTree(Vector2[] nodes)
    {
        int dimension = 0;
        rootNode = BuildTree(nodes, 0, nodes.Length, dimension);
        PrintTree(rootNode);
    }

    KDTreeNode BuildTree(Vector2[] nodes, int index, int length, int dimension)
    {
        if (length <= 0)
        {
            return null;
        }
        if (length == 1)
        {
            return new KDTreeNode(nodes[index]);
        }
        Array.Sort(nodes, index, length, new CompareVector(dimension));

        //在数量为偶数时,取中点有不同取法, 这里选择数值较大点
        int midIndex = index + length / 2;// - (length % 2 == 0 && dimension == 0 ? 1 : 0);
        KDTreeNode tep;
        tep = new KDTreeNode(nodes[midIndex]);
        tep.lchild = BuildTree(nodes, index, midIndex - index, (dimension + 1) % 2);
        tep.rchild = BuildTree(nodes, midIndex + 1, length - (midIndex - index + 1), (dimension + 1) % 2);
        return tep;
    }
}

本文由作者按照 CC BY 4.0 进行授权