日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > 平衡二叉樹

平衡二叉樹

來源:程序員人生   發布時間:2015-05-22 08:44:45 閱讀次數:3492次

平衡2叉樹又稱為AVL樹,

AVL樹是最早發明的自平衡2叉查找樹。在AVL樹中任何節點的兩個兒子子樹的高度最大差別為1,所以它也被稱為高度平衡樹。查找、插入和刪除在平均和最壞情況下都是O(log n)。增加和刪除可能需要通過1次或屢次樹旋轉來重新平衡這個樹。

保護平衡2叉樹需要有4種旋轉的情況

左左旋轉

右右旋轉

左右旋轉

右右旋轉

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

測試用例:

#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; }


生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 污视频网站在线观看 | 久久国产精品成人免费观看的软件 | 欧美视频一区二区 | 99国产精品久久久久久久成人热 | 国产欧美一区二区精品性色 | 欧美在线免费视频 | 91在线精品秘密一区二区 | 国产精品污www在线观看 | 天天天综合网 | 91亚洲成人| 亚洲一区二区三区在线看 | 视频一区在线观看 | 久在线视频 | 精品久久久久一区 | 亚洲精品一区二区三区中文字幕 | 国产露脸精品产三级国产 | 亚洲日本va中文字幕久久 | 亚洲第一视频网站 | 亚洲色图网站 | 亚洲欧美日本在线 | 亚洲经典在线观看 | 欧美亚洲大片 | 欧美日韩免费在线视频 | 成人性生交大片 | 欧美极品一区二区三区 | 99综合久久 | 快射视频在线观看 | 午夜在线免费观看视频 | 国产精品一区在线观看 | 亚洲一区二区三区中文字幕 | 久久人人爽人人爽 | jizzz亚洲| 欧美激情在线观看视频 | 免费看成人吃奶视频在线 | 亚洲香蕉在线观看 | 国产黄色大片 | 国产网站在线免费观看 | 欧美三级免费网站 | 国产精品精品久久久 | 成人免费视频国产 | 中国大陆高清aⅴ毛片 |