您的位置:首页 > 理论基础 > 数据结构算法

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

2017-08-19 21:11 381 查看

指针版:

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->
f126
;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传送门
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 树堆 treap