1、AVL樹簡介
AVL樹本質上還是一棵二叉搜索樹,又稱高度平衡的二叉搜索樹。它能保持二叉樹的高度平衡,盡量降低二叉樹的高度,減少樹的平均搜索長度。對于二叉搜索樹的介紹和實現,可查看本人上一篇博客。
2、AVL樹的特點
1)本身首先是一棵二叉搜索樹。
2)帶有平衡條件:每個結點的左右子樹的高度之差的絕對值(平衡因子)最多為1。
3)樹中的每個左子樹和右子樹都是AVL樹。
4)每個結點都有一個平衡因子,任一結點的平衡因子是-1,0,1.
注:結點的平衡因子 = 右子樹高度 - 左子樹高度
3、AVL樹的效率
一棵AVL樹有N個結點,其高度可以保持在lgN,插入/刪除/查找的時間復雜度也是lgN。
AVL樹的復雜程度真是比二叉搜索樹高了整整一個數量級——它的原理并不難弄懂,但要把它用代碼實現出來還真的有點費腦筋。下面我們來看看AVL樹實現的接口,通過三叉鏈進行結點的實現。
template<classK,classV>structAVLTreeNode//三叉鏈{AVLTreeNode<K,V>*_left;AVLTreeNode<K,V>*_right;AVLTreeNode<K,V>*_parent;K_key;V_value;int_bf;//右子樹與左子樹的高度差AVLTreeNode(constK&key=K(),constV&value=V())//加上K()和V(),可缺省構造:_left(NULL),_right(NULL),_parent(NULL),_key(key),_value(value),_bf(0){}};template<classK,classV>classAVLTree{typedefAVLTreeNode<K,V>Node;public:AVLTree():_root(NULL){}voidInsert(constK&key,constV&value);Node*Find(constK&key);intHeight();boolIsBalance();voidPrintAVLTree();private:Node*_Find(Node*root,constK&key);void_RotateL(Node*&parent);void_RotateR(Node*&parent);void_RotateLR(Node*&parent);void_RotateRL(Node*&parent);int_Height(Node*root);bool_IsBalance(Node*root);void_PrintAVLTree(Node*root);protected:Node*_root;};
下面對插入進行元素的分析:
1)判斷樹是否為空,為空時,新建根結點。
2)查找插入的key是否存在,存在就退出函數,不存在就執行3)。
3)找到插入key的位置,然后插入結點cur。
4)更新平衡因子:從cur開始向上其父結點進行更新平衡因子,如果結點的平衡因子不滿足AVL樹,進行旋轉調節平衡因子。
template<classK,classV>voidAVLTree<K,V>::insert(constK&key,constV&value){if(_root==NULL){_root=newNode(key,value);return;}if(Find(key))//存在key{return;}Node*prev=NULL;Node*cur=_root;while(cur)//插入key的位置cur{if(key<cur->_key){prev=cur;cur=cur->_left;}elseif(key>cur->_key){prev=cur;cur=cur->_right;}}cur=newNode(key,value);//插如結點curif(prev->_key>key){prev->_left=cur;cur->_parent=prev;}elseif(prev->_key<key){prev->_right=cur;cur->_parent=prev;}//prev為cur的上一個結點,即為cur是prev的父親結點prev=cur;cur=prev->_parent;while(cur){//更新平衡因子:從插如的cur開始向上更新平衡因子cur->_bf=_Height(cur->_right)-_Height(cur->_left);if(cur->_bf!=-1&&cur->_bf!=1&&cur->_bf!=0)//不滿足AVL樹的結點,進行旋轉調節平衡因子{//平衡因子為2時,一定存在右子樹;平衡因子為-2時,一定存在左子樹//左單旋:21(平衡因子)if(cur->_bf==2&&cur->_right->_bf==1){_RotateL(cur);//引用傳遞}//右單旋:-2-1elseif(cur->_bf==-2&&cur->_left->_bf==-1){_RotateR(cur);}//左右旋轉:-21elseif(cur->_bf==-2&&cur->_left->_bf==1){_RotateLR(cur);}//右左旋轉:2-1elseif(cur->_bf==2&&cur->_right->_bf==-1){_RotateRL(cur);}}prev=cur;cur=cur->_parent;}}
進行旋轉調節平衡因子,分四種情況:
(1)左單旋:cur的平衡因子為2,cur->_right的平衡因子為1。
(2)右單旋:cur的平衡因子為-2,cur->_left的平衡因子為-1。
(3)左右旋轉:cur的平衡因子為-2,cur->_left的平衡因子為1。
(4)右左旋轉:cur的平衡因子為-2,cur->_right的平衡因子為-1。
左右旋轉和右左旋轉可通過調用左單旋和右單旋進行,注意結束后重置平衡因子。
如果不是很清楚,可以自己畫圖進行分析。
左單旋:
template<classK,classV>voidAVLTree<K,V>::_RotateL(Node*&parent){Node*subR=parent->_right;Node*subRL=subR->_left;parent->_right=subRL;//1subR->_parent=parent->_parent;//1subR->_left=parent;//2parent->_parent=subR;//2if(subRL)//注意不為空,進行鏈接subRL->_parent=parent;parent->_bf=subR->_bf=0;//進行subR的父親結點和subR的鏈接if(subR->_parent==NULL)//為空時,parent為根結點,更改根結點_root=subR;else//不為空,進行鏈接{if(subR->_parent->_key>subR->_key)subR->_parent->_left=subR;elsesubR->_parent->_right=subR;}parent=subR;}
右單旋:
template<classK,classV>voidAVLTree<K,V>::_RotateR(Node*&parent){Node*subL=parent->_left;Node*subLR=subL->_right;//不能變換順序parent->_left=subL->_right;//1subL->_parent=parent->_parent;//1subL->_right=parent;//2parent->_parent=subL;//2if(subLR)//注意不為空,進行鏈接subLR->_parent=parent;parent->_bf=subL->_bf=0;//進行subL的父親結點和subL的鏈接if(subL->_parent==NULL)//為空時,parent為根結點,更改根結點_root=subL;else//不為空,進行鏈接{if(subL->_parent->_key>subL->_key)subL->_parent->_left=subL;elsesubL->_parent->_right=subL;}parent=subL;}
左右旋轉:
template<classK,classV>voidAVLTree<K,V>::_RotateLR(Node*&parent){Node*pNode=parent;//需重新定義parent,在進行左右旋轉后,parent指向發生了變化Node*subLNode=pNode->_left;Node*subLRNode=subLNode->_right;_RotateL(parent->_left);_RotateR(parent);//在單旋時,parent和subL的平衡因子都為0,在進行左右旋轉和右左旋轉會出錯,故重新設置平衡因子//subLRNode的平衡因子存在三種情況:為0,為-1,為1。subLRNode的平衡因子影響parent和subL的平衡因子if(subLRNode->_bf==1){pNode->_bf=1;subLNode->_bf=0;}elseif(subLRNode->_bf==-1){pNode->_bf=0;subLNode->_bf=-1;}else{parent->_bf=0;subLNode->_bf=0;}}
右左旋轉:
template<classK,classV>voidAVLTree<K,V>::_RotateRL(Node*&parent){Node*pNode=parent;Node*subRNode=pNode->_right;Node*subRLNode=subRNode->_left;_RotateR(parent->_right);_RotateL(parent);if(subRLNode->_bf==1){pNode->_bf=-1;subRNode->_bf=0;}elseif(subRLNode->_bf==-1){pNode->_bf=0;subRNode->_bf=1;}else{pNode->_bf=0;subRNode->_bf=0;}}
測試用例如下:
voidAVLTreeTest(){AVLTree<int,int>avlt;//intarr[10]={16,3,7,11,9,26,18,14,15,23};intarr[10]={4,2,6,1,3,5,15,7,16,14};for(inti=0;i<10;++i){avlt.insert(arr[i],i);avlt.PrintAVLTree();}cout<<avlt.IsBalance()<<endl;}
看完上述內容,你們對數據結構中的AVL樹是什么意思有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注本站行業資訊頻道,感謝大家的支持。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
金融危機的根源是什么?一、泡沫經濟的形成。泡沫經濟逐漸膨脹到一定程度時就會破裂,資金鏈斷裂相繼引起一系列的連鎖反應,而種種連鎖反應對金融領域、實體經濟、企業和民眾造成一系列的惡性影響。據調查分析,1994-2001 年的 7 年間,美國房價不過上升了 53.1%的比例,而 2001-2007年間,美國的房價卻上升了 63.4%的比例,信用的極度擴張后,最后帶來的一定是極度的收縮,特別是房地產行業,...
企業征信是指征信機構作為提供信用信息服務的企業,按一定規則合法采集企業、個人的信用信息,加工整理形成企業、個人的信用報告等征信產品,有償提供給經濟活動中的貸款方、賒銷方、招標方、出租方、保險方等有合法需求的信息使用者,為其了解交易對方的信用狀況提供便利。企業征信查詢的具體內容包括:1、企業的工商注冊、變更基本信息;2、企業信貸、質押擔保、貿易融資等信息;司法判決、執行信息;3、稅務處罰、表彰信息;...
什么是保理公司?保理公司是指賣方將貨物出售給買方,賣方可以將貿易過程中銷售或合同產生的應收賬款轉讓給保理公司,然后保理公司提前提供現金流給賣方用于采購和生產,以避免企業在恢復期的資金周轉問題。隨著市場的發展,賒銷在交易中越來越普遍,奠定了良好的市場基礎。例如:a公司與b公司簽訂了合同,所以a公司向b公司提供了商品或服務,理論上,b公司應該向a公司付款嗎?但是,當A公司完成了服務和產品,B公司沒有付...