[模板] 树堆 - Treap的指针和数组实现及一些例题

指针版:

template <class T, class Compare = std::less<T> >
class Treap {
private:
    struct treap {//成员结构体
        int size, fix;//以当前节点为根的树的节点数目,和调整树结构的fix随机数
        T key;//每个节点的权,可以定义成自己想要的类型
        Compare cmp;//比较函数,默认是小于号
        treap *ch[2];//左右儿子,左为0,右为1

        treap(T key) {//构造函数
            size = 1;
            fix = rand();
            this->key = key;
            ch[0] = ch[1] = NULL;
        }

        int compare(T x) const {//比较函数,相等为-1
            if (x == key) return -1;
            return cmp(x ,key) ? 0 : 1;
            //小于返回0(左儿子),大于返回1(右儿子)
        }

        void Maintain() {//维持树的形态
            size = 1;//先将当前节点的size值为1
            if (ch[0] != NULL) size += ch[0]->size;
            if (ch[1] != NULL) size += ch[1]->size;
            //然后更新左右儿子的size到当前节点
        }
    }*root;//为这个class创建数据成员root,为树根。
    Compare cmp;//创建比较函数

    void Rotate(treap *&t, int d) {//树的旋转,0为左旋,1为右旋
    //注意作用对象一定是需要旋转的那颗子树的根
        treap *k = t->ch[d ^ 1];
        t->ch[d ^ 1] = k->ch[d];
        k->ch[d] = t;
        t->Maintain();//此时t成了儿子节点,所以先更新t
        k->Maintain();
        t = k;
    }

    void Insert(treap *&t, T x) {//按照二叉树的性质插入x到树中
        if (t == NULL) t = new treap(x);
        else {
            //int d = t->compare(x);
            int d = cmp(x ,t->key) ? 0 : 1;
            Insert(t->ch[d], x);
            if (t->ch[d]->fix > t->fix) Rotate(t, d ^ 1);
            //如果不平衡的话,就进行旋转
        }
        t->Maintain();
    }

    void Delete(treap *&t, T x) {//按照二叉树的性质进行查找并删除
        int d = t->compare(x);
        if (d == -1) {//如果权值相等,说明当前节点是要删除的节点
            treap *tmp = t;
            if (t->ch[0] == NULL) {
                t = t->ch[1];
                delete tmp;
                tmp = NULL;
            } else if (t->ch[1] == NULL) {
                t = t->ch[0];
                delete tmp;
                tmp = NULL;
            } else {//如果不是,判断进入左子树还是右子树
                int k = t->ch[0]->fix > t->ch[1]->fix ? 1 : 0;
                Rotate(t, k);
                Delete(t->ch[k], x);
            }
        } else Delete(t->ch[d], x);
        if (t != NULL) t->Maintain();
    }

    bool Find(treap *t, int x) {//查找x是否存在
        while (t != NULL) {
            int d = t->compare(x);
            if (d == -1) return true;
            t = t->ch[d];
        }
        return false;
    }

    T Kth(treap *t, int k) {//查找第k小的节点的权
        if (t == NULL || k <= 0 || k > t->size) return -1;
        if (t->ch[0] == NULL) {
            if (k == 1) return t->key;
            return Kth(t->ch[1], k - 1);
        }
        if (t->ch[0]->size >= k) return Kth(t->ch[0], k);
        if (t->ch[0]->size + 1 == k) return t->key;
        return Kth(t->ch[1], k - 1 - t->ch[0]->size);
    }

    int Rank(treap *t, int x) {//返回这个节点在树中从小到大位列第几
        int r;
        if (t->ch[0] == NULL) r = 0;
        else r = t->ch[0]->size;
        if (x == t->key) return r + 1;
        if (x < t->key) return Rank(t->ch[0], x);
        return r + 1 + Rank(t->ch[1], x);
    }

    treap* PreSuc(treap *t, int x, int d) {// d = 0 : 前驱 , d = 1 : 后驱
        treap * pre = NULL;
        while(t != NULL && t->v != x) {
            int k = t->compare(x);
            if(k == (d^1)) pre = t;
            t = t->ch[k];
        }
        t = t->ch[d];
        if(t == NULL) return pre;
        else {
            while(t->ch[d^1] != NULL) {
                t = t->ch[d^1];
            }
            return t;
        }
    }

    void Deletetreap(treap *&t) {//删除以当前节点为根的整棵树
        if (t == NULL) return;
        if (t->ch[0] != NULL) Deletetreap(t->ch[0]);
        if (t->ch[1] != NULL) Deletetreap(t->ch[1]);
        delete t;
        t = NULL;
    }

    void Print(treap *t) {//中序遍历
        if (t == NULL) return;
        Print(t->ch[0]);
        cout << t->key << ' ';
        Print(t->ch[1]);
    }

public:
//从这里开始是对用户开放的函数
    Treap() {
        root = NULL;
    }
    ~Treap() {
        Deletetreap(root);
    }
    void insert(T x) {
        Insert(root, x);
    }
    void clear() {
        Deletetreap(root);
    }
    T kth(int x) {
        return Kth(root, x);
    }
    void print() {
        Print(root);
    }
    int size() {
        return root->size;
    }
};

数组版:

struct treap {
    int v, info, fix, ch[2], size;
    //v和info是当时写的这道题的权值,fix是随机权
    //ch[0]和ch[1]分别是左右儿子,size是以当前节点为根的树的大小
    treap() {}

    treap(int info, int v) : info(info), v(v) {
        ch[0] = ch[1] = -1;
        fix = rand();
        size = 1;
    }

    int compare(int x) {
        if (v == x) return -1;
        return x < v ? 0 : 1;
    }
} node[maxn];

int root, tot;

void Maintain(int t) {//相当于update
    node[t].size = 1;
    if (node[t].ch[0] != -1) node[t].size += node[node[t].ch[0]].size;
    if (node[t].ch[1] != -1) node[t].size += node[node[t].ch[1]].size;
}

void Rotate(int &t, int d) {//旋转
    if (t == -1) return;
    int tmp = node[t].ch[d ^ 1];
    node[t].ch[d ^ 1] = node[tmp].ch[d];
    node[tmp].ch[d] = t;
    Maintain(t);
    Maintain(tmp);
    t = tmp;
}

void Insert(int &t, int info, int v) {//插入
    if (t == -1) {
        t = ++tot;
        node[t] = treap(info, v);
    } else {
        //int d = node[t].compare(v);
        int d = v < node[t].v ? 0 : 1;
        Insert(node[t].ch[d], info, v);
        if (node[t].fix < node[node[t].ch[d]].fix) Rotate(t, d ^ 1);
    }
    Maintain(t);
}

int Find(int t, int v) {//查找
    if (t == -1) return t;
    int d = node[t].compare(v);
    if (d == -1) return t;
    return Find(node[t].ch[d], v);
}

int Findmax(int t) {//最大值
    if (t == -1) return -1;
    while (node[t].ch[1] != -1) {
        t = node[t].ch[1];
    }
    return t;
}

int Findmin(int t) {//最小值
    if (t == -1) return -1;
    while (node[t].ch[0] != -1) {
        t = node[t].ch[0];
    }
    return t;
}

void Delete(int &t, int x) {//删除权为x的节点
    if (t == -1) return;
    int k = node[t].compare(x);
    if (k == -1) {
        if (node[t].ch[0] != -1 && node[t].ch[1] != -1) {
            int d = node[node[t].ch[0]].fix < node[node[t].ch[1]].fix ? 0 : 1;
            Rotate(t, d);
            Delete(node[t].ch[d]);
        } else {
            if (node[t].ch[0] == -1) t = node[t].ch[1];
            else t = node[t].ch[0];
        }
    } else Delete(node[t].ch[k], x);
    if (t != -1) Maintain(t);
}

void Print(int t) {//中序遍历
    if (t == -1) return;
    Print(node[t].ch[0]);
    cout << node[t].v << ' ';
    Print(node[t].ch[1]);
}

应用:

  应该可以实现STL中set和map容器的一些简单功能。(只是简单地实现)

例题:

题目题解
POJ-3481传送门
POJ-1442传送门
HDU-4585传送门
HDU-4557传送门
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值