Treap原理和实现方法
Treap是一棵二叉搜索樹,只是每個(gè)節(jié)點(diǎn)多了一個(gè)優(yōu)先級(jí)fix,對(duì)于每個(gè)節(jié)點(diǎn),該節(jié)點(diǎn)的優(yōu)先級(jí)小于等于其所有孩子的優(yōu)先級(jí)。
當(dāng)然,引入優(yōu)先級(jí)fix的目的就是防止BST退化成一條鏈,從而影響查找效率。
?
所以,這樣看來就是:Treap中對(duì)于節(jié)點(diǎn)的關(guān)鍵字key來說,它是一棵二叉搜索樹,而對(duì)于fix來說,它是一個(gè)最小堆,所以
Treap可以看成是Tree+Heap,只是這里的Heap不一定是完全二叉樹。Treap的平均時(shí)間復(fù)雜度為log(n).
?
Treap跟笛卡爾樹幾乎是一模一樣的,只是用途不同。
笛卡爾樹是把已有的一些(key,?fix)二元組拿來構(gòu)造樹,然后利用構(gòu)樹過程和構(gòu)造好的樹來解決LCA,RMQ等等問題。而
Treap的目的只是對(duì)一些key進(jìn)行二叉搜索,但是為了保證樹的平衡性,為每個(gè)key隨機(jī)地額外增加了一個(gè)fix屬性,這樣從概
率上來講可以讓這棵樹更加平衡。
?
對(duì)于Treap來說,主要有幾大操作:插入,刪除,查找,旋轉(zhuǎn),找第K大元素,找關(guān)鍵字x的排名,計(jì)算Treap的高度,刪除
Treap,其它的操作比如合并,分離,反轉(zhuǎn)等等以后再說,另外,對(duì)于Treap來說,它的中序遍歷的結(jié)果就是按照關(guān)鍵字從小到
大的順序排列的。
?
?
下面用一個(gè)題來看看Treap的各種操作。
題目:http://poj.org/problem?id=1442
?
題意:給一個(gè)序列,然后給出m個(gè)查詢,每次查詢輸入一個(gè)數(shù)x,對(duì)于第i次查詢,輸出前x個(gè)數(shù)中第i大的關(guān)鍵字的值。
?
分析:我們可以用其它數(shù)據(jù)結(jié)構(gòu)解決,這里我們先學(xué)用Treap怎么做吧,方法就是:每次我們都插入前x個(gè)數(shù)中沒有插過的,當(dāng)
然程序中我們用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(); //必須先維護(hù)t,再維護(hù)k,因?yàn)榇藭r(shí)t是k的子節(jié)點(diǎn)k->Maintain();t=k; }void Insert(Treap* &t,int x) {if(t==NULL) t=new Treap(x);else{//int d=t->compare(x); //如果值相等的元素只插入一個(gè)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(); }//一般來說,在調(diào)用刪除函數(shù)之前要先用Find()函數(shù)判斷該元素是否存在 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; }
?
總結(jié)
以上是生活随笔為你收集整理的Treap原理和实现方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU4405(概率DP求期望)
- 下一篇: SPOJ3273(Treap)