伸展树学习总结
伸展樹
與AVL樹類似, 伸展樹也是二叉搜索樹的一種形式, 伸展樹無需保證時刻保持全樹的平衡,也不需要像AVL樹一樣要求記錄平衡因子的附加信息
伸展樹的提出源于信息訪問的局部性(剛被訪問過的信息有可能再次被訪問,要被訪問的元素可能位于剛訪問過的元素的附近), 就伸展樹而言,可采用剛被訪問的元素移至數據列表的前端,從而降低后續的操作時間
簡易伸展樹的最壞情況
每次使用search,將訪問后的元素移至樹根節點, 如果采用單次zig/zag旋轉(先對該節點的父節點進行旋轉,再對祖父進行旋轉,每旋轉一次,節點上升一層), 如果總節點數為n,那么總的旋轉次數將高達O(n*n), 平攤到每個節點,復雜度(O(n))都高于AVL樹, 簡易伸展并不會改變當前樹的拓撲結構
如圖:
雙層旋轉
由于單層旋轉將會造成O(n)多,高于AVL樹,就此提出改進措施:
進行雙層旋轉, 每次的旋轉不再是從當前節點的parent開始,而是從當前節點的grandpa開始;先對g旋轉,再對p旋轉,這種旋轉方式將在zig-zig,zag-zag下展現效果,如圖
對比簡易伸展與雙層旋轉,將會發現雙層旋轉每進行一次search操作, 那么樹的高度將會折半,那么如果訪問最壞的節點也不會出現O(n)的復雜度,單次操作可在O(logn)時間內完成, 但是如果旋轉方式為zig-zag/zag-zig, 雙層旋轉并不能改變樹高,雙層旋轉將導致樹的拓撲結構發生改變
有一種情況為:可能在最后的雙層旋轉過程中,v只有parent而沒有grandpa,但是這種情況只會在最后出現,并且只出現一次,所以并不會影響樹的整體旋轉效果,因此雙層旋轉的方式是有效的
伸展樹接口定義
基于二叉平衡搜索樹類,重寫search()(查找過程也會改變樹的拓撲結構,所以有必要進行重寫), insert(), remove()接口
伸展樹的伸展調整算法:
search實現
//在search過程中,將節點移動 template<typename T>BinNodePosi* Splay<T>::search(const T& e){BinNodePosi* p=searchIn(_root,e,_hot=null);//從根節點位置開始查找_root=splay((p?p:root));//無論查找是否成功都將返回與之對應的那個節點或者相似的節點至_root位置return _root; }insert實現
//由于查找的過程中就實現了將要找的相似元素移動至_root位置,再將要插入的元素與root位置的節點作比較,節點重連實現插入操作 template<typename T>BinNodePosi* Splay<T>::insert(const T& e){if(!_root) {++_size; return _root= new BinNode<T>(e);}//為空樹的情況if(e==search(e)->data) return _root;//元素已存在無需插入++_size; BinNodePosi* t=_root;//創建新節點if(_root->data<e){//插入e時,以roo為分界線包含root,左邊部分t變為e的左孩子,右邊部分變為e的右孩子t->parent=_root=BinNode<T>(e,null,t,t->rChild);//構造e節點,左右孩子為t,t->rChildif(t->rChild) {t->rChild->parent=_root;t->rChild=null;}//將t的rChild的parent由t改為_root,自身連接位置改為null,防止野指針}else{t->parent=_root=new BinNode<T>(e,null,t->lChild,t);if(t->lChild) {t->lChild->parent=_root;t->lChild=null;}//原理同上}updateHeight(t);//更新祖先高度return _root;//無論e是否在原樹中,返回值_root->data總是等于e }刪除實現
原理與insert一致,當進行完search操作后,位于root位置的則是要刪除的元素或者是相似的元素,在root的左子樹內查找要刪除元素的直接后繼succ()(表示二叉樹中序遍歷序列列表)將其替代即可完成刪除(這步操作與平衡搜索樹的remove一致),保證樹的局部性
template<typename T>bool Splay<T>::remove(const T& e){if(!_root||(e!=search(e)->data)) return false;//查找的節點信息未在樹中BinNodePosi* w=_root;//要刪除的節點已經伸展至樹根位置if(!_root->lChild) {//若無左子樹_root=_root->rChild; if(_root) _root->parent=null;}else if(!_root->rChild){//無右子樹_root=_root->lChild; if(_root) _root->parent=null;}else{//左右子樹都存在BinNodePosi* lTREE=_root->lChild;lTREE->parent=null;_root->lChild=null;//將左子樹暫時切除_root=_root->rChild;_root->parent=null;search(w->data);//該查找必定失敗,但是也將右子樹中的最小節點伸展至root的位置//該過程也可調用直接后繼,根據中序遍歷在右子樹中查找最小節點_root->lChild=lTREE;lTREE->parent=_root;//將左子樹重新歸位}delete w;_size--;//釋放要刪除的節點if(_root) updateHeight(_root);//樹非空時,更新高度return true; }總結:伸展樹復雜度與AVL樹一致O(logn),局部性較強,平均效率較高, 但是針對最壞情況下的單次操作時任需要O(n), 不適用于對效率敏感的場所
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: 台达n2系列变频器_台达变频器C2000
- 下一篇: ps绿化工具_绿化消防车价位