平衡二叉树也叫平衡二叉搜索树,又被称为AVL树,可以保证查询效率较高,它是一颗空树或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是平衡二叉树
具有下列性质:
- 它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。
- 若将二叉树节点的平衡因子BF定义为该节点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有节点的平衡因子只可能为-1,0,1.
- 只要二叉树上有一个节点的平衡因子的绝对值大于1,那么这颗平衡二叉树就失去了平衡。
/*** 《平衡二叉树》* 平衡算法:* 1、单向左旋平衡处理* 2、单向右旋平衡处理* 3、双向旋转(先左后右)平衡处理* 4、双向旋转(先右后左)平衡处理** 下图二叉排序树(BST)存在的问题分析* 1* \* 2* \* 3* \* 4* 左子树全部为空,从形式上看,更像一个单链表。插入速度没有影响。查询速度明显降低(因为需要依次比较), 不能发挥BST的优势,* 因为每次还需要比较左子树,其查询速度比单链表还慢。解决方案-平衡二叉树(AVL)。*/public class AVLTree {/*** 根结点*/private TreeNode rootNode;/*** 树结点*/class TreeNode {/*** 结点值*/private int value;/*** 左子结点*/private TreeNode left;/*** 左子结点*/private TreeNode right;public TreeNode(int value) {this.value = value;}/*** 返回以该结点为根结点的树的高度*/private int height() {return Math.max((this.left != null ? this.left.height() : 0), (this.right != null ? this.right.height() : 0)) + 1;}/*** 返回左子树的高度*/private int leftHeight() {if (this.left == null) {return 0;}return this.left.height();}/*** 返回右子树的高度*/private int rightHeight() {if (this.right == null) {return 0;}return this.right.height();}/*** 左旋转*/private void leftRotate() {// 1、创建新的结点,以当前根结点的值TreeNode newNode = new TreeNode(this.value);// 2、把新的结点的左子结点设置成当前结点的左子结点newNode.left = this.left;// 3、把新的结点的右子结点设置成当前结点的右子结点的左子结点newNode.right = this.right.left;// 4、把当前结点的值替换成右子结点的值this.value = this.right.value;// 5、把当前结点的右子结点设置成当前结点右子结点的右子结点this.right = this.right.right;// 6、把当前结点的左子结点设置成新的结点this.left = newNode;}/*** 右旋转*/private void rightRotate() {// 1、创建新的结点,以当前根结点的值TreeNode newNode = new TreeNode(this.value);// 2、把新的结点的右子结点设置成当前结点的右子结点newNode.right = this.right;// 3、把新的结点的左子结点设置成当前结点的左子结点的右子结点newNode.left = this.left.right;// 4、把当前结点的值替换成左子结点的值this.value = this.left.value;// 5、把当前结点的左子结点设置成当前结点左子结点的左子结点this.left = this.left.left;// 6、把当前结点的右子结点设置成新的结点this.right = newNode;}/*** 插入结点*/private void addNode(TreeNode node) {// 插入结点小于当前结点,则往当前结点左子结点进行插入if (node.value < this.value) {if (this.left == null) {// 左子结点为空时,则直接插入this.left = node;} else {// 左子结点不为空时,则往左子结点插入this.left.addNode(node);}// 否则往当前结点右子结点进行插入} else {if (this.right == null) {// 右子结点为空时,则直接插入this.right = node;} else {// 右子结点不为空时,则往右子结点插入this.right.addNode(node);}}// 当添加完一个结点后,如果: (右子树的高度-左子树的高度) > 1 , 左旋转if(rightHeight() - leftHeight() > 1) {//如果它的右子树的左子树的高度大于它的右子树的右子树的高度if(right != null && right.leftHeight() > right.rightHeight()) {//先对右子结点进行右旋转right.rightRotate();//然后在对当前结点进行左旋转leftRotate(); //左旋转..} else {//直接进行左旋转即可leftRotate();}// 当添加完一个结点后,如果 (左子树的高度 - 右子树的高度) > 1, 右旋转} else if(leftHeight() - rightHeight() > 1) {//如果它的左子树的右子树高度大于它的左子树的高度if(left != null && left.rightHeight() > left.leftHeight()) {//先对当前结点的左结点(左子树)->左旋转left.leftRotate();//再对当前结点进行右旋转rightRotate();} else {//直接进行右旋转即可rightRotate();}}}/*** 中序遍历*/private void middleOrder() {// 1、中序遍历左子树if (this.left != null) {this.left.middleOrder();}// 2、输出结点System.out.printf("%s ", this.value);// 3、中序遍历右子树if (this.right != null) {this.right.middleOrder();}}}/*** 中序遍历*/public void middleOrderPrint() {if (rootNode == null) {return;}rootNode.middleOrder();}/*** 插入结点*/public void add(int value) {TreeNode node = new TreeNode(value);// 根结点为空时,则插入结点直接当作根结点if (rootNode == null) {rootNode = node;} else {rootNode.addNode(node);}}public static void main(String[] args) {int[] arr1 = {4, 3, 6, 5, 7, 8};int[] arr2 = {10, 12, 8, 9, 7, 6};int[] arr3 = {10, 11, 7, 6, 8, 9};//树1左旋转AVLTree avlTree1 = new AVLTree();for (int i = 0; i < arr1.length; i++) {avlTree1.add(arr1[i]);}System.out.println("左旋转平衡处理~~");System.out.println("树1的高度=" + avlTree1.rootNode.height());System.out.println("树1的左子树高度=" + avlTree1.rootNode.leftHeight());System.out.println("树1的右子树高度=" + avlTree1.rootNode.rightHeight());System.out.println();//树2右旋转AVLTree avlTree2 = new AVLTree();for (int i = 0; i < arr2.length; i++) {avlTree2.add(arr2[i]);}System.out.println("右旋转平衡处理~~");System.out.println("树2的高度=" + avlTree2.rootNode.height());System.out.println("树2的左子树高度=" + avlTree2.rootNode.leftHeight());System.out.println("树2的右子树高度=" + avlTree2.rootNode.rightHeight());System.out.println();//树3双旋转AVLTree avlTree3 = new AVLTree();for (int i = 0; i < arr3.length; i++) {avlTree3.add(arr3[i]);}System.out.println("双旋转平衡处理~~");System.out.println("树3的高度=" + avlTree3.rootNode.height());System.out.println("树3的左子树高度=" + avlTree3.rootNode.leftHeight());System.out.println("树3的右子树高度=" + avlTree3.rootNode.rightHeight());System.out.println();}}
