-
Notifications
You must be signed in to change notification settings - Fork 0
/
kd-tree.js
106 lines (84 loc) · 2.9 KB
/
kd-tree.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
class Node {
constructor(point, dimension, left = null, right = null) {
this.left = left;
this.right = right;
this.point = point;
this.dimension = dimension;
}
}
class KDTree {
constructor(points) {
this.root = this.buildKDTree(points, 0);
}
buildKDTree(points, depth) {
if (points.length === 0) {
return null;
}
const dimension = depth % points[0].length;
points.sort((a, b) => a[dimension] - b[dimension]);
const medianIndex = Math.floor(points.length / 2);
const medianPoint = points[medianIndex];
const leftPoints = points.slice(0, medianIndex);
const rightPoints = points.slice(medianIndex + 1);
return new Node(
medianPoint,
dimension,
this.buildKDTree(leftPoints, depth + 1),
this.buildKDTree(rightPoints, depth + 1)
);
}
// Função para encontrar os k vizinhos mais próximos de um ponto
findNearestNeighbors(queryPoint, k) {
let best = [];
let bestDistances = [];
for (let i = 0; i < k; i++) {
best.push(null);
bestDistances.push(Number.MAX_VALUE);
}
const findNearest = (node, depth = 0) => {
if (node === null) {
return;
}
const dimension = depth % queryPoint.length;
const comparePoint = node.point;
const queryValue = queryPoint[dimension];
const nodeValue = comparePoint[dimension];
const leftChild = (queryValue < nodeValue) ? node.left : node.right;
const rightChild = (queryValue < nodeValue) ? node.right : node.left;
findNearest(leftChild, depth + 1);
const distance = this.distance(queryPoint, comparePoint);
for (let i = 0; i < k; i++) {
if (distance < bestDistances[i]) {
best.splice(i, 0, comparePoint);
bestDistances.splice(i, 0, distance);
best.pop();
bestDistances.pop();
break;
}
}
if (Math.abs(queryValue - nodeValue) < bestDistances[k - 1]) {
findNearest(rightChild, depth + 1);
}
};
findNearest(this.root);
return best;
}
// Função para calcular a distância euclidiana entre dois pontos
distance(point1, point2) {
return Math.sqrt(point1.reduce((sum, val, i) => sum + (val - point2[i]) ** 2, 0));
}
}
// Exemplo de uso da árvore KD
const points = [
[2, 3],
[5, 4],
[9, 6],
[4, 7],
[8, 1],
[7, 2]
];
const kdTree = new KDTree(points);
const queryPoint = [9, 2];
const k = 2;
const nearestNeighbors = kdTree.findNearestNeighbors(queryPoint, k);
console.log(`Os ${k} vizinhos mais próximos de [${queryPoint}] são:`, nearestNeighbors);