[Loj.ac-java&c++] Treap - 旋转树(树堆 / 平衡树)

本文介绍了Treap的概念,它是一种结合了二叉搜索树和堆特性的平衡树。讨论了左旋、右旋、前驱和后继等概念,并提供了Java和C++的实现代码。注意到相同逻辑的Java代码运行速度较慢,而C++代码运行效率更高。
摘要由CSDN通过智能技术生成

问题:

说明:

https://oi-wiki.org/ds/treap/

来 写 一 个 Treap。

问题链接:https://loj.ac/problem/104

提交记录:

https://loj.ac/s/860484

https://loj.ac/s/1029437

输入案例:

传了一份测试数据:https://download.csdn.net/download/qq_28033719/12709334 


我的代码:

知识准备

1、树堆:

是一种平衡树,由二叉搜索树(BST)分化而来,而且结合了堆排序特征(最大堆,最小堆),通过权值把最大或最小权值提升到根节点,那么树进行打结点时候,可以不用形成一条链表的情况,因此操作时间稳定在(Log n),具体有证明的。

2、左旋转 右旋转

左旋转:左手方向旋转,也叫做逆时针旋转,比如根节点3,右节点6, 3 -> 6 旋转就像是逆时针旋转。

左旋
   3              3    6           6
  / \            / \  / \         / \
 2   6     =>   2   4   7  =>    3  7
    / \                         / \
   4   7                       2  4

右旋转:和左旋转相反

右旋反过来
     6            3    6           3
    / \          / \  / \         / \
   3   7   =>   2   4    7  =>   2  6
  / \                              / \
 2  4                             4   7

3、前驱 后继

前驱:小于 target 的最大那个数

后继:大于 target 的最小那个数

4、具体代码:

我看了模板然后自己弄了下,还是弄成对象比较适合,也可以用数组(但数组的逻辑太反人类,我弄了好久没通过)

先放一个数组版的,再放一个对象版的,说实在,java提交记录看到都是100MS以上,换成数组也是,但是我如果用cpp写的代码就10ms一个记录,一样的逻辑,一样的判断但速度完全没法比。

数组版:

import java.util.Scanner;

public class Treap_Array {
    private int BIN = 100005, LEFT = 0, RIGHT = 1, index = 0, ROOT = 0;
    private int[] val = new int[BIN], num = new int[BIN],
                  size = new int[BIN], random = new int[BIN];
    private int[][] child = new int[BIN][2];

    public void pushup(int r) {
        size[r] = num[r] + size[child[r][LEFT]] + size[child[r][RIGHT]];
    }

    // true - left, false - right
    public int rotate(int r, boolean dir) {
        int temp;
        if(dir) {
            temp = child[r][RIGHT];
            child[r][RIGHT] = child[temp][LEFT];
            child[temp][LEFT] = r;
        } else {
            temp = child[r][LEFT];
            child[r][LEFT] = child[temp][RIGHT];
            child[temp][RIGHT] = r;
        }
        pushup(r); pushup(temp); return temp;
    }

    public int insert(int r, int v) {
        if(val[r] == 0) { // check val
            r = ++ index;
            val[r] = v; num[r] = size[r] = 1;
            random[r] = (int)(Math.random() * BIN);
        }
        else if(val[r] == v)  ++ num[r];
        else {
            int dir = val[r] > v ? 0 : 1;
            child[r][dir] = insert(child[r][dir], v);
            if(random[r] < random[child[r][dir]]
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值