Treap学习总结
Treap学习总结
最近在研究平衡树,这里是我的treap学习笔记。
Treap是一种用来排序的数据结构,编写比较容易,时间复杂度也很好。
Treap = Tree + Heap
为了解决查找树退化的问题,在所学的数据结构里,能保证树的层数尽量少,分布尽量均匀,我们最先想到的就是完全二叉树了。而具有完全二叉树性质的数据结构很明显,堆就是其中之一,所以我们可以试想一想,如果在满足二叉查找树的前提下,同时又能满足堆的性质,是不是就可以避免这个树的退化呢?
当然,如果都以权值作为标准的话,很明显是不可能做到的,但是我们可以再给每个节点添加一个修正值,让这个修正值构成堆,而原始值满足BST,这样就解决了二叉查找树的平衡问题了。
由于是一个学习总结,就不在描述treap的工作原理了,直接上代码了。
1,数据结构定义
1 struct node 2 { 3 int l,r; 4 int key,kind,fix; 5 }a[MaxN]; //Treap
2,左旋/右旋操作
1 //左旋 2 void turn_left(int &x) 3 { 4 int y=a[x].r; 5 6 a[y].size=a[x].size; 7 a[x].size-=a[a[rc].r].size+1; 8 9 a[x].r=a[y].l; 10 a[y].l=x; 11 x=y; 12 } 13 //右旋 14 void turn_right(int &x) 15 { 16 int y=a[x].l; 17 18 a[y].size=a[x].size; 19 a[x].size-=a[a[lc].l].size+1; 20 21 a[x].l=a[y].r; 22 a[y].r=x; 23 x=y; 24 } 25 26 //其中的size域存放的是以当前节点为根的子树上的节点个数,用来查找第K大值
3,插入操作
1 //插入 2 void insert(int &k,int tkey) 3 { 4 if (k==-1) 5 { 6 k=++tot; 7 a[k].key=tkey; 8 a[k].size=1; 9 //memcpy(a[k].name,name,sizeof(name)); 10 a[k].fix=rand(); 11 } 12 else 13 if (tkey<a[k].key) 14 { 15 insert(a[k].l,tkey); 16 a[k].size++; 17 if (a[ a[k].l ].fix>a[k].fix) 18 turn_right(k); 19 } 20 else 21 { 22 insert(a[k].r,tkey); 23 a[k].size++; 24 if (a[ a[k].r ].fix>a[k].fix) 25 turn_left(k); 26 } 27 28 }
4,删除操作
1 void Delete(int &k,int tkey) 2 { 3 int lc=a[k].l; int rc=a[k].r; 4 5 if (tkey==a[k].key) //找到要删除的节点 对其删除 6 { 7 if (lc==-1 || rc==-1) //情况一,该节点可以直接被删除 8 { 9 if (rc==-1) k=lc; //用左子节点代替它 10 else k=rc; //用右子节点代替它 11 flag=true; 12 } 13 else //情况二 14 { 15 if (a[lc].fix > a[rc].fix) //左子节点修正值较大,右旋 16 { 17 turn_right(k); 18 Delete(a[k].r,tkey); //修正子树 19 if (flag) a[k].size--; 20 } 21 else //左子节点修正值较小,左旋 22 { 23 turn_left(k); 24 Delete(a[k].l,tkey); 25 if (flag) a[k].size--; 26 } 27 } 28 } 29 else 30 if (tkey < a[k].key) { 31 Delete(a[k].l,tkey); //在左子树查找要删除的节点 32 if (flag) a[k].size--; 33 } 34 else { 35 Delete(a[k].r,tkey); //在右子树查找要删除的节点 36 if (flag) a[k].size--; 37 } 38 }
5,查找操作[代码是用来查找第K大数的]
1 int Search(int &now,int k) 2 { 3 int lc=a[now].l; int rc=a[now].r; 4 if (k < a[lc].size + 1) //左子树中查找排名第k的元素 5 return Search(a[now].l,k); 6 else if (k > a[lc].size + 1) //在右子树中查找排名第k-(a[lc]size+1)的元素 7 return Search(a[now].r,k-(a[lc].size + 1)); 8 else 9 return a[now].key; //返回当前节点 10 }
Treap的应用方面还是比较广的,最基本的应用就是查找元素排名和查找第K大值,所以可以用来动态的统计数据以及优化动态规划。