二十六、平衡二叉树
二十六、平衡二叉樹(shù)
文章目錄
- 二十六、平衡二叉樹(shù)
- 題目描述
- 解題思路
- 上機(jī)代碼
題目描述
程序輸入一個(gè)字符串(只包含小寫(xiě)字母),請(qǐng)按照字符的輸入順序建立平衡二叉排序樹(shù),并分別輸出二叉樹(shù)的先序序列、中序序列和后序序列,最后輸出該二叉樹(shù)向左旋轉(zhuǎn) 90 度后的結(jié)構(gòu)。
例如:向左旋轉(zhuǎn) 90 度后,以每層向里縮進(jìn) 4 個(gè)空格的方式輸出,輸出結(jié)果為:
?????i
??g
?????f
a
?????d
??c
?????b
輸入:agxnzyimk
輸出:
Preorder: xigamknzy
Inorder: agikmnxyz
Postorder: agknmiyzx
Tree:
??z
????y
x
??????n
????m
??????k
??i
????g
??????a
| 測(cè)試用例 1 | agxnzyimk | Preorder: xigamknzy Inorder: agikmnxyz Postorder: agknmiyzx Tree: ????z ????????y x ????????????n ????????m ????????????k i ????????g ????????????a | 1秒 | 64M | 0 |
| 測(cè)試用例 2 | asdfghjkl | Preorder: gdafjhlks Inorder: adfghjkls Postorder: afdhksljg Tree: ????????????s ????????l ????????????k ????j ????????h g ????????f ????d ????????a | 1秒 | 64M | 0 |
解題思路
教材第233—236頁(yè)詳細(xì)介紹了平衡二叉樹(shù)的定義和實(shí)現(xiàn)方式,第236—238頁(yè)給出了部分代碼實(shí)例。
平衡二叉樹(shù)又稱(chēng)AVL樹(shù),它的左子樹(shù)和右子樹(shù)都是平衡二叉樹(shù),且左子樹(shù)和右子樹(shù)的深度之差的絕對(duì)值不超過(guò)1。將二叉樹(shù)上結(jié)點(diǎn)的平衡因子定義為該結(jié)點(diǎn)的左子樹(shù)深度減去右子樹(shù)的深度,平衡二叉樹(shù)上所有結(jié)點(diǎn)的平衡因子只能是-1、0或1。
平衡二叉樹(shù)的類(lèi)型定義為:
typedef struct NODE {char data; //數(shù)據(jù)域 int bf; //平衡因子 struct NODE *lchild; //左孩子 struct NODE *rchild; //右孩子 }BSnode, *BSTree;平衡化:
- L平衡旋轉(zhuǎn):將A的左孩子B向右上旋轉(zhuǎn)代替A成為根結(jié)點(diǎn),將A結(jié)點(diǎn)向右下旋轉(zhuǎn)成為B的右子樹(shù)的根結(jié)點(diǎn),而B(niǎo)的原右子樹(shù)作為A結(jié)點(diǎn)的左子樹(shù)
- R平衡旋轉(zhuǎn):將A的右孩子B向左上旋轉(zhuǎn)代替A成為根結(jié)點(diǎn),將A結(jié)點(diǎn)向左下旋轉(zhuǎn)成為B的左子樹(shù)的根結(jié)點(diǎn),而B(niǎo)的原左子樹(shù)作為A結(jié)點(diǎn)的右子樹(shù)
- LR平衡旋轉(zhuǎn):先將A結(jié)點(diǎn)的左孩子B的右子樹(shù)的根節(jié)點(diǎn)C向左上旋轉(zhuǎn)提升到B結(jié)點(diǎn)的位置,然后再把該C結(jié)點(diǎn)向右上旋轉(zhuǎn)提升到A結(jié)點(diǎn)的位置
- RL平衡旋轉(zhuǎn):先將A結(jié)點(diǎn)的右孩子B的左子樹(shù)的根節(jié)點(diǎn)C向右上旋轉(zhuǎn)提升到B結(jié)點(diǎn)的位置,然后再把該C結(jié)點(diǎn)向左上旋轉(zhuǎn)提升到A結(jié)點(diǎn)的位置
上機(jī)代碼
#include<cstdio> #include<cstdlib> #include<cstdlib>#define LH +1 //左高 #define EH 0 //等高 #define RH -1 //右高 typedef struct NODE {char data; //數(shù)據(jù)域 int bf; //平衡因子 struct NODE *lchild; //左孩子 struct NODE *rchild; //右孩子 }BSnode, *BSTree;void R_Rotate(BSTree *ptr)//右旋 {BSTree lc = (*ptr)->lchild; //lc指向的*ptr的左孩子的根結(jié)點(diǎn) (*ptr)->lchild = lc->rchild; //lc的右子樹(shù)掛接為*ptr的左子樹(shù) lc->rchild = *ptr;*ptr = lc; //ptr指向新的結(jié)點(diǎn)" } void L_Rotate(BSTree *ptr)//左旋 {BSTree rc = (*ptr)->rchild; //rc指向的*ptr的由孩子的根結(jié)點(diǎn)(*ptr)->rchild = rc->lchild; //rc的左子樹(shù)掛接為*ptr的右子樹(shù)rc->lchild = *ptr;*ptr = rc; //ptr指向新的結(jié)點(diǎn) } void LeftBalance(BSTree *root)//左平衡旋轉(zhuǎn)處理 {BSTree lc;BSTree rd;lc = (*root)->lchild; //ls指向*root的左根結(jié)點(diǎn)//檢測(cè)*root的左子樹(shù)的平衡度,并作相應(yīng)處理switch (lc->bf){case LH:{//新結(jié)點(diǎn)插入在*root的左孩子的左子樹(shù)上,要做單右旋處理(*root)->bf = lc->bf = EH;R_Rotate(root);break;}case RH:{//新結(jié)點(diǎn)插入在*root左孩子的右子樹(shù)上要做雙旋處理//rd指向*t的左孩子的右子樹(shù)根上rd = lc->rchild;switch (rd->bf){//修改*root及其左孩子的平衡因子case LH:{(*root)->bf = RH;lc->bf = EH;break;}case EH:{(*root)->bf = lc->bf = EH;break;}case RH:{(*root)->bf = EH;lc->bf = LH;break;}}rd->bf = EH;//對(duì)*root的左子樹(shù)左左旋平衡處理L_Rotate(&(*root)->lchild);//對(duì)*root做右旋平衡處理R_Rotate(root);}} } void RightBalance(BSTree *root)//右平衡旋轉(zhuǎn)處理 {BSTree lc;BSTree rd;lc = (*root)->rchild;switch (lc->bf){case RH:{(*root)->bf = lc->bf = EH;L_Rotate(root);break;}case LH:{rd = lc->lchild;switch (rd->bf){case LH:{(*root)->bf = EH;lc->bf = RH;break;}case EH:{(*root)->bf = lc->bf = EH;break;}case RH:{(*root)->bf = LH;lc->bf = EH;break;}}rd->bf = EH;R_Rotate(&(*root)->rchild);L_Rotate(root);}} }int InsertAVL(BSTree *root, char e, bool *taller) {if ((*root) == NULL){//該樹(shù)為一棵空樹(shù),創(chuàng)建一個(gè)新節(jié)點(diǎn)作為根節(jié)點(diǎn)(*root) = (BSTree)malloc(sizeof(BSnode));(*root)->bf = EH;(*root)->data = e;(*root)->lchild = NULL;(*root)->rchild = NULL;*taller = true;}else if (e == (*root)->data)//關(guān)鍵字相同,則不再繼續(xù)插入{*taller = false;return 0;}else if (e < (*root)->data)//應(yīng)該繼續(xù)在*root的左子樹(shù)進(jìn)行搜索{if (!InsertAVL(&(*root)->lchild, e, taller))//未插入{return 0;}//已插入到*root的左子樹(shù)中并且左子樹(shù)長(zhǎng)高if (*taller){//檢查*root的平衡度switch ((*root)->bf){//原本左子樹(shù)比右子樹(shù)高case LH:{//平衡因子為-1//左旋LeftBalance(root);*taller = false;break;}//原本左右樹(shù)一樣高,現(xiàn)在因?yàn)樽笞訕?shù)長(zhǎng)高樹(shù)長(zhǎng)高case EH:{//平衡因子為0(*root)->bf = LH;*taller = true;break;}//原本右子樹(shù)比左子樹(shù)高,現(xiàn)在等高case RH:{//平衡因子為1(*root)->bf = EH;*taller = false;break;}}}}else{//應(yīng)繼續(xù)在*root的右子樹(shù)中進(jìn)行搜索 if (!InsertAVL(&(*root)->rchild, e, taller))//未插入{return 0;}//已插入到*root的右子樹(shù)且右子樹(shù)長(zhǎng)高if (*taller){//檢查*root的平衡度switch ((*root)->bf){case LH:{//原本左子樹(shù)比右子樹(shù)高,現(xiàn)在相等(*root)->bf = EH;*taller = false;break;}case EH:{//原來(lái)左右子樹(shù)登高,現(xiàn)在因?yàn)橛易訕?shù)長(zhǎng)高樹(shù)長(zhǎng)高(*root)->bf = RH;*taller = true;break;}case RH:{//原本右子樹(shù)比左子樹(shù)高,需要做右旋平衡處理 RightBalance(root);*taller = false;break;}}}}return 1; } void printBIT(BSTree root, int x) {if (root != NULL){printBIT(root->rchild, x + 1);for (int i = 0; i < x; i++)printf(" ");printf("%c\n", root->data);printBIT(root->lchild, x + 1);} } void preorder(BSTree root) {if (root != NULL){printf("%c", root->data);preorder(root->lchild);preorder(root->rchild);} } void inorder(BSTree root)//二叉樹(shù)的中序遍歷 {if (root != NULL){inorder(root->lchild);printf("%c", root->data);inorder(root->rchild);} } void postorder(BSTree root) {if (root != NULL){postorder(root->lchild);postorder(root->rchild);printf("%c", root->data);} } int main() {char e;bool taller;//taller變量反應(yīng)T長(zhǎng)高與否BSTree root = NULL;while (e = getchar()){if (e == '\n')break;InsertAVL(&root, e, &taller);}//先序printf("Preorder: ");preorder(root);printf("\n");//中序printf("Inorder: ");inorder(root);printf("\n");//后序printf("Postorder: ");postorder(root);printf("\n");printf("Tree:\n");printBIT(root, 0);//system("pause");return 0; }總結(jié)
- 上一篇: 二十五、求单点的最短路径
- 下一篇: 二十七、排序