AVL树的基本操作与实现

package BST树;

import java.util.TreeSet;

class AVLNode<T extends Comparable>{
private T data;
private AVLNode left;
private AVLNode right;
private int height; // 记录节点当前的高度值

public AVLNode(T data, AVLNode<T> left, AVLNode<T> right, int height) {
    this.data = data;
    this.left = left;
    this.right = right;
    this.height = height;
}

public T getData() {
    return data;
}

public void setData(T data) {
    this.data = data;
}

public AVLNode<T> getLeft() {
    return left;
}

public void setLeft(AVLNode<T> left) {
    this.left = left;
}

public AVLNode<T> getRight() {
    return right;
}

public void setRight(AVLNode<T> right) {
    this.right = right;
}

public int getHeight() {
    return height;
}

public void setHeight(int height) {
    this.height = height;
}

}

/**

  • 描述: 平衡二叉搜索树

  • 平衡:节点左右子树的高度差不超过1

  • 引入了四种旋转方式:

  • 1.左孩子的左子树太高: 右旋转操作

  •    40              30
    
  •  30      =>     20    40    =>   node,child
    
  • 20

  • 2.右孩子的右子树太高: 左旋转操作

  • 40                  50
    
  •    50      =>   40       60   =>   node,child
    
  •       60
    
  • 3.左孩子的右子树太高

  •  40             40             30
    
  • 20 => 30 => 20 40

  •  30         20
    
  • 4.右孩子的左子树太高

  • 40 40 50

  •   60   =>        50       => 40        60
    
  • 50 60

  • 问题:

  • 1.AVL是不是一个二叉搜索树?

  • 2.AVL是不是一颗平衡树?

  • 3.树的平衡指的是什么?

  • 4.AVL树是怎么旋转的?

  • 5.AVL树最差,最好,平均 增删查时间复杂度?

  • 6.AVL树在插入删除过程中,最差的情况下,需要旋转的次数是多少次?O(log2n) 删除 插入 最多2次搞定

  • AVL为了保持树的平衡,而做的旋转操作过多,当数据量大的时候,AVL树的增加,删除时间花费越来越大

  • @Author shilei

  • @Date 2019/7/3
    */
    public class AVL<T extends Comparable> {
    private AVLNode root;

    public AVL(){
    this.root = null;
    }

    /**

    • 递归实现AVL树的插入操作
    • @param data
      */
      public void insert(T data){
      this.root = insert(this.root, data);
      }

    /**

    • 以参数root为起始节点,搜索一个合适的位置添加data,然后把子树的根节点返回

    • @param root

    • @param data

    • @return
      */
      private AVLNode insert(AVLNode root, T data) {
      if(root == null){
      return new AVLNode<>(data, null, null, 1);
      }

      if(root.getData().compareTo(data) > 0){
      root.setLeft(insert(root.getLeft(), data));
      // 判断root节点是否失衡 #1
      if(height(root.getLeft()) - height(root.getRight()) > 1){
      if(height(root.getLeft().getLeft())
      >= height(root.getLeft().getRight())){
      // 左孩子的左子树太高
      root = rightRotate(root);
      } else {
      // 左孩子的右子树太高
      root = leftBalance(root);
      }
      }
      } else if(root.getData().compareTo(data) < 0){
      root.setRight(insert(root.getRight(), data));
      // 判断root节点是否失衡 #2
      if(height(root.getRight()) - height(root.getLeft()) > 1){
      if(height(root.getRight().getRight())
      >= height(root.getRight().getLeft())){
      // 右孩子的右子树太高
      root = leftRotate(root);
      } else {
      // 右孩子的左子树太高
      root = rightBalance(root);
      }
      }
      }

      // 递归回溯过程中,更新节点的高度值 #3
      root.setHeight(maxHeight(root.getLeft(), root.getRight()) + 1);
      return root;
      }

    /**

    • 实现AVL树的递归删除
    • @param data
      */
      public void remove(T data){
      this.root = remove(this.root, data);
      }

    private AVLNode remove(AVLNode root, T data) {
    if(root == null){
    return null;
    }

     if(root.getData().compareTo(data) > 0){
         root.setLeft(remove(root.getLeft(), data));
         // #1
         if(height(root.getRight()) - height(root.getLeft()) > 1){
             if(height(root.getRight().getRight())
                     >= height(root.getRight().getLeft())){
                 root = leftRotate(root);
             } else {
                 root= rightBalance(root);
             }
         }
     } else if(root.getData().compareTo(data) < 0){
         // #2
         root.setRight(remove(root.getRight(), data));
         if(height(root.getLeft()) - height(root.getRight()) > 1){
             if(height(root.getLeft().getLeft())
                     >= height(root.getLeft().getRight())){
                 root = rightRotate(root);
             } else {
                 root= leftBalance(root);
             }
         }
     } else {
         if(root.getLeft() != null && root.getRight() != null){
             // #3 左右子树哪个高,删除哪个,为了防止删除带来的旋转操作,提高效率
             if(height(root.getLeft()) >= height(root.getRight())){
                 // 用前驱替换
                 AVLNode<T> pre = root.getLeft();
                 while(pre.getRight() != null){
                     pre = pre.getRight();
                 }
                 root.setData(pre.getData());
                 root.setLeft(remove(root.getLeft(), pre.getData())); //删除前驱
             } else {
                 // 用后继替换
                 AVLNode<T> post = root.getRight();
                 while(post.getLeft() != null){
                     post = post.getLeft();
                 }
                 root.setData(post.getData());
                 root.setRight(remove(root.getRight(), post.getData())); // 删除后继
             }
         } else {
             if(root.getLeft() != null){
                 return root.getLeft();
             } else if(root.getRight() != null){
                 return root.getRight();
             } else {
                 return null;
             }
         }
     }
    
     // 递归回溯过程中,更新节点的高度值 #4
     root.setHeight(maxHeight(root.getLeft(), root.getRight()) + 1);
     return root;
    

    }

    /**

    • 以参数node为根节点进行左旋操作,把旋转后的树的根节点返回
    • @param node
    • @return
      */
      private AVLNode leftRotate(AVLNode node){
      AVLNode child = node.getRight();
      node.setRight(child.getLeft());
      child.setLeft(node);
      node.setHeight(maxHeight(node.getLeft(), node.getRight()) + 1);
      child.setHeight(maxHeight(child.getLeft(), child.getRight()) + 1);
      return child;
      }

    /**

    • 以参数node为根节点进行右旋操作,把旋转后的树的根节点返回
    • @param node
    • @return
      */
      private AVLNode rightRotate(AVLNode node){
      AVLNode child = node.getLeft();
      node.setLeft(child.getRight());
      child.setRight(node);
      node.setHeight(maxHeight(node.getLeft(), node.getRight()) + 1);
      child.setHeight(maxHeight(child.getLeft(), child.getRight()) + 1);
      return child;
      }

    /**

    • 以参数node为根节点进行左平衡操作,把旋转后的树的根节点返回
    • @param node
    • @return
      */
      private AVLNode leftBalance(AVLNode node){
      node.setLeft(leftRotate(node.getLeft()));
      return rightRotate(node);
      }

    /**

    • 以参数node为根节点进行右平衡操作,把旋转后的树的根节点返回
    • @param node
    • @return
      */
      private AVLNode rightBalance(AVLNode node){
      node.setRight(rightRotate(node.getRight()));
      return leftRotate(node);
      }

    /**

    • 获取node为根节点的树的高度
    • @param node
    • @return
      */
      private int height(AVLNode node){
      return node == null ? 0 : node.getHeight();
      }

    /**

    • 返回以node1和node2为根节点的子树高度的最大值
    • @param node1
    • @param node2
    • @return
      */
      private int maxHeight(AVLNode node1, AVLNode node2){
      int l = height(node1);
      int r = height(node2);
      return l > r ? l : r;
      }

    public static void main(String[] args) {
    AVL avl = new AVL<>();
    long begin=0, end=0;

     begin = System.currentTimeMillis();
     for (int i = 1; i <= 10; i++) {
         avl.insert(i);
     }
    
     avl.remove(10);
     avl.remove(9);
     avl.remove(5);
     end = System.currentTimeMillis();
     System.out.println("avl spend time:" + (end-begin) + "ms");
    
     /*TreeSet<Integer> ts = new TreeSet<>();
     begin = System.currentTimeMillis();
     for (int i = 1; i <= 10000000; i++) {
         ts.add(i);
     }
     end = System.currentTimeMillis();
     System.out.println("TreeSet spend time:" + (end-begin) + "ms");
    
     System.out.println();*/
    

    }
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AVL树是一种自平衡二叉搜索树,可以用来实现字典类型。在实现字典类型时,我们可以将键值对存储在AVL树的节点中,其中键作为节点的关键字,值则作为节点的附加数据。 下面是一个简单的AVL树实现字典类型的Python代码: ```python class AVLNode: def __init__(self, key, val): self.key = key self.val = val self.left = None self.right = None self.height = 1 class AVLTree: def __init__(self): self.root = None def insert(self, key, val): self.root = self._insert(self.root, key, val) def _insert(self, node, key, val): if not node: return AVLNode(key, val) if key < node.key: node.left = self._insert(node.left, key, val) elif key > node.key: node.right = self._insert(node.right, key, val) else: node.val = val node.height = 1 + max(self._height(node.left), self._height(node.right)) balance = self._get_balance(node) if balance > 1 and key < node.left.key: return self._right_rotate(node) if balance < -1 and key > node.right.key: return self._left_rotate(node) if balance > 1 and key > node.left.key: node.left = self._left_rotate(node.left) return self._right_rotate(node) if balance < -1 and key < node.right.key: node.right = self._right_rotate(node.right) return self._left_rotate(node) return node def search(self, key): node = self._search(self.root, key) if node: return node.val else: return None def _search(self, node, key): if not node: return None if key == node.key: return node if key < node.key: return self._search(node.left, key) else: return self._search(node.right, key) def _height(self, node): if not node: return 0 return node.height def _get_balance(self, node): if not node: return 0 return self._height(node.left) - self._height(node.right) def _left_rotate(self, node): new_root = node.right node.right = new_root.left new_root.left = node node.height = 1 + max(self._height(node.left), self._height(node.right)) new_root.height = 1 + max(self._height(new_root.left), self._height(new_root.right)) return new_root def _right_rotate(self, node): new_root = node.left node.left = new_root.right new_root.right = node node.height = 1 + max(self._height(node.left), self._height(node.right)) new_root.height = 1 + max(self._height(new_root.left), self._height(new_root.right)) return new_root ``` 在这个实现中,我们定义了AVLNode类来表示AVL树的节点。每个节点包含一个键、一个值、左右子树指针以及节点高度。AVLTree类是AVL树实现,包含了插入、搜索、左旋和右旋等基本操作。 在insert操作中,我们首先按照二叉搜索树的规则找到要插入的位置。然后更新节点高度,并计算平衡因子。如果平衡因子超过了1或-1,我们就需要进行旋转来保持AVL树的平衡。 在search操作中,我们按照二叉搜索树的规则搜索键值对应的节点,并返回其值。 这个AVL树实现可以用来实现字典类型。我们可以将键值对存储在AVL树的节点中,并通过搜索操作来查找键对应的值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值