I'm currently trying to build a KD-Tree in 2 dimensions (Latitude and Longitude) to query for the nearest coordinate. I push the coordinates (ID, Latitude, Longitude) in a vector and pass this vector in the constructor of my KD-Tree.
But when I set a breakpoint to the end of the constructor (after the recursive build-call returned) my root-item contains just rubbish in its left- and right-pointers. During the build-routine it seems that they contain quite a long time the right values, but at some point they get lost... does anyone see the mistake i obviously made in my recursive routine?
#include "stdafx.h"
#include "KDTree.h"
KDTree::KDTree(void)
{
}
KDTree::KDTree(vector<Coordinate*> c)
{
coordinates = c;
root = &KDItem();
build(root, 0, 0, c.size() - 1);
}
KDTree::~KDTree(void)
{
}
void KDTree::build(KDItem* item, int depth, int startIndex, int stopIndex)
{
int coordinateCount = stopIndex - startIndex + 1;
if (coordinateCount == 1)
{
(*item).left = NULL;
(*item).right = NULL;
(*item).value = NULL;
(*item).leaf = coordinates[startIndex];
return;
}
(*item).left = &KDItem();
(*item).right = &KDItem();
int medianIndex = 0;
float median = 0;
if (depth % 2 == 0)
{
sort(coordinates.begin() + startIndex, coordinates.begin() + stopIndex + 1, Coordinate::sortByLatitude);
Coordinate::findLatitudeMedian(&coordinates, startIndex, stopIndex, &median, &medianIndex);
}
else
{
sort(coordinates.begin() + startIndex, coordinates.begin() + stopIndex + 1, Coordinate::sortByLongitude);
Coordinate::findLongitudeMedian(&coordinates, startIndex, stopIndex, &median, &medianIndex);
}
(*item).value = median;
build((*item).left, depth+1,startIndex, medianIndex-1);
build((*item).right, depth+1,medianIndex,stopIndex);
}
int KDTree::findNearestNodeIndex(float latitude, float longitude)
{
KDItem* item = findNearestItem(latitude, longitude, root);
return (*(*item).leaf).Index();
}
KDItem* KDTree::findNearestItem(float firstVal, float secondVal, KDItem* item)
{
if ((*item).value == NULL) return item;
if (firstVal < (*item).value)
{
return findNearestItem(secondVal, firstVal, (*item).left);
}
else
{
return findNearestItem(secondVal, firstVal, (*item).right);
}
}
KDItem *item = &KDItem()
is not a valid way to allocate a new object. This KDItem will exist on the stack until it goes out of scope (at function return, for example). Try
(*item).left = new KDItem();
Be sure to delete
the objects in your destructor. Also, it's much more idiomatic (and readable) to write item->left
instead of (*item).left