/// <summary> /// Inserts an entry not present in the current version. /// </summary> /// <returns>New version with inserted vertex</returns> public Tree <K, V> Insert(K Key, V Value) { var newVersion = Version.GetSuccessor(); // Key must not be present in tree! var n = new Node(Key, Value, newVersion).GetTemporaryAccessorForVersion(newVersion); if (Root is null) { var newRoot = n.GetPermanentAccessor(); Node.RemoveListOfAccessors(); return(new Tree <K, V> { Root = newRoot, Version = newVersion }); } var root = Root.Node.GetTemporaryAccessorForVersion(newVersion); var path = GetPath(Key, root); if (Key.CompareTo(path.Last().Key) < 0) { path.Last().Base.Left = n; } else { path.Last().Base.Right = n; } var top = BalancePath(path).GetPermanentAccessor(); Node.RemoveListOfAccessors(); FatNode.FinishUpdate(); return(new Tree <K, V> { Root = top, Version = newVersion }); }
/// <summary> /// Removes an element with specified key producing a new version. /// </summary> /// <returns>New version with deleted vertex.</returns> public Tree <K, V> Delete(K Key) { if (Root is null) { throw new InvalidOperationException("Cannot delete from empty tree."); } // If there is only one vertex return null. // This is a technical detail and behaviour may be changed to produce empty tree with a new version. if (Root.Left is null && Root.Right is null) { return(null); } // Key must be present in tree! var newVersion = Version.GetSuccessor(); Node.NodeAccessor prev = null; var root = Root.Node.GetTemporaryAccessorForVersion(newVersion); var current = root; while (!current.Key.Equals(Key)) { prev = current; current = current.Key.CompareTo(Key) < 0 ? current.Right : current.Left; } var sub = current; Node.NodeAccessor top; if (current.Left == null && current.Right == null) { // Leaf if (prev.Right == current) { prev.Right = null; } else { prev.Left = null; } top = BalancePath(GetPath(prev.Key, root)); } // Switch key and value with a leaf vertex else if (current.Left == null) { SwapModPathEnds(current.Key, current.Right.Key); current.Key = current.Right.Key; current.Value = current.Right.Value; current.Right = null; top = BalancePath(GetPath(current.Key, root)); } else if (current.Right == null) { SwapModPathEnds(current.Key, current.Left.Key); current.Key = current.Left.Key; current.Value = current.Left.Value; current.Left = null; top = BalancePath(GetPath(current.Key, root)); } else if (prev.Key.CompareTo(Key) > 0) { current = prev.Right; while (current.Right != null) { prev = current; current = current.Right; } ; SwapModPathEnds(Key, current.Key); sub.Key = current.Key; sub.Value = current.Value; if (current.Left == null) { prev.Right = null; top = BalancePath(GetPath(prev.Key, root)); } else { SwapModPathEnds(Key, current.Left.Key); current.Key = current.Left.Key; current.Value = current.Left.Value; current.Left = null; top = BalancePath(GetPath(current.Key, root)); } } else { current = prev.Left; while (current.Left != null) { prev = current; current = current.Left; } ; SwapModPathEnds(Key, current.Key); sub.Key = current.Key; sub.Value = current.Value; if (current.Right == null) { prev.Left = null; top = BalancePath(GetPath(prev.Key, root)); } else { SwapModPathEnds(Key, current.Right.Key); current.Key = current.Right.Key; current.Value = current.Right.Value; current.Right = null; top = BalancePath(GetPath(current.Key, root)); } } var newRoot = top.GetPermanentAccessor(); Node.RemoveListOfAccessors(); FatNode.FinishUpdate(); return(new Tree <K, V> { Root = newRoot, Version = newVersion }); // Update the Key in all modifying paths that end with the vertex subject to key change. void SwapModPathEnds(K first, K second) { List <Node.NodeAccessor> nodes = new List <Node.NodeAccessor>(2); var c1 = Root; while (c1 != null) { if (c1.ModPathEnd == second || c1.ModPathEnd2 == second) { nodes.Add(c1); } c1 = c1.Key.CompareTo(second) > 0 ? c1.Left : c1.Right; } c1 = Root; while (c1 != null) { if (c1.ModPathEnd == first) { c1.ModPathEnd = second; } if (c1.ModPathEnd2 == first) { c1.ModPathEnd2 = second; } c1 = c1.Key.CompareTo(first) > 0 ? c1.Left : c1.Right; } foreach (var node in nodes) { if (c1.ModPathEnd == second) { c1.ModPathEnd = first; } if (c1.ModPathEnd2 == second) { c1.ModPathEnd2 = first; } } } }