Beispiel #1
0
        public static T Build <T>(IEnumerable <T> items, IAccessors <T> ops) where T : notnull
        {
            var iter = items.GetEnumerator();

            if (!iter.MoveNext())
            {
                throw new Exception("Cannot build a Red/Black tree from an empty collection");
            }

            // Use the first item as the root
            var root = iter.Current;

            ops.Colour(root, EColour.Black);

            // Insert all items into the tree
            for (; iter.MoveNext();)
            {
                root = Insert(root, iter.Current, ops);
                Check(root, ops);
            }

            return(root);
        }
Beispiel #2
0
        public static T Insert <T>([DisallowNull] T root, [DisallowNull] T item, IAccessors <T> ops) where T : notnull
        {
            using var stack_inst = StackPool <T> .Instance.Alloc();

            var stack = stack_inst.Value;

            // Insert 'item'. Record the path down the tree in 'stack'
            stack.Push(root);
            for (; ;)
            {
                var side = ops.Compare(item, stack.Top !) < 0 ? Left : Right;
                if (ops.Child(side, stack.Top) is T child)
                {
                    stack.Push(child);
                }
                else
                {
                    ops.Child(side, stack.Top, item);
                    stack.Push(item);
                    break;
                }
            }

            // Climb back to the root node, fixing colours as we go
            for (; stack.Count > 2;)
            {
                // Get the leaf and its parent
                var node   = stack.Pop();
                var parent = stack.Pop();

                // If either 'node' or 'parent' is black, no more changes are needed
                if (ops.Colour(node) == EColour.Black || ops.Colour(parent) == EColour.Black)
                {
                    break;
                }

                var gparent     = stack.Pop();
                var parent_side = Side(parent, gparent, ops);

                // Red Uncle
                if (ops.Child(-parent_side, gparent) is T uncle && ops.Colour(uncle) == EColour.Red)
                {
                    // Recolour
                    ops.Colour(gparent, EColour.Red);
                    ops.Colour(parent, EColour.Black);
                    ops.Colour(uncle, EColour.Black);
                    stack.Push(gparent);
                    continue;
                }

                // Black Uncle
                // If 'node_side' is not equal to 'parent_side', swap 'node' and 'parent' to transform case 2 -> case 3
                var node_side = Side(node, parent, ops);
                if (node_side != parent_side)
                {
                    Rotate(-node_side, parent, gparent, ops);
                }

                // Case 3 -> swap 'parent' and 'gparent' and recolour
                ops.Colour(gparent, EColour.Red);
                gparent = Rotate <T>(-parent_side, gparent, stack.Top, ops);
                ops.Colour(gparent, EColour.Black);

                // If we rotate the root element, update 'root'
                if (stack.Count == 0)
                {
                    root = gparent;
                }
            }

            // Return the root, ensuring it's black
            ops.Child(0, default, root);