[STL] SGI STL红黑树实现的边界条件

背景

SGI STL红黑树实现上的特殊点,在于红黑树有一个header辅助节点;
- 该header的父节点为root节点;
- 其左节点为当前二叉树中的最小值(最左);
- 其右节点为当前二叉树中的最大值(最右);
- 该节点本身就正好用来当做end迭代器;

其初始化代码如下:

void init() {
    header = new Node();
    header->color = __rb_tree_red;
    header->parent = nullptr;
    header->left = header;
    header->right = header; 
}

问题

由于header辅助节点的存在,当我们使用迭代器进行“前进”、“后退”的操作时,我们需要考虑一些边界条件;

以前进为例,既然是前进,要考虑的边界无非两种:

  • 迭代器当前指向了红黑树中的最后一个节点,下一个节点就是end了;
  • 迭代器本身就已经指向end,但是请注意在C++中对end迭代器调用++的行为是未定义的,我们无需考虑;

基于上述两点考虑,我们可以写出如下的初步代码:

void increment() {
    if (node == header->right) { // 边界条件1: 当迭代器目前已指向最后一个节点;
        node = header;
        return;
    }

    // 函数入口处的判断条件,保证了此处必然可以找到对应的正常节点(非header);
    if (node->right != nullptr) {
        node = node->right;
        while (ndoe->left)
            node = node->left;
    } else {  
        node *parent = node->parent;
        while (parent->right == node) {
            node = parent;
            parent = parent->parent;    
        }
        node = parent;
    }
}

稍微细看,我们就可以发现条件 if (node->right != nullptr) 本身就保证了,其必然可以从右子树中找到下一个正常节点;
因此,我们试着把边界处理放到else这个分支中;根据最后一个节点所在的位置,我们可以分两种情况进行考虑:
1. 最后一个节点在根节点的右侧;
2. 最后一个节点在根节点;

针对边界条件1, else分支中的代码:
当运行到 (node指向root,parent指向header时),parent->right != node,循环终止,node = parent符合预期效果;

针对边界条件2, else分支中的代码:
node指向root,parent指向header时, parent->right == node,因此node = parent(header), parent = parent->parent(root),二者交换位置;此时,node已经指向了header,无需额外赋值操作;

综上 ,我们需要一个判断条件,来决定是否执行node = parent 这个赋值操作;
另外,需要补充的一点就是,除了我们刚刚考虑的上述两种边界条件之外,正常情况下都是要node = parent赋值的;
因此,我们的判断条件,应该从边界条件2本身的特点出发,进行思考;
因此,我们写出如下的判断条件: if (header->right != root)

void increment() {
    if (node->right != nullptr) {
        node = node->right;
        while (node->left)
            node = node->left;
    } else {
        node *parent = node->parent;
        while (parent->right == node) {
            node = parent;
            parent = parent->parent;    
        }
        if (header->right != root)  // Todo: SGI STL源码中是node->right != y 是否完全等价呢?
            node = parent;
    }
}

类似地,我们对decrement进行分析,“后退”存在的特殊情况就是:迭代器已经指向了end位置;
// 同理,针对first为止,使用decrement应该是未定义行为;

void decrement() {
    if (node->color == _rb_tree_red && 
        node->parent->parent == node)
        node = node->right; // 当node为header时候(即迭代器已经指向end位置时);
    else if (node->left != nullptr) {
        base_ptr child = node->left;
        while (child->right != nullptr)
            child = child->right;
        node = child;
    } else {
        base_ptr parent = node->parent;
        while (node == parent->left) {
            node = parent;
            parent = parent->parent;
        }
        node = parent;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值