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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

伸展树 Splay 模板

發布時間:2024/4/17 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 伸展树 Splay 模板 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

學習Splay的時候參考了很多不同的資料,然而參考資料太雜的后果就是模板調出來一直都有問題,尤其是最后發現網上找的各種資料均有不同程度的錯誤。

好在啃了幾天之后終于算是啃下來了。

?

Splay也算是平衡樹的一種,但是跟AVL樹、SBT不同的是,Splay并不是一直保持嚴格的平衡,因此在速度上可能要慢一些,但是統計學上仍能保證Splay具有O(logn)的均攤復雜度。

Splay原生不需要附加任何空間,它的先天優勢是其特有的Splay操作可以非常靈活地改變整棵樹的結構形態,完成一般線段樹、平衡樹做不到的任務。

?

  • 基本操作-左右旋

Splay的基本操作與其他平衡樹相似,都是進行結點的左右旋轉。與之前寫的SBT相比,Splay除了左右兒子域以外還需要一個father域,這個是因為下面的Splay操作需要用到父節點來判斷當前的形態。

  • 核心操作-splay

Splay(x,y)的作用是將當前點x旋轉到y的子結點上,一般寫y=0時則將x旋轉到整棵樹的根。這個操作在splay的所有函數中基本上最后都要加上,簡單的理解就是將常用的結點盡可能地上移到深度較淺的地方,據統計若去掉函數最后對操作結點的splay,則整個程序將會慢上數倍。

splay基本的想法是根據當前結點父節點形態的不同,分成四種情況,逐步將結點旋轉到根上。

  • 進階操作

插入、查找值、查找第k個等等...基本與普通的二叉查找樹相似,但是記得在最后要加上splay,將使用過的結點旋轉到根。

?

特殊的刪除操作:

splay本身是一棵二叉搜索樹,可以進行一般的刪除操作。另外,二叉搜索樹的性質配合splay的操作可以做到O(logn)動態刪除一整個區間的結點,而一般的平衡樹則只能一個一個刪除。

例如:刪除大于l且小于r的數,先將序號小于l的最大結點伸展到根,序號大于r的最小的結點伸展到根的右子樹,則此時,r的后繼結點的左子樹中就存放著從l到r的所有結點,此時只要把這棵子樹整個斷開即可。

?

............

?

/* *********************************************** MYID : Chen Fan LANG : G++ PROG : Splay Tree ************************************************ */#include <iostream> #include <cstdio> #include <cstring> #include <algorithm>using namespace std;#define MAXN 100000int sons[MAXN][2]; int father[MAXN],size[MAXN],data[MAXN]; int spt=0,spttail=0;void rotate(int x,int w) //rotate(node,0/1) {int y=father[x];sons[y][1-w]=sons[x][w];if (sons[x][w]) father[sons[x][w]]=y;father[x]=father[y];if (father[y])if (y==sons[father[y]][0]) sons[father[y]][0]=x;else sons[father[y]][1]=x;sons[x][w]=y;father[y]=x;size[x]=size[y];size[y]=size[sons[y][0]]+size[sons[y][1]]+1; }void splay(int x,int y) //splay(node,position) {if (!x) return ;while(father[x]!=y){if (father[father[x]]==y)if (x==sons[father[x]][0]) rotate(x,1);else rotate(x,0);else if (father[x]==sons[father[father[x]]][0])if (x==sons[father[x]][0]){rotate(father[x],1);rotate(x,1);} else {rotate(x,0);rotate(x,1);}else if (x==sons[father[x]][1]){rotate(father[x],0);rotate(x,0);} else {rotate(x,1);rotate(x,0);}}if (!y) spt=x; }void search(int x,int w) {while(data[x]!=w){if (w<data[x]){if (sons[x][0]) x=sons[x][0];else break;} else if (w>data[x]){if (sons[x][1]) x=sons[x][1];else break;}}splay(x,0); }void insert(int w) //insert(value) {spttail++;data[spttail]=w;size[spttail]=1;sons[spttail][0]=0;sons[spttail][1]=0;if (!spt){father[spttail]=0;spt=spttail;} else {int x=spt;while(1){size[x]++;if (w<data[x])if (sons[x][0]) x=sons[x][0];else break;else if (sons[x][1]) x=sons[x][1];else break;}father[spttail]=x;if (w<data[x]) sons[x][0]=spttail;else sons[x][1]=spttail;splay(spttail,0);} }void select(int x,int v) //select(root,k) {while(v!=size[sons[x][0]]+1){if (v<=size[sons[x][0]]) x=sons[x][0];else {v-=size[sons[x][0]]+1;x=sons[x][1];}}splay(x,0); }int succ(int t) {t=sons[t][1];while(sons[t][0]) t=sons[t][0];splay(t,0);return t; }void del(int x) //del(number) {splay(x,0);int y=sons[x][0];while(!sons[y][1]){y=sons[y][1];}int z=sons[x][1];while(!sons[z][0]){z=sons[z][0];}if (y+z==0){spt=0;spttail=0;return ;}if (y){splay(y,0);size[y]--;}if (z){splay(z,y);sons[z][0]=0;size[z]--;} }int rank(int v) //rank(value) {search(spt,v);return size[sons[spt][0]]+1; }int main() {memset(father,0,sizeof(father));memset(size,0,sizeof(size));memset(sons,0,sizeof(sons));memset(data,0,sizeof(data));spt=0;spttail=0;return 0; }

?

轉載于:https://www.cnblogs.com/jcf94/p/4333497.html

總結

以上是生活随笔為你收集整理的伸展树 Splay 模板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。