昨晚終於明白了splay雙旋中的一些細節,今日整理如下
注:題目用的2002HNOI營業額統計,測試結果均來及codevs 網站的評測結果 http://codevs.cn/problem/1296/
本題完整代碼請見http://www.cnblogs.com/TheRoadToTheGold/p/6372009.html
1、這是旋轉部分的代碼
inline void splay(int x,int goal) { while(pre[x]!=goal) { int y=pre[x]; int kind=ch[y][0]==x; if(pre[y]==goal) rot(x,kind);//父節點是目標節點,單旋 else { kind=ch[pre[y]][0]==y; if(ch[y][!kind]==x)//一字型 { rot(y,kind); rot(x,kind); } else//之字型 { rot(x,!kind); rot(x,kind); } } } root=x; }
理解較淺,目前認為之字形旋轉的本質就是單旋,一字型才算雙旋
2、雙旋與單旋的區別
先看看運行結果
左邊是單旋,右邊是雙旋,空間幾乎一樣,時間差距很大
why?
圖1:
圖2的單旋結果
圖2:
雙旋結果
可以發現,雙旋之后的層數要比單旋之后的層數少1
這只是5層(本圖中第6層對5不干擾),如果層數更多呢
所以,雙旋層數比單旋要更少
手推一下,上圖中第1次旋轉結果的樹的形態與單旋結果的樹的形態是一樣的,只是4和3換了個位
所以雙旋的優越性在一字型層數>4時才會體現
為什么雙旋層數要少?
繼續觀察圖2的第2個和第3個,發現少的那一層是因為4和1處在了同一層
即雙旋 使 待旋轉點的旋轉方向的孩子 與待旋轉點的爺爺節點 處在同一層
換用字母表示:
設a的旋轉方向的孩子是b,a的父節點是c,c的父節點是d
那么雙旋使b、d處在同一層,因為b、d都成為了c的孩子
為什么?分析雙旋的兩次旋轉
先旋轉父節點,使爺爺節點和自己都成為父節點的孩子,此時父節點和自己處在同一層,原來的爺爺節點成為自己的父節點
然后旋轉自己,自己旋轉方向的孩子節點成為自己現在父節點(原先爺爺節點)的孩子,也就是和自己原先父節點處在了同一層
這也是我認為之字型旋轉也是單旋的原因,因為之字型旋轉是讓自己旋轉2次,與單旋並無不同
3、旋轉順序
A、代碼中一字型旋轉順序是先轉父節點,再轉自己
①不能改成先轉自己,再轉父節點
先轉自己讓自己到父節點的位置,父節點到自己的孩子位置,再轉父節點,又轉回去了,跟沒轉一個樣
②可以改成旋轉自己兩次,但那樣就相當於單旋
B、之字型旋轉的旋轉順序是連續轉自己2次
看圖,
可以發現連續轉自己兩次,每次使自己上移一層
而如果先轉父節點,可以發現自己原來在哪兒還在那兒,只是父節點和爺爺節點換了而已,相當於這一次白轉了
當然你也可以先轉父節點,再轉自己(兩次旋轉方向相同),因為的正確性是有保證的
對比一下,上邊是先轉父節點,再轉自己,下邊是連續轉自己兩次(一字型旋轉均是先轉父節點,再轉自己)
上邊空間明顯大,時間也多點兒