/// <summary> /// Applies rebalances /// </summary> /// <param name="node">Node</param> /// <param name="selfSize">Size of the subtree the node represents</param> private void Rebalance(IBinaryTreeNode <TKey, TValue> node, long selfSize) { //Find the scapegoat long currSize = selfSize; long siblingSize, nodeSize; IBinaryTreeNode <TKey, TValue> current = node; do { //Get the sibling subtree size siblingSize = current.GetSibling <TKey, TValue>().GetSize <TKey, TValue>(); if (current.Parent != null) { //Total size of the Node is Current size of this subtree plus size of //sibling subtree plus one for the current node nodeSize = currSize + siblingSize + 1; current = current.Parent; //Is the current node weight balanced? if (currSize <= (this._balanceFactor * nodeSize) && siblingSize <= (this._balanceFactor * siblingSize)) { //Weight balanced so continue on currSize = nodeSize; } else { //Not weight balanced so this is the scapegoat we rebalance from break; } } else { //Rebalance at the root is gonna be O(n) for sure break; } } while (current != null); //Check how we need to rebuild after the rebalance IBinaryTreeNode <TKey, TValue> parent = current.Parent; bool rebuildLeft = false; if (parent != null) { rebuildLeft = ReferenceEquals(current, parent.LeftChild); } //Now do a rebalance of the scapegoat which will be whatever current is set to IBinaryTreeNode <TKey, TValue>[] nodes = current.Nodes.ToArray(); foreach (IBinaryTreeNode <TKey, TValue> n in nodes) { n.Isolate(); } int median = nodes.Length / 2; //Console.WriteLine("m = " + median); IBinaryTreeNode <TKey, TValue> root = nodes[median]; root.LeftChild = this.RebalanceLeftSubtree(nodes, 0, median - 1); root.RightChild = this.RebalanceRightSubtree(nodes, median + 1, nodes.Length - 1); //Don't use this check because it's expensive, may be useful to turn of for debugging if you ever have issues with the ScapegoatTree //if (root.Nodes.Count() != nodes.Length) throw new InvalidOperationException("Scapegoat rebalance lost data, expected " + nodes.Length + " Nodes in rebalanced sub-tree but got " + root.Nodes.Count()); //Use the rebalanced tree in place of the current node if (parent == null) { //Replace entire tree this.Root = root; } else { //Replace subtree if (rebuildLeft) { parent.LeftChild = root; } else { parent.RightChild = root; } } //Reset Max Node code after a rebalance this._maxNodeCount = this._nodeCount; }