多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > php開(kāi)源 > php教程 > 平衡二叉樹(shù)

平衡二叉樹(shù)

來(lái)源:程序員人生   發(fā)布時(shí)間:2015-05-22 08:44:45 閱讀次數(shù):3487次

平衡2叉樹(shù)又稱為AVL樹(shù),

AVL樹(shù)是最早發(fā)明的自平衡2叉查找樹(shù)。在AVL樹(shù)中任何節(jié)點(diǎn)的兩個(gè)兒子子樹(shù)的高度最大差別為1,所以它也被稱為高度平衡樹(shù)。查找、插入和刪除在平均和最壞情況下都是O(log n)。增加和刪除可能需要通過(guò)1次或?qū)掖螛?shù)旋轉(zhuǎn)來(lái)重新平衡這個(gè)樹(shù)。

保護(hù)平衡2叉樹(shù)需要有4種旋轉(zhuǎn)的情況

左左旋轉(zhuǎn)

右右旋轉(zhuǎn)

左右旋轉(zhuǎn)

右右旋轉(zhuǎn)

//******************************************************************************************** //***說(shuō)明:2叉排序樹(shù)遍歷是從小到大的順序,AVL樹(shù)也是bst,但是滿足所有的樹(shù)的左右高度相差不大于1 //***平衡2叉樹(shù)是1種特殊的2叉樹(shù),滿足以上要求,主要是為了進(jìn)1步的優(yōu)化,提高操作的效力(O(log(n))) //***針對(duì)下面情況進(jìn)行調(diào)劑 //***測(cè)試pat1066 http://www.patest.cn/contests/pat-a-practise/1066 //*********1*******************************1**********2*************************************** //**************************************************/*************************************** //***********2**************************************1***4************************************* //*******************------>**************************/************************************* //*************3**************************************3***5*********************************** //**************4***************************************************************************** //******************************************************************************************* //****************5*************************************************************************** // 其中主要的策略就是選擇,旋轉(zhuǎn)1共分為下面4種情況 //******** A ********** B ************** C ********************* D *************************** //******************************************************************************************** //***** 6 **** 6 ************2***********************2**************************** //***** / **** / ***********/**********************/**************************** //***** 3 7 **** 2 7 **********1***5*******************1***4************************** //***** / **** / *************/**********************/************************** //*****1 4 **** 1 4 ************3***6*******************3***6************************ //***** **** / **************************************/************************* //***** 2 **** 3 **************4***********************5************************** //******************************************************************************************** //******************************************************************************************** //******************************************************************************************** //******************************************************************************************** //******************************************************************************************** /********************************************************************************************* *A、6節(jié)點(diǎn)的左子樹(shù)3節(jié)點(diǎn)高度比右子樹(shù)7節(jié)點(diǎn)大2,左子樹(shù)3節(jié)點(diǎn)的左子樹(shù)1節(jié)點(diǎn)高度大于右子樹(shù)4節(jié)點(diǎn),這類情況成為左左。 *B、6節(jié)點(diǎn)的左子樹(shù)2節(jié)點(diǎn)高度比右子樹(shù)7節(jié)點(diǎn)大2,左子樹(shù)2節(jié)點(diǎn)的左子樹(shù)1節(jié)點(diǎn)高度小于右子樹(shù)4節(jié)點(diǎn),這類情況成為左右。 *C、2節(jié)點(diǎn)的左子樹(shù)1節(jié)點(diǎn)高度比右子樹(shù)5節(jié)點(diǎn)小2,右子樹(shù)5節(jié)點(diǎn)的左子樹(shù)3節(jié)點(diǎn)高度大于右子樹(shù)6節(jié)點(diǎn),這類情況成為右左。 *D、2節(jié)點(diǎn)的左子樹(shù)1節(jié)點(diǎn)高度比右子樹(shù)4節(jié)點(diǎn)小2,右子樹(shù)4節(jié)點(diǎn)的左子樹(shù)3節(jié)點(diǎn)高度小于右子樹(shù)6節(jié)點(diǎn),這類情況成為右右。 * *說(shuō)明:2叉排序樹(shù)遍歷是從小到大的順序,AVL樹(shù)也是bst,但是滿足所有的樹(shù)的左右高度相差不大于1 */ #ifndef AVL_H #define AVL_H #include <iostream> using namespace std; /*AVL樹(shù)節(jié)點(diǎn)信息*/ template <typename T> class TreeNode { public : TreeNode():lchild(NULL),rchild(NULL),freq(1),hgt(0){} T data ;/*值*/ int hgt;/*以此節(jié)點(diǎn)為根的樹(shù)的高度*/ unsigned int freq;/*頻率*/ TreeNode * lchild,*rchild;/*左右孩子*/ }; /*AVL樹(shù)類的屬性和方法聲明*/ template <typename T> class AVLTree { private : TreeNode<T> *root; /*根節(jié)點(diǎn)*/ void InsertPri(TreeNode<T> * &node, T x); /*插入x*/ TreeNode <T>* FindPri(TreeNode<T> *node ,T x); /*查找x*/ void InSubTree(TreeNode<T> *node); /*中序遍歷*/ void DeletePri(TreeNode<T> * &node, T x); /*刪除*/ int height(TreeNode<T> *node); /*樹(shù)的高度*/ void SingRotateLeft(TreeNode<T> * &k2); /*左左情況下的旋轉(zhuǎn)*/ void SingRotateRight(TreeNode<T> * &k2); /*右右情況的旋轉(zhuǎn)*/ void DoubleRotateLR(TreeNode<T> * &k3); /*左右情況的旋轉(zhuǎn)*/ void DoubleRotateRL(TreeNode<T> * &k3); /*左右情況的旋轉(zhuǎn)*/ int Max(int cmpa,int cmpb); /*求最大值*/ public : AVLTree():root(NULL){} void insert(T x); /*插入接口*/ TreeNode<T> * Find(T x); /*查找接口*/ void Delete(T x); /*刪除接口*/ void Treversal(); /*遍歷接口*/ }; /*計(jì)算以節(jié)點(diǎn)為根的樹(shù)的高度*/ template <typename T> int AVLTree <T>::height(TreeNode<T>* node) { return node!=NULL? node->hgt:⑴; } /*求最大值*/ template <typename T> int AVLTree<T>::Max(int cmpa,int cmpb) { return cmpa>cmpb ? cmpa :cmpb; } /************************************************************************/ /* 單旋轉(zhuǎn) 單旋轉(zhuǎn)是針對(duì)左左和右右這兩種情況的解決方案,這兩種情況是 *對(duì)稱的,只要解決了左左這類情況,右右就很好辦了。圖3是左左情況的解決方案, *節(jié)點(diǎn)k2不滿足平衡特性,由于它的左子樹(shù)k1比右子樹(shù)Z深2層,而且k1子樹(shù)中,更深 *的1層的是k1的左子樹(shù)X子樹(shù),所以屬于左左情況 (左左情況下的選擇) */ /*為使樹(shù)恢復(fù)平衡,我們把k2變成這棵樹(shù)的根節(jié)點(diǎn),由于k2大于k1,把k2置于k1的右 *子樹(shù)上,而本來(lái)在k1右子樹(shù)的Y大于k1,小于k2,就把Y置于k2的左子樹(shù)上,這樣既 *********************滿足了2叉查找樹(shù)的性質(zhì),又滿足了平衡2叉樹(shù)的性質(zhì)。*/ /************************************************************************/ //****************k2******************************k1********************** //***************/******************************/*********************** //**************k1**z****--------->*************x***k2******************** //*************/**********************************/********************* //************x***y*******************************y***z******************* /*這樣的操作只需要1部份指針改變,結(jié)果我們得到另外1顆2叉查找樹(shù),它是1棵AVL樹(shù),由于X向 *上1移動(dòng)了1層,Y還停留在原來(lái)的層面上,Z向下移動(dòng)了1層。整棵樹(shù)的新高度和之前沒(méi)有在左子 *樹(shù)上插入的高度相同,插入操作使得X高度長(zhǎng)高了。因此,由于這顆子樹(shù)高度沒(méi)有變化,所以通往根 *節(jié)點(diǎn)的路徑就不需要繼續(xù)旋轉(zhuǎn)了。***********************************************/ /*左左旋轉(zhuǎn)*/ template <typename T> void AVLTree<T>::SingRotateLeft(TreeNode<T> * &k2) { TreeNode<T> *k1; k1=k2->lchild; k2->lchild=k1->rchild; k1->rchild=k2; k2->hgt=Max(height(k2->lchild),height(k2->rchild))+1; k1->hgt=Max(height(k1->lchild),k2->hgt)+1; k2=k1;/*最后1定要更新根節(jié)點(diǎn)*/ } /*右右旋轉(zhuǎn)*/ template <typename T> void AVLTree<T>::SingRotateRight(TreeNode<T> * &k2) { TreeNode<T> *k1; k1=k2->rchild; k2->rchild=k1->lchild; k1->lchild=k2; k2->hgt=Max(height(k2->lchild),height(k2->rchild))+1; k1->hgt=Max(height(k1->rchild),k2->hgt)+1; k2=k1;/*最后1定要更新根節(jié)點(diǎn)*/ } /**************************雙旋轉(zhuǎn)(左右情況下的雙旋轉(zhuǎn))************************/ //************************************************************************ //*************k3******************k3**********************k2************* //************/******************/**********************/************** //**********k1***d*---->********k2***d*****---->********k1****k3********** //*********/*******************/*********************/****/*********** //********a****k2*************k1***c******************a***b*c***d********* //************/*************/******************************************* //***********b***c**********a***b***************************************** //************************************************************************ //************************************************************************ //************************************************************************ /************************************************************************/ /* *左右旋轉(zhuǎn) *為使樹(shù)恢復(fù)平衡,我們需要進(jìn)行兩步,第1步,把k1作為根,進(jìn)行1次右右旋轉(zhuǎn),旋轉(zhuǎn)以后就變成 *了左左情況,所以第2步再進(jìn)行1次左左旋轉(zhuǎn),最后得到了1棵以k2為根的平衡2叉樹(shù)樹(shù)。 */ template <typename T> void AVLTree<T>::DoubleRotateLR(TreeNode<T> * &k3) { SingRotateRight(k3->lchild); SingRotateLeft(k3); } /*右左旋轉(zhuǎn)*/ template <typename T> void AVLTree<T>::DoubleRotateRL(TreeNode<T> * &k3) { SingRotateLeft(k3->rchild); SingRotateRight(k3); } /************************************************************************* *插入的方法和2叉查找樹(shù)基本1樣,區(qū)分是,插入完成后需要從插入的節(jié)點(diǎn)開(kāi)始保護(hù) *1個(gè)到根節(jié)點(diǎn)的路徑,每經(jīng)過(guò)1個(gè)節(jié)點(diǎn)都要保持樹(shù)的平衡。 *保持樹(shù)的平衡要根據(jù)高度差的特點(diǎn)選擇不同的旋轉(zhuǎn)算法。 *insert *************************************************************************/ template <typename T> void AVLTree<T>::InsertPri(TreeNode<T>* &node, T x) { if(node==NULL)/*如果節(jié)點(diǎn)為空,就在此節(jié)點(diǎn)處加入x信息*/ { node =new TreeNode<T>(); node->data=x; return ; } if (node->data>x)/*如果X小于節(jié)點(diǎn)的值,就繼續(xù)再節(jié)點(diǎn)的左子樹(shù)中插入*/ { InsertPri(node->lchild,x); if (2==height(node->lchild)-height(node->rchild)) { if (x<node->lchild->data) { SingRotateLeft(node); } else DoubleRotateLR(node); } } else if (node->data<x)/*如果X大于節(jié)點(diǎn)的值,就繼續(xù)再節(jié)點(diǎn)的右子樹(shù)中插入*/ { InsertPri(node->rchild,x); if (2==height(node->rchild)-height(node->lchild)) { if (x>node->rchild->data) { SingRotateRight(node); } else DoubleRotateRL(node); } } else node->freq++;/*如果相等,頻率加1*/ node->hgt=Max(height(node->lchild),height(node->rchild))+1; } /************************************************************************/ /* 插入接口 */ /************************************************************************/ template <typename T> void AVLTree<T>::insert(T x) { InsertPri(root,x); } /************************************************************************/ /* 查找 */ /*和2叉查找樹(shù)相比,查找方法沒(méi)有變法,不過(guò)根據(jù)存儲(chǔ)的特性, *AVL樹(shù)能保持在1個(gè)O(logN)的穩(wěn)定的時(shí)間,而2叉查找樹(shù)則相當(dāng)不穩(wěn)定。 /************************************************************************/ template<typename T> TreeNode<T>* AVLTree<T>::FindPri(TreeNode<T> *node ,T x) { if(node==NULL)/*如果節(jié)點(diǎn)為空說(shuō)明沒(méi)找到,返回NULL*/ return NULL; if(node->data>x)/*如果x小于節(jié)點(diǎn)的值,就繼續(xù)在節(jié)點(diǎn)的左子樹(shù)中查找x*/ return FindPri(node->lchild,x); if (node->data<x)/*如果x大于節(jié)點(diǎn)的值,就繼續(xù)在節(jié)點(diǎn)的左子樹(shù)中查找x*/ return FindPri(node->rchild,x); return node;/*如果相等,就找到了此節(jié)點(diǎn)*/ } /*查找接口*/ template<typename T> TreeNode<T>* AVLTree<T>::Find(T x) { return FindPri(root,x); } /************************************************************************/ /* 刪除 */ /*刪除的方法也和2叉查找樹(shù)的1致,區(qū)分是,刪除完成后, *需要從刪除節(jié)點(diǎn)的父親開(kāi)始向上保護(hù)樹(shù)的平衡1直到根節(jié)點(diǎn)。 /************************************************************************/ template<typename T> void AVLTree<T>::DeletePri(TreeNode<T> * &node, T x) { if(node==NULL)/*空*/ return ; if(x<node->data) {/*如果x小于節(jié)點(diǎn)的值,就繼續(xù)在節(jié)點(diǎn)的左子樹(shù)中刪除x,刪除完成后,需要調(diào)劑樹(shù),使之保持平衡*/ DeletePri(node->lchild,x); if (2==height(node->rchild)-height(node->lchild)) { if(node->rchild->lchild!=NULL && (height(node->rchild->lchild)>height(node->rchild->rchild)) ) DoubleRotateRL(node); else SingRotateRight(node); } } else if (x>node->data) {/*如果大于節(jié)點(diǎn)的值,就繼續(xù)在節(jié)點(diǎn)的右子樹(shù)中刪除x,刪除完成后,需要調(diào)劑樹(shù),使之保持平衡*/ DeletePri(node->rchild,x); if (2==height(node->lchild)-height(node->rchild)) { if(node->rchild->lchild!=NULL && (height(node->lchild->rchild)>height(node->lchild->lchild)) ) DoubleRotateLR(node); else SingRotateLeft(node); } } else/*相等,刪除,然后調(diào)劑,使之平衡*/ { if (node->lchild && node->rchild)/*此節(jié)點(diǎn)有兩個(gè)兒子*/ { TreeNode<T>* temp=node->rchild;/*temp指向節(jié)點(diǎn)的右兒子*/ while(temp->lchild!=NULL) temp=temp->lchild;/*找到中序遍歷的后繼節(jié)點(diǎn),一定在最左側(cè)那個(gè)*/ node->data=temp->data;/*調(diào)劑節(jié)點(diǎn)數(shù)據(jù)信息*/ node->freq=temp->freq; DeletePri(node->rchild,temp->data);/*刪除邊沿節(jié)點(diǎn)*/ if (2==height(node->lchild)-height(node->rchild)) { if (node->lchild->rchild!=NULL && (height(node->lchild->rchild)>height(node->lchild->lchild)) ) DoubleRotateLR(node); else SingRotateLeft(node); } } else/*此節(jié)點(diǎn)有1個(gè)或0個(gè)兒子*/ { TreeNode<T> *temp=node; if(node->lchild==NULL)/*有右兒子或沒(méi)有兒子*/ node=node->rchild; else if(node->rchild==NULL)/*有左兒子*/ node=node->lchild; delete(temp); temp=NULL; } } if(node==NULL) return ; node->hgt=Max(height(node->lchild),height(node->rchild))+1; return ; } /*刪除接口*/ template<typename T> void AVLTree<T>::Delete(T x) { DeletePri(root,x); } /*中序遍歷函數(shù)*/ template<typename T> void AVLTree<T>::InSubTree(TreeNode<T> *node) { if(node==NULL) return ; InSubTree(node->lchild);/*先遍歷左子樹(shù)*/ cout<<node->data<<" ";/*輸出根節(jié)點(diǎn)*/ InSubTree(node->rchild);/*再遍歷右子樹(shù)*/ } /*中序遍歷接口*/ template<typename T> void AVLTree<T>::Treversal() { //cout<<root->data; InSubTree(root); } #endif//avl.h

測(cè)試用例:

#include "AVL.h" int arrs[7]={88,70,61,96,120,90,65}; int main(int argc,char** argv) { AVLTree<int> te; for (int i=0;i<7;i++) { te.insert(arrs[i]); } te.Treversal(); return 0; }


生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲另类图片专区 | 国产成人一区二区三区免费观看 | 国产成人乱码一区二区三区在线 | 一区二区影视 | 第一色区 | 国产小情侣激情小视频免费看 | 羞羞动漫官网 | 一区二区三区四区无限乱码 | 欧美zzzz| 成人私拍福利视频在线 | 欧美福利二区 | 日本欧美在线播放 | 欧洲美女性做爰 | 免费看逼逼 | 国产一区二区播放 | 动漫精品欧美一区二区三区 | 欧美极品尤物在线播放一级 | 中国国产一国产一级毛片视频 | 激情视频网站在线观看 | 亚洲毛片视频 | 国产麻豆高清在线观看 | 91av久久| 手机在线看片国产日韩生活片 | 天天精品 | 欧美大屁股精品毛片视频 | 亚洲精品国产成人一区二区 | yellow中文字幕在线 | 日本一本在线视频 | 高清完整视频在线播放 | 波多野结衣在线观看免费区 | 午夜影院在线看 | 爰上碰23在线视频 | 婷婷丁香激情五月 | 一级做a爰片性色毛片新版的 | www色.com| 视频在线观看一区二区三区 | 欧美高清一区 | 国产成人综合网 | 亚洲欧美偷拍视频 | 日韩在线不卡一区在线观看 | 小说区图片区综合久久亚洲 |