/// <summary> /// Balances the subtree rooted in <paramref name="node"/> and recomputes the 'height' field. /// This method assumes that the children of this node are already balanced and have an up-to-date 'height' value. /// </summary> /// <returns>The new root node</returns> private static SharpTreeNode Rebalance(SharpTreeNode node) { Debug.Assert(node.left == null || Math.Abs(node.left.Balance) <= 1); Debug.Assert(node.right == null || Math.Abs(node.right.Balance) <= 1); // Keep looping until it's balanced. Not sure if this is stricly required; this is based on // the Rope code where node merging made this necessary. while (Math.Abs(node.Balance) > 1) { // AVL balancing // note: because we don't care about the identity of concat nodes, this works a little different than usual // tree rotations: in our implementation, the "this" node will stay at the top, only its children are rearranged if (node.Balance > 1) { if (node.right.Balance < 0) { node.right = node.right.RotateRight(); } node = node.RotateLeft(); // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the left node; so rebalance that. node.left = Rebalance(node.left); } else if (node.Balance < -1) { if (node.left.Balance > 0) { node.left = node.left.RotateLeft(); } node = node.RotateRight(); // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the right node; so rebalance that. node.right = Rebalance(node.right); } } Debug.Assert(Math.Abs(node.Balance) <= 1); node.height = (byte)(1 + Math.Max(Height(node.left), Height(node.right))); node.totalListLength = -1; // mark for recalculation // since balancing checks the whole tree up to the root, the whole path will get marked as invalid return(node); }
/// <summary> /// Balances the subtree rooted in <paramref name="node"/> and recomputes the 'height' field. /// This method assumes that the children of this node are already balanced and have an up-to-date 'height' value. /// </summary> /// <returns>The new root node</returns> static SharpTreeNode Rebalance(SharpTreeNode node) { Debug.Assert(node.left == null || Math.Abs(node.left.Balance) <= 1); Debug.Assert(node.right == null || Math.Abs(node.right.Balance) <= 1); // Keep looping until it's balanced. Not sure if this is stricly required; this is based on // the Rope code where node merging made this necessary. while (Math.Abs(node.Balance) > 1) { // AVL balancing // note: because we don't care about the identity of concat nodes, this works a little different than usual // tree rotations: in our implementation, the "this" node will stay at the top, only its children are rearranged if (node.Balance > 1) { if (node.right.Balance < 0) { node.right = node.right.RotateRight(); } node = node.RotateLeft(); // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the left node; so rebalance that. node.left = Rebalance(node.left); } else if (node.Balance < -1) { if (node.left.Balance > 0) { node.left = node.left.RotateLeft(); } node = node.RotateRight(); // If 'node' was unbalanced by more than 2, we've shifted some of the inbalance to the right node; so rebalance that. node.right = Rebalance(node.right); } } Debug.Assert(Math.Abs(node.Balance) <= 1); node.height = (byte)(1 + Math.Max(Height(node.left), Height(node.right))); node.totalListLength = -1; // mark for recalculation // since balancing checks the whole tree up to the root, the whole path will get marked as invalid return node; }