谈谈数据结构-Treap

谈谈数据结构-Treap

分类:Data Structure Treap

1. Treap原理

Treap=(Binary Search)Tree + Heap
Treap 去掉fix域和rotate过程,就是一个很简单的排序二叉树BST。
虽然在插入数据完全离散的情况下,BST的期望复杂度也是 O(logn) O ( log ⁡ n ) ,但是,无论是在算法竞赛中,还是实际情况中,很难保证输入数据是完全离散的。所以在很多情况,BST是很容易退化成链式。
而fix,rotate的功能就是通过随机得到的fix来确定rotate是左旋还是右旋。说白了就是按照BST去插入节点,按照Heap的性质去调整树的高度、去维护二叉树的稳定性。
在随机数生成器足够稳定的情况下,具有非常良好的性能。Treap基本操作的期望复杂度是 O(logn) O ( log ⁡ n )
Treap相对AVL、SBT、Splay等平衡树来说,编程复杂度小得多!而且,Splay是一个均摊的复杂度 O(logn) O ( log ⁡ n ) ,在某一些数据上,并不如Treap稳定~~
总之,Treap简单!实用!

Treap本身并不复杂。但是,这种通过增加随机域,保证数据离散性的做法很棒。

还不明白的,可以参考以下链接:

2. 模板代码

以下代码是旋转版本的Treap的,功能比较简单。。
支持内存池静态分配节点内存+内存回收。。
Treap 的功能还有很多诶。。

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;
typedef pair<long long, long long> pll;

const int inf = 0x3f3f3f3f;
const long long infl = 0x3f3f3f3f3f3f3f3fLL;

template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R>
void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }

template<class T> struct Treap {
    static const int TREAP_SIZE = 1000005;
    struct TNode {
        int fix;
        T val;
        int size;
        int cnt;
        TNode* ch[2];
        void init() {
            fix = rand();
            size = cnt = 0;
            ch[0] = ch[1] = NULL;
        }
        TNode() { init(); }
        TNode(T v) : val(v) { init(); }
    } node[TREAP_SIZE], *pRoot;
    queue<TNode*> trash; // 内存回收
    int tot;
    void init() {
        tot = 0;
        pRoot = NULL;
        while (!trash.empty()) trash.pop();
    }
    Treap() { init(); }
    inline int size(TNode* rt) { return rt == NULL ? 0 : rt->size; }
    void pushUp(TNode* rt) {
        rt->size = rt->cnt;
        rt->size += size(rt->ch[0]);
        rt->size += size(rt->ch[1]);
    }
    TNode* cre_node(T val) {
        TNode* pt = NULL;
        if (!trash.empty()) {
            pt = trash.front(); trash.pop();
        } else {
            pt = &node[tot++];
        }
        pt->init();
        pt->val = val;
        pt->size = pt->cnt = 1;
        return pt;
    }
    /**
     * 对子树进行旋转
     * @param  rt 旋转前子树根节点
     * @param  d 左旋false,右旋true
     * @return    旋转后子树根节点
     */
    TNode* rotate(TNode* rt, bool d) {
        if (rt == NULL || rt->ch[d ^ 1] == NULL) return rt;
        TNode* pt = rt->ch[d ^ 1];
        rt->ch[d ^ 1] = pt->ch[d];
        pt->ch[d] = rt;
        return pt;
    }
    /**
     * 在子树中插入一个节点
     * @param  rt  插入前子树根节点指针
     * @param  val 插入的值
     * @return     插入后子树根节点指针
     */
    TNode* insert(TNode* rt, const T& val) {
        if (rt == NULL) return cre_node(val);
        if (rt->val == val) {
            rt->cnt += 1;
            rt->size += 1;
            return rt;
        }
        bool d = (val > rt->val);
        rt->ch[d] = insert(rt->ch[d], val);
        if (rt->ch[d]->fix < rt->fix) rt = rotate(rt, d ^ 1);
        pushUp(rt);
        return rt;
    }
    /**
     * 在子树中删除一个节点,分两种情况旋转
     * @param  rt  删除前子树根节点指针
     * @param  val 删除的值
     * @return     删除后子树根节点指针
     */
    TNode* remove(TNode* rt, const T& val) {
        if (rt == NULL) return NULL;
        if (rt->val == val) {
            if (rt->cnt > 1) {
                rt->cnt -= 1;
                return rt;
            }
            if (rt->ch[0] == NULL || rt->ch[1] == NULL) {
                // 当前节点只有一个子节点,直接删除
                trash.push(rt);
                if (rt->ch[0] != NULL) return rt->ch[0];
                else return rt->ch[1];
            } else {
                // 当前节点只有两个子节点,先旋转再删除
                bool d = (rt->ch[0]->fix < rt->ch[1]->fix);
                rt = rotate(rt, d);
                rt->ch[d] = remove(rt->ch[d], val);
            }
        } else {
            bool d = (val > rt->val);
            rt->ch[d] = remove(rt->ch[d], val);
            d = (val > rt->val);
            if (rt->ch[d] && rt->ch[d]->fix < rt->fix) rt = rotate(rt, d ^ 1);
        }
        pushUp(rt);
        return rt;
    }
    /**
     * 获取子树的第k小数, indexed from 0
     * @param  rt 子树根节点
     * @return    k
     */
    T kth(TNode* rt, const int& k) {
        assert(k < size(rt));
        int lsz = size(rt->ch[0]);
        if (k < lsz) return kth(rt->ch[0], k);
        else if (k < lsz + rt->cnt) return rt->val;
        else return kth(rt->ch[1], k - lsz - rt->cnt);
    }
    /**
     * 获取在子树中,按从小到大,小于val的数有多少个
     * @param  rt  子树根节点
     * @param  val 值
     * @return     个数(排名)
     */
    int rank(TNode* rt, const T& val) {
        if (rt == NULL) return 0;
        if (val == rt->val) return size(rt->ch[0]);
        else if (val < rt->val) return rank(rt->ch[0], val);
        else return rank(rt->ch[1], val) + size(rt->ch[0]) + rt->cnt;
    }
    /**
     * 顺序输出子树序列
     * @param rt 子树根节点
     */
    void print(TNode* rt) {
        if (rt == NULL) return;
        print(rt->ch[0]);
        debug(rt->val, rt->cnt);
        print(rt->ch[1]);
    }
};
Treap<int> treap;

int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    // int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for (int i = 1; i <= 10; ++i) {
        treap.pRoot = treap.insert(treap.pRoot, i);
    }
    treap.pRoot = treap.insert(treap.pRoot, 5);
    treap.pRoot = treap.insert(treap.pRoot, 5);
    treap.pRoot = treap.remove(treap.pRoot, 5);
    treap.print(treap.pRoot);
    debug("kth:", treap.kth(treap.pRoot, 7));
    debug("rank", treap.rank(treap.pRoot, 7));
#ifdef ___LOCAL_WONZY___
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值