Предупреждение: довольно длинный вопрос, возможно, слишком длинный. Если это так, я прошу прощения.
Я работаю над программой, включающей поиск ближайшего соседа (ей) дерева kd (в этом примере это 11-мерное дерево с 3961 отдельными точками). Мы только что узнали о них, и хотя я хорошо понимаю, что делает дерево, я очень растерялся, когда дело доходит до поиска ближайшего соседа.
Я установил двумерный массив точек, каждая из которых содержит качество и местоположение, которое выглядит следующим образом.
struct point{
double quality;
double location;
}
// in main
point **parray;
// later points to an array of [3961][11] points
Затем я перевел данные так, чтобы они имели нулевое среднее значение, и изменил их масштаб на единицу дисперсии. Я не буду публиковать код, так как он не важен для моих вопросов. После этого я построил точки в дереве в случайном порядке следующим образом:
struct Node {
point *key;
Node *left;
Node *right;
Node (point *k) { key = k; left = right = NULL; }
};
Node *kd = NULL;
// Build the data into a kd-tree
random_shuffle(parray, &parray[n]);
for(int val=0; val<n; val++) {
for(int dim=1; dim<D+1; dim++) {
kd = insert(kd, &parray[val][dim], dim);
}
}
Довольно стандартные вещи. Если я неправильно использовал random_shuffle () или что-то не так по структуре моего дерева, пожалуйста, дайте мне знать. Это должно перетасовать первое измерение parray, оставляя 11 измерений каждого в порядке и нетронутым.
Теперь я перехожу к функции соседей (), и вот тут я запутался.
Функция соседа () (последняя половина — псевдокод, где я, честно говоря, понятия не имею, с чего начать):
Node *neighbor (Node *root, point *pn, int d,
Node *best, double bestdist) {
double dist = 0;
// Recursively move down tree, ignore the node we are comparing to
if(!root || root->key == pn) return NULL;
// Dist = SQRT of the SUMS of SQUARED DIFFERENCES of qualities
for(int dim=1; dim<D+1; dim++)
dist += pow(pn[d].quality - root->key->quality, 2);
dist = sqrt(dist);
// If T is better than current best, current best = T
if(!best || dist<bestdist) {
bestdist = dist;
best = root;
}
// If the dist doesn't reach a plane, prune search, walk back up tree
// Else traverse down that tree
// Process root node, return
}
Вот вызов соседа в main (), в основном незавершенный. Я не уверен, что должно быть в main () и что должно быть в функции гости ():
// Nearest neighbor(s) search
double avgdist = 0.0;
// For each neighbor
for(int i=0; i<n; i++) {
// Should this be an array/tree of x best neighbors to keep track of them?
Node *best;
double bestdist = 1000000000;
// Find nearest neighbor(s)?
for(int i=0; i<nbrs; i++) {
neighbor(kd, parray[n], 1, best, &bestdist);
}
// Determine "distance" between the two?
// Add to total dist?
avgdist += bestdist;
}
// Average the total dist
// avgdist /= n;
Как видите, я застрял в последних двух разделах кода. Я ломал голову над этим уже несколько дней, и я все еще застрял. Это должно произойти очень скоро, поэтому, конечно, любая помощь приветствуется. Заранее спасибо.
Kd-дерево не включает в себя тасование.
Фактически, вы захотите использовать сортировку (или, лучше, быстрый выбор), чтобы построить дерево.
Сначала решите это для ближайший сосед (1НН). Должно быть достаточно ясно, как найти kNN, как только у вас будет работать эта часть, сохраняя кучу лучших кандидатов и используя k-ую точку для сокращения.