看了这么久的平衡树,是时候做个总结了。
以poj 3481为例,敲了四份代码,分别是Treap ,Size Balance Tree,Avl Tree,splay tree。
唯独少了红黑树T_T。。。
总的来说每种平衡树各有各的优点吧:
Treap写起来简单上手也快如果熟练的话不到十分种可以敲完。
SBT速度快名不虚传。。。
Avl树高度平衡吧,不过实际的效果不尽如人意,可能是我实现的姿势不对吧/(ㄒoㄒ)/~~
splay tree各方面比较均衡,特别的伸展树在维护序列方面相对其它几种树优势明显。
可持久化的Treap除外(因为没比较过故不好妄下结论)。
总之,只要理解了旋转操作和建树的思想,每种树实现起来都很方便。。。
好了少扯淡了代码如下:
Treap:
#include
#include
#include
#define Max_N 110000
#define size(_) ((_)==NULL ? 0 : (_)->size)
typedef struct _trp{
int client, key, size, fix;
struct _trp *ch[2];
}treap, *Treap;
treap stack[Max_N];
int sz = 0;
int run(){
static int x = 1840828537;
x += (x << 2) | 1;
return x;
}
void update(Treap x){
if (x == NULL) return;
x->size = size(x->ch[0]) + size(x->ch[1]) + 1;
}
void rotate(Treap *x, int d){
Treap k = (*x)->ch[!d];
(*x)->ch[!d] = k->ch[d];
k->ch[d] = *x;
k->size = (*x)->size;
update(*x);
*x = k;
}
void insert(Treap *x, int client, int key){
if (*x == NULL){
*x = &stack[sz++];
(*x)->ch[0] = (*x)->ch[1] = NULL;
(*x)->key = key, (*x)->size = 1, (*x)->client = client, (*x)->fix = run();
} else {
int d = key > (*x)->key;
insert(&((*x)->ch[d]), client, key);
update(*x);
if ((*x)->ch[d]->fix < (*x)->fix) rotate(x, !d);
}
}
void _delete(Treap *x, int key){
if (*x == NULL) return;
if ((*x)->key == key){
if (!(*x)->ch[0] || !(*x)->ch[1]){
*x = (*x)->ch[0] ? (*x)->ch[0] : (*x)->ch[1];
} else {
int d = (*x)->ch[0]->fix < (*x)->ch[1]->fix;
rotate(x, d);
_delete(&((*x)->ch[d]), key);
}
} else {
_delete(&((*x)->ch[key>(*x)->key]), key);
}
if (*x != NULL) update(*x);
}
Treap find_kth(Treap x, int k){
int t = 0;
for (; x != NULL;){
t = size(x->ch[0]);
if (k == t + 1) break;
else if (k <= t) x = x->ch[0];
else k -= t + 1, x = x->ch[1];
}
return x;
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w+", stdout);
#endif
int n, a, b;
Treap root = NULL, ret = NULL;
while (~scanf("%d", &n) && n){
ret = NULL;
if (2 == n || 3 == n){
if (2 == n && root) ret = find_kth(root, root->size);
else if (3 == n && root) ret = find_kth(root, 1);
if (!ret || !root) printf("0\n");
else printf("%d\n", ret->client), _delete(&root, ret->key);
} else {
scanf("%d %d", &a, &b);
insert(&root, a, b);
}
}
return 0;
}
SBT:
#include
#include
#include
#define Max_N 110000
#define size(_) ((_)==NULL ? 0 : (_)->size)
typedef struct _sbt{
int client, key, size;
struct _sbt *ch[2];
}SBTNode, *SBT;
SBTNode stack[Max_N];
int sz = 0;
void rotate(SBT *x, int d){
SBT k = (*x)->ch[!d];
(*x)->ch[!d] = k->ch[d];
k->ch[d] = *x;
k->size = (*x)->size;
(*x)->size = size((*x)->ch[0]) + size((*x)->ch[1]) + 1;
*x = k;
}
void Maintain(SBT *x, int d){
if ((*x)->ch[d] == NULL) return;
if (size((*x)->ch[d]->ch[d]) > size((*x)->ch[!d])) rotate(x, !d);
else if (size((*x)->ch[d]->ch[!d]) > size((*x)->ch[!d]))
rotate(&((*x)->ch[d]), d), rotate(x, !d);
else return;
Maintain(&((*x)->ch[d]), 0);
Maintain(&((*x)->ch[!d]), 1);
Maintain(x, 0), Maintain(x, 1);
}
void insert(SBT *x, int client, int key){
if (*x == NULL){
*x = &stack[sz++];
(*x)->ch[0] = (*x)->ch[1] = NULL;
(*x)->key = key, (*x)->size = 1, (*x)->client = client;
} else {
(*x)->size++;
insert(&((*x)->ch[key > (*x)->key]), client, key);
Maintain(x, key >= (*x)->key);
}
}
void _delete(SBT *x, int key){
if (*x == NULL) return;
(*x)->size--;
if ((*x)->key == key){
if (!(*x)->ch[0] || !(*x)->ch[1]){
*x = (*x)->ch[0] ? (*x)->ch[0] : (*x)->ch[1];
} else {
SBT ret = (*x)->ch[1];
for (; ret->ch[0] != NULL; ret = ret->ch[0]);
_delete(&((*x)->ch[1]), (*x)->key = ret->key);
}
} else {
_delete(&((*x)->ch[key > (*x)->key]), key);
}
}
SBT find_kth(SBT x, int k){
int t = 0;
for (; x != NULL;){
t = size(x->ch[0]);
if (k == t + 1) break;
else if (k <= t) x = x->ch[0];
else k -= t + 1, x = x->ch[1];
}
return x;
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w+", stdout);
#endif
int n, a, b;
SBT root = NULL, ret = NULL;
while (~scanf("%d", &n) && n){
ret = NULL;
if (2 == n || 3 == n){
if (2 == n && root) ret = find_kth(root, root->size);
else if (3 == n && root) ret = find_kth(root, 1);
if (!ret || !root) printf("0\n");
else printf("%d\n", ret->client), _delete(&root, ret->key);
} else {
scanf("%d %d", &a, &b);
insert(&root, a, b);
}
}
return 0;
}
Avl:
#include
#include
#include
#define Max_N 200000
#define _max(a,b) ((a)>(b)?(a):(b))
#define size(_) ((_)==NULL ? 0 : (_)->size)
#define Height(_) ((_)==NULL ? -1 : (_)->Height)
typedef struct _avl{
int client, key, size, Height;
struct _avl *ch[2];
}AvlTree, *Avl;
AvlTree stack[Max_N];
int sz = 0;
void update(Avl x){
if (x == NULL) return;
x->size = size(x->ch[0]) + size(x->ch[1]) + 1;
x->Height = _max(Height(x->ch[0]), Height(x->ch[1])) + 1;
}
void rotate(Avl *x, int d){
Avl k = (*x)->ch[!d];
(*x)->ch[!d] = k->ch[d];
k->ch[d] = *x;
update(*x);
update(k);
*x = k;
}
void Maintain(Avl *x, int d){
if (Height((*x)->ch[d]) - Height((*x)->ch[!d]) == 2){
if (Height((*x)->ch[d]->ch[d]) - Height((*x)->ch[d]->ch[!d]) == 1) rotate(x, !d);
else if (Height((*x)->ch[d]->ch[d]) - Height((*x)->ch[d]->ch[!d]) == -1){
rotate(&((*x)->ch[d]), d), rotate(x, !d);
}
}
}
void insert(Avl *x, int client, int key){
if (*x == NULL){
*x = &stack[sz++];
(*x)->ch[0] = (*x)->ch[1] = NULL;
(*x)->key = key, (*x)->Height = 0, (*x)->size = 1, (*x)->client = client;
} else {
int d = key > (*x)->key;
insert(&((*x)->ch[d]), client, key);
update(*x);
Maintain(x, d);
}
}
void _delete(Avl *x, int key){
if (*x == NULL) return;
if ((*x)->key == key){
if (!(*x)->ch[0] || !(*x)->ch[1]){
*x = (*x)->ch[0] ? (*x)->ch[0] : (*x)->ch[1];
} else {
Avl ret = (*x)->ch[1];
for (; ret->ch[0] != NULL; ret = ret->ch[0]);
_delete(&((*x)->ch[1]), (*x)->key = ret->key);
}
} else {
_delete(&((*x)->ch[key > (*x)->key]), key);
}
if (*x != NULL){
update(*x);
Maintain(x, 0), Maintain(x, 1);
}
}
Avl find_kth(Avl x, int k){
int t = 0;
for (; x != NULL;){
t = size(x->ch[0]);
if (k == t + 1) break;
else if (k <= t) x = x->ch[0];
else k -= t + 1, x = x->ch[1];
}
return x;
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w+", stdout);
#endif
int n, a, b;
Avl root = NULL, ret = NULL;
while (~scanf("%d", &n) && n){
ret = NULL;
if (2 == n || 3 == n){
if (2 == n && root) ret = find_kth(root, root->size);
else if (3 == n && root) ret = find_kth(root, 1);
if (!ret || !root) printf("0\n");
else printf("%d\n", ret->client), _delete(&root, ret->key);
} else {
scanf("%d %d", &a, &b);
insert(&root, a, b);
}
}
return 0;
}
splay tree:
#include
#include
#include
#define Max_N 200000
#define size(_) ((_)==null ? 0 : (_)->size)
typedef struct _spt{
int client, key, size;
struct _spt *pre, *ch[2];
}splay;
splay *null, *root, stack[Max_N];
int sz = 0;
splay *_calloc(int client, int key){
splay *p = &stack[sz++];
p->pre = p->ch[0] = p->ch[1] = null;
p->size = 1, p->key = key, p->client = client;
return p;
}
void push_up(splay *x){
if (x == null) return;
x->size = size(x->ch[0]) + size(x->ch[1]) + 1;
}
void rotate(splay *x, int d){
splay *y = x->pre;
y->ch[!d] = x->ch[d];
if (x->ch[d] != null) x->ch[d]->pre = y;
x->pre = y->pre;
if (y->pre != null) y->pre->ch[y->pre->ch[0] != y] = x;
x->ch[d] = y;
y->pre = x;
push_up(y);
if (y == root) root = x;
}
void splay_splay(splay *x, splay *f){
for (; x->pre != f;){
if (x->pre->pre == f){
rotate(x, x->pre->ch[0] == x);
} else {
splay *y = x->pre, *z = y->pre;
if (z->ch[0] == y){
if (y->ch[0] == x) rotate(y, 1), rotate(x, 1);
else rotate(x, 0), rotate(x, 1);
} else {
if (y->ch[1] == x)
rotate(y, 0), rotate(x, 0);
else rotate(x, 1), rotate(x, 0);
}
}
}
push_up(x);
}
void insert(int client, int key){
splay *fp = null, *p = root;
if (root == null){
root = _calloc(client, key);
return;
}
for (; p != null;){
fp = p;
if (key > p->key) p = p->ch[1];
else p = p->ch[0];
}
p = _calloc(client, key);
if (fp->key > key) fp->ch[0] = p;
else fp->ch[1] = p;
p->pre = fp;
splay_splay(p, null);
push_up(p);
}
void _delete(int key){
splay *p = root, *rt = null;
while (p != null && p->key != key) p = p->ch[key > p->key];
if (p == null) return;
splay_splay(p, null);
rt = root->ch[0];
if (rt == null){
rt = root->ch[1];
} else {
splay *tmp = rt->ch[1];
while (tmp != null && tmp->ch[1] != null) tmp = tmp->ch[1];
if (tmp != null) splay_splay(tmp, root);
rt = root->ch[0];
rt->ch[1] = root->ch[1];
root->ch[1]->pre = rt;
}
root = rt;
root->pre = null;
if (root != null) push_up(root);
}
void initialize(){
null = _calloc(-1, -1);
null->size = 0;
root = null;
}
splay *find_kth(splay *x, int k){
int t = 0;
for (; x != null;){
t = size(x->ch[0]);
if (k == t + 1) break;
else if (k <= t) x = x->ch[0];
else k -= t + 1, x = x->ch[1];
}
if (x == null){
return null;
} else {
splay_splay(x, null);
return root;
}
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w+", stdout);
#endif
int n, a, b;
initialize();
splay *ret = NULL;
while (~scanf("%d", &n) && n){
ret = NULL;
if (2 == n || 3 == n){
if (2 == n && root) ret = find_kth(root, root->size);
else if (3 == n && root) ret = find_kth(root, 1);
if (ret == null || root == null) printf("0\n");
else printf("%d\n", ret->client), _delete(ret->key);
} else {
scanf("%d %d", &a, &b);
insert(a, b);
}
}
return 0;
}
最后上对比结果:从上到下依次是,splay tree, treap,sbt,avl。
其实蒟蒻只会用c语言不会c++,但提交代码的时候选了c++和gcc两种o(╯□╰)o。。。