平衡二叉树也叫平衡二叉搜索树,又被称为AVL树,可以保证查询效率较高,它是一颗空树或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是平衡二叉树

    具有下列性质:

    • 它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。
    • 若将二叉树节点的平衡因子BF定义为该节点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有节点的平衡因子只可能为-1,0,1.
    • 只要二叉树上有一个节点的平衡因子的绝对值大于1,那么这颗平衡二叉树就失去了平衡。

    平衡二叉树 - 图1
    平衡二叉树 - 图2
    平衡二叉树 - 图3

    1. /**
    2. * 《平衡二叉树》
    3. * 平衡算法:
    4. * 1、单向左旋平衡处理
    5. * 2、单向右旋平衡处理
    6. * 3、双向旋转(先左后右)平衡处理
    7. * 4、双向旋转(先右后左)平衡处理
    8. *
    9. * 下图二叉排序树(BST)存在的问题分析
    10. * 1
    11. * \
    12. * 2
    13. * \
    14. * 3
    15. * \
    16. * 4
    17. * 左子树全部为空,从形式上看,更像一个单链表。插入速度没有影响。查询速度明显降低(因为需要依次比较), 不能发挥BST的优势,
    18. * 因为每次还需要比较左子树,其查询速度比单链表还慢。解决方案-平衡二叉树(AVL)。
    19. */
    20. public class AVLTree {
    21. /**
    22. * 根结点
    23. */
    24. private TreeNode rootNode;
    25. /**
    26. * 树结点
    27. */
    28. class TreeNode {
    29. /**
    30. * 结点值
    31. */
    32. private int value;
    33. /**
    34. * 左子结点
    35. */
    36. private TreeNode left;
    37. /**
    38. * 左子结点
    39. */
    40. private TreeNode right;
    41. public TreeNode(int value) {
    42. this.value = value;
    43. }
    44. /**
    45. * 返回以该结点为根结点的树的高度
    46. */
    47. private int height() {
    48. return Math.max((this.left != null ? this.left.height() : 0), (this.right != null ? this.right.height() : 0)) + 1;
    49. }
    50. /**
    51. * 返回左子树的高度
    52. */
    53. private int leftHeight() {
    54. if (this.left == null) {
    55. return 0;
    56. }
    57. return this.left.height();
    58. }
    59. /**
    60. * 返回右子树的高度
    61. */
    62. private int rightHeight() {
    63. if (this.right == null) {
    64. return 0;
    65. }
    66. return this.right.height();
    67. }
    68. /**
    69. * 左旋转
    70. */
    71. private void leftRotate() {
    72. // 1、创建新的结点,以当前根结点的值
    73. TreeNode newNode = new TreeNode(this.value);
    74. // 2、把新的结点的左子结点设置成当前结点的左子结点
    75. newNode.left = this.left;
    76. // 3、把新的结点的右子结点设置成当前结点的右子结点的左子结点
    77. newNode.right = this.right.left;
    78. // 4、把当前结点的值替换成右子结点的值
    79. this.value = this.right.value;
    80. // 5、把当前结点的右子结点设置成当前结点右子结点的右子结点
    81. this.right = this.right.right;
    82. // 6、把当前结点的左子结点设置成新的结点
    83. this.left = newNode;
    84. }
    85. /**
    86. * 右旋转
    87. */
    88. private void rightRotate() {
    89. // 1、创建新的结点,以当前根结点的值
    90. TreeNode newNode = new TreeNode(this.value);
    91. // 2、把新的结点的右子结点设置成当前结点的右子结点
    92. newNode.right = this.right;
    93. // 3、把新的结点的左子结点设置成当前结点的左子结点的右子结点
    94. newNode.left = this.left.right;
    95. // 4、把当前结点的值替换成左子结点的值
    96. this.value = this.left.value;
    97. // 5、把当前结点的左子结点设置成当前结点左子结点的左子结点
    98. this.left = this.left.left;
    99. // 6、把当前结点的右子结点设置成新的结点
    100. this.right = newNode;
    101. }
    102. /**
    103. * 插入结点
    104. */
    105. private void addNode(TreeNode node) {
    106. // 插入结点小于当前结点,则往当前结点左子结点进行插入
    107. if (node.value < this.value) {
    108. if (this.left == null) {
    109. // 左子结点为空时,则直接插入
    110. this.left = node;
    111. } else {
    112. // 左子结点不为空时,则往左子结点插入
    113. this.left.addNode(node);
    114. }
    115. // 否则往当前结点右子结点进行插入
    116. } else {
    117. if (this.right == null) {
    118. // 右子结点为空时,则直接插入
    119. this.right = node;
    120. } else {
    121. // 右子结点不为空时,则往右子结点插入
    122. this.right.addNode(node);
    123. }
    124. }
    125. // 当添加完一个结点后,如果: (右子树的高度-左子树的高度) > 1 , 左旋转
    126. if(rightHeight() - leftHeight() > 1) {
    127. //如果它的右子树的左子树的高度大于它的右子树的右子树的高度
    128. if(right != null && right.leftHeight() > right.rightHeight()) {
    129. //先对右子结点进行右旋转
    130. right.rightRotate();
    131. //然后在对当前结点进行左旋转
    132. leftRotate(); //左旋转..
    133. } else {
    134. //直接进行左旋转即可
    135. leftRotate();
    136. }
    137. // 当添加完一个结点后,如果 (左子树的高度 - 右子树的高度) > 1, 右旋转
    138. } else if(leftHeight() - rightHeight() > 1) {
    139. //如果它的左子树的右子树高度大于它的左子树的高度
    140. if(left != null && left.rightHeight() > left.leftHeight()) {
    141. //先对当前结点的左结点(左子树)->左旋转
    142. left.leftRotate();
    143. //再对当前结点进行右旋转
    144. rightRotate();
    145. } else {
    146. //直接进行右旋转即可
    147. rightRotate();
    148. }
    149. }
    150. }
    151. /**
    152. * 中序遍历
    153. */
    154. private void middleOrder() {
    155. // 1、中序遍历左子树
    156. if (this.left != null) {
    157. this.left.middleOrder();
    158. }
    159. // 2、输出结点
    160. System.out.printf("%s ", this.value);
    161. // 3、中序遍历右子树
    162. if (this.right != null) {
    163. this.right.middleOrder();
    164. }
    165. }
    166. }
    167. /**
    168. * 中序遍历
    169. */
    170. public void middleOrderPrint() {
    171. if (rootNode == null) {
    172. return;
    173. }
    174. rootNode.middleOrder();
    175. }
    176. /**
    177. * 插入结点
    178. */
    179. public void add(int value) {
    180. TreeNode node = new TreeNode(value);
    181. // 根结点为空时,则插入结点直接当作根结点
    182. if (rootNode == null) {
    183. rootNode = node;
    184. } else {
    185. rootNode.addNode(node);
    186. }
    187. }
    188. public static void main(String[] args) {
    189. int[] arr1 = {4, 3, 6, 5, 7, 8};
    190. int[] arr2 = {10, 12, 8, 9, 7, 6};
    191. int[] arr3 = {10, 11, 7, 6, 8, 9};
    192. //树1左旋转
    193. AVLTree avlTree1 = new AVLTree();
    194. for (int i = 0; i < arr1.length; i++) {
    195. avlTree1.add(arr1[i]);
    196. }
    197. System.out.println("左旋转平衡处理~~");
    198. System.out.println("树1的高度=" + avlTree1.rootNode.height());
    199. System.out.println("树1的左子树高度=" + avlTree1.rootNode.leftHeight());
    200. System.out.println("树1的右子树高度=" + avlTree1.rootNode.rightHeight());
    201. System.out.println();
    202. //树2右旋转
    203. AVLTree avlTree2 = new AVLTree();
    204. for (int i = 0; i < arr2.length; i++) {
    205. avlTree2.add(arr2[i]);
    206. }
    207. System.out.println("右旋转平衡处理~~");
    208. System.out.println("树2的高度=" + avlTree2.rootNode.height());
    209. System.out.println("树2的左子树高度=" + avlTree2.rootNode.leftHeight());
    210. System.out.println("树2的右子树高度=" + avlTree2.rootNode.rightHeight());
    211. System.out.println();
    212. //树3双旋转
    213. AVLTree avlTree3 = new AVLTree();
    214. for (int i = 0; i < arr3.length; i++) {
    215. avlTree3.add(arr3[i]);
    216. }
    217. System.out.println("双旋转平衡处理~~");
    218. System.out.println("树3的高度=" + avlTree3.rootNode.height());
    219. System.out.println("树3的左子树高度=" + avlTree3.rootNode.leftHeight());
    220. System.out.println("树3的右子树高度=" + avlTree3.rootNode.rightHeight());
    221. System.out.println();
    222. }
    223. }