添加链接描述
参照上面的博客 实现了一下平衡二叉树,这段代码花费了我很多的时间 ,主要是没有跳出里面的循环 下面附上代码 会在代码中介绍具体算法
#include <iostream>
using namespace std;
//二叉树的二叉链表结构
typedef struct node
{
int bf; //平衡因子
int key; //数据
struct node *leftChild, *rightChild; //左孩子,右孩子指针
}BBSTNode;
const int LH = 1; // 左子树高于右子树
const int RH = -1; //右子树高于左子树
const int EH = 0; //左右子树等高
//针对LL型的树结构做右旋
void RightRotate(BBSTNode *& p)
{
BBSTNode * lc;//lc指向p的左子树的根节点
lc = p->leftChild;
p->leftChild = lc->rightChild;//让lc的右子树挂接p的左子树的位置
lc->rightChild = p;//p结点挂载在lc的右子数位置
p = lc; //lc变成新的根节点
}
//针对RR型的树结构做左旋
void LeftRotate(BBSTNode *& p)
{
BBSTNode * rc;//lc指向p的右子树根节点
rc = p->rightChild;
p->rightChild = rc->leftChild;//将rc的左子树挂载在p的右子树上
rc->leftChild = p;//p挂在lc的左子树上
p = rc; //rc变为新的根节点
}
//左子树因长高而失衡
void LeftBalance(BBSTNode *& root)
{
BBSTNode * lc; //根的左子树
lc = root->leftChild;//lc指向root树的左子树根结点
switch(lc->bf)
{//检查root左子树的平衡度
case LH:
//如果是左边高 那么就行右旋处理
lc->bf = root->bf = EH; //修改根和左子树的平衡因子
RightRotate(root);
break;
case RH:
//如果新结点插入在T的左孩子的右子树上 要做双旋处理
BBSTNode * rd; //根的左子树的右子树
rd = lc->rightChild;//rd指向root的左孩子的右子树上
switch(rd->bf)
{
case LH:
lc->bf = EH, root->bf = RH;
break;
case EH:
lc->bf = root->bf = EH;
break;
case RH://这一步没太看明白
root->bf = EH, lc->bf = LH;
break;
}
rd->bf = EH;
LeftRotate(root->leftChild);
RightRotate(root);
break;
}
}
//右子树因长高而失衡
void RightBalance(BBSTNode *& root)
{
BBSTNode * rc; //根的右子树
rc = root->rightChild;
//检查右子树
switch(rc->bf)
{
case RH:
root->bf = EH, rc->bf = EH;
LeftRotate(root);
break;
case LH:
BBSTNode * ld;
ld = rc->leftChild;
switch(ld->bf)
{
case LH:
root->bf = EH, rc->bf = RH;
break;
case EH:
root->bf = rc->bf = EH;
break;
case RH:
root->bf = LH, rc->bf = EH;
break;
}
ld->bf = EH;
RightRotate(root->rightChild);
LeftRotate(root);
break;
}
}
//递归插入数据
int insertAVL(BBSTNode * & root, int key, bool & taller)
{
if(!root) //根节点为空则插入之
{
root = new BBSTNode();//申请一块空间
root->key = key;//数据域赋值
root->leftChild = root->rightChild = NULL;//左右孩子指针指向空
root->bf = EH;//平衡因子设置为等高
taller = true;//增高标志
}
else
{
if(key == root->key)//如果树中有同关键字的结点 则不再插入
{
taller = false;
return 0;
}
else if(key < root->key)//在根结点的左字数中插入
{
if(!insertAVL(root->leftChild, key, taller))//递归遍历
{
//如果没有插入成功 返回0
return 0;
}
if(taller)//已经查到左子树中 且左子树长高了
{
switch(root->bf)//检查T的平衡度
{
case LH://原本左子树比右子树高,现在结点还加到了左子树上 需要做平衡处理
LeftBalance(root);
taller = false;
break;
case EH://原本左右子树等高 现在因为左子树增高而增高
root->bf = LH;
taller = true;
break;
case RH://原本右子树高 现在左右子树登高
root->bf = EH;
taller = false;
break;
}
}
}
else
{//在右子树中插入
if(!insertAVL(root->rightChild, key, taller))
{
return 0;
}
if(taller)
{
switch(root->bf)
{
case LH:
root->bf = EH;
taller = false;
break;
case EH:
root->bf = RH;
taller = true;
break;
case RH://原本右子树比左子树高 现在点还插在了右边 所需需要做平衡处理
RightBalance(root);
tallerxuexi = false;
break;
}
}
}
}
}
//中序遍历平衡二叉树
void in(BBSTNode * root)
{
if(root)
{
in(root->leftChild);
cout << root->key << '\t';
in(root->rightChild);
}
}
int main()
{
BBSTNode * root; //平衡二叉树的根指针
root = NULL; //跟指针初始化
int a[10]={3,2,1,4,5,6,7,10,9,8};
bool taller;
//建树,没输入一个结点,则输出中序遍历序
for(int i=0;i<10;i++)
{
insertAVL(root, a[i], taller);
in(root);
cout << endl;
}
return 0;
}
下面是运行的结果
3
2 3
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 10
1 2 3 4 5 6 7 9 10
1 2 3 4 5 6 7 8 9 10
在这段代码中 卡住了很久
else if(key < root->key)//在根结点的左字数中插入
128 {
129 if(!insertAVL(root->leftChild, key, taller))//递归遍历
130 {
131 //如果没有插入成功 返回0
132 return 0;
133 }
134 if(taller)//已经查到左子树中 且左子树长高了
135 {
136 switch(root->bf)//检查T的平衡度
137 {
138 case LH://原本左子树比右子树高,现在结点还加到了左子树上 需要做平衡处理
139 LeftBalance(root);
140 taller = false;
141 break;
142 case EH://原本左右子树等高 现在因为左子树增高而增高
143 root->bf = LH;
144 taller = true;
145 break;
146
147
148
149
150 case RH://原本右子树高 现在左右子树登高
151 root->bf = EH;
152 taller = false;
153 break;
154 }
155 }
156 }
这里由于每次循环 root都是更新的 我之前在手动运算的时候 结果偏差比较多 .原因就是我一开始把root带入,但是在循环中 root可能是root->leftchild等 再一层层退出循环 ,就能得到结论 手动运算一遍收获比较大!