Treap原理和实现方法
Treap是一棵二叉搜索樹,只是每個節點多了一個優先級fix,對于每個節點,該節點的優先級小于等于其所有孩子的優先級。
當然,引入優先級fix的目的就是防止BST退化成一條鏈,從而影響查找效率。
?
所以,這樣看來就是:Treap中對于節點的關鍵字key來說,它是一棵二叉搜索樹,而對于fix來說,它是一個最小堆,所以
Treap可以看成是Tree+Heap,只是這里的Heap不一定是完全二叉樹。Treap的平均時間復雜度為log(n).
?
Treap跟笛卡爾樹幾乎是一模一樣的,只是用途不同。
笛卡爾樹是把已有的一些(key,?fix)二元組拿來構造樹,然后利用構樹過程和構造好的樹來解決LCA,RMQ等等問題。而
Treap的目的只是對一些key進行二叉搜索,但是為了保證樹的平衡性,為每個key隨機地額外增加了一個fix屬性,這樣從概
率上來講可以讓這棵樹更加平衡。
?
對于Treap來說,主要有幾大操作:插入,刪除,查找,旋轉,找第K大元素,找關鍵字x的排名,計算Treap的高度,刪除
Treap,其它的操作比如合并,分離,反轉等等以后再說,另外,對于Treap來說,它的中序遍歷的結果就是按照關鍵字從小到
大的順序排列的。
?
?
下面用一個題來看看Treap的各種操作。
題目:http://poj.org/problem?id=1442
?
題意:給一個序列,然后給出m個查詢,每次查詢輸入一個數x,對于第i次查詢,輸出前x個數中第i大的關鍵字的值。
?
分析:我們可以用其它數據結構解決,這里我們先學用Treap怎么做吧,方法就是:每次我們都插入前x個數中沒有插過的,當
然程序中我們用index來劃分界限,然后輸出Kth(root,i)即可。
#include <iostream> #include <string.h> #include <stdlib.h> #include <stdio.h>using namespace std;struct Treap {int size;int key,fix;Treap *ch[2];Treap(int key){size=1;fix=rand();this->key=key;ch[0]=ch[1]=NULL;}int compare(int x) const{if(x==key) return -1;return x<key? 0:1;}void Maintain(){size=1;if(ch[0]!=NULL) size+=ch[0]->size;if(ch[1]!=NULL) size+=ch[1]->size;} };void Rotate(Treap* &t,int d) {Treap *k=t->ch[d^1];t->ch[d^1]=k->ch[d];k->ch[d]=t;t->Maintain(); //必須先維護t,再維護k,因為此時t是k的子節點k->Maintain();t=k; }void Insert(Treap* &t,int x) {if(t==NULL) t=new Treap(x);else{//int d=t->compare(x); //如果值相等的元素只插入一個int d=x < t->key ? 0:1; //如果值相等的元素都插入Insert(t->ch[d],x);if(t->ch[d]->fix > t->fix)Rotate(t,d^1);}t->Maintain(); }//一般來說,在調用刪除函數之前要先用Find()函數判斷該元素是否存在 void Delete(Treap* &t,int 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) {while(t!=NULL){int d=t->compare(x);if(d==-1) return true;t=t->ch[d];}return false; }int Kth(Treap *t,int k) {if(t==NULL||k<=0||k>t->size)return -1;if(t->ch[0]==NULL&&k==1)return t->key;if(t->ch[0]==NULL)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); }void DeleteTreap(Treap* &t) {if(t==NULL) return;if(t->ch[0]!=NULL) DeleteTreap(t->ch[0]);if(t->ch[1]!=NULL) DeleteTreap(t->ch[1]);delete t;t=NULL; }void Print(Treap *t) {if(t==NULL) return;Print(t->ch[0]);cout<<t->key<<endl;Print(t->ch[1]); }int val[1000005];int main() {int n,x,m;while(~scanf("%d%d",&n,&m)){for(int i=1; i<=n; i++)scanf("%d",&val[i]);int index=1;Treap *root=NULL;for(int i=1; i<=m; i++){scanf("%d",&x);for(int j=index; j<=x; j++)Insert(root,val[j]);index=x+1;printf("%d\n",Kth(root,i));}DeleteTreap(root);}return 0; }
?
總結
以上是生活随笔為你收集整理的Treap原理和实现方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU4405(概率DP求期望)
- 下一篇: SPOJ3273(Treap)