目前只测试了 inesert 和 erase 操作。 insert 操作完全正确(至少连续的 insert 操作,中间没有 erase ,没有任何问题), erase 操作(测试的是连续的删除操作,从 begin 开始删)会出现两种错误:
把 erase fix 注释掉后完全正常,并且与标准库的比较过。 测试的代码:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(1, 50000);
int arr[10000];
for (int i = 0; i != 10000; ++i)
arr[i] = dis(gen);
glglT::multiset<int> g(arr, arr + 10000);
auto git = g.begin();
for (std::size_t i = 0; i != 5000; ++i)
git = g.erase(git);
erase 的写法,真正 erase 的函数由于没有 fix 的话,是完全正常的,所以暂时不贴。
iterator erase(const_iterator itr)
{//erase 不移动值,只移动结点本身
this->erase((itr++).curr);
return static_cast<iterator>(itr);
}
erase fix,之前判断了删除的node的颜色是黑色,才调用。
void erase_fix(rebind_ptr p, bool is_left)
{//表示删除的结点是其 parent 的左边还是右边, p 的 left 和 right 赋值正确了的,最大最小结点即 eot->l 和 eot->r 也赋值正确
for (rebind_ptr black_p = is_left ? p->l : p->r; p != eot;) {
if (black_p->is_red) {
black_p->is_red = false;
return;
}
rebind_ptr b = is_left ? p->r : p->l;
if (b->is_red) {
if (is_left) {
this->left_rotate(p, b);
b = p->r;
} else {
this->right_rotate(p, b);
b = p->l;
}
}
rebind_ptr c = is_left ? b->r : b->l;
if (!c->is_red) {
if (is_left ? !b->l->is_red : !b->r->is_red) {
b->is_red = true;
black_p = p;
p = p->p;
is_left = black_p == p->l;
continue;
}
is_left ? this->right_rotate(b, b->l) : this->left_rotate(b, b->r);
b->is_red = true;
c = b;
b = b->p;
b->is_red = false;
}
is_left ? this->left_rotate(p, b) : this->right_rotate(p, b);
c->is_red = false;
glglT::swap(p->is_red, b->is_red);
break;
} eot->p->is_red = false;
}
需要别的信息的话,我会在添加的。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.