A data structure is called a K-dimensional tree , or simply a K-D tree . It is made for effective spatial searches in K-dimensional domains. It is a multi-dimensional generalization of the binary search tree. K-D trees are used in a variety of domains, including computer graphics, nearest-neighbor analysis, and data mining. They are very helpful for tackling a variety of computational geometry issues, such as range search and nearest neighbor search.
Properties and Structure:
- Each node in a K-D tree represents a point in the K-dimensional space .
- Each node contains two children: a left child and a right child , arranged in a binary tree structure.
- At every level of the tree, points are split alternating along several dimensions.
- The selection of the dividing dimension at each level might be based on several heuristics, such as choosing the dimension with the greatest spread or cycling through the different dimensions.
- Insertion: To add a new point to the K-D tree , one must navigate the tree to choose the best location for the new node by the splitting rule.
- Search: K-D trees allow several search functions, such as range search, which locates all points inside a given range, and nearest neighbor search, which locates the point in the tree that is closest to a particular query point.
- Deletion: Carefully examining the tree structure and rearranging the tree as necessary are required when removing a node from the K-D tree while preserving its attributes.
Operations:
Applications:
K-D trees are widely used in many different fields, such as:
- Applications such as databases and data mining use nearest neighbor search.
- Geographic information systems (GIS) use spatial indexing.
- Effective range search for geographical information systems and computational geometry.
- To produce scenes more quickly in computer graphics by speeding up ray tracing algorithms .
Code:
Let's take an example to illustrate the K-Dimensional tree in C++:
Example
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
struct Point {
std::vector<double> coords;
};
struct Node {
Poincpp tutorial;
Node* left;
Node* right;
};
// Function to create a new node
Node* newNode(Poincpp tutorial) {
Node* node = new Node;
node->point = point;
node->left = node->right = nullptr;
return node;
}
// Function to calculate the distance between two points
double distance(Point a, Point b)
{
double dist = 0;
for (size_t i = 0; i < a.coords.size(); ++i)
{
dist += (a.coords[i] - b.coords[i]) * (a.coords[i] - b.coords[i]);
}
return std::sqrt(dist);
}
// Function to insert a new node into the K-D tree
Node* insertNode(Node* root, Poincpp tutorial, unsigned depth)
{
if (root == nullptr)
{
return newNode(point);
}
unsigned k = point.coords.size();
unsigned cd = depth % k;
if (point.coords[cd] < (root->point.coords[cd]))
{
root->left = insertNode(root->left, point, depth + 1);
}
else
{
root->right = insertNode(root->right, point, depth + 1);
}
return root;
}
// Function to find the nearest neighbor
Node* findNearestNeighbor(Node* root, Poincpp tutorial, unsigned depth, Node* best, double& bestDist)
{
if (root == nullptr) return best;
double dist = distance(root->point, point);
if (dist < bestDist)
{
bestDist = dist;
best = root;
}
unsigned k = point.coords.size();
unsigned cd = depth % k;
if (point.coords[cd] < root->point.coords[cd])
{
best = findNearestNeighbor(root->left, point, depth + 1, best, bestDist);
if (point.coords[cd] + bestDist >= root->point.coords[cd])
{
best = findNearestNeighbor(root->right, point, depth + 1, best, bestDist);
}
}
else
{
best = findNearestNeighbor(root->right, point, depth + 1, best, bestDist);
if (point.coords[cd] - bestDist <= root->point.coords[cd])
{
best = findNearestNeighbor(root->left, point, depth + 1, best, bestDist);
}
}
return best;
}
// Function to perform a range search and return points within a specified range
void range_Search(Node* root, Point low, Point high, unsigned depth)
{
if (root == nullptr) return;
unsigned k = low.coords.size();
unsigned cd = depth % k;
if (root->point.coords[cd] >= low.coords[cd])
{
range_Search(root->left, low, high, depth + 1);
}
if (root->point.coords[cd] <= high.coords[cd] && root->point.coords[cd] >= low.coords[cd])
{
// This point is within the range
std::cout << "Point: [";
for (size_t i = 0; i < k - 1; ++i)
{
std::cout << root->point.coords[i] << ", ";
}
std::cout << root->point.coords[k - 1] << "]\n";
}
if (root->point.coords[cd] <= high.coords[cd])
{
range_Search(root->right, low, high, depth + 1);
}
}
// Sample usage of the K-D tree
int main()
{
Node* root = nullptr;
std::vector<Point> points = { { {3, 6} }, { {17, 15} }, { {13, 15} }, { {6, 12} }, { {9, 1} }, { {2, 7} }, { {10, 19} } };
for (const auto& point: points)
{
root = insertNode(root, point, 0);
}
// Perform nearest neighbor search
Point queryPoint = { {7, 10} };
double bestDist = std::numeric_limits<double>::max();
Node* nearest = findNearestNeighbor(root, queryPoint, 0, nullptr, bestDist);
std::cout << "Nearest Neighbor: [";
for (size_t i = 0; i < queryPoint.coords.size() - 1; ++i)
{
std::cout << nearest->point.coords[i] << ", ";
}
std::cout << nearest->point.coords[queryPoint.coords.size() - 1] << "]\n";
// Perform range search
Point low = { {4, 5} };
Point high = { {14, 14} };
std::cout << "Points within range:\n";
range_Search(root, low, high, 0);
return 0;
}
Output:
Output
Nearest Neighbor: [6, 12]
Points within range:
Point: [6, 12]
- Construction of a 2D point K-D tree .
- Find the closest neighbor for a specific query point.
- Use range search to locate points within a given range.