public ITwoThree <T> Insert(T item, IComparer <T> comparer, out ITwoThree <T> splitLeft, out ITwoThree <T> splitRight, out T splitValue) { // Default split values. splitLeft = splitRight = null; splitValue = default(T); // Get side to insert node. var side = GetSide(item, comparer); // Values are equal, no need to change tree. if (IsSame(side)) { return(this); } // Insert value into proper node. T pv; ITwoThree <T> pl, pr; var child = GetChild(side); var node = child.Insert(item, comparer, out pl, out pr, out pv); // Insert propagated single node. if (node != null) { return(node == child ? this : NewChangedNode(node, side)); } // Insert propagated two nodes and value, meaning it split. // Sinde this is 3-node, we are at full capacity and need to split too. switch (side) { case Side.Left: splitLeft = new TwoNode <T>(pv, pl, pr); splitRight = new TwoNode <T>(Second, Middle, Right); splitValue = First; break; case Side.Middle: splitLeft = new TwoNode <T>(First, Left, pl); splitRight = new TwoNode <T>(Second, pr, Right); splitValue = pv; break; case Side.Right: splitLeft = new TwoNode <T>(First, Left, Middle); splitRight = new TwoNode <T>(pv, pl, pr); splitValue = Second; break; } return(null); }
private ITwoThree <T> RedistributeOrMerge(T value, ITwoThree <T> left, ITwoThree <T> right, Side removedSide, out bool removed) { removed = false; if (removedSide == Side.Right) { if (left is ThreeNode <T> ) { // Right redistribute case. var red = (ThreeNode <T>)left; var l = new TwoNode <T>(red.First, red.Left, red.Middle); var r = new TwoNode <T>(value, red.Right, right); return(new TwoNode <T>(red.Second, l, r)); } // Right merge case. var m = (TwoNode <T>)left; removed = true; return(new ThreeNode <T>(m.Value, value, m.Left, m.Right, right)); } if (removedSide == Side.Left) { if (right is ThreeNode <T> ) { // Left redistribute case. var led = (ThreeNode <T>)right; var l = new TwoNode <T>(value, left, led.Left); var r = new TwoNode <T>(led.Second, led.Middle, led.Right); return(new TwoNode <T>(led.First, l, r)); } // Left merge case. var m = (TwoNode <T>)right; removed = true; return(new ThreeNode <T>(value, m.Value, left, m.Left, m.Right)); } throw new InvalidOperationException(); }
private static ITwoThree <T> RedistributeRight(T first, T second, ITwoThree <T> left, ITwoThree <T> middle, ITwoThree <T> right) { // Case A if (left is TwoNode <T> && middle is TwoNode <T> ) { var sm = (TwoNode <T>)middle; var l = left; var r = new ThreeNode <T>(sm.Value, second, sm.Left, sm.Right, right); return(new TwoNode <T>(first, l, r)); } // Case B if (middle is ThreeNode <T> ) { var sm = (ThreeNode <T>)middle; var l = left; var m = new TwoNode <T>(sm.First, sm.Left, sm.Middle); var r = new TwoNode <T>(second, sm.Right, right); return(new ThreeNode <T>(first, sm.Second, l, m, r)); } // Case C if (left is ThreeNode <T> && middle is TwoNode <T> ) { var sl = (ThreeNode <T>)left; var sm = (TwoNode <T>)middle; var l = new TwoNode <T>(sl.First, sl.Left, sl.Middle); var m = new TwoNode <T>(first, sl.Right, sm.Left); var r = new TwoNode <T>(second, sm.Right, right); return(new ThreeNode <T>(sl.Second, sm.Value, l, m, r)); } throw new InvalidOperationException(); }
private static ITwoThree <T> RedistributeMiddle(T first, T second, ITwoThree <T> left, ITwoThree <T> middle, ITwoThree <T> right) { // Case A if (left is TwoNode <T> && right is TwoNode <T> ) { var sl = (TwoNode <T>)left; var l = new ThreeNode <T>(sl.Value, first, sl.Left, sl.Right, middle); var r = right; return(new TwoNode <T>(second, l, r)); } // Case B if (right is ThreeNode <T> ) { var sr = (ThreeNode <T>)right; var l = left; var m = new TwoNode <T>(second, middle, sr.Left); var r = new TwoNode <T>(sr.Second, sr.Middle, sr.Right); return(new ThreeNode <T>(first, sr.First, l, m, r)); } // Case C if (left is ThreeNode <T> && right is TwoNode <T> ) { var sl = (ThreeNode <T>)left; var l = new TwoNode <T>(sl.First, sl.Left, sl.Middle); var m = new TwoNode <T>(first, sl.Right, middle); var r = right; return(new ThreeNode <T>(sl.Second, second, l, m, r)); } throw new InvalidOperationException(); }