- DSA - Home
- DSA - Overview
- DSA - Environment Setup
- DSA - Algorithms Basics
- DSA - Asymptotic Analysis
- Data Structures
- DSA - Data Structure Basics
- DSA - Data Structures and Types
- DSA - Array Data Structure
- DSA - Skip List Data Structure
- Linked Lists
- DSA - Linked List Data Structure
- DSA - Doubly Linked List Data Structure
- DSA - Circular Linked List Data Structure
- Stack & Queue
- DSA - Stack Data Structure
- DSA - Expression Parsing
- DSA - Queue Data Structure
- DSA - Circular Queue Data Structure
- DSA - Priority Queue Data Structure
- DSA - Deque Data Structure
- Searching Algorithms
- DSA - Searching Algorithms
- DSA - Linear Search Algorithm
- DSA - Binary Search Algorithm
- DSA - Interpolation Search
- DSA - Jump Search Algorithm
- DSA - Exponential Search
- DSA - Fibonacci Search
- DSA - Sublist Search
- DSA - Hash Table
- Sorting Algorithms
- DSA - Sorting Algorithms
- DSA - Bubble Sort Algorithm
- DSA - Insertion Sort Algorithm
- DSA - Selection Sort Algorithm
- DSA - Merge Sort Algorithm
- DSA - Shell Sort Algorithm
- DSA - Heap Sort Algorithm
- DSA - Bucket Sort Algorithm
- DSA - Counting Sort Algorithm
- DSA - Radix Sort Algorithm
- DSA - Quick Sort Algorithm
- Matrices Data Structure
- DSA - Matrices Data Structure
- DSA - Lup Decomposition In Matrices
- DSA - Lu Decomposition In Matrices
- Graph Data Structure
- DSA - Graph Data Structure
- DSA - Depth First Traversal
- DSA - Breadth First Traversal
- DSA - Spanning Tree
- DSA - Topological Sorting
- DSA - Strongly Connected Components
- DSA - Biconnected Components
- DSA - Augmenting Path
- DSA - Network Flow Problems
- DSA - Flow Networks In Data Structures
- DSA - Edmonds Blossom Algorithm
- DSA - Maxflow Mincut Theorem
- Tree Data Structure
- DSA - Tree Data Structure
- DSA - Tree Traversal
- DSA - Binary Search Tree
- DSA - AVL Tree
- DSA - Red Black Trees
- DSA - B Trees
- DSA - B+ Trees
- DSA - Splay Trees
- DSA - Range Queries
- DSA - Segment Trees
- DSA - Fenwick Tree
- DSA - Fusion Tree
- DSA - Hashed Array Tree
- DSA - K-Ary Tree
- DSA - Kd Trees
- DSA - Priority Search Tree Data Structure
- Recursion
- DSA - Recursion Algorithms
- DSA - Tower of Hanoi Using Recursion
- DSA - Fibonacci Series Using Recursion
- Divide and Conquer
- DSA - Divide and Conquer
- DSA - Max-Min Problem
- DSA - Strassen's Matrix Multiplication
- DSA - Karatsuba Algorithm
- Greedy Algorithms
- DSA - Greedy Algorithms
- DSA - Travelling Salesman Problem (Greedy Approach)
- DSA - Prim's Minimal Spanning Tree
- DSA - Kruskal's Minimal Spanning Tree
- DSA - Dijkstra's Shortest Path Algorithm
- DSA - Map Colouring Algorithm
- DSA - Fractional Knapsack Problem
- DSA - Job Sequencing with Deadline
- DSA - Optimal Merge Pattern Algorithm
- Dynamic Programming
- DSA - Dynamic Programming
- DSA - Matrix Chain Multiplication
- DSA - Floyd Warshall Algorithm
- DSA - 0-1 Knapsack Problem
- DSA - Longest Common Sub-sequence Algorithm
- DSA - Travelling Salesman Problem (Dynamic Approach)
- Hashing
- DSA - Hashing Data Structure
- DSA - Collision In Hashing
- Disjoint Set
- DSA - Disjoint Set
- DSA - Path Compression And Union By Rank
- Heap
- DSA - Heap Data Structure
- DSA - Binary Heap
- DSA - Binomial Heap
- DSA - Fibonacci Heap
- Tries Data Structure
- DSA - Tries
- DSA - Standard Tries
- DSA - Compressed Tries
- DSA - Suffix Tries
- Treaps
- DSA - Treaps Data Structure
- Bit Mask
- DSA - Bit Mask In Data Structures
- Bloom Filter
- DSA - Bloom Filter Data Structure
- Approximation Algorithms
- DSA - Approximation Algorithms
- DSA - Vertex Cover Algorithm
- DSA - Set Cover Problem
- DSA - Travelling Salesman Problem (Approximation Approach)
- Randomized Algorithms
- DSA - Randomized Algorithms
- DSA - Randomized Quick Sort Algorithm
- DSA - Karger’s Minimum Cut Algorithm
- DSA - Fisher-Yates Shuffle Algorithm
- Miscellaneous
- DSA - Infix to Postfix
- DSA - Bellmon Ford Shortest Path
- DSA - Maximum Bipartite Matching
- DSA Useful Resources
- DSA - Questions and Answers
- DSA - Selection Sort Interview Questions
- DSA - Merge Sort Interview Questions
- DSA - Insertion Sort Interview Questions
- DSA - Heap Sort Interview Questions
- DSA - Bubble Sort Interview Questions
- DSA - Bucket Sort Interview Questions
- DSA - Radix Sort Interview Questions
- DSA - Cycle Sort Interview Questions
- DSA - Quick Guide
- DSA - Useful Resources
- DSA - Discussion
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.