Example #1
0
        /// <summary>
        /// Uses the Round-Robin strategy to create a KdTree of the given dimension for the set of points.
        /// </summary>
        public KdTree(params Point[] points)
        {
            if (points == null)
            {
                throw new ArgumentNullException();
            }

            if (!points.Any())
            {
                throw new ArgumentOutOfRangeException();
            }

            dimension = points.First().Dimension();

            if (points.Any(p => p.Dimension() != dimension))
            {
                throw new ArgumentException();
            }

            Shuffle(points);

            // Partitions the points in the range [low, high] into a subtree defined by the cutting dimension l
            Node KdTree(int low, int high, int l)
            {
                if (high < low)
                {
                    return(null);
                }

                var byLevel = new Point.ByDimension(l);

                QuickSort(points, low, high, byLevel);
                var mid  = low + (high - low) / 2;
                var newL = (l + 1) % dimension;

                return(new Node
                {
                    point = points[mid],
                    left = KdTree(low, mid - 1, newL),
                    right = KdTree(mid + 1, high, newL)
                });
            }

            root = KdTree(0, points.Length - 1, 0);
        }
Example #2
0
        /// <summary>
        /// Remove a point <code>p</code> from the tree.
        /// raises <exception cref="System.InvalidOperationException"> if the point does not exist.
        /// </summary>
        public void Delete(Point p)
        {
            // Implementation ported from CMU Bioinformatics lecture slides (offered by Carl Kingsford)
            if (p == null)
            {
                throw new ArgumentNullException();
            }

            if (p.Dimension() != dimension)
            {
                throw new ArgumentException();
            }

            // Returns the smallest point wrt to the given dimension d
            // in the tree rooted at n (here l is the cutting dimension of n)
            Point Min(Node n, int d, int l)
            {
                if (n == null)
                {
                    return(null);
                }

                var newL = (l + 1) % dimension;

                if (l == d)
                {
                    // If we are on the correct plane then we only need to inspect the left branch
                    if (n.left == null)
                    {
                        return(n.point);
                    }
                    else
                    {
                        return(Min(n.left, d, newL));
                    }
                }
                else
                {
                    // Otherwise we need to take a look at both branches
                    var leftPt  = Min(n.left, d, newL);
                    var rightPt = Min(n.right, d, newL);
                    var byDim   = new Point.ByDimension(d);

                    if (leftPt == null && rightPt == null)
                    {
                        return(n.point);
                    }
                    else if (leftPt == null)
                    {
                        return(byDim.Min(n.point, rightPt));
                    }
                    else if (rightPt == null)
                    {
                        return(byDim.Min(n.point, leftPt));
                    }
                    else
                    {
                        return(byDim.Min(n.point, leftPt, rightPt));
                    }
                }
            }

            // Delete q from the tree rooted at n (here l is the cutting dimension of n), and return the new subtree
            Node Delete(Point q, Node n, int l)
            {
                if (n == null)
                {
                    throw new InvalidOperationException();  // Not found (it is OK to throw here)
                }
                var newL = (l + 1) % dimension;

                if (n.point == q)
                {
                    // Found the point
                    if (n.right != null)
                    {
                        // Replace the point with the smallest one in the right branch of n
                        n.point = Min(n.right, l, newL);  // n.b. Cannot be null, by design
                        n.right = Delete(n.point, n.right, newL);
                    }
                    else if (n.left != null)
                    {
                        // Only have a left branch, so move its contents to the right
                        n.point = Min(n.left, l, newL);
                        n.right = Delete(n.point, n.left, newL);
                        n.left  = null;
                    }
                    else
                    {
                        n = null;
                    }
                }
                else if (q[l] < n.point[l])
                {
                    n.left = Delete(q, n.left, newL);
                }
                else
                {
                    n.right = Delete(q, n.right, newL);
                }
                return(n);
            }

            root = Delete(p, root, 0);
        }