如果二叉排序树的左、右子树的高度之差的绝对值不超过1,这样的排序二叉树称为平衡二叉树,它的平均查找长度达到O(log2n)。
为了避免树的高度增长过快,降低二叉排序树的性能,我们规定在插入和删除二叉树结点时,要保证任意结点的左、右子树高度差的绝对值不超过1。这样的二叉树称为平衡二叉树。
平衡二叉树可定义为它或是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的高度差的绝对值不超过1。
需要注意的有以下两点:
插入操作中:
LR和RL旋转的时候,调用LL和RR旋转,其原因是这样做复合LR和RL的最终要求,这里调用LL(RR)旋转函数,不是说
在左子树的左子树(右子树的右子树)插入了结点,而只是为了可以达到LR(RL)的最终形态。这里也可以不调用LL和RR函数,对指针进行操作也可以,不过需要对四代指针进行操作,比较麻烦。
删除操作(难点):
同插入操作一样,删除结点时也有可能破坏平衡性,这就要求我们删除的时候要进行平衡性调整。
删除分为以下几种情况:
首先在整个二叉树中搜索要删除的结点,如果没搜索到直接返回不作处理,否则执行以下操作:
1.要删除的节点是当前根节点T。
如果左右子树都非空。在高度较大的子树中实施删除操作。
分两种情况:
(1)、左子树高度大于右子树高度,将左子树中最大的那个元素赋给当前根节点,然后删除左子树中元素值最大的那个节点。
(2)、左子树高度小于右子树高度,将右子树中最小的那个元素赋给当前根节点,然后删除右子树中元素值最小的那个节点。
如果左右子树中有一个为空,那么直接用那个非空子树或者是NULL替换当前根节点即可。
2、要删除的节点元素值小于当前根节点T值,在左子树中进行删除。
递归调用,在左子树中实施删除。这个是需要判断当前根节点是否仍然满足平衡条件,如果满足平衡条件,只需要更新当前根节点T的高度信息。否则,需要进行旋转调整:如果T的左子节点的左子树的高度大于T的左子节点的右子树的高度,进行相应的单旋转。否则进行双旋转。
3、要删除的节点元素值大于当前根节点T值,在右子树中进行删除。
#include <iostream>
#include <queue>
#include <stack>
using namespace std;
template <typename T>
struct avlTreeNode{
T data;
int height;
avlTreeNode* left;
avlTreeNode* right;
avlTreeNode(T val, avlTreeNode<T>* l, avlTreeNode<T>* r):data(val), height(0), left(l), right(r){}
};
template <typename T>
class avlTree{
private:
avlTreeNode<T>* root;
int max(int a, int b){return a > b ? a : b;}
public:
avlTree(){root = NULL;}
avlTreeNode<T>*& getRoot(){return root;}
int getHeight(avlTreeNode<T>* ptr);//获得子树的高度
void llRotation(avlTreeNode<T>* &root);//对以root为根节点的最小不平衡子树进行LL平衡旋转
void lrRotation(avlTreeNode<T>* &root);//对以root为根节点的最小不平衡子树进行LR平衡旋转
void rrRotation(avlTreeNode<T>* &root);//对以root为根节点的最小不平衡子树进行RR平衡旋转
void rlRotation(avlTreeNode<T>* &root);//对以root为根节点的最小不平衡子树进行RL平衡旋转
void addValue(avlTreeNode<T>* &root, T val);//向平衡树中增加结点
void delValue(avlTreeNode<T>* &root, T val);//删除值val所在结点
void creatAvlTree();//建立平衡树
avlTreeNode<T>* getMin(avlTreeNode<T>* root) const;//找到以root为根节点的树中最小的节点
avlTreeNode<T>* getMax(avlTreeNode<T>* root) const;//找到以root为根节点的树中最大的节点
void printAvlTreeOfPre() const;//先序遍历输出结果
void printAvlTreeOfIn() const;//中序遍历输出结果
};
template <typename T>
int avlTree<T>::getHeight(avlTreeNode<T>* ptr){
if(ptr != NULL)
return ptr -> height;
return 0;
}
template <typename T>
void avlTree<T>::llRotation(avlTreeNode<T>* &root){
//进行右单旋转,这里需要注意的是需要对两个结点的高度进行调整
avlTreeNode<T>* temp = root;
root = root -> left;
temp -> left = root -> right;
root -> right = temp;
temp -> height = max(getHeight(temp -> left), getHeight(temp -> right)) + 1;
root -> height = max(getHeight(root -> left), getHeight(root -> right)) + 1;
}
template <typename T>
void avlTree<T>::rrRotation(avlTreeNode<T>* &root){
//进行左单旋转,这里需要注意的是需要对两个结点的高度进行调整
avlTreeNode<T>* temp = root;
root = root -> right;
temp -> right = root -> left;
root -> left = temp;
temp -> height = max(getHeight(temp -> left), getHeight(temp -> right)) + 1;
root -> height = max(getHeight(root -> left), getHeight(root -> right)) + 1;
}
template <typename T>
void avlTree<T>::lrRotation(avlTreeNode<T>* &root){
//先进行左旋转,在进行右旋转
rrRotation(root -> left);
llRotation(root);
}
template <typename T>
void avlTree<T>::rlRotation(avlTreeNode<T>* &root){
//先进行左旋转,在进行右旋转
llRotation(root -> right);
rrRotation(root);
}
template <typename T>
void avlTree<T>::addValue(avlTreeNode<T>* &root, T val){
if(root == NULL){//根节点是NULL
root = new avlTreeNode<T>(val, NULL, NULL);
}else if(root -> data > val){//插入到左子树
addValue(root -> left, val);
if(getHeight(root -> left) - getHeight(root -> right) == 2){
if(root -> left -> data > val){
llRotation(root);
}else{
lrRotation(root);
}
}
}else if(root -> data < val){//插入到右子树
addValue(root -> right, val);
if(getHeight(root -> left) - getHeight(root -> right) == -2){
if(root -> right -> data > val){
rlRotation(root);
}else{
rrRotation(root);
}
}
}else{
cout << "平衡树中已有该结点" <<endl;
}
root -> height = getHeight(root -> left) > getHeight(root -> right) ? getHeight(root -> left) + 1:getHeight(root -> right) + 1;
}
template <typename T>
void avlTree<T>::creatAvlTree(){
T val;
cin >> val;
while(val != '#'){
addValue(root, val);
cin >> val;
}
}
template <typename T>
void avlTree<T>::delValue(avlTreeNode<T>* &root, T val){
if(root == NULL)//树中没有值为val的节点
return;
if(root -> data == val){
if(root -> left != NULL && root -> right != NULL){
//左子树高度大,删除左子树中值最大的结点,将其赋给根结点
if(getHeight(root -> left) > getHeight(root -> right)){
root -> data = getMax(root -> left) -> data;
delValue(root -> left, root -> data);
}else{//右子树高度更大,删除右子树中值最小的结点,将其赋给根结点
root -> data = getMin(root -> right) -> data;
delValue(root -> right, root -> data);
}
}else{//左右子树有一个不为空,直接用需要删除的结点的子结点替换即可
avlTreeNode<T>* temp = root;
root = root -> left == NULL ? root -> right: root -> left;
delete temp;
}
}else if(root -> data < val){//在root的右子树删除val
delValue(root -> right, val);
if(getHeight(root -> right) - getHeight(root -> left) == -2){//需要进行调整
if(getHeight(root -> left -> left) > getHeight(root -> left -> right)){
llRotation(root);
}else{
lrRotation(root);
}
}else{//不需要调整
root -> height = max(getHeight(root -> right), getHeight(root -> left)) + 1;
}
}else if(root -> data > val){//在root的左子树删除val
delValue(root -> left, val);
if(getHeight(root -> right) - getHeight(root -> left) == 2)
{//需要进行调整
if(getHeight(root -> right -> left) > getHeight(root -> right -> right)){
rlRotation(root);
}else{
rrRotation(root);
}
}else{//不需要调整
root -> height = max(getHeight(root -> right), getHeight(root -> left)) + 1;
}
}
}
template <typename T>
avlTreeNode<T>* avlTree<T>::getMin(avlTreeNode<T>* root) const{//找到以root为根节点的树中最小的节点
if(root == NULL)
return NULL;
while(root -> left != NULL){
root = root -> left;
}
return root;
}
template <typename T>
avlTreeNode<T>* avlTree<T>::getMax(avlTreeNode<T>* root) const{//找到以root为根节点的树中最大的节点
if(root == NULL)
return NULL;
while(root -> right != NULL){
root = root -> right;
}
return root;
}
template <typename T>
void avlTree<T>::printAvlTreeOfPre() const{
if(root == NULL)
return;
stack <avlTreeNode<T>*> stc;
stc.push(root);
while(!stc.empty()){
avlTreeNode<T>* temp = stc.top();
stc.pop();
cout << temp -> data << " ";
if(temp -> right != NULL){
stc.push(temp -> right);
}
if(temp -> left != NULL){
stc.push(temp -> left);
}
}
}
template <typename T>
void avlTree<T>::printAvlTreeOfIn() const{
if(root == NULL)
return;
stack <avlTreeNode<T>*> stc;
avlTreeNode<T>* temp = root;
while(!stc.empty() || temp != NULL){
if(temp != NULL){
stc.push(temp);
temp = temp -> left;
}else{
temp = stc.top();
stc.pop();
cout << temp -> data << " ";
temp = temp -> right;
}
}
}
int main(){
avlTree<char>* tree = new avlTree<char>;
tree -> creatAvlTree();
cout<<endl<<"前序遍历结果:"<<endl;
tree -> printAvlTreeOfPre();
cout<<endl<<"中序遍历结果:"<<endl;
tree -> printAvlTreeOfIn();
cout<<endl;
tree -> delValue(tree -> getRoot(), 'a');
cout<<endl<<"删除结点a之后的前序遍历结果:"<<endl;
tree -> printAvlTreeOfPre();
cout<<endl<<"删除结点a之后的中序遍历结果:"<<endl;
tree -> printAvlTreeOfIn();
cout<<endl;
return 0;
}
测试结果如下: