【伸展树】自顶向下写法

来源:互联网 发布:淘宝怎么找人工客服 编辑:程序博客网 时间:2024/06/06 01:38

一般的伸展树都是自底向上的吧...因为大部分人都是足控喜欢简单的实现。

参考了很多网上的写法,自顶向下写法中有两点比较容易令人看不懂,这里特意解释一下。

splay的思路是把原树劈成3棵树,左树小于目标节点的值,右树大于目标节点的值,中树是未知的。



图片引用自这里


tree_node * splay(int i, tree_node * t){    tree_node N, *l, *r, *y;        if(t == NULL) return t;        N.left = N.right = NULL;</span>        l = r = &N;    for(;;)    {        if(i < t->item)        {            if(t->left == NULL)  break;                        if(i < t->left->item)            {                y = t->left;                                        t->left = y->right;                y->right = t;                t = y;                                if(t->left == NULL) break;            }                        r->left = t;                                         r = t;            t = t->left;</span>        }                else if(i > t->item)        {            if(t->right == NULL) break;                        if(i > t->right->item)            {                y = t->right;                                       t->right = y->left;                y->left = t;                t = y;                                if(t->right == NULL) break;            }                        l->right = t;                                         l = t;            t = t->right;</span>        }                else        {            break;        }    }        l->right = t->left;                                  r->left = t->right;        t->left = N.right;    t->right = N.left;        return t;}

程序引用自这里


要点1:图中使用了L和R两棵树,而程序实现时为了方便操作,使用了一个中间节点N,它的左右子树就是LR,相当于把LR挂在了N上,然后LR向下互不干扰的拓展。

要点2:中树向下拓展中需要把多余的节点转移到LR树上去,这时我们可以发现,如果转移向L,那么应该连向它的最右节点(根据值的关系后转移到左树上的节点更大一些,所以需要接到左树的最大值上),R则反之。所以我们需要一个操作去查找LR树的最大,小值节点(这个谁都会),但是程序里没有出现相关的代码片段,所以这里有蹊跷猫腻姿势黑科技技巧。奥秘在于每次转移向LR的子树都不存在右或左子树(具体自己体会吧...),所以我们连接完成后直接令LR向右或左前进一步,暴露出它的空子树,方便我们直接连接,同时也完成了我们寻找最大,小位置插入的过程。


最后填上我缩短的代码:

#include <cstdio>struct node{int v; node *ch[2];}Nodes[500000]; int tail = 1;node *newNode(int v){node *n = Nodes + tail++;n->v = v; n->ch[0] = n->ch[1] = NULL;return n;}void rotate(node *&x, int d){node *y = x->ch[d]; x->ch[d] = y->ch[d^1]; y->ch[d^1] = x; x = y;}node *splay(node *x, int v){node N; node *T[2] = {&N, &N};while(x->v != v){int d = (x->v > v ? 0 : 1);if(x->ch[d] && (d ? x->ch[d]->v < v : x->ch[d]->v > v)){rotate(x, d);}if(!x->ch[d]) break;T[d^1]->ch[d] = x; T[d^1] = x; x = x->ch[d];}T[0]->ch[1] = x->ch[0]; T[1]->ch[0] = x->ch[1];x->ch[0] = N.ch[1]; x->ch[1] = N.ch[0];return x;}node *insert(node *x, int v){if(!x){x = newNode(v); return x;}else {x = splay(x, v);if(x->v == v) return x;else{int d = (x->v > v ? 0 : 1);node *t = newNode(v);t->ch[d] = x->ch[d]; x->ch[d] = NULL; t->ch[d^1] = x;return t;}}}node *erase(node *x, int v){if(!x) return NULL;x = splay(x, v);if(x->v == v){int d = (x->ch[0] ? x->ch[1] ? -1 : 1 : 0);if(d == -1){d = v & 1; node *t =splay(x->ch[d], v); t->ch[d^1] = x->ch[d^1];return t;}else return x->ch[d^1];}return x;}void travel(node *x){if(x){travel(x->ch[0]);printf("%d ", x->v);travel(x->ch[1]);}}int main(){node *root = NULL;for(int x; ~scanf("%d", &x) && x != 0; root = insert(root, x), travel(root), printf("\n"));for(int x; ~scanf("%d", &x) && x != 0; root = erase(root, x),  travel(root), printf("\n"));return 0;} 



0 0
原创粉丝点击