前面講解了伸展樹的原始姿態:二叉搜尋樹!這篇文章呢就講解一下伸展樹的兩種操作:右旋(zag)和左旋(zig)操作:
伸展樹右旋的圖示:
(旋轉的結果就是:使結點t的位置向上移動:人往高處走嘛)
右旋有乙個前提:結點t是結點f的左孩子!根據二叉搜尋樹的性質:各結點滿足以下不等式:
a旋轉後,這個等式也不能變!這樣裡能理解a,b,r結點的掛接情況了
同樣的左旋也也可模擬過來,
伸展樹左旋的圖示:
(旋轉的結果就是:使結點t的位置向根結點移動,也就是使其深度更小:人往高處走嘛)
關於旋轉,有的程式函式名為:zig() zag(),有的直接就稱為:rotate(),其實都是一樣的!沒什麼區別!
簡單的伸展操作了解了,我們看一下poj3580中的要求。
poj3580裡有這樣一種操作要求:insert x p
: insert
pafter
ax. for example, performing "
insert
2 4" on results in ,就是在序列的指定位置處插入乙個數!
像這樣的操作用線段樹是很難實現的,但是用伸展樹就很容易了!
比如序列:1 2 3 4 5,我們要在3的後面插入0,使序列變成:1 2 3 0 4 5
#include#define inf ~0u>>1
#define mn 200005
#define nil splay
using
namespace std;
struct splaytree
node(int _key):key(_key)
}splay[mn],*sp,*root,*head,*tail;
//// //對伸展樹進行初始化,也就是把head和tail加入到樹中,
void init()
//更新結點的值
void update(node *&t)
//結點t往右旋轉
void zig(node *&t)
t->right=f,r->father=f,f->father=t,f->left=r;
update(f);update(t);
} //結點t往左旋轉
void zag(node *&t)
t->left=f,ll->father=f,f->father=t,f->right=ll;
update(f);update(t);
} //暫時只維護區間,不作伸展操作
void splay(node *&root,node *&t)
elseelse
} }
} //往第pos位後插入key
void insert(int key,int pos)
if(flag)p->right=t;
else p->left=t;
t->father=p;
splay(root,t);
} void inorder(node *t)
}tree;
//這裡需要注意的是,splaytree一定要定義成全域性變數,不然會因為棧溢位而報記憶體錯誤
int main();//a[0]位置的資料不用
int i;
//初始化
tree.init();
//初始化序列資料
for(i=1;i<5;i++)
//把0插入到數列的第4個位置
tree.insert(0,4);
//按下標的順序輸出
tree.inorder(tree.root);
return 0; }
程式輸出的結果:2147483647 1 2 3 0 4 5 2147483647 除了head和tail,就正好是我們維護的序列了(head和tail的key值為inf,即0x7fffffff=(2147483647))。
伸展樹的學習(一) 學習的前提
學習伸展樹差不多有兩個多星期了吧!慢慢地也領悟到了它最基本的實現,都不敢說是 初窺門庭!最先看的是楊思雨的 伸展樹的基本操作與應用 現在回頭看確實寫得挺清晰易懂,但是可能是自己看書沒仔細看,或許是悟性太差吧!一直沒看懂,特別是結點旋轉的那幾張圖,即把x旋轉到樹的根結點!後來也不知道是看到哪篇部落格,...
已知樹的中序序列和先序 後序序列,求樹的結構?
已知樹的中序序列和先序 後序序列,求樹的結構?這類問題比較經典了,剛好csdn上有人問起,所以自己寫了乙個遞迴演算法,根據中序和先序 後序 建立樹結構。這裡需要說明的是 必須要知道中序序列,先序和後序可選的情況下才能推導出樹結構,只知道後序先序是推導不出。簡單說明一下基本思路,例 已知後序 debg...
已知前序遍歷序列和中序遍歷序列,求二叉樹的後序遍歷
已知前序遍歷序列和中序遍歷序列,求二叉樹的後序遍歷思路 在前序遍歷的序列中第乙個就是樹的根結點,此時再在中序遍歷的序列裡查詢這個根結點,則中序遍歷的序列里根結點左側的就是左子樹,右側的就是右子樹,再對左右子樹進行同樣的操作,此時可以使用遞迴實現,這樣便能構造出這個二叉樹。class treenode...