【日志】旋转Treap

旋转Treap

Treap树的名字来自于Tree+Heap,因为它结合了树(二叉搜索树)和堆(二叉堆)。(所以可以翻译为树堆?)。
虽然感觉除了代码长点,这个旋转Treap也不是不好,但是fhp能做到的它做不到……不过一些操作下反而更快

虽然Treap相对简单,但是下面这行代码对写平衡树很有用。

#define debug(x) std::cerr << #x << " " << x << '\n'

结点性质

在Treap中,各个结点的值val具有跟二叉搜索树一致的性质。同时,每个Treap的结点中还有一个权值(优先值)rank,整颗Treap的结点权值分布类似于大根堆或者小根堆。

也就是因为这个rank是随机数,所以其分配到哪个值都有可能。因此Treap的整个结构是期望平衡的。

因此,在旋转Theap中需要维护上面的两个性质,因此其具有一个关键的操作:旋转。

Treap的结点定义如下。

struct Node {
   
    int val, rank, cnt, size;
  	int child[2];
};

旋转

Treap的旋转就像二叉树的旋转一样,具有左旋和右旋。(这个可以画个图去理解。)

  • 左旋,即将当前节点的左儿子提上来,同时这个结点变成其左儿子的右节点。
  • 右旋,即将当前节点的右儿子提上来,同时这个结点变为其右儿子的左节点。

旋转操作可以有两种实现,根据孩子结点的实现的不同,有具体实现左旋和右旋,也有像下面方式的一个函数实现旋转(根据参数d旋转)。

class Treap {
   
  	private:
    	struct Node {
   
          	int val, size, cnt, rank;
            int child[2];
            Node(int val = 0, int size = 0, int cnt = 0, int rank = 0) 
                : val(val), size(size), cnt(cnt), rank(rank) {
   
                    child[0] = child[1] = 0;
                }
            bool operator < (const Node &a) const {
   
                return rank < a.rank;
            }
            bool operator > (const Node &a) const {
   
                return rank > a.rank;
            }
        };
    	vector<Node>tr;
    	int tot, root;
    	int create(int val) {
   
            int now = ++ tot;
            tr[now].size = tr[now].cnt = 1;
            tr[now].val = val;
            tr[now].rank = rand();
            return now;
        }
    	void update(int now) {
   
            tr[now].size = tr[now].cnt + tr[tr[now].child[0]].size + tr[tr[now].child[1]].size;
        }
    	void rotate(int &now, int d) {
   
            int tmp = tr[now].child[d ^ 1];
            tr[now].child[d ^ 1] = tr[tmp].child[d];
            tr[tmp].child[d] = now;
            update(now);
            update(tmp);
            now = tmp;
        }
    public:
    	void inti(int size) {
   
            tr.assign(size + 1, Node());
            tot = root = 0;
        }
    void insert(int &now, int val);
    void insert(int val) {
   
        insert(root, val);
    }
    void delet(int &now, int val);
    void delet(int val) {
   
        delet(root, val);
    }
};

插入

Treap的插入和BST的插入一致。但是要注意维护优先值的堆的性质。

void Treap::insert(int &now, int val) {
   
    if (!now) {
   
        now = create(val);
        return;
    }
    if (tr[now].val == val) {
   
        tr[now].cnt ++;
    } else {
   
        int d = val < tr[now].val ? 0 : 1;
        insert(tr[now].child[d], val);
        if (tr[now] < tr[tr[now].child[d]]) {
   
            rotate(now, d ^ 1);
        }
    }
    update(now);
}

删除

Treap的删除可以采用BST的策略删除,也可以使用堆的性质去删除。

void Treap::delet(int &now, int val) {
   
    if (!now) {
   
        return;
    }
    if (tr[now]->val == val) {
   
        if (tr[now]->cnt > 1) {
   
            tr[now]-
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值