替罪羊树
-
\(\alpha\) 平衡因子 ( \(0.5 < \alpha < 1\))
-
替罪羊树原理 : 当树不平衡时 , 中序遍历收集树上的所有节点,然后用二分的方式重构整棵树, 使其变成标准的平衡树. 查询代价由树高决定, 重构代价由重构节点个数和平衡因子决定
-
节点信息:
- val , 键值,代表节点储存的信息
- count : 平衡树最好不要有键值相同的节点, 插入重复的值只需要把对应节点的count 值修改就可以了.
- left , right , 左右孩子指针.
- diff , 子树中含有的节点数的多少 (即不同的数的个数)
- size , 记录树上总共收集了多少个变量
-
\(\alpha\) 因子 越接近 1 , 重构次数越少, 查询复杂度上升, \(\alpha\) 越接近 0.5 , 树高越小, 重构次数越多, 查询时间复杂度下降
class TZYTree{
public:
#define ls(p) t[p].l
#define rs(p) t[p].rstruct node{int l , r; // 左右孩子指针, 如果没有孩子就为0int val; // 代表当前节点的值int diff; // 代表子树中有多少个节点int count; // 代表当前节点有多少个数int size; // 代表子树中有多少个数node() : l(0) , r(0), diff(0),count(0),size(0),val(0){}};const double alpha = 0.7; // 平衡因子int cnt = 0; // 代表有序表当前已使用的节点数int top = 0; // 代表最上方不平衡的节点, 如果 top = 0 , 则说明不存在不平衡的节点int Head = 0; // 记录替罪羊树的根节点的下标, 如果表中无元素则下标为 0 int father = 0; // 记录最上方不平衡的节点的父节点, 重构之后可能需要修改指针, 如果是整棵树 , 那么 father = 0int side = 0; // 记录不最上方的不平衡节点是它的父节点的左孩子还是右孩子 , 1为左孩子 , 0 为右孩子int pos = 0; // 记录 order 表中最后一个数据的下标 , 即 1 - posstatic const int inf = INT_MAX;std::vector<node> t;std::vector<int> order;TZYTree (int n) {// n 代表有序表最大数量assign(n);}void assign(int n){t.assign( n + 2,node());order.assign(n+2,0);}// 新增一个节点int add(int x) { t[++cnt].val = x;t[cnt].size = t[cnt].diff =t[cnt].count = 1;return cnt;}void up( int p){t[p].size = t[ls(p)].size + t[rs(p)].size + t[p].count;t[p].diff = t[ls(p)].diff + t[rs(p)].diff + (t[p].count > 0);}// 收集为中序遍历void inorder(int p) {if (p !=0){inorder(ls(p));if(t[p].count >0 ){order[++pos] = p; // 注意这里只是中序遍历把节点下标上传}inorder(rs(p));}}// l 代表order 中的序号 , 中序遍历重构int build(int l , int r) {if(l > r) return 0;int mid = (l + r)/2;int head = order[mid];ls(head) = build(l,mid-1);rs(head) = build(mid+1,r);up(head);return head;}void rebuild() {if(top != 0) {// 即存在不平衡现象pos = 0;inorder(top);if (pos > 0) {if( father == 0) {Head = build(1,pos); // 头节点重连} else if(side == 1) {ls(father) = build(1,pos);} else {rs(father) = build(1,pos);}}}}bool balance(int p) {// 如果子树中的节点数大于 整颗树的节点数乘以 alpha 倍, 则重构return alpha * t[p].diff >= std::max(t[ls(p)].diff , t[rs(p)].diff);}void insert(int number) {top = father = side = 0;insert(Head,0,0,number);rebuild();}void insert(int p,int f,int s,int num) {if(p == 0) {if(f == 0) {Head = add(num);} else if(s == 1) {ls(f) = add(num);} else {rs(f) = add(num);}} else {// assert(p >t.size());if( t[p].val == num) {t[p].count++;} else if(t[p].val > num) {insert(ls(p),p,1,num);} else {insert(rs(p),p,2,num);}up(p);if(!balance(p)) {top = p;father = f;side = s;}}}void remove(int p, int f, int s,int num) {if(t[p].val == num) {t[p].count--;} else if(t[p].val > num) {remove(ls(p),p,1,num);} else {remove(rs(p),p,2,num);}up(p);if(!balance(p)) {father = f , side = s , top = p;}}void remove(int num) {if(rank(num) != rank(num+1)) {top = father = side = 0;remove(Head,0,0,num);}}int rank(int num) {return small(Head,num) + 1;}int small(int p , int num) {if(p == 0) {return 0;}if(t[p].val >= num) {return small(ls(p),num);} else {return t[ls(p)].size + small(rs(p),num) + t[p].count;}}int index(int x) {return index(Head,x);}int index(int p, int x) {if(t[ls(p)].size >= x) {return index(ls(p),x);} else if(t[ls(p)].size + t[p].count >= x) {return p;} else {return index(rs(p),x - t[ls(p)].size - t[p].count);}}// 查找小于某个数的最大值int pre(int x) {int kth = rank(x);if(kth == 1) {return -inf;} else {return index(kth-1);}}// 查找大于某个数的最小值int post(int x) {int kth = rank(x + 1);if(kth == t[Head].size + 1) { // 也就是没有大于某个数的值就放回 infreturn inf;} else {return index(kth);}}void clear(){Head = cnt = 0;t.clear();order.clear();}#undef ls
#undef rs
};