Treap树

Posted dalgleish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Treap树相关的知识,希望对你有一定的参考价值。

Treap树包含所有二叉树的性质,但是以一个随机的优先值排序。《算法导论》关于这个Treap树的原理和实现描述非常少,我就直接给代码吧,原理大家自己百度了。

首先定义的个类

template <typename T>
class tp_tree {
public:
    typedef struct _tp_type {
        _tp_type(_tp_type *_p, _tp_type *_left, _tp_type *_right, T _key, int _pr) :
            parent(_p), left(_left), right(_right), key(_key), priority(_pr) {}
        T key;
        int priority;
        _tp_type *left, *right, *parent;
    }tp_type, *ptp_type;
    tp_tree(T *A, int n) :root(NULL) {
        R = hash_mod(n, 3);
        priority_table = new T[R*R];//哈希表
        seed = hash_seed(NULL, R);
        memset(priority_table, 0, sizeof(T)*R*R);
        printf("R=%d, Max slot=%d\n", R, R*R);
        for (int i = 0; i < n; i++) 
            tp_insert(A[i]);
    }
    ~tp_tree() {
        tp_empty(root);
        hash_seed_free(seed);
        hash_seed_free(priority_table);
    }
    void left_rotate(ptp_type x);
    void right_rotate(ptp_type x);
    void tp_insert(T key);
    ptp_type tp_search(T key);
    void tp_delete(T key);
    void tp_empty(ptp_type x);
    void tp_show(ptp_type x);
    ptp_type tp_root();
private:
    int hash_mod(int n, int iCheck);//取大小
    int *hash_seed(int *pKey, int R);//获取种子
    void hash_seed_free(int *v);//释放种子
    int hash(int key, int R, int *v);//哈希映射
    void tp_insert_fixup(ptp_type x);
    //测试使用
    int tp_max_depth(ptp_type x);
    int tp_min_depth(ptp_type x);
    ptp_type root;
    int *seed, R;
    T *priority_table;//用于保留T对象,下标是优先值
};

关于各个成员实现

left_roate函数

template <typename T>
void tp_tree<T>::left_rotate(typename tp_tree<T>::ptp_type x) {
    ptp_type y = x->right;//y非空
    x->right = y->left;
    if (y->left) y->left->parent = x;//交换子节点
    y->parent = x->parent;//更新父节点
    if (x->parent == NULL)//将y连接到x的父节点
        root = y;
    else {
        if (x == x->parent->left)
            x->parent->left = y;
        else
            x->parent->right = y;
    }
    y->left = x;
    x->parent = y;
}

right_rotate函数

template <typename T>
void tp_tree<T>::right_rotate(typename tp_tree<T>::ptp_type x) {
    ptp_type y = x->left;
    x->left = y->right;
    if (y->right) y->right->parent = x;
    y->parent = x->parent;
    if (x->parent == NULL)
        root = y;
    else {
        if (x == x->parent->left)
            x->parent->left = y;
        else
            x->parent->right = y;
    }
    y->right = x;
    x->parent = y;
}

tp_insert函数

template <typename T>
void tp_tree<T>::tp_insert(T key) {
    ptp_type z = NULL, x = root, y = NULL;
    //生成优先值
    int m = hash(key, R, seed);//T类对象,一定要自己实现一个operator int(),使用指针就不需要了
    while (priority_table[m])//循环检查优先表是否被占用
        m = (m + 1) % (R*R);
    priority_table[m] = key;
    z = new tp_type(NULL, NULL, NULL, key, m);
    while (x) {
        y = x;//保留根节点
        if (key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    if (y == NULL)
        root = z;
    else {
        if (key < y->key)
            y->left = z;
        else
            y->right = z;
        z->parent = y;
    }
    tp_insert_fixup(z);
}

tp_insert_fixup成员,插入后修复函数

template <typename T>
void tp_tree<T>::tp_insert_fixup(typename tp_tree<T>::ptp_type x) {
    ptp_type y;
    while ((y = x->parent) && x->parent->priority > x->priority) {//始终保持父节点的优先值最小
        if (y->right == x)
            left_rotate(y);
        else if (y->left == x)
            right_rotate(y);
    }
}

tp_search成员函数

template <typename T>
typename tp_tree<T>::ptp_type tp_tree<T>::tp_search(T key) {
    ptp_type x = root;
    while (x != NULL && key != x->key) {
        if (key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    return x;
}

tp_delete成员函数,采用堆删除方式,在删除的同时中,就修复了节点

template <typename T>
void tp_tree<T>::tp_delete(T key) {
    ptp_type x = tp_search(key), y;
    if (x == NULL) return;
    while (x->left != NULL && x->right != NULL) {//treap堆式删除,将需要的删除的节点通过旋转,移动出来
        if (x->left->priority < x->right->priority)
            right_rotate(x);
        else
            left_rotate(x);
    }
    y = x;//保留待删除节点
    if (x == root)
        root = x->left ? x->left : x->right;
    else if (x->parent->right == x) 
        x->parent->right = x->left ? x->left : x->right;
    else 
        x->parent->left= x->left ? x->left : x->right;
    //清理哈希优先表
    int m = hash(key, R, seed);//T类对象,一定要自己实现一个operator int(),使用指针就不需要了
    while (priority_table[m]) {//循环检查优先表是否被占用
        if (priority_table[m] == key) break;//T类对象还要实现一个operator =(),使用指针就不需要了
        m = (m + 1) % (R*R);
    }
    priority_table[m] = 0;
    //printf("key=%d,hash priority=%d\n", key, m);
    delete y;
}

tp_empty成员函数,删除所有节点

template <typename T>
void tp_tree<T>::tp_empty(typename tp_tree<T>::ptp_type x) {
    if (x != NULL) {
        tp_empty(x->left);
        tp_empty(x->right);
        tp_delete(x->key);
    }
}

tp_show成员,显示节点,用了AVL树的求深度算法,方便观察并验证算法是否正确

template <typename T>
void tp_tree<T>::tp_show(typename tp_tree<T>::ptp_type x) {
    if (x != NULL) {
        tp_show(x->left);
        if (x == root)
            printf("[root]key=%d, priority=%d (%d, %d)\n", x->key, x->priority, tp_max_depth(x),tp_min_depth(x));
        else
            printf("key=%d, priority=%d (%d, %d)\n", x->key, x->priority, tp_max_depth(x), tp_min_depth(x));
        tp_show(x->right);
    }
}
//测试使用
template <typename T>
int tp_tree<T>::tp_max_depth(typename tp_tree<T>::ptp_type x) {
    if (x == NULL)
        return 0;
    int l = tp_max_depth(x->left);
    int r = tp_max_depth(x->right);
    return (l > r ? l : r) + 1;
}

template <typename T>
int tp_tree<T>::tp_min_depth(typename tp_tree<T>::ptp_type x) {
    if (x == NULL)
        return 0;
    int l = tp_min_depth(x->left);
    int r = tp_min_depth(x->right);
    return (l < r ? l : r) + 1;
}

tp_root成员函数

template <typename T>
typename tp_tree<T>::ptp_type tp_tree<T>::tp_root() {
    return root;
}

下面几个成员函数,基本来自于之前我写的hash算法那章节,所以没什么好说的

template <typename T>
int tp_tree<T>::hash_mod(int n, int iCheck) {
    int iStart = n / iCheck, prime = (iStart == 1) ? 2 : iStart;
    assert(iCheck >= 0 && iCheck <= 8);
    //odd起始要跳过已经判断了的奇数
    for (int j = 0, odd = (iStart % 2 == 0) ? iStart / 2 : (iStart - 1) / 2 + 1;
        j < 8 - iCheck; odd++) {
        //生成一个素数
        bool fPrime = true;
        for (int k = 2; k <= sqrt(prime); k++)
            if (prime % k == 0) {
                fPrime = false;
                break;
            }
        if (fPrime) //记录素数
            j++;
        prime = odd * 2 + 1;//待判断的奇数
    }
    return prime - 2;
}

template <typename T>
int *tp_tree<T>::hash_seed(int *pKey, int R) {
    int *v = new int[R], key;
    memset(v, 0, R * sizeof(R));
    if (pKey == NULL) {
        srand(time(NULL));
        for (int i = 0; i < R; i++)
            v[i] = rand() % R;
    }
    else {
        key = *pKey;
        for (int i = 0; i < R && key; i++) {
            v[i] = key % R;
            key = key / R;
        }
    }
    return v;
}


template <typename T>
void tp_tree<T>::hash_seed_free(int *v) {
    delete[] v;
}

template <typename T>
int tp_tree<T>::hash(int key, int R, int *v) {
    int slot = 0, M = R*R;
    int *numV = hash_seed(&key, R);
    for (int i = 0; i < R; i++)
        slot += numV[i] * v[i];
    hash_seed_free(numV);
    return slot % M;
}

 

所有代码均经过测试,结果正确!

以上是关于Treap树的主要内容,如果未能解决你的问题,请参考以下文章

平衡树合集(Treap,Splay,替罪羊,FHQ Treap)

[代码] bzoj 3224 普通平衡树(无旋treap)

Treap树

fhq-Treap 文艺平衡树代码记录

POJ 1442 Black Box(treap树)

非旋Treap