K-d tree: Difference between revisions

Content added Content deleted
m (Made the code compilable on gcc and g++ versions 4.8, code looks better now hopefully)
m (Added Sidef)
Line 1,708: Line 1,708:
Searched for=List(0, 0, 0) found=List(3, 3, 3) distance=5.1962 visited=4
Searched for=List(0, 0, 0) found=List(3, 3, 3) distance=5.1962 visited=4
Searched for=List(4, 5, 6) found=List(3, 6, 6) distance=1.4142 visited=6</pre>
Searched for=List(4, 5, 6) found=List(3, 6, 6) distance=1.4142 visited=6</pre>

=={{header|Sidef}}==
{{trans|Perl 6}}
<lang ruby>struct Kd_node {
d,
split,
left,
right,
}

struct Orthotope {
min,
max,
}

class Kd_tree(n, bounds) {

method init {
n = self.nk2(0, n);
}

method nk2(split, e) {
return(nil) if (e.len <= 0);
var exset = e.sort_by { _[split] }
var m = (exset.len // 2);
var d = exset[m];
while ((m+1 < exset.len) && (exset[m+1][split] == d[split])) {
++m;
}

var s2 = ((split + 1) % d.len); # cycle coordinates
Kd_node(d: d, split :split,
left: self.nk2(s2, exset.first(m)),
right: self.nk2(s2, exset.last(m-1)));
}
}

struct T3 {
nearest,
dist_sqd = Inf,
nodes_visited = 0,
}

func find_nearest(k, t, p) {
func nn(kd, target, hr, max_dist_sqd) {
kd || return T3(nearest: [0]*k);

var nodes_visited = 1;
var s = kd.split;
var pivot = kd.d;
var left_hr = Orthotope(hr.min, hr.max);
var right_hr = Orthotope(hr.min, hr.max);
left_hr.max[s] = pivot[s];
right_hr.min[s] = pivot[s];

var nearer_kd;
var further_kd;
var nearer_hr;
var further_hr;
if (target[s] <= pivot[s]) {
(nearer_kd, nearer_hr) = (kd.left, left_hr);
(further_kd, further_hr) = (kd.right, right_hr);
}
else {
(nearer_kd, nearer_hr) = (kd.right, right_hr);
(further_kd, further_hr) = (kd.left, left_hr);
}

var n1 = nn(nearer_kd, target, nearer_hr, max_dist_sqd);
var nearest = n1.nearest;
var dist_sqd = n1.dist_sqd;
nodes_visited += n1.nodes_visited;

if (dist_sqd < max_dist_sqd) {
max_dist_sqd = dist_sqd;
}
var d = (pivot[s] - target[s] -> sqr);
if (d > max_dist_sqd) {
return T3(nearest: nearest, dist_sqd: dist_sqd, nodes_visited: nodes_visited);
}
d = (pivot ~Z- target »sqr»() «+»);
if (d < dist_sqd) {
nearest = pivot;
dist_sqd = d;
max_dist_sqd = dist_sqd;
}

var n2 = nn(further_kd, target, further_hr, max_dist_sqd);
nodes_visited += n2.nodes_visited;
if (n2.dist_sqd < dist_sqd) {
nearest = n2.nearest;
dist_sqd = n2.dist_sqd;
}

T3(nearest: nearest, dist_sqd: dist_sqd, nodes_visited: nodes_visited);
}

return nn(t.n, p, t.bounds, Inf);
}

func show_nearest(k, heading, kd, p) {
print <<"-END"
#{heading}:
Point: [#{p.join(',')}]
END
var n = find_nearest(k, kd, p);
print <<"-END"
Nearest neighbor: [#{n.nearest.join(',')}]
Distance: #{sqrt(n.dist_sqd)}
Nodes visited: #{n.nodes_visited()}

END
}

func random_point(k) { k.of { 1.rand } }
func random_points(k, n) { n.of { random_point(k) } }

var kd1 = Kd_tree([[2, 3],[5, 4],[9, 6],[4, 7],[8, 1],[7, 2]],
Orthotope(min: [0, 0], max: [10, 10]));
show_nearest(2, "Wikipedia example data", kd1, [9, 2]);

var N = 1000;
var t0 = Time.micro;
var kd2 = Kd_tree(random_points(3, N), Orthotope(min: [0,0,0], max: [1,1,1]));

var t1 = Time.micro;
show_nearest(2,
"k-d tree with #{N} random 3D points (generation time: #{t1 - t0}s)",
kd2, random_point(3));</lang>
{{out}}
<pre>
Wikipedia example data:
Point: [9,2]
Nearest neighbor: [8,1]
Distance: 1.41421356237309504880168872420969807857
Nodes visited: 3

k-d tree with 1000 random 3D points (generation time: 0.2788s):
Point: [0.289499487347118,0.478347415036239,0.0840989033842838]
Nearest neighbor: [0.236838086359516,0.441335249292905,0.10584223360787]
Distance: 0.06794038545814229393836650539536525446
Nodes visited: 32
</pre>


=={{header|Tcl}}==
=={{header|Tcl}}==