📜  K维树|设置1(搜索和插入)

📅  最后修改于: 2021-04-17 10:30:49             🧑  作者: Mango

KD树(也称为K维树)是一种二叉搜索树,其中每个节点中的数据是空间中的K维点。简而言之,它是用于组织K维空间中的点的空间划分(详细信息)数据结构。

KD树中的非叶节点将空间分为两部分,称为半空间。

该空间左侧的点由该节点的左侧子树表示,空间右侧的点由右侧子树表示。我们将在不久的将来解释关于如何划分空间和形成树的概念。

为了简单起见,让我们通过示例来了解2D树。

根将具有x对齐的平面,根的子代都将具有y对齐的平面,根的孙子都将具有x对齐的平面,而根的曾孙将具有y对齐的平面,依此类推。

概括:
让我们将平面编号为0、1、2…(K – 1)。从上面的示例中可以很清楚地看到,深度为D的点(节点)将具有A对齐平面,其中A的计算公式为:

A = D mod K

如何确定一个点将位于左侧子树还是右侧子树中?

如果根节点在平面A中对齐,则左子树将包含其平面中的坐标小于根节点坐标的所有点。同样,右子树将包含其平面上的坐标等于根节点坐标的所有点。

创建二维树:
考虑二维平面中的以下点:
(3,6),(17,15),(13,15),(6,12),(9,1),(2,7),(10,19)

  1. 插入(3,6):由于树为空,因此使其成为根节点。
  2. 插入(17,15):将其与根节点点进行比较。由于根节点是X对齐的,因此将比较X坐标值以确定它是在右子树中还是在右子树中。这一点将是Y对齐的。
  3. 插入(13,15):此点的X值大于根节点中点的X值。因此,这将位于(3,6)的右子树中。再次将该点的Y值与点(17,15)的Y值进行比较(为什么?)。因为它们相等,所以这一点将位于(17,15)的右子树中。这一点将是X对齐的。
  4. 插入(6,12):此点的X值大于根节点中点的X值。因此,这将位于(3,6)的右子树中。再次将该点的Y值与点(17,15)的Y值进行比较(为什么?)。由于12 <15,因此该点将位于(17,15)的左子树中。这一点将是X对齐的。
  5. 插入(9,1):类似地,该点位于(6,12)的右侧。
  6. 插入(2,7):类似地,该点位于(3,6)的左侧。
  7. 插入(10,19):同样,该点位于(13,15)的左侧。

ktree_1

空间如何划分?
所有7个点将在XY平面中绘制如下:

  1. 点(3,6)会将空间分为两部分:画线X = 3。
  2. 点(2,7)将X = 3线左侧的空间水平分成两部分。
    在X = 3线的左侧绘制Y = 7线。
  3. 点(17,15)将X = 3线右边的空间水平分成两部分。
    在X = 3线的右边绘制Y = 15线。
  • 点(6,12)将Y = 15线下方和X = 3线右侧的空间分成两部分。
    在X = 3线的右侧和Y = 15线下方绘制X = 6线。
  • 点(13,15)将Y = 15线下方和X = 6线右侧的空间分成两部分。
    在X = 6线的右侧和Y = 15线下方绘制X = 13线。
  • 点(9,1)将X = 3,X = 6和Y = 15的线分成两部分。
    在X = 3和X = 6之间绘制Y = 1线。
  • 点(10,19)将X = 3线右侧和Y = 15线上方的空间分成两部分。
    在X = 3线的右侧和Y = 15线的上方绘制Y = 19线。

以下是KD Tree基本操作(例如搜索,插入和删除)的C++实现。

// A C++ program to demonstrate operations of KD tree
#include
using namespace std;
  
const int k = 2;
  
// A structure to represent node of kd tree
struct Node
{
    int point[k]; // To store k dimensional point
    Node *left, *right;
};
  
// A method to create a node of K D tree
struct Node* newNode(int arr[])
{
    struct Node* temp = new Node;
  
    for (int i=0; ipoint[i] = arr[i];
  
    temp->left = temp->right = NULL;
    return temp;
}
  
// Inserts a new node and returns root of modified tree
// The parameter depth is used to decide axis of comparison
Node *insertRec(Node *root, int point[], unsigned depth)
{
    // Tree is empty?
    if (root == NULL)
       return newNode(point);
  
    // Calculate current dimension (cd) of comparison
    unsigned cd = depth % k;
  
    // Compare the new point with root on current dimension 'cd'
    // and decide the left or right subtree
    if (point[cd] < (root->point[cd]))
        root->left  = insertRec(root->left, point, depth + 1);
    else
        root->right = insertRec(root->right, point, depth + 1);
  
    return root;
}
  
// Function to insert a new point with given point in
// KD Tree and return new root. It mainly uses above recursive
// function "insertRec()"
Node* insert(Node *root, int point[])
{
    return insertRec(root, point, 0);
}
  
// A utility method to determine if two Points are same
// in K Dimensional space
bool arePointsSame(int point1[], int point2[])
{
    // Compare individual pointinate values
    for (int i = 0; i < k; ++i)
        if (point1[i] != point2[i])
            return false;
  
    return true;
}
  
// Searches a Point represented by "point[]" in the K D tree.
// The parameter depth is used to determine current axis.
bool searchRec(Node* root, int point[], unsigned depth)
{
    // Base cases
    if (root == NULL)
        return false;
    if (arePointsSame(root->point, point))
        return true;
  
    // Current dimension is computed using current depth and total
    // dimensions (k)
    unsigned cd = depth % k;
  
    // Compare point with root with respect to cd (Current dimension)
    if (point[cd] < root->point[cd])
        return searchRec(root->left, point, depth + 1);
  
    return searchRec(root->right, point, depth + 1);
}
  
// Searches a Point in the K D tree. It mainly uses
// searchRec()
bool search(Node* root, int point[])
{
    // Pass current depth as 0
    return searchRec(root, point, 0);
}
  
// Driver program to test above functions
int main()
{
    struct Node *root = NULL;
    int points[][k] = {{3, 6}, {17, 15}, {13, 15}, {6, 12},
                       {9, 1}, {2, 7}, {10, 19}};
  
    int n = sizeof(points)/sizeof(points[0]);
  
    for (int i=0; i

输出:

Found
Not Found
 

请参阅以下文章,以查找最小和删除操作。

  • KD树(查找最小值)
  • KD树(删除)