/// <summary> /// FindRange method /// Method for searching elements in concrete range /// </summary> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> /// <param name="node"></param> /// <param name="xDimension">True is first dimension</param> /// <param name="result">List of searching elements</param> private void FindRange(T x1, T y1, T x2, T y2, Node node, bool xDimension, ref List <TData> result) { if (node != null) { // When get leaf, control its coordinates // and add to result list if they in the range if (node is Leaf leaf) { if (IsInsideRangeX(x1, x2, leaf) && IsInsideRangeY(y1, y2, leaf)) { result.Add(leaf.Data); } } // Actions for navigation nodes else { NavigationalNode navigational = node as NavigationalNode; // Search in first dimension if (xDimension) { // If whole interval is inside the range go to second dimension if (x1.CompareTo(navigational.Min) <= 0 && navigational.Max.CompareTo(x2) <= 0) { FindRange(x1, y1, x2, y2, navigational.OtherDimensionNode, !xDimension, ref result); } // If whole interval is out of range do nothing else if (navigational.Max.CompareTo(x1) <= 0 || navigational.Min.CompareTo(x2) >= 0) { } // If part of interval is inside the range go find to both children else if (navigational.Min.CompareTo(x1) <= 0 || x2.CompareTo(navigational.Max) <= 0) { FindRange(x1, y1, x2, y2, navigational.LeftChild, xDimension, ref result); FindRange(x1, y1, x2, y2, navigational.RightChild, xDimension, ref result); } } // Search in second dimension else { // If whole interval is inside the range look to all leafs of subtree if (y1.CompareTo(navigational.Min) <= 0 && navigational.Max.CompareTo(y2) <= 0) { LookAllSubtree(x1, y1, x2, y2, navigational, ref result); } // If part of interval is inside the range go find to both children else if (navigational.Min.CompareTo(y1) <= 0 || y2.CompareTo(navigational.Max) <= 0) { FindRange(x1, y1, x2, y2, navigational.LeftChild, xDimension, ref result); FindRange(x1, y1, x2, y2, navigational.RightChild, xDimension, ref result); } } } } }
/// <summary> /// GoUp method /// Part of GetRightSibling /// </summary> /// <param name="node">Current node</param> /// <returns>Right sibling for current node</returns> private Leaf GoUp(Node node) { NavigationalNode parent = node.Parent; // We got root via its right child // All leafs are worked out if (parent == null) { return(null); } // If we came via right child, go upper if (node == parent.RightChild) { return(GoUp(parent)); } else { // If we came via left child go to most left child of right child if (parent.RightChild is NavigationalNode navigationalChild) { return(GetMostLeftChild(navigationalChild)); } else { // Or return right child if it is leaf return(parent.RightChild as Leaf); } } }
/// <summary> /// BuildTree method /// Call BuildSubtree method for X dimension, then for Y dimension /// </summary> /// <param name="datas">Elements stored in leafs</param> /// <param name="otherDimensionNode">X node for Y node</param> /// <param name="xDimension">Dimension where we are. If it's true, it's X</param> /// <returns>Subtree root</returns> private Node BuildTree(TData[] datas, NavigationalNode otherDimensionNode, bool xDimension) { Node pointer = BuildSubtree(datas, null, xDimension); if (otherDimensionNode != null) { (pointer as NavigationalNode).OtherDimensionNode = otherDimensionNode; } return(pointer); }
/// <summary> /// BuildSubtree method /// This method do most of work /// for tree building. /// </summary> /// <param name="datas">Elements stored in leafs</param> /// <param name="parent">Parent of node, that this method must return</param> /// <param name="xDimension">Dimension where we are. If it's true, it's X</param> /// <returns>Node of tree</returns> private Node BuildSubtree(TData[] datas, NavigationalNode parent, bool xDimension) { Node pointer = null; if (datas.Length > 1) { // Set range for navigational node NavigationalNode node = new NavigationalNode(); if (xDimension) { Array.Sort(datas, comparerByX); node.Min = datas.First().X; node.Max = datas.Last().X; } else { Array.Sort(datas, comparerByY); node.Min = datas.First().Y; node.Max = datas.Last().Y; } // Halve datas. One half of datas go to left subtree // the other one go to right subtree TData[] datasL = datas.Take(datas.Length / 2).ToArray(); TData[] datasR = datas.Skip(datas.Length / 2).ToArray(); node.LeftChild = BuildSubtree(datasL, node, xDimension); node.RightChild = BuildSubtree(datasR, node, xDimension); pointer = node; } else { // if datas parametr has only one element // this one will be a leaf Leaf leaf = new Leaf(); leaf.Data = datas.First(); pointer = leaf; } // If we are in X dimension and current node is navigational one, // go to Y Dimension and build tree for it if (xDimension && pointer is NavigationalNode navigational) { navigational.OtherDimensionNode = (NavigationalNode)BuildTree(datas, navigational, !xDimension); } // Set parametrs that are common for both leafs and navigational nodes pointer.XDimension = xDimension; pointer.Parent = parent; return(pointer); }
/// <summary> /// GetMostLeftChild method /// Returns most left child in subtree /// </summary> /// <param name="node">Subtree root</param> /// <returns>Most left child</returns> private Leaf GetMostLeftChild(NavigationalNode node) { Node pointer = node.LeftChild; if (pointer is Leaf leaf) { return(leaf); } else { return(GetMostLeftChild(pointer as NavigationalNode)); } }
/// <summary> /// LookAllSubtree method /// Take every leaf of subtree and /// control its coordinates. If they /// are inside range add to result list /// </summary> /// <param name="x1"></param> /// <param name="y1"></param> /// <param name="x2"></param> /// <param name="y2"></param> /// <param name="node">Root of subtree</param> /// <param name="result">List of searching elements</param> private void LookAllSubtree(T x1, T y1, T x2, T y2, NavigationalNode node, ref List <TData> result) { // Find the most left child in subtree Leaf pointer = GetMostLeftChild(node); // If something went wrong and not all links was built if (pointer.RightSibling == null) { BuildLinks(pointer); } do { // Control leaf coordinates and add to // result list if they are inside range if (IsInsideRangeX(x1, x2, pointer) && IsInsideRangeY(y1, y2, pointer)) { result.Add(pointer.Data); } // Go to next leaf pointer = pointer.RightSibling; // End when all leafs was controlled } while (pointer != null); }