如何复制红黑树,它的分配器应该是什么

时间:2016-02-05 07:33:18

标签: c++ copy containers assign allocator

Q#2续订。请回答新的Q#2! --Dannyu NDos,2017年1月17日

我一直在创建一个名为DRV的关联容器,它代表一个有限的离散随机变量。这是一棵红黑树。我从标准std::map得到了帮助,但我也对此感到困惑。

Q#1。其副本ctor的时间复杂度是多少?不应该是O(n log n)吗?我的DRV副本ctor有O(log n),但是使用std::async

旧Q#2。为什么默认分配器为std::allocator<value_type>?不是它分配容器的内部节点类型?在这种情况下,不需要单独动态分配值。

新Q#2。鉴于Alloc是容器的分配器类型,容器必须包含哪个分配器,Alloctypename std::allocator_traits<Alloc>::template rebind_alloc</*the type of the node*/>?< / p>

2 个答案:

答案 0 :(得分:1)

  1. 复制构造函数不需要排序,只需要复制N个节点O(N)
  2. std::allocator<value_type>在内部“反弹”(搜索“重新绑定”here)以分配地图节点(值+树布线数据)

答案 1 :(得分:0)

我自己对问题#1的回答:我是这样做的:
1。以递归方式复制(容器尺寸/ 2)元素,颜色全黑。
2。复制以下元素,该元素是最中心的元素,将是根元素,颜色为黑色。
3. 以递归方式复制剩余元素,颜色全黑。 4. 。将 2。中复制的元素与 1中复制的元素中的根元素相连。
5. 2。中复制的元素与 3中复制的元素中的根元素相连接。
6。将最深的元素涂成红色 例如:http://imgur.com/gallery/tUtoK
这将在O(n)时间内形成完美平衡的红黑树 即使我使用std::async对此进行并行化,由于Amdahl定律,它仍具有O(n)时间复杂度。
以下是实施:

/* includes... */
template <class T, class Comp = std::less<T>, class Alloc = std::allocator<T>> class set { // A red-black tree, motivated from std::set
public:
    /* typedefs... */
protected:
    typedef RedBlackTreeNode<T> Nodev; // The node type
    typedef Nodev *pNodev; // The pointer to node type
    typedef typename std::allocator_traits<Alloc>::template rebind_alloc<Nodev> Rebounda; // Rebound allocator type
    typedef std::allocator_traits<Rebounda> Reboundat; // Rebound allocator traits
    mutable ListNode_e endn; // The past-the-end node
    size_type sz; // Size
    value_compare comp; // comparator
    Rebounda alloc; // allocator
    pNodev initp() const noexcept { // the pointer to the node at the end
        return static_cast<pNodev>(endn.pre);
    }
    void partial_clear(const_iterator i) noexcept { // Destructs the node at i and after
        while (cend() != i) {
            pNodev p = static_cast<pNodev>(i++.refer);
            Reboundat::destroy(alloc, p);
            Reboundat::deallocate(alloc, p, 1);
        }
    }
    /// partial_copy_Lvalue, partial_assign_Lvalue
    /// @steps
    ///    1. Copy the (container size / 2) elements at the beginning recursively, with color all black.
    ///    2. Copy the following element, which is the centermost element and will be the root element, with color black.
    ///    3. Copy the remaining element at the end recursively, with color all black.
    ///    4. Connect the element copied in 2. with the root element among the elements copied in 1.
    ///    5. Connect the element copied in 2. with the root element among the elements copied in 3.
    ///    6. Paint the deepest elements red.
    /// @param
    ///    size: the size of the container
    ///    other_i: the iterator refering the element to be copied in 2.
    /// @return
    ///    pNodev: the pointer to the root of the (partial) tree
    ///    size_type: the depth of the shallowest leaf node of the (partial) tree
    std::pair<pNodev, size_type> partial_copy_Lvalue(size_type size, const_iterator &&other_i) {
        if (size == 0)
            return std::make_pair(nullptr, 0);
        else {
            std::pair<pNodev, size_type> l = partial_copy_Lvalue(size >> 1, std::move(other_i)); /// 1.
            Reboundat::construct(alloc, Reboundat::allocate(alloc, 1), endn, Nodev::color_t::black, *other_i++); /// 2.
            pNodev resultp = initp();
            std::pair<pNodev, size_type> r = partial_copy_Lvalue(size - (size >> 1) - 1, std::move(other_i)); /// 3.
            resultp->left = l.first; /// 4.
            resultp->right = r.first; /// 5.
            if (resultp->left)
                resultp->left->parent = resultp; /// 4.
            if (resultp->right)
                resultp->right->parent = resultp; /// 5.
            if (l.second < r.second && resultp->right)
                resultp->right->colorleavesred(); /// 6, case 1
            else if (l.second > r.second && resultp->left)
                resultp->left->colorleavesred(); /// 6, case 2
            return std::make_pair(resultp, std::min(l.second, r.second) + 1);
        }
    }
    void copy(const set &other) { // Copies the nodes from other. Precondition : this is empty
        if (!other.empty())
            partial_copy_Lvalue(other.sz, other.cbegin());
    }
    std::pair<pNodev, size_type> partial_assign_Lvalue(size_type size, ListIt<T> &&this_i,
        const_iterator &&other_i, const const_iterator &other_cend) {
        if (size == 0) {
            if (other_i == other_cend)
                partial_clear(const_iterator(this_i.refer));
            return std::make_pair(nullptr, 0);
        } else {
            std::pair<pNodev, size_type> l = partial_assign_Lvalue(size >> 1, std::move(this_i), std::move(other_i), other_cend); /// 1.
            std::pair<pNodev, size_type> r;
            pNodev resultp;
            if (this_i.refer == cend().refer) {
                Reboundat::construct(alloc, Reboundat::allocate(alloc, 1), endn, Nodev::color_t::black, *other_i++); /// 2, case 1
                resultp = initp();
                r = partial_copy_Lvalue(size - (size >> 1) - 1, std::move(other_i)); /// 3, case 1
            } else {
                resultp = static_cast<pNodev>(this_i.refer);
                static_cast<pNodev>(this_i.refer)->parent = nullptr;
                static_cast<pNodev>(this_i.refer)->color = Nodev::color_t::black;
                *this_i++ = *other_i++; /// 2, case 2
                r = partial_assign_Lvalue(size - (size >> 1) - 1, std::move(this_i), std::move(other_i), other_cend); /// 3, case 2
            }
            resultp->left = l.first; /// 4.
            resultp->right = r.first; /// 5.
            if (resultp->left)
                resultp->left->parent = resultp; /// 4.
            if (resultp->right)
                resultp->right->parent = resultp; /// 5.
            if (l.second < r.second && resultp->right)
                resultp->right->colorleavesred(); /// 6, case 1
            else if (l.second > r.second && resultp->left)
                resultp->left->colorleavesred(); /// 6, case 2
            return std::make_pair(resultp, std::min(l.second, r.second) + 1);
        }
    }
public:
    /* constructors... */
    virtual ~set() {
        clear();
    }
    set &operator = (const set &other) {
        sz = other.sz;
        if (std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value && alloc != other.alloc) {
            clear();
            alloc = other.alloc;
            copy(other);
        } else
            partial_assign_Lvalue(other.sz, ListIt<T>(cbegin().refer), other.cbegin(), other.cend());
        return *this;
    }
    /* ... */
};

另请参阅:How is allocator-aware container assignment implemented?