K-Dimensional (K-D) Trees in Datastructures



The K-D is a multi-dimensional binary search tree. It is defined as a data structure for storing multikey records. This structure has been implemented to solve a number of "geometric" problems in statistics and data analysis.

A k-d tree (short for k-dimensional tree) is defined as a space-partitioning data structure for organizing points in a k-dimensional space. Data structure k-d trees are implemented for several applications, for example, searches involving a multidimensional search key (e.g. range searches and nearest neighbor searches). k-d trees are treated as a special case of binary space partitioning trees.

Properties of K-D Trees

Following are the properties of k-d trees:

  • The depth of the k-d tree is O(log n) where n is the number of points.
  • Each node in the tree contains a k-dimensional point and pointers to the left and right child nodes.
  • The choice of the axis at each level of the tree follows a cycle through the axes.
  • And choice of axis at each level will affect's the tree's performance in terms of search speed.

Operations on K-D Trees

Following are the operations that can be performed on k-d trees:

  • Insert(x): Insert a point x into the k-d tree.
  • Delete(x): Delete a point x from the k-d tree.
  • Search(x): Search for a point x in the k-d tree.

Construction of K-D Trees

The construction of k-d trees is done by using recursive partitioning. The steps to construct a k-d tree are as follows:

  • Choose the axis of the splitting plane.
  • Choose the median as the pivot element.
  • Split the points into two sets: one set contains points less than the median and the other set contains points greater than the median.
  • Repeat the above steps for the left and right subtrees.

Now, let's code the construction of k-d trees:

Code to Construct K-D Trees and Insert Operation

We performed insert operation in order to construct a k-d tree.

Following is the example code to construct a k-d tree in C, C++, Java, and Python:

#include <stdio.h>
#include <stdlib.h>

// Structure to represent a node of the k-d tree
struct Node {
   int point[2];
   struct Node *left, *right;
};

// Function to create a new node
struct Node* newNode(int arr[]) {
   struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
   temp->point[0] = arr[0];
   temp->point[1] = arr[1];
   temp->left = temp->right = NULL;
   return temp;
}

// Function to insert a new node
struct Node* insertNode(struct Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return newNode(point);

   unsigned cd = depth % 2;

   if (point[cd] < (root->point[cd]))
      root->left = insertNode(root->left, point, depth + 1);
   else
      root->right = insertNode(root->right, point, depth + 1);

   return root;
}

// Function to construct a k-d tree
struct Node* constructKdTree(int points[][2], int n) {
   struct Node* root = NULL;
   for (int i = 0; i < n; i++)
      root = insertNode(root, points[i], 0);
   return root;
}

// Function to print the k-d tree (Preorder Traversal)
void printKdTree(struct Node* root) {
   if (root == NULL)
      return;
   printf("(%d, %d)\n", root->point[0], root->point[1]);
   printKdTree(root->left);
   printKdTree(root->right);
}

// Main function
int main() {
   int points[][2] = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
   int n = sizeof(points) / sizeof(points[0]);
   struct Node* root = constructKdTree(points, n);
   printKdTree(root);
   return 0;
}

Output

(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
// C++ program to construct a k-d tree
#include <iostream>
using namespace std;

// Structure to represent a node of the k-d tree
struct Node {
   int point[2];
   Node *left, *right;
};

// Function to create a new node
Node* newNode(int arr[]) {
   Node* temp = new Node;
   temp->point[0] = arr[0];
   temp->point[1] = arr[1];
   temp->left = temp->right = NULL;
   return temp;
}

// Function to insert a new node
Node* insertNode(Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return newNode(point);

   unsigned cd = depth % 2;

   if (point[cd] < (root->point[cd]))
      root->left = insertNode(root->left, point, depth + 1);
   else
      root->right = insertNode(root->right, point, depth + 1);

   return root;
}

// Function to construct a k-d tree
Node* constructKdTree(int points[][2], int n) {
   Node* root = NULL;
   for (int i = 0; i < n; i++)
      root = insertNode(root, points[i], 0);
   return root;
}

// Function to print the k-d tree
void printKdTree(Node* root) {
   if (root == NULL)
      return;
   cout << "(" << root->point[0] << ", " << root->point[1] << ")" << endl;
   printKdTree(root->left);
   printKdTree(root->right);
}

// Main function
int main() {
   int points[][2] = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
   int n = sizeof(points) / sizeof(points[0]);
   Node* root = constructKdTree(points, n);
   printKdTree(root);
   return 0;
}

Output

Following is the output of the above code:

(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
// Java program to construct a k-d tree
class Node {
   int[] point;
   Node left, right;
   Node(int[] point) {
      this.point = point;
      this.left = this.right = null;
   }
}

public class KdTree {
   Node root;

   Node insertNode(Node root, int[] point, int depth) {
      if (root == null)
         return new Node(point);

      int cd = depth % 2;

      if (point[cd] < root.point[cd])
         root.left = insertNode(root.left, point, depth + 1);
      else
         root.right = insertNode(root.right, point, depth + 1);

      return root;
   }

   Node constructKdTree(int[][] points) {
      for (int i = 0; i < points.length; i++)
         root = insertNode(root, points[i], 0);
      return root;
   }

   void printKdTree(Node root) {
      if (root == null)
         return;
      System.out.println("(" + root.point[0] + ", " + root.point[1] + ")");
      printKdTree(root.left);
      printKdTree(root.right);
   }

   public static void main(String[] args) {
      int[][] points = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
      KdTree tree = new KdTree();
      tree.constructKdTree(points);
      tree.printKdTree(tree.root);
   }
}

Output

Following is the output of the above code:

(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
# Python program to construct a k-d tree
class Node:
   def __init__(self, point):
      self.point = point
      self.left = None
      self.right = None

def insertNode(root, point, depth):
    if root is None:
        return Node(point)
    
    cd = depth % 2
    
    if point[cd] < root.point[cd]:
        root.left = insertNode(root.left, point, depth + 1)
    else:
        root.right = insertNode(root.right, point, depth + 1)
    
    return root

def constructKdTree(points):
    root = None
    for point in points:
        root = insertNode(root, point, 0)
    return root

def printKdTree(root):
    if root is None:
        return
    print("(", root.point[0], ", ", root.point[1], ")")
    printKdTree(root.left)
    printKdTree(root.right)

points = [[3, 6], [17, 15], [13, 15], [6, 12], [9, 1], [2, 7], [10, 19]]
root = constructKdTree(points)
printKdTree(root)

Output

Following is the output of the above code:

(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)

Delete Operation on K-D Trees

The delete operation in k-d trees is performed by following the below steps:

  • Find the node to be deleted.
  • If the node is a leaf node, delete it directly.
  • If the node has only one child, replace the node with its child.
  • If the node has two children, find the inorder successor of the node, replace the node with the inorder successor, and delete the inorder successor.

Code to Delete a Node from K-D Trees

Following is the example code to delete a node from k-d trees in C, C++, Java, and Python:

// C program to delete a node from a k-d tree
#include <stdio.h>
#include <stdlib.h>

// Structure to represent a node of the k-d tree
struct Node {
   int point[2];
   struct Node *left, *right;
};

// Function to create a new node
struct Node* newNode(int arr[]) {
   struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
   temp->point[0] = arr[0];
   temp->point[1] = arr[1];
   temp->left = temp->right = NULL;
   return temp;
}

// Function to insert a new node
struct Node* insertNode(struct Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return newNode(point);

   unsigned cd = depth % 2;

   if (point[cd] < root->point[cd])
      root->left = insertNode(root->left, point, depth + 1);
   else
      root->right = insertNode(root->right, point, depth + 1);

   return root;
}

// Function to find the minimum value node in a k-d tree
struct Node* minValueNode(struct Node* root, int d, unsigned depth) {
   if (root == NULL)
      return NULL;

   unsigned cd = depth % 2;

   if (cd == d) {
      if (root->left == NULL)
         return root;
      return minValueNode(root->left, d, depth + 1);
   }

   struct Node* left = minValueNode(root->left, d, depth + 1);
   struct Node* right = minValueNode(root->right, d, depth + 1);

   struct Node* min = root;
   if (left != NULL && left->point[d] < min->point[d])
      min = left;
   if (right != NULL && right->point[d] < min->point[d])
      min = right;

   return min;
}

// Function to delete a node from the k-d tree
struct Node* deleteNode(struct Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return NULL;

   unsigned cd = depth % 2;

   if (root->point[0] == point[0] && root->point[1] == point[1]) {
      if (root->right != NULL) {
         struct Node* min = minValueNode(root->right, cd, depth + 1);
         root->point[0] = min->point[0];
         root->point[1] = min->point[1];
         root->right = deleteNode(root->right, min->point, depth + 1);
      } else if (root->left != NULL) {
         struct Node* min = minValueNode(root->left, cd, depth + 1);
         root->point[0] = min->point[0];
         root->point[1] = min->point[1];
         root->right = deleteNode(root->left, min->point, depth + 1);
         root->left = NULL;
      } else {
         free(root);
         return NULL;
      }
   } else if (point[cd] < root->point[cd]) {
      root->left = deleteNode(root->left, point, depth + 1);
   } else {
      root->right = deleteNode(root->right, point, depth + 1);
   }

   return root;
}

// Function to construct a k-d tree
struct Node* constructKdTree(int points[][2], int n) {
   struct Node* root = NULL;
   for (int i = 0; i < n; i++)
      root = insertNode(root, points[i], 0);
   return root;
}

// Function to print the k-d tree (Preorder Traversal)
void printKdTree(struct Node* root) {
   if (root == NULL)
      return;
   printf("(%d, %d)\n", root->point[0], root->point[1]);
   printKdTree(root->left);
   printKdTree(root->right);
}

// Main function
int main() {
   int points[][2] = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
   int n = sizeof(points) / sizeof(points[0]);
   struct Node* root = constructKdTree(points, n);
   
   printf("K-D Tree before deletion:\n");
   printKdTree(root);

   int deletePoint[] = {13, 15}; // Deleting (13, 15)
   root = deleteNode(root, deletePoint, 0);

   printf("K-D Tree after deletion:\n");
   printKdTree(root);

   return 0;
}

Output

K-D Tree before deletion:
(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
K-D Tree after deletion:
(3, 6)
(2, 7)
(17, 15)
(6, 12)
(9, 1)
(10, 19)
// C++ program to delete a node from a k-d tree
#include <iostream>
using namespace std;

// Structure to represent a node of the k-d tree
struct Node {
   int point[2];
   Node *left, *right;
};

// Function to create a new node
Node* newNode(int arr[]) {
   Node* temp = new Node;
   temp->point[0] = arr[0];
   temp->point[1] = arr[1];
   temp->left = temp->right = NULL;
   return temp;
}

// Function to insert a new node
Node* insertNode(Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return newNode(point);

   unsigned cd = depth % 2;

   if (point[cd] < (root->point[cd]))
      root->left = insertNode(root->left, point, depth + 1);
   else
      root->right = insertNode(root->right, point, depth + 1);

   return root;
}

// Function to find the minimum value node
Node* minValueNode(Node* root, int d, unsigned depth) {
   if (root == NULL)
      return NULL;

   unsigned cd = depth % 2;

   if (cd == d) {
      if (root->left == NULL)
         return root;
      return minValueNode(root->left, d, depth + 1);
   }

   Node* left = minValueNode(root->left, d, depth + 1);
   Node* right = minValueNode(root->right, d, depth + 1);

   Node* min = root;
   if (left != NULL && left->point[d] < min->point[d])
      min = left;
   if (right != NULL && right->point[d] < min->point[d])
      min = right;

   return min;
}

// Function to delete a node

Node* deleteNode(Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return NULL;

   unsigned cd = depth % 2;

   if (root->point[0] == point[0] && root->point[1] == point[1]) {
      if (root->right != NULL) {
         Node* min = minValueNode(root->right, cd, depth + 1);
         root->point[0] = min->point[0];
         root->point[1] = min->point[1];
         root->right = deleteNode(root->right, min->point, depth + 1);
      } else if (root->left != NULL) {
         Node* min = minValueNode(root->left, cd, depth + 1);
         root->point[0] = min->point[0];
         root->point[1] = min->point[1];
         root->right = deleteNode(root->left, min->point, depth + 1);
         root->left = NULL;
      } else
         return NULL;
   } else if (point[cd] < root->point[cd])
      root->left = deleteNode(root->left, point, depth + 1);
   else
      root->right = deleteNode(root->right, point, depth + 1);

   return root;
}

// Function to construct a k-d tree
Node* constructKdTree(int points[][2], int n) {
   Node* root = NULL;
   for (int i = 0; i < n; i++)
      root = insertNode(root, points[i], 0);
   return root;
}

// Function to print the k-d tree
void printKdTree(Node* root) {
   if (root == NULL)
      return;
   cout << "(" << root->point[0] << ", " << root->point[1] << ")" << endl;
   printKdTree(root->left);
   printKdTree(root->right);
}

// Main function
int main() {
   int points[][2] = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
   int n = sizeof(points) / sizeof(points[0]);
   Node* root = constructKdTree(points, n);
   cout << "K-D Tree before deletion:" << endl;
   printKdTree(root);
   root = deleteNode(root, points[2], 0);
   cout << "K-D Tree after deletion:" << endl;
   printKdTree(root);
   return 0;
}

Output

Following is the output of the above code:

K-D Tree before deletion:
(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
K-D Tree after deletion:
(3, 6)
(2, 7)
(17, 15)
(6, 12)
(9, 1)
(10, 19)
// Java program to delete a node from a k-d tree
class Node {
   int[] point;
   Node left, right;
   Node(int[] point) {
      this.point = point;
      this.left = this.right = null;
   }
}

public class KdTree {
   Node root;

   Node insertNode(Node root, int[] point, int depth) {
      if (root == null)
         return new Node(point);

      int cd = depth % 2;

      if (point[cd] < root.point[cd])
         root.left = insertNode(root.left, point, depth + 1);
      else
         root.right = insertNode(root.right, point, depth + 1);

      return root;
   }

   Node minValueNode(Node root, int d, int depth) {
      if (root == null)
         return null;

      int cd = depth % 2;

      if (cd == d) {
         if (root.left == null)
            return root;
         return minValueNode(root.left, d, depth + 1);
      }

      Node left = minValueNode(root.left, d, depth + 1);
      Node right = minValueNode(root.right, d, depth + 1);

      Node min = root;
      if (left != null && left.point[d] < min.point[d])
         min = left;
      if (right != null && right.point[d] < min.point[d])
         min = right;

      return min;
   }

   Node deleteNode(Node root, int[] point, int depth) {
      if (root == null)
         return null;

      int cd = depth % 2;

      if (root.point[0] == point[0] && root.point[1] == point[1]) {
         if (root.right != null) {
            Node min = minValueNode(root.right, cd, depth + 1);
            root.point[0] = min.point[0];
            root.point[1] = min.point[1];
            root.right = deleteNode(root.right, min.point, depth + 1);
         } else if (root.left != null) {
            Node min = minValueNode(root.left, cd, depth + 1);
            root.point[0] = min.point[0];
            root.point[1] = min.point[1];
            root.right = deleteNode(root.left, min.point, depth + 1);
            root.left = null;
         } else
            return null;
      } else if (point[cd] < root.point[cd])
         root.left = deleteNode(root.left, point, depth + 1);
        else
            root.right = deleteNode(root.right, point, depth + 1);

        return root;
    }

    void printKdTree(Node root) {
        if (root == null)
            return;
        System.out.println("(" + root.point[0] + ", " + root.point[1] + ")");
        printKdTree(root.left);
        printKdTree(root.right);
    }

    public static void main(String[] args) {
        int[][] points = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
        KdTree tree = new KdTree();
        for (int[] point : points)
            tree.root = tree.insertNode(tree.root, point, 0);
        System.out.println("K-D Tree before deletion:");
        tree.printKdTree(tree.root);
        tree.root = tree.deleteNode(tree.root, points[2], 0);
        System.out.println("K-D Tree after deletion:");
        tree.printKdTree(tree.root);
    }
}

Output

Following is the output of the above code:

K-D Tree before deletion:
(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
K-D Tree after deletion:
(3, 6)
(2, 7)
(17, 15)
(6, 12)
(9, 1)
(10, 19)
# Python program to delete a node from a k-d tree
class Node:
   def __init__(self, point):
      self.point = point
      self.left = None
      self.right = None

def insertNode(root, point, depth):

    if root is None:
        return Node(point)
    
    cd = depth % 2
    
    if point[cd] < root.point[cd]:
        root.left = insertNode(root.left, point, depth + 1)
    else:
        root.right = insertNode(root.right, point, depth + 1)
    
    return root

def minValueNode(root, d, depth):

    if root is None:
        return None
    
    cd = depth % 2
    
    if cd == d:
        if root.left is None:
            return root
        return minValueNode(root.left, d, depth + 1)
    
    left = minValueNode(root.left, d, depth + 1)
    right = minValueNode(root.right, d, depth + 1)
    
    min = root
    if left is not None and left.point[d] < min.point[d]:
        min = left
    if right is not None and right.point[d] < min.point[d]:
        min = right
    
    return min

def deleteNode(root, point, depth):

    if root is None:
        return None
    
    cd = depth % 2
    
    if root.point[0] == point[0] and root.point[1] == point[1]:
        if root.right is not None:
            min = minValueNode(root.right, cd, depth + 1)
            root.point[0] = min.point[0]
            root.point[1] = min.point[1]
            root.right = deleteNode(root.right, min.point, depth + 1)
        elif root.left is not None:
            min = minValueNode(root.left, cd, depth + 1)
            root.point[0] = min.point[0]
            root.point[1] = min.point[1]
            root.right = deleteNode(root.left, min.point, depth + 1)
            root.left = None
        else:
            return None
    elif point[cd] < root.point[cd]:
        root.left = deleteNode(root.left, point, depth + 1)
    else:
        root.right = deleteNode(root.right, point, depth + 1)
    
    return root

def printKdTree(root):
    if root is None:
        return
    print("(", root.point[0], ", ", root.point[1], ")")
    printKdTree(root.left)
    printKdTree(root.right)

points = [[3, 6], [17, 15], [13, 15], [6, 12], [9, 1], [2, 7], [10, 19]]
root = None
for point in points:
    root = insertNode(root, point, 0)
print("K-D Tree before deletion:")
printKdTree(root)
root = deleteNode(root, points[2], 0)
print("K-D Tree after deletion:")
printKdTree(root)

Output

Following is the output of the above code:

K-D Tree before deletion:
(3, 6)
(2, 7)
(17, 15)
(13, 15)
(6, 12)
(9, 1)
(10, 19)
K-D Tree after deletion:
(3, 6)
(2, 7)
(17, 15)
(6, 12)
(9, 1)
(10, 19)

Search Operation on K-D Trees

The search operation in k-d trees is performed by following the below steps:

  • Start from the root node.
  • If the point is equal to the root node, return the root node.
  • If the point is less than the root node, search in the left subtree.
  • If the point is greater than the root node, search in the right subtree.

Code to Search a Node in K-D Trees

Following is the example code to search a node in k-d trees in C, C++, Java, and Python:

#include <stdio.h>
#include <stdlib.h>

// Structure to represent a node of the k-d tree
struct Node {
   int point[2];
   struct Node *left, *right;
};

// Function to create a new node
struct Node* newNode(int arr[]) {
   struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
   temp->point[0] = arr[0];
   temp->point[1] = arr[1];
   temp->left = temp->right = NULL;
   return temp;
}

// Function to insert a new node
struct Node* insertNode(struct Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return newNode(point);

   unsigned cd = depth % 2;

   if (point[cd] < root->point[cd])
      root->left = insertNode(root->left, point, depth + 1);
   else
      root->right = insertNode(root->right, point, depth + 1);

   return root;
}

// Function to search a node in a k-d tree
struct Node* searchNode(struct Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return NULL;

   if (root->point[0] == point[0] && root->point[1] == point[1])
      return root;

   unsigned cd = depth % 2;

   if (point[cd] < root->point[cd])
      return searchNode(root->left, point, depth + 1);
   return searchNode(root->right, point, depth + 1);
}

// Function to construct a k-d tree
struct Node* constructKdTree(int points[][2], int n) {
   struct Node* root = NULL;
   for (int i = 0; i < n; i++)
      root = insertNode(root, points[i], 0);
   return root;
}


// Function to free memory allocated for the k-d tree
void freeKdTree(struct Node* root) {
   if (root == NULL)
      return;
   freeKdTree(root->left);
   freeKdTree(root->right);
   free(root);
}

// Main function
int main() {
   int points[][2] = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
   int n = sizeof(points) / sizeof(points[0]);
   struct Node* root = constructKdTree(points, n);


   int searchPoint[] = {13, 15}; // Searching for (13, 15)
   struct Node* node = searchNode(root, searchPoint, 0);

   if (node != NULL)
      printf("Node found: (%d, %d)\n", node->point[0], node->point[1]);
   else
      printf("Node not found\n");

   // Free allocated memory
   freeKdTree(root);

   return 0;
}

Output

Node found: (13, 15)
// C++ program to search a node in a k-d tree
#include <iostream>
using namespace std;

// Structure to represent a node of the k-d tree
struct Node {
   int point[2];
   Node *left, *right;
};

// Function to create a new node
Node* newNode(int arr[]) {
   Node* temp = new Node;
   temp->point[0] = arr[0];
   temp->point[1] = arr[1];
   temp->left = temp->right = NULL;
   return temp;
}

// Function to insert a new node
Node* insertNode(Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return newNode(point);

   unsigned cd = depth % 2;

   if (point[cd] < (root->point[cd]))
      root->left = insertNode(root->left, point, depth + 1);
   else
      root->right = insertNode(root->right, point, depth + 1);

   return root;
}

// Function to search a node
Node* searchNode(Node* root, int point[], unsigned depth) {
   if (root == NULL)
      return NULL;

   unsigned cd = depth % 2;

   if (root->point[0] == point[0] && root->point[1] == point[1])
      return root;

   if (point[cd] < root->point[cd])
      return searchNode(root->left, point, depth + 1);
   return searchNode(root->right, point, depth + 1);
}

// Function to construct a k-d tree

Node* constructKdTree(int points[][2], int n) {
   Node* root = NULL;
   for (int i = 0; i < n; i++)
      root = insertNode(root, points[i], 0);
   return root;
}

// Function to print the k-d tree
void printKdTree(Node* root) {
   if (root == NULL)
      return;
   cout << "(" << root->point[0] << ", " << root->point[1] << ")" << endl;
   printKdTree(root->left);
   printKdTree(root->right);
}

// Main function

int main() {
   int points[][2] = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
   int n = sizeof(points) / sizeof(points[0]);
   Node* root = constructKdTree(points, n);
   Node* node = searchNode(root, points[2], 0);
   if (node != NULL)
      cout << "Node found: (" << node->point[0] << ", " << node->point[1] << ")" << endl;
   else
      cout << "Node not found" << endl;
   return 0;
}

Output

Following is the output of the above code:

Node found: (13, 15)
// Java program to search a node in a k-d tree
class Node {
   int[] point;
   Node left, right;
   Node(int[] point) {
      this.point = point;
      this.left = this.right = null;
   }
}

public class KdTree {
   Node root;

   Node insertNode(Node root, int[] point, int depth) {
      if (root == null)
         return new Node(point);

      int cd = depth % 2;

      if (point[cd] < root.point[cd])
         root.left = insertNode(root.left, point, depth + 1);
      else
         root.right = insertNode(root.right, point, depth + 1);

      return root;
   }

   Node searchNode(Node root, int[] point, int depth) {
      if (root == null)
         return null;

      int cd = depth % 2;

      if (root.point[0] == point[0] && root.point[1] == point[1])
         return root;

      if (point[cd] < root.point[cd])
         return searchNode(root.left, point, depth + 1);
      return searchNode(root.right, point, depth + 1);
   }

   void printKdTree(Node root) {
      if (root == null)
         return;
      System.out.println("(" + root.point[0] + ", " + root.point[1] + ")");
      printKdTree(root.left);
      printKdTree(root.right);
   }

   public static void main(String[] args) {
      int[][] points = {{3, 6}, {17, 15}, {13, 15}, {6, 12}, {9, 1}, {2, 7}, {10, 19}};
      KdTree tree = new KdTree();
      for (int[] point : points)
         tree.root = tree.insertNode(tree.root, point, 0);
      Node node = tree.searchNode(tree.root, points[2], 0);
      if (node != null)
         System.out.println("Node found: (" + node.point[0] + ", " + node.point[1] + ")");
      else
         System.out.println("Node not found");
   }
}

Output

Following is the output of the above code:

Node found: (13, 15)
# Python program to search a node in a k-d tree

class Node:
   def __init__(self, point):
      self.point = point
      self.left = None
      self.right = None

def insertNode(root, point, depth):
    if root is None:
        return Node(point)
    
    cd = depth % 2
    
    if point[cd] < root.point[cd]:
        root.left = insertNode(root.left, point, depth + 1)
    else:
        root.right = insertNode(root.right, point, depth + 1)
    
    return root

def searchNode(root, point, depth):
    if root is None:
        return None
    
    cd = depth % 2
    
    if root.point[0] == point[0] and root.point[1] == point[1]:
        return root
    
    if point[cd] < root.point[cd]:
        return searchNode(root.left, point, depth + 1)
    return searchNode(root.right, point, depth + 1)

def printKdTree(root):
    if root is None:
        return
    print("(", root.point[0], ", ", root.point[1], ")")
    printKdTree(root.left)
    printKdTree(root.right)

points = [[3, 6], [17, 15], [13, 15], [6, 12], [9, 1], [2, 7], [10, 19]]
root = None
for point in points:
    root = insertNode(root, point, 0)
node = searchNode(root, points[2], 0)
if node is not None:
    print("Node found: (", node.point[0], ", ", node.point[1], ")")
else:
    print("Node not found")

Output

Following is the output of the above code:

Node found: (13, 15)

Time Complexity of K-D Trees

The time complexity of k-d trees for various operations is as follows:

  • Insertion: The time complexity of inserting a node in a k-d tree is O(log n), where n is the number of nodes in the tree.
  • Deletion: O(log n).
  • Search: O(log n).

Applications of K-D Trees

K-D trees are used in the following applications:

  • Nearest Neighbor Search: K-D trees are used for finding the nearest neighbor of a given point in a k-dimensional space.
  • Range Search: K-D trees are used to find all points within a given range of a query point.
  • Approximate Nearest Neighbor Search: K-D trees are used to find an approximate nearest neighbor of a given point in a k-dimensional space.
  • Image Processing: K-D trees are used in image processing to find similar images.

Conclusion

In this chapter, we discussed k-d trees, which are a data structure used for storing k-dimensional points. We discussed the construction of k-d trees, operations on k-d trees, and the time complexity of k-d trees. We also provided example code to construct, insert, delete, and search nodes in k-d trees in C, C++, Java, and Python.

Advertisements