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树的主要内容,如果未能解决你的问题,请参考以下文章