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
是容器的分配器类型,容器必须包含哪个分配器,Alloc
或typename std::allocator_traits<Alloc>::template rebind_alloc</*the type of the node*/>
?< / p>
答案 0 :(得分:1)
N
个节点O(N)
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?