数据结构小记【Python/C++版】——AVL树篇

一,基本概念

AVL树是一种结构平衡的BST树,被称为平衡二叉树。

AVL树的具体特点是,每一个节点的左子树和右子树的高度差的绝对值最多为1,且其左子树和右子树也是AVL树。

BST树有时候会退化为一个链表,但是AVL树不会,因为AVL树具有自平衡属性。

AVL的自平衡是基于平衡因子来维持,平衡因子就是BST树中每个节点的左子树和右子树的高度差。因此对于AVL树来说,平衡因子的值应始终为 -1、0 或 +1。

如果平衡因子为1,则左子树比右子树深一级。

如果平衡因子为0,则左右子树处于相同的深度。

如果平衡因子为-1,则左子树比右子树浅一级。

最小不平衡子树:距离插入节点最近,且以平衡因子绝对值大于1的节点为根结点的子树。

二,AVL树的基本操作

插入节点和删除节点的操作,请参考前面写过的BST树的基本操作。

此处主要讲AVL树的再平衡问题,因AVL树是否平衡是基于平衡因子来衡量的,而插入节点和删除节点的操作容易打破AVL树原有的平衡,使平衡因子的绝对值大于1。此时的AVL树变成了不平衡的BST树,为了让BST树再次平衡成为AVL树,需要进行一系列的操作来改变树的结构,这个操作被称为旋转

当整个AVL树失去平衡时,仅需要对最小不平衡子树进行旋转即可。

旋转操作的本质是子节点和根节点位置的互换

1.左旋

1.发现一个子树的平衡因子为-2,定为最小不平衡子树。

2.找到破坏平衡的节点,即最小不平衡子树的根节点。

3.左旋最小不平衡子树,使破坏平衡的节点成为子树的左子节点。

2.右旋

1.发现一个子树的平衡因子为2,定为最小不平衡子树

2.找到破坏平衡的节点,即最小不平衡子树的根节点。

3.右旋最小不平衡子树,使破坏平衡的节点成为子树的右子节点。

3.左右旋

左旋+右旋的组合

对根节点的左子树执行左旋。

对整个不平衡子树执行右旋。

4.右左旋

右旋+左旋的组合

对根节点的右子树执行右旋。

对整个不平衡子树执行左旋。

三,AVL树的代码实现

案例场景: 

原始的AVL树:


插入节点"9",基于BST树的插入操作,生成新的不平衡的BST树。

此时,BST树的最小不平衡子树是:11->8->9(广度优先遍历)。

最小不平衡子树经过左右旋以后达到再平衡,生成新的AVL树。

再平衡以后的AVL树。

代码实现: 

Python实现:

import sys

#初始化节点
class TreeNode(object):
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None
        self.height = 1

class AVLTree(object):
    def insert_node(self, root, key):
        #基于BST树的方式插入节点
        if not root:
            return TreeNode(key)
        elif key < root.key:
            root.left = self.insert_node(root.left, key)
        else:
            root.right = self.insert_node(root.right, key)

        root.height = 1 + max(self.getHeight(root.left),
                              self.getHeight(root.right))

        #BST树再平衡
        balanceFactor = self.getBalance(root)
        if balanceFactor > 1:
            if key < root.left.key:
                return self.rightRotate(root)
            else:
                root.left = self.leftRotate(root.left)
                return self.rightRotate(root)

        if balanceFactor < -1:
            if key > root.right.key:
                return self.leftRotate(root)
            else:
                root.right = self.rightRotate(root.right)
                return self.leftRotate(root)
        return root

    def leftRotate(self, z):
        y = z.right
        T2 = y.left
        y.left = z
        z.right = T2
        z.height = 1 + max(self.getHeight(z.left),
                           self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                           self.getHeight(y.right))
        return y

    def rightRotate(self, z):
        y = z.left
        T3 = y.right
        y.right = z
        z.left = T3
        z.height = 1 + max(self.getHeight(z.left),
                           self.getHeight(z.right))
        y.height = 1 + max(self.getHeight(y.left),
                           self.getHeight(y.right))
        return y

    def getHeight(self, root):
        if not root:
            return 0
        return root.height

    def getBalance(self, root):
        if not root:
            return 0
        return self.getHeight(root.left) - self.getHeight(root.right)

    def preOrder(self, root):
        if not root:
            return
        print("{0} ".format(root.key), end="")
        self.preOrder(root.left)
        self.preOrder(root.right)

    def printTree(self, currPtr, indent, last):
        if currPtr != None:
            sys.stdout.write(indent)
            if last:
                sys.stdout.write("R----")
                indent += "     "
            else:
                sys.stdout.write("L----")
                indent += "|    "
            print(currPtr.key)
            self.printTree(currPtr.left, indent, False)
            self.printTree(currPtr.right, indent, True)

myTree = AVLTree()
root = None
nums = [33, 13, 53, 11, 21, 61, 8]
for num in nums:
    root = myTree.insert_node(root, num)
myTree.printTree(root, "", True)
new_node = 9
root = myTree.insert_node(root, new_node)
print("After Insert: ")
myTree.printTree(root, "", True)

运行结果:

R----33
     L----13
     |    L----11
     |    |    L----8
     |    R----21
     R----53
          R----61
After Insert:
R----33
     L----13
     |    L----9
     |    |    L----8
     |    |    R----11
     |    R----21
     R----53
          R----61

C++实现:

#include <iostream>
using namespace std;

//初始化节点
class Node {
public:
    int key;
    Node* left;
    Node* right;
    int height;
};
int max(int a, int b);

int height(Node* N) {
    if (N == NULL)
        return 0;
    return N->height;
}
int max(int a, int b) {
    return (a > b) ? a : b;
}

Node* newNode(int key) {
    Node* node = new Node();
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1;
    return (node);
}

Node* rightRotate(Node* y) {
    Node* x = y->left;
    Node* T2 = x->right;
    x->right = y;
    y->left = T2;
    y->height = max(height(y->left),
        height(y->right)) +
        1;
    x->height = max(height(x->left),
        height(x->right)) +
        1;
    return x;
}

Node* leftRotate(Node* x) {
    Node* y = x->right;
    Node* T2 = y->left;
    y->left = x;
    x->right = T2;
    x->height = max(height(x->left),
        height(x->right)) +
        1;
    y->height = max(height(y->left),
        height(y->right)) +
        1;
    return y;
}

int getBalanceFactor(Node* N) {
    if (N == NULL)
        return 0;
    return height(N->left) -
        height(N->right);
}

Node* insertNode(Node* node, int key) {
    //基于BST树的方式插入节点
    if (node == NULL)
        return (newNode(key));
    if (key < node->key)
        node->left = insertNode(node->left, key);
    else if (key > node->key)
        node->right = insertNode(node->right, key);
    else
        return node;

    //BST树再平衡
    node->height = 1 + max(height(node->left),
        height(node->right));
    int balanceFactor = getBalanceFactor(node);
    if (balanceFactor > 1) {
        if (key < node->left->key) {
            return rightRotate(node);
        }
        else if (key > node->left->key) {
            node->left = leftRotate(node->left);
            return rightRotate(node);
        }
    }
    if (balanceFactor < -1) {
        if (key > node->right->key) {
            return leftRotate(node);
        }
        else if (key < node->right->key) {
            node->right = rightRotate(node->right);
            return leftRotate(node);
        }
    }
    return node;
}

void printTree(Node* root, string indent, bool last) {
    if (root != nullptr) {
        cout << indent;
        if (last) {
            cout << "R----";
            indent += "   ";
        }
        else {
            cout << "L----";
            indent += "|  ";
        }
        cout << root->key << endl;
        printTree(root->left, indent, false);
        printTree(root->right, indent, true);
    }
}
int main() {
    Node* root = NULL;
    root = insertNode(root, 33);
    root = insertNode(root, 13);
    root = insertNode(root, 53);
    root = insertNode(root, 11);
    root = insertNode(root, 21);
    root = insertNode(root, 61);
    root = insertNode(root, 8);
    printTree(root, "", true);
    root = insertNode(root, 9);
    cout << "After Insert:" << endl;
    printTree(root, "", true);
}

运行结果:

R----33
   L----13
   |  L----11
   |  |  L----8
   |  R----21
   R----53
      R----61
After Insert:
R----33
   L----13
   |  L----9
   |  |  L----8
   |  |  R----11
   |  R----21
   R----53
      R----61

四,参考阅读

https://www.guru99.com/avl-tree.html

https://www.programiz.com/dsa/avl-tree

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
AVL树是一种自平衡二叉搜索树,它的平衡因子(左子树高度减去右子树高度)在任何时候都是-1、0或1。当插入或删除节点后,如果AVL树失去平衡,则需要通过旋转来重新平衡它。 在Python中实现AVL树,可以使用节点类和AVL树类。节点类包括节点值、左子树、右子树、高度和平衡因子等属性。AVL树类包括根节点、插入节点、删除节点、旋转方法和平衡方法等方法。 下面是一个简单的Python实现AVL树的代码示例: ```python class Node: def __init__(self, val): self.val = val self.left = None self.right = None self.height = 1 self.balance = 0 class AVLTree: def __init__(self): self.root = None def insert(self, val): self.root = self._insert(self.root, val) def _insert(self, node, val): if not node: return Node(val) if val < node.val: node.left = self._insert(node.left, val) else: node.right = self._insert(node.right, val) node.height = 1 + max(self.get_height(node.left), self.get_height(node.right)) node.balance = self.get_balance(node) if node.balance > 1 and val < node.left.val: return self.right_rotate(node) if node.balance < -1 and val > node.right.val: return self.left_rotate(node) if node.balance > 1 and val > node.left.val: node.left = self.left_rotate(node.left) return self.right_rotate(node) if node.balance < -1 and val < node.right.val: node.right = self.right_rotate(node.right) return self.left_rotate(node) return node def delete(self, val): self.root = self._delete(self.root, val) def _delete(self, node, val): if not node: return node if val < node.val: node.left = self._delete(node.left, val) elif val > node.val: node.right = self._delete(node.right, val) else: if not node.left or not node.right: temp = node.left if node.left else node.right if not temp: node = None else: node = temp else: temp = self.get_min(node.right) node.val = temp.val node.right = self._delete(node.right, temp.val) if not node: return node node.height = 1 + max(self.get_height(node.left), self.get_height(node.right)) node.balance = self.get_balance(node) if node.balance > 1 and self.get_balance(node.left) >= 0: return self.right_rotate(node) if node.balance < -1 and self.get_balance(node.right) <= 0: return self.left_rotate(node) if node.balance > 1 and self.get_balance(node.left) < 0: node.left = self.left_rotate(node.left) return self.right_rotate(node) if node.balance < -1 and self.get_balance(node.right) > 0: node.right = self.right_rotate(node.right) return self.left_rotate(node) return node def right_rotate(self, node): left_child = node.left node.left = left_child.right left_child.right = node node.height = 1 + max(self.get_height(node.left), self.get_height(node.right)) left_child.height = 1 + max(self.get_height(left_child.left), self.get_height(left_child.right)) node.balance = self.get_balance(node) left_child.balance = self.get_balance(left_child) return left_child def left_rotate(self, node): right_child = node.right node.right = right_child.left right_child.left = node node.height = 1 + max(self.get_height(node.left), self.get_height(node.right)) right_child.height = 1 + max(self.get_height(right_child.left), self.get_height(right_child.right)) node.balance = self.get_balance(node) right_child.balance = self.get_balance(right_child) return right_child def get_height(self, node): if not node: return 0 return node.height def get_balance(self, node): if not node: return 0 return self.get_height(node.left) - self.get_height(node.right) def get_min(self, node): while node.left: node = node.left return node ``` 这个实现包括插入、删除、旋转和平衡等基本操作。你可以按需调用这些方法,来实现你的具体需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值