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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

伸展树学习总结

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

伸展樹

與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()接口
伸展樹的伸展調整算法:

template<typename T>inline void attachAsLChild(NodePosi p, NodePosi lc){p->lChild=lc;if(lc)lc->parent=p;//為p,lc建立父(左)子的關系,可能lc為null } template<typename T>inline void attachAsRChild(NodePosi p, NodePosi rc){p->rChild=rc;if(rc)rc->parent=p;//為p,lc建立父(左)子的關系,可能lc為null }template<typename T>BinNodePosi* Splay<T>::splay(BinNodePosi* v){//從v的位置開始進行伸展操作if(!v) return null;BinNodePosi* p,g;//v的父親與祖父while((p=v->parent)&&(g=p->parent)){//自下而上進行雙層伸展BinNodePosi* gg=g->parent;if(p->lChild==v)if(g->lChild==p){//zig-zig//忽略具體旋轉過程,直接拼接操作attachAsLChild(g,p->rChild);//將g拼接到p上attachAsLChild(p,v->rChild);//將p拼接到v上attachAsRChild(p,g);attachAsRChild(v,p);//操作同上}else{//zig-zagattachAsLChild(p,v->rChild);attachAsRChild(g,v->lChild);attachAsLChild(v,g);attachAsRChild(v,p);}else if(g->RChild==p){//zag-zagattachAsRChild(g,p->lChild);attachAsRChild(p,v->lChild);attachAsLChild(p,g);attachAsLChild(v,p);} else{//zag-zigattachAsRChild(p,v-lChild);attachAsLChild(g,v->rChild);attachAsRChild(v,g);attachAsLChild(v,p);}if(!gg) v->parent=null;//v伸展至最頂端,變為rootelse//曾祖父存在,直接將v作為曾祖父的左孩子或右孩子(g==gg->lChild)?attachAsLChild(gg,v):attachAsRChild(gg,v);updateHeight(g);updateHeight(p);updateHeight(v);}if(p=v->parent){//v旋轉到最后還有一個p,需要完成一次單旋if(p-lChild==v){attachAsLChild(p,v->rChild);attachAsRChild(v,p);}else {attachAsRChild(p,v->lChild);attachAsLChild(v,p);}updateHeight(p);updateHeight(v);}v->parent=null; returnv;//v已移至root位置 }

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), 不適用于對效率敏感的場所

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

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

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