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();*/
}
}