[模板] 树堆 - 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 | 传送门 |
相关文章推荐
- 入门经典_Chap06_例题[二]:二叉树的指针及数组实现
- 字典树模板(数组实现和指针实现)
- HDU1251 统计难题(字典树模板题--数组实现+指针实现)
- 用python实现一些数组的面试题
- C语言中使用指针实现数组排序
- 程序语言的底层描述(5)——数组、指针的汇编实现以及C程序嵌入汇编
- 给定一个数组和一个数M,在数组中求一些数使它们的和最接近M------用递归法实现的。。。。。。
- 增强String replace方法,实现对字符串进行模板替换,支持对象、数组
- 用c++模板实现 线性表(数组表示)
- 理解数组,结构 ,函数指针,指针函数,数组指针,指针数组,结构指针的定义和实现
- bzoj 1588 营业额统计 (treap 数组实现)
- 数组实现的队列(限制最大长度)的head、tail指针的修改方法。
- 约瑟夫环问题的PHP实现 使用PHP数组内部指针操作函数
- 使用指针的方式实现数组逆序
- c++用二维数组实现多个字符数组的长度变换(微难一些)
- 【模板】【Treap/SBT】【树堆】普通平衡树【洛谷P3369】
- C/C++基础———C/C++中函数指针和数组指针、数组名的一些个人理解
- 泛型编程(模板函数,模板类的套用) Myvector 具体案例 实现可存放int 数组 char数组 类对象数组 以及一组指针
- c++ 返回数组以及指针的一些问题
- 对数组a中n个整数反序存放,可用指针实现。