平衡二叉树的原理与功能实现(AVL)

AVL树学习

学习重点:

  1. AVL树的定义 2. AVL树插入操作 3. 插入新结点后如何调整"不平衡问题" 4.查找效率分析

1.定义:

平衡二叉树:树上任一结点的左子树和右子树的高度之差不超过1

结点的平衡因子 = 左子树高度 - 右子树高度

只要有任何一个结点的平衡因子的绝对值大于1,那此树就不是平衡二叉树

平衡二叉树结点:

typedef struct AVLNode{
  int key;
  int balance; //平衡因子
  struct AVLNode *lchild, *rchild;
}AVLNode, *AVLTree;

2.调平衡思想

每次插入一个结点,其祖先结点的平衡因子都会改变,从插入结点往上走,第一个平衡因子大于1的结点称为trouble finder,而插入结点称之为trouble maker,此时以trouble finder为根结点的树称为最小不平衡子树

注意:每次调整的对象都是最小不平衡子树

3.调整最小不平衡子树A的方法

分为四种不同情况讨论:

  1. LL 在A的左孩子的左子树插入结点导致不平衡
  2. RR 在A的右孩子的右子树中插入导致不平衡
  3. LR 在A的左孩子的右子树中插入导致不平衡
  4. RL 在A的右孩子的左子树中插入导致不平衡
1.LL:

调整目标:1.恢复最小不平衡子树A的平衡 2.保持二叉排序树的特性

LL平衡旋转:(右单旋转)由于在结点A的左孩子的左子树上插入了新结点,A的平衡因子由1增至2,导致以A为根的子树失去平衡,需要一次向右的旋转操作。将A的左孩子B向右上旋转代替A称为根结点,将A向右下旋转成为B的右子树的根结点,B的原右子树则作为A结点的左子树

还有一种理解方法:找到当前的最小不平衡子树后,确定要旋转的结点为三个(trouble maker trouble finder以及他们的连接者),根据结点的平衡因子,谁的平衡因子的值在三个待旋转的结点的中间,谁就作为根结点,其余结点根据左右位置判断大小分配位置(也可以根据平衡因子判断,平衡因子最大的在右边,平衡因子最小的在左边)

2.RR

RR平衡旋转:(左单旋转)由于在结点A的右孩子的右子树上插入了新结点,A的平衡因子由-1减至-2,导致以A为根的子树失去平衡,需要一次向左的旋转操作。将A的右孩子B向左上旋转成为根结点,A结点向左下旋转成为B的左子树的根结点,而B的原左子树则作为A结点的右子树

以上两个涉及的旋转都是单旋转

3.LR

LR平衡旋转:(先左后右双旋转)先将A结点的左孩子B的右子树的根结点C向左上旋转提升到B结点的位置,然后再把该C结点向右上旋转提升到A结点的位置

4.RL

RL平衡旋转:(先有后左双旋转)**先将A结点的右孩子B的左子树的根结点C向右上旋转提升到B结点的位置。然后再把该C结点向左上旋转提升到A结点的位置

注意:在最小平衡子树中,左孩子只能进行右上旋,右孩子只能进行左上旋

接下来,是AVL树的具体实现以及调平衡功能的实现

功能实现代码:

功能描述:根据输入的一组序列生成AVL树,一边构造树,一边调整平衡,最终得到一棵AVL树

/*平衡二叉树代码实现*/

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
/*平衡二叉树结构定义*/
typedef struct Node{
    int data;
    int bal; //平衡因子
    struct Node *lchild, *rchild, *parent; // 比一般的搜索树多了父亲结点
}BiNode, *BiTree;

/*先实现两种单旋转方法*/

/*右单旋转实现(LL型): 核心思想就是把左侧结点旋转上来,成为新的根结点,
而原先的根结点成为它的右孩子结点,再根据BST的原则把下层的子树分配好位置*/
void RotateRight(BiTree &parent, BiTree &T){
    /*传入的parent是最小不平衡子树的根结点,T是整棵树的根结点*/
    BiNode* this_father = parent->parent; // 记录最小不平衡子树根结点的父结点
    BiNode* SubL = parent->lchild; // 记录左孩子
    BiNode* SubLR = SubL->rchild; // 记录左孩子的右孩子
    // 令SubLR为parent的左孩子
    parent->lchild = SubLR;
    if(SubLR){
        SubLR->parent = parent;
    }
    //将SubL旋上来,成为新的根结点
    SubL->rchild = parent;
    parent->parent = SubL;
    // 接下来,更新this_father的孩子结点(从parent换成SubL)
    if(!this_father){ // 如果this_father不存在,则说明parent就是整棵树的根结点
        T = SubL;
        SubL->parent = NULL; //往上没有了
    }
    else{ // 若存在,则需要判断是左孩子还是右孩子
        if(this_father->lchild == parent){
            this_father->lchild = SubL;
        }
        else{
            this_father->rchild = SubL;
        }
        SubL->parent = this_father;
    }
}

/*左单旋实现(RR型): 与LL型的旋转方法完全对称*/
void RotateLeft(BiTree &parent, BiTree &T){
    /*parent是最小不平衡子树的根结点,T是该树的根结点*/
    BiNode* this_father = parent->parent;
    BiNode* SubR = parent->rchild;
    BiNode* SubRL = SubR->lchild; // 记录右孩子的左孩子(因为这个结点要换地方)
    parent->rchild = SubRL;
    if(SubRL){
        SubRL->parent = parent;
    }
    SubR->lchild = parent;
    parent->parent = SubR; // SubR成为新的根结点
    if(!this_father){
        T = SubR;
        SubR->parent = NULL;
    }
    else{
        if(this_father->lchild == parent){
            this_father->lchild = SubR;
        }
        else{
            this_father->rchild = SubR;
        }
        SubR->parent = this_father;
    }
}

// 接下来实现双旋转(LR RL型)
void RotateLR(BiTree &parent, BiTree &T){
    /*先对SubL进行左旋变化,在对parent进行右旋变化
    注意:对SubL左旋变化时,把它当成最小不平衡子树的根结点!!*/
    BiNode* SubL = parent->lchild;
    RotateLeft(SubL, T);
    RotateRight(parent, T); 
}

void RotateRL(BiTree &parent, BiTree &T){
    BiNode* SubR = parent->rchild;
    RotateRight(SubR, T);
    RotateLeft(parent, T);
}


/*求平衡因子操作实现*/

/*计算树的高度(递归实现)*/
int Height(BiTree T){
    int lheight, rheight;
    if(T == NULL){
        return 0;
    }
    rheight = Height(T->rchild);
    lheight = Height(T->lchild);
    if(lheight > rheight){
        return lheight+1;
    }
    else{
        return rheight+1;
    }
}

/*平衡因子= 右子树高度 - 左子树高度 (只是这么设定)*/
void CalBalance(BiTree T){
    if(T == NULL){
        return;
    }
    T->bal = Height(T->rchild) - Height(T->lchild);
    CalBalance(T->lchild);
    CalBalance(T->rchild); // 递归计算,计算所有结点的平衡因子
}

/*接下来就是平衡二叉树的插入操作
根据给定的数据序列,插入生成平衡二叉树,并在插入结束后判断是否平衡
如果不平衡,就需要根据不平衡问题的类别进行旋转调平衡*/

/*失衡分析:设插入结点为p, 插入结点的父结点为x,现考察x结点的parent结点
1. 当abs(parent->bal) == 1, 树保持平衡,但以parent为根结点的子树高度增加1,所以
此时需要考虑parent的父结点是否失衡(也就是需要向上回溯)
2. 当abs(parent->bal) == 0, 树保持平衡,且以parent为根结点的子树高度不变,故而不需要
向上回溯
3. 当abs(parent->bal) > 1, 树失衡,此时考察导致结点parent的失衡的trouble maker在哪,
以此判断使用四种旋转类型的那种进行调平衡*/

void ToBalance(BiTree &x, BiTree &T){ // 插入后调整平衡函数
    /*x结点是插入结点的父结点*/
    BiNode* parent = NULL;
    // 若插入结点不是树的根结点
    if(x){
        parent = x->parent; // 考察其parent结点
        while(parent){
            // 情形3
            if(parent->bal < -1){ // 左孩子问题
                if(parent->lchild->bal == -1){
                    // 说明trouble发生在左孩子的左子树,即LL型
                    RotateRight(parent, T);
                }
                else{
                    // trouble发生在左孩子的右子树,即LR型
                    RotateLR(parent, T);
                }
                break; // 旋转完要break退出循环
            }
            if(parent->bal > 1){ // 右孩子问题
                if(parent->rchild->bal == 1){
                    //trouble发生在右孩子的右子树上,即RR型
                    RotateLeft(parent, T);
                }
                else{
                    // trouble发生在右孩子的左子树上,即RL型
                    RotateRL(parent, T);
                }
                break;
            }
            // 情形2: 不需要回溯(树的高度没变)
            else if(parent->bal == 0){
                break;
            }
            // 情形1
            parent = parent->parent; // 回溯:往前判断
        }
    }
}

/*结合调平衡函数和计算平衡因子的函数设计插入结点函数*/

BiNode* NewNode(int data){
    BiNode* p = new BiNode;
    p->bal = 0;
    p->data = data;
    p->lchild = p->rchild = p->parent = NULL;
    return p;
}

void Insert(BiTree &T, int data){
    BiNode* parent = NULL; // 记录插入结点的父结点
    BiNode* p = T;
    if(T == NULL){
        T = NewNode(data);
    }
    else{
        while(p){
            parent = p; // 记录父亲结点
            if(p->data == data){
                //存在一样值的已有结点
                return;
            }
            else if(p->data > data){
                p = p->lchild;
            }
            else{
                p = p->rchild;
            }
        }
        p = NewNode(data);
        if(parent->data > data){
            parent->lchild = p;
        }
        else{
            parent->rchild = p;
        }
        p->parent = parent;
    }
    // 更新平衡因子并维护平衡
    CalBalance(T);
    ToBalance(parent, T);
    CalBalance(T);
}

void CreateTree(BiTree &T, int str[], int len){
    for(int i = 0;i < len; i++){
        Insert(T, str[i]);
    }
}

void PreOrder(BiTree &T){
    if(T){
        std::cout << T->data << ",";
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

/*删除操作,后续再进行学习*/

int main(){
    int number, len = 0;
    int str[200000];
    char x;
    while(std::cin >> number >> x){
        str[len] = number;
        len++;
    }
    BiTree T = NULL;
    CreateTree(T, str, len);
    PreOrder(T);
    return 0;
}



python实现:

import re


class TreeNode(object):
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right
        self.height = 0
class AVLTree(object):
    def __init__(self):
        self.root = None
    def find(self, key):
        if not self.root:
            return None
        else:
            return self._find(key, self.root)
    def _find(self, key, node):
        if not node:
            return None
        elif key < node.data:
            return self._find(key, node.left)
        elif key > node.data:
            return self._find(key, node.right)
        else:
            return node
    def findMin(self):
        if self.root is None:
            return None
        else:
            return self._findMin(self.root)
    def _findMin(self, node):
        if node.left:
            return self._findMin(node.left)
        else:
            return node
    def findMax(self):
        if self.root is None:
            return None
        else:
            return self._findMax(self.root)
    def _findMax(self, node):
        if node.right:
            return self._findMax(node.right)
        else:
            return node
    def height(self, node):
        if node is None:
            return -1
        else:
            return node.height
    #在node节点的左孩子k1的左子树添加了新节点,左旋转
    def singleLeftRotate(self, node):
        k1 = node.left
        node.left = k1.right
        k1.right = node
        node.height = max(self.height(node.right), self.height(node.left)) + 1
        k1.height = max(self.height(k1.left), node.height) + 1
        return k1
    #在node节点的右孩子k1的右子树添加了新节点,右旋转
    def singleRightRotate(self, node):
        k1 = node.right
        node.right = k1.left
        k1.left = node
        node.height = max(self.height(node.right), self.height(node.left)) + 1
        k1.height = max(self.height(k1.right), node.height) + 1
        return k1
    #在node节点的左孩子的右子树添加了新节点,先左后右
    def doubleRightRotate(self, node):
        node.right = self.singleLeftRotate(node.right)
        return self.singleRightRotate(node)
    #在node节点的右孩子的左子树添加了新节点,先右后左
    def doubleLeftRotate(self, node):
        node.left = self.singleRightRotate(node.left)
        return self.singleLeftRotate(node)
    def insert(self, key):
        if not self.root:
            self.root = TreeNode(key)
        else:
            self.root = self._insert(key, self.root)
    def _insert(self, key, node):
        if node is None:
            node = TreeNode(key)
        elif key < node.data:
            node.left = self._insert(key, node.left)
            if (self.height(node.left) - self.height(node.right)) == 2:
                if key < node.left.data:
                    node = self.singleLeftRotate(node)
                else:
                    node = self.doubleLeftRotate(node)
        elif key > node.data:
            node.right = self._insert(key, node.right)
            if (self.height(node.right) - self.height(node.left)) == 2:
                if key > node.right.data:
                    node = self.singleRightRotate(node)
                else:
                    node = self.doubleRightRotate(node)
        node.height = max(self.height(node.right), self.height(node.left)) + 1
        return node
    def delete(self, key):
        if self.root is None:
            raise KeyError('Error,empty tree')
        else:
            self.root = self._delete(key, self.root)
    def _delete(self, key, node):
        if node is None:
            raise KeyError('Error,key not in tree')
        elif key < node.data:
            node.left = self._delete(key, node.left)
            if (self.height(node.right) - self.height(node.left)) == 2:
                if self.height(node.right.right) >= self.height(node.right.left):
                    node = self.singleRightRotate(node)
                else:
                    node = self.doubleRightRotate(node)
            node.height = max(self.height(node.left), self.height(node.right)) + 1
        elif key > node.data:
            node.right = self._delete(key, node.right)
            if (self.height(node.left) - self.height(node.right)) == 2:
                if self.height(node.left.left) >= self.height(node.left.right):
                    node = self.singleLeftRotate(node)
                else:
                    node = self.doubleLeftRotate(node)
            node.height = max(self.height(node.left), self.height(node.right)) + 1
        elif node.left and node.right:
            if node.left.height <= node.right.height:
                minNode = self._findMin(node.right)
                node.key = minNode.key
                node.right = self._delete(node.key, node.right)
            else:
                maxNode = self._findMax(node.left)
                node.key = maxNode.key
                node.left = self._delete(node.key, node.left)
            node.height = max(self.height(node.left), self.height(node.right)) + 1
        else:
            if node.right:
                node = node.right
            else:
                node = node.left
        return node

    # 先序遍历
    def preOrderTraverse(self, node):
        if node is not None:
            print(node.data, end=',')
            self.preOrderTraverse(node.left)
            self.preOrderTraverse(node.right)

if __name__ == '__main__':
    str = input()
    a = []
    a = re.findall(r'\d+\.?\d*', str) # 正则表达式获得一行字符串的所有数字
    a = list(map(int, a))
    avl = AVLTree()

    for i in a:
        avl.insert(i)
    avl.preOrderTraverse(avl.root)
    
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值