[ create a new paste ] login | about

Link: http://codepad.org/AEVVnfSc    [ raw code | fork ]

C++, pasted on Nov 26:
#include <cassert>
#include <memory>

enum class Color { R, B };

// 1. No red node has a red child.
// 2. Every path from root to empty node contains the same
// number of black nodes.

template<class T> class RBTree {
    struct Node {
        Node(Color c,
            std::shared_ptr<const Node> const & lft,
            T val,
            std::shared_ptr<const Node> const & rgt)
            : _c(c), _lft(lft), _val(val), _rgt(rgt) {}

        Color _c;
        std::shared_ptr<const Node> _lft;
        T _val;
        std::shared_ptr<const Node> _rgt;
    };

    explicit RBTree(std::shared_ptr<const Node> const & node) : _root(node) {}

    Color rootColor() const {
        assert (!isEmpty());
        return _root->_c;
    }

public:
    RBTree() {}

    RBTree(Color c, RBTree const & lft, T val, RBTree const & rgt)
        : _root(std::make_shared<const Node>(c, lft._root, val, rgt._root)) {
        assert(lft.isEmpty() || lft.root() < val);
        assert(rgt.isEmpty() || val < rgt.root());
    }

    RBTree(std::initializer_list<T> init) {
        RBTree t;
        for (T v : init)
            t = t.insert(v);
        _root = t._root;
    }

    bool isEmpty() const { return !_root; }

    T root() const {
        assert(!isEmpty());
        return _root->_val;
    }

    RBTree left() const {
        assert(!isEmpty());
        return RBTree(_root->_lft);
    }

    RBTree right() const {
        assert(!isEmpty());
        return RBTree(_root->_rgt);
    }

    bool member(T x) const {
        if (isEmpty())
            return false;
        T y = root();
        if (x < y)
            return left().member(x);
        else if (y < x)
            return right().member(x);
        else
            return true;
    }

    RBTree insert(T x) const {
        RBTree t = ins(x);
        return RBTree(Color::B, t.left(), t.root(), t.right());
    }

    // 1. No red node has a red child.
    void assert1() const {
        if (!isEmpty()) {
            auto lft = left();
            auto rgt = right();
            if (rootColor() == Color::R) {
                assert(lft.isEmpty() || lft.rootColor() == Color::B);
                assert(rgt.isEmpty() || rgt.rootColor() == Color::B);
            }
            lft.assert1();
            rgt.assert1();
        }
    }

    // 2. Every path from root to empty node contains the same
    // number of black nodes.
    int countB() const {
        if (isEmpty())
            return 0;
        int lft = left().countB();
        int rgt = right().countB();
        assert(lft == rgt);
        return (rootColor() == Color::B)? 1 + lft: lft;
    }

private:
    RBTree ins(T x) const {
        assert1();
        if (isEmpty())
            return RBTree(Color::R, RBTree(), x, RBTree());
        T y = root();
        Color c = rootColor();
        if (x < y)
            return balance(c, left().ins(x), y, right());
        else if (y < x)
            return balance(c, left(), y, right().ins(x));
        else
            return *this; // no duplicates
    }

    static RBTree balance(Color c, RBTree const & lft, T x, RBTree const & rgt) {
        if (c == Color::B && lft.doubledLeft())
            return RBTree(Color::R
                        , lft.left().paint(Color::B)
                        , lft.root()
                        , RBTree(Color::B, lft.right(), x, rgt));
        else if (c == Color::B && lft.doubledRight())
            return RBTree(Color::R
                        , RBTree(Color::B, lft.left(), lft.root(), lft.right().left())
                        , lft.right().root()
                        , RBTree(Color::B, lft.right().right(), x, rgt));
        else if (c == Color::B && rgt.doubledLeft())
            return RBTree(Color::R
                        , RBTree(Color::B, lft, x, rgt.left().left())
                        , rgt.left().root()
                        , RBTree(Color::B, rgt.left().right(), rgt.root(), rgt.right()));
        else if (c == Color::B && rgt.doubledRight())
            return RBTree(Color::R
                        , RBTree(Color::B, lft, x, rgt.left())
                        , rgt.root()
                        , rgt.right().paint(Color::B));
        else
            return RBTree(c, lft, x, rgt);
    }

    bool doubledLeft() const {
        return !isEmpty()
            && rootColor() == Color::R
            && !left().isEmpty()
            && left().rootColor() == Color::R;
    }

    bool doubledRight() const {
        return !isEmpty()
            && rootColor() == Color::R
            && !right().isEmpty()
            && right().rootColor() == Color::R;
    }

    RBTree paint(Color c) const {
        assert(!isEmpty());
        return RBTree(c, left(), root(), right());
    }

private:
    std::shared_ptr<const Node> _root;
};

template<class T, class F> void forEach(RBTree<T> const & t, F f) {
    if (!t.isEmpty()) {
        forEach(t.left(), f);
        f(t.root());
        forEach(t.right(), f);
    }
}

template<class T, class Beg, class End> RBTree<T> insert(RBTree<T> t, Beg it, End end) {
    if (it == end)
        return t;
    T item = *it;
    auto t1 = insert(t, ++it, end);
    return t1.insert(item);
}

//-------------------------------

#include <iostream>
#include <string>
#include <algorithm>

template<class T> void print(RBTree<T> const & t) {
    forEach(t, [](T v) {
        std::cout << v << " ";
    });
    std::cout << std::endl;
}

void testInit() {
    RBTree<int> t{ 50, 40, 30, 10, 20, 30, 100, 0, 45, 55, 25, 15 };
    print(t);
}

int main() {
    testInit();

    std::string init =  "a red black tree walks into a bar "
                        "has johnny walker on the rocks "
                        "and quickly rebalances itself."
                        "A RED BLACK TREE WALKS INTO A BAR "
                        "HAS JOHNNY WALKER ON THE ROCKS "
                        "AND QUICKLY REBALANCES ITSELF.";
    auto t = insert(RBTree<char>(), init.begin(), init.end());
    print(t);
    t.assert1();

    std::cout << "Black depth: " << t.countB() << std::endl;
    std::cout << "Member z: " << t.member('z') << std::endl;
    std::for_each(init.begin(), init.end(), [t](char c) {
        if (!t.member(c))
            std::cout << "Error: " << c << " not found\n";
    });

    return 0;
}


Create a new paste based on this one


Comments: