二叉搜索树(BST)存在的问题
我们先把{1,2,3,4,5,6}这颗二叉搜索树创建出来,结果如下图:
可以看出这颗而擦搜索树的左子树全部为空,看起来更像一个单链表.
此时它的插入速度没有影响,但查询速度明显降低(因为需要依次比较,所以时间复杂度变为O(n)
), 不能发挥BST的优势,而且因为每次还需要比较左子树,其查询速度比单链表还慢。
为了解决以上问题于是主角登场了------平衡二叉树(AVL)
平衡二叉树(AVL)
概念:平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。
特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1
,并且左右两个子树都是一棵平衡二叉树
。
非平衡二叉树转平衡二叉树
—左旋转
根据数组 {4,3,6,5,7,8}创建出对应的平衡二叉树。
步骤:
1.创建一个新的节点newNode
,值等于当前根节点的值
2.把新节点的左子树设置为当前节点的左子树newNode.left=left;
3.把新节点的右子树设置为当前节点的右子树的左子树newNode.right=right.left;
4.把当前节点的值换为右子节点的值value=right.value;
5.把当前节点的右子树设置成右子树的右子树right=right.right;
6.把当前节点的左子树设置为新节点left=newNode;
代码:
public void leftRotate(){
//1.创建一个新的节点`newNode`,值等于当前根节点的值
Node newNode=new Node(value);
// 2.把新节点的右子树子树设置为当前节点的右子树
newNode.right=right;
// 3.把新节点的左子树设置为当前节点的左子树的右子树
newNode.left=left.right;
// 4.把当前节点的值换为左子节点的值
value=left.value;
// 5.把当前节点的左子树设置成左子树的左子树
left=left.left;
// 6.把当前节点的右子树设置为新节点
right=newNode;
}
—右旋转
根据数组{10,12, 8, 9, 7, 6}创建出对应的平衡二叉树。
步骤:
1.创建一个新的节点newNode
,值等于当前根节点的值
2.把新节点的右子树子树设置为当前节点的右子树newNode.right=right;
3.把新节点的左子树设置为当前节点的左子树的右子树newNode.left=left.right.;
4.把当前节点的值换为左子节点的值value=left.value;
5.把当前节点的左子树设置成左子树的左子树left=left.left;
6.把当前节点的右子树设置为新节点right=newNode;
代码:
//右旋转
public void rightRotate(){
//1.创建一个新的节点`newNode`,值等于当前根节点的值
Node newNode=new Node(value);
// 2.把新节点的左子树设置为当前节点的左子树
newNode.left=left;
// 3.把新节点的右子树设置为当前节点的右子树的左子树`
newNode.right=right.left;
// 4.把当前节点的值换为右子节点的值
value=right.value;
// 5.把当前节点的右子树设置成右子树的右子树
right=right.right;
// 6.把当前节点的左子树设置为新节点
left=newNode;
}
—双旋转
上面的两个数组进行一次单旋转就可以吧非平衡二叉树转换成平衡二叉树,但某些数组不能经过一次单旋转就完成平衡二叉树,如{10,11,7,6,8,9},符合右旋转条件,右旋转后如下图,仍然是非平衡二叉树。
解决办法:当符合右旋转的条件时,如果她的右子树高度大于它的左子树高度,先对当前这个节点的左节点进行左旋转,然后再对当前节点进行右旋转。
完整代码实现:
public class AVLTreeDemo {
public static void main(String[] args) {
int array[]={
10,11,7,6,8,9};
//创建一个AVLTree对象
AVLTree avlTree=new AVLTree();
//添加节点
for(int i=0;i<array.length;i++){
avlTree.add(new Node(array[i]));
}
//遍历
System.out.println("中序遍历");
avlTree.infixOrder();
System.out.println("转换为平衡二叉树后");
System.out.println("树的高度="+avlTree.getRoot().height());
System.out