Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Map and Set Using a Single Red-Black Tree Template

Tech May 9 4

Encapsulating containers like map and set with a single Red-Black Tree (RBTree) template presents several design considerations. The key goals include implementing iterators, supporting increment/decrement operations, and enforcing container-specific constraints: preventing value modification in set and key modification in map.

Adapting a Single Tree Structure

A unified RBTree template must handle differing data requirements:

  • For map, data is a pair<const K, V>. The const K ensures the key is immutable.
  • For set, the key and data type are identical (K). The template parameters K and T both become K.

A functor KeyOfT extracts the comparison key from the stored data. For map, it returns the first member of the pair; for set, it returns the value itself.

The Insert method returns a pair<Node*, bool>. Using a raw node pointer resolves potential type conflicts when the same RBTree must return different iterator types (iterator vs const_iterator) to its encapsulating containers.

Red-Black Tree Iterator

The iterator provides access to nodes in sorted order. The core structure includes dereferencing operators and comparison logic.

template<typename DataType>
struct TreeIterator {
    typedef RBTreeNode<DataType> TreeNode;
    typedef TreeIterator<DataType> IteratorSelf;
    TreeNode* nodePtr;

    TreeIterator(TreeNode* node) : nodePtr(node) {}

    DataType& operator*() { return nodePtr->nodeData; }
    DataType* operator->() { return &(nodePtr->nodeData); }

    bool operator!=(const IteratorSelf& other) const {
        return nodePtr != other.nodePtr;
    }
    bool operator==(const IteratorSelf& other) const {
        return nodePtr == other.nodePtr;
    }

Implementing Pre-increment (++)

The iterator advances to the next node in an in-order traversal.

  • If the current node has a right child, the successor is the leftmost node in that right subtree.
  • Otherwise, traverse upwards until reaching an ancestor where the current node is in the ancestor's left subtree. That ancestor is the successor.
    IteratorSelf& operator++() {
        if (nodePtr->rightChild) {
            TreeNode* temp = nodePtr->rightChild;
            while (temp->leftChild) {
                temp = temp->leftChild;
            }
            nodePtr = temp;
        } else {
            TreeNode* curr = nodePtr;
            TreeNode* parent = curr->parentNode;
            while (parent && curr == parent->rightChild) {
                curr = parent;
                parent = parent->parentNode;
            }
            nodePtr = parent;
        }
        return *this;
    }
};

RBTree Public Interface

template<typename KeyType, typename DataType, typename KeyExtractor>
class RedBlackTree {
    typedef RBTreeNode<DataType> TreeNode;
public:
    typedef TreeIterator<DataType> iterator;

    iterator begin() {
        TreeNode* temp = rootNode;
        while (temp && temp->leftChild) {
            temp = temp->leftChild;
        }
        return iterator(temp);
    }

    iterator end() {
        return iterator(nullptr);
    }

    std::pair<TreeNode*, bool> Insert(const DataType& data) {
        // ... Insertion and balancing logic ...
        return std::make_pair(newNode, insertionSuccess);
    }
private:
    TreeNode* rootNode = nullptr;
};

Map Implementation

namespace ContainerLib {
    template<typename Key, typename Value>
    class Map {
        struct MapKeyExtractor {
            const Key& operator()(const std::pair<Key, Value>& element) const {
                return element.first;
            }
        };
        RedBlackTree<Key, std::pair<const Key, Value>, MapKeyExtractor> rbTree;
    public:
        typedef typename decltype(rbTree)::iterator iterator;

        iterator begin() { return rbTree.begin(); }
        iterator end() { return rbTree.end(); }

        std::pair<iterator, bool> insert(const std::pair<Key, Value>& element) {
            return rbTree.Insert(element);
        }

        Value& operator[](const Key& k) {
            auto result = insert({k, Value{}});
            return (result.first)->second;
        }
    };
}

Set Implementation

namespace ContainerLib {
    template<typename Key>
    class Set {
        struct SetKeyExtractor {
            const Key& operator()(const Key& element) const {
                return element;
            }
        };
        RedBlackTree<Key, Key, SetKeyExtractor> rbTree;
    public:
        // Both iterator types are const_iterators to prevent modification.
        typedef typename decltype(rbTree)::const_iterator iterator;
        typedef typename decltype(rbTree)::const_iterator const_iterator;

        iterator begin() const { return rbTree.begin(); }
        iterator end() const { return rbTree.end(); }

        std::pair<iterator, bool> insert(const Key& element) {
            return rbTree.Insert(element);
        }
    };
}

In the Set implementation, both iterator and const_iterator are aliased to the RBTree's const_iterator. This prevents modification of set elements. The RBTree's Insert method returns a pair<TreeNode*, bool>, which the set::insert can implicitly convert to its required pair<iterator, bool> return type without a type mismatch.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.