日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Treap原理和实现方法

發(fā)布時(shí)間:2024/4/11 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Treap原理和实现方法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。