平衡二叉树(AVL)
二叉树是一种非常适合查找的数据结构,因而引入AVL树,BST树,红黑树
一、性质:
(1)它是一棵空树或者它的左右子树高度差不能超过1.且它的左右两个子树也是二叉平衡树。
(2)它是一种BST树,因而它拥有BST树的性质
二、目的:
用于增,删,查
造成AVL树不平衡有四种情况,解决策略如下:
(1)右孩子的右孩子造成:
child =node.right
node.right=child.left;
child.left=node;
(2)右孩子的左孩子造成:
进行两次旋转
(3)由左孩子的左孩子引起失衡(左平衡)
(4)由左孩子的右孩子引起的不平衡
发生两次旋转即可
下边是我们用递归实现的接口:
先创建节点
class AVLNode <T extends Comparable<T>> {
private T data;
private AVLNode<T>Left;
private AVLNode<T>Right;
private int hight;//记录当前节点的高度值
public AVLNode() {
}
public AVLNode(T data, AVLNode<T> left, AVLNode<T> right, int hight) {
this.data = data;
Left = left;
Right = right;
this.hight = hight;
}
public T getData() {
return data;
}
public AVLNode<T> getLeft() {
return Left;
}
public AVLNode<T> getRight() {
return Right;
}
public void setData(T data) {
this.data = data;
}
public void setLeft(AVLNode<T> left) {
Left = left;
}
public void setRight(AVLNode<T> right) {
Right = right;
}
public int getHight() {
return hight;
}
public void setHight(int hight) {
this.hight = hight;
}
}
创建一颗AVL树:
class AVLTree<T extends Comparable<T>>{
private AVLNode<T>root;
public AVLTree() {
this.root = null;
}
public void insert(T data){
this. root=insert(this.root,data );
}
四种旋转操作:
以参数node为根节点进行左旋操作,把旋转后的树的根节点返回
/**
* 以参数node为根节点进行左旋操作,把旋转后的树的根节点返回
* @param
* @return
*/
public AVLNode<T> leftRotate(AVLNode<T> node){
AVLNode<T> child=node.getRight();
node.setRight(child.getLeft());
child.setLeft(node);
//旋转之后更新高度
node.setHight(maxHeigh(node.getLeft(), node.getRight())+1);
child.setHight(maxHeigh(child.getLeft(), child.getRight())+1);
return child;
}
在这里插入代码片
右旋
/**
* 以参数node为根节点进行右旋操作,把旋转后的树的根节点返回
* @param
* @return
*/
public AVLNode<T> rightRotate(AVLNode<T> node){
AVLNode<T> child=node.getLeft();
node.setLeft(child.getRight());
child.setRight(node);
//更新child node 的高度
node.setHight(maxHeigh(node.getLeft(), node.getRight())+1);
child.setHight(maxHeigh(child.getLeft(), child.getRight())+1);
return child;
}
左平衡操作
/**
* 以参数node为根节点进行左平衡操作,把旋转后的树的根节点返回
* @param node
* @return
*/
public AVLNode<T>leftBalance(AVLNode<T> node){
node.setLeft( leftRotate( node.getLeft()));
return rightRotate(node);
}
右平衡操作
/**
* 以参数node为根节点进行右平衡操作,把旋转后的树的根节点返回
* @param node
* @return
*/
public AVLNode<T> rightBanlance(AVLNode<T>node){
//以node.right做右旋操作
AVLNode<T>child=node.getRight();
node.setRight(rightRotate(child));
return leftRotate(node);
}
插入操作(递归方式)
public AVLTree() {
this.root = null;
}
public void insert(T data){
this. root=insert(this.root,data );
}
//插入
private AVLNode<T> insert( AVLNode<T> 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));
//插入过程会发生左右不平衡的情况
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));
if (height(root.getRight()) - height(root.getLeft())> 1) {
if (height(root.getRight().getRight()) >= height(root.getRight().getLeft())) {
root = leftRotate(root);
} else {
root = rightBanlance(root);
}
}
}
//更新节点高度
root.setHight(maxHeigh(root.getLeft(), root.getRight()) + 1);
return root;
}
删除(递归方式)
/**
* 实现AVL树的递归删除
* @param data
*/
public void remove(T data){
this.root= remove(this.root, data);
}
private AVLNode<T> remove(AVLNode<T> root,T data) {
if (root == null) {
return null;
}
if (root.getData().compareTo(data) > 0) {
root.setLeft(remove(root.getLeft(), data));
//删除之后,可能会引起不平衡,进行旋转并且更新高度
if (height(root.getLeft()) - height(root.getRight()) > 1) {
if(height(root.getRight().getRight())>height(root.getRight().getLeft())){
root=leftRotate(root);
}else {
root=rightBanlance(root);
}
}
} else if (root.getData().compareTo(data) < 0) {
root.setRight(remove(root.getRight(), data));
if (height(root.getLeft().getLeft()) >= height(root.getLeft().getRight())) {
root = rightRotate(root);
} else {
root = leftBalance(root);
}
}
else {
if (root.getLeft() != null && root.getLeft() != null) {
//要根据待删节点的左右子树的高度,左子树过高则找前驱,右子树过高则找后继
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 {
//含一个节点和叶子节点
// AVLNode<T> child=root.getLeft();
if (root.getLeft() != null) {
return root.getLeft();
} else if (root.getRight() != null) {
return root.getRight();
} else {
return null;
}
}
}
return root;
}
分别以前序遍历,中序遍历,后序遍历方式打印出元素顺序
(前序遍历)
//前序遍历
public void preSOrder(){
preOrder(this.root);
}
public void preOrder(AVLNode<T>root){
if(root==null){
return ;
}
System.out.println(root);
preOrder(root.getLeft());
preOrder(root.getRight());
}
(中序遍历)
//中序遍历
public void inOrder(){
inOder(this.root);
}
public void inOder(AVLNode<T> root){
if(root==null){
return;
}
inOder(root.getLeft());
System.out.println(root.getData());
inOder(root.getRight());
}
(后序遍历)
//后序遍历
public void postOrder(){
postOrder(this.root);
}
public void postOrder(AVLNode<T> root){
if(root==null){
return;
}
postOrder(root.getLeft());
postOrder(root.getRight());
System.out.println(root.getData());
}
节点个数
//计算BST树的节点个数
public int num_Data(){
return num_Data(this.root);
}
public int num_Data(AVLNode<T> root){
if(root==null){
return 0;
}
return num_Data(root.getLeft())+num_Data(root.getRight())+1;
}
测试用例
public class TestDome {
public static void main(String[] args) {
AVLTree<Integer> avl = new AVLTree<>();
int[] arr = {1, 2, 3,4,5,6,7,8,9,10};
for (int i : arr) {
avl.insert(i);
}
//avl.remove(2);
// avl.num_Data();
int n=avl.num_Data();
System.out.println();
// System.out.println("================");
// avl.inOrder();
// System.out.println("================");
// avl.postOrder();
// System.out.println( avl.quire(2));
}
}