当前位置:   article > 正文

平衡二叉树(java)_java实现平衡二叉树

java实现平衡二叉树

一、基本概念

平衡二叉树也叫平衡二叉搜索树 (Self-balancingbinarysearch tree) 又被称为AVL树,可以保证查询效率较高。

具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1.并且左右两个子树都是一棵平衡二叉树。

二、原理图

左旋转示意

 有旋转示意

 需要双旋转(根节点左子树进行左旋转后,根节点进行右旋转,反之亦然)

 三、代码

  1. /**
  2. * 创建节点
  3. */
  4. public class Node {
  5. int value;
  6. Node left;
  7. Node right;
  8. public Node(int value) {
  9. this.value = value;
  10. }
  11. /**
  12. * 左旋转
  13. */
  14. private void leftRotate() {
  15. // 创建新的节点,以当前根节点的值
  16. Node newNode = new Node(value);
  17. // 把新的节点的左子树,设置成为当前节点的左子树
  18. newNode.left = left;
  19. // 把新的节点的右子树设置成,复制节点的右子树的左子树
  20. newNode.right = right.left;
  21. // 把当前节点的值替换成右子节点的值
  22. value = right.value;
  23. // 把当前节点的右子树,设置为右子树的右子树
  24. right = right.right;
  25. // 吧当前节点的左子树设置新的节点
  26. left = newNode;
  27. }
  28. /**
  29. * 有旋转
  30. */
  31. private void rightRotate() {
  32. Node newNode = new Node(value);
  33. newNode.right = right;
  34. newNode.left = left.right;
  35. value = left.value;
  36. left = left.left;
  37. right = newNode;
  38. }
  39. /**
  40. * 返回左子树的高度
  41. *
  42. * @return
  43. */
  44. public int leftHeight() {
  45. if (left != null) {
  46. return left.height();
  47. } else {
  48. return 0;
  49. }
  50. }
  51. /**
  52. * 返回右子树的高度
  53. *
  54. * @return
  55. */
  56. public int rightHeight() {
  57. if (right == null) {
  58. return 0;
  59. }
  60. return right.height();
  61. }
  62. /**
  63. * 返回当前节点的高度
  64. *
  65. * @return
  66. */
  67. public int height() {
  68. return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
  69. }
  70. /**
  71. * 添加节点
  72. *
  73. * @param node
  74. */
  75. public void add(Node node) {
  76. if (node == null) {
  77. return;
  78. }
  79. // 判断传入节点的值,和当前子树根节点的关系
  80. if (node.value < this.value) {
  81. if (this.left != null) {
  82. //左子树递归
  83. this.left.add(node);
  84. } else {
  85. this.left = node;
  86. }
  87. } else {
  88. if (this.right != null) {
  89. //右子树递归
  90. this.right.add(node);
  91. } else {
  92. this.right = node;
  93. }
  94. }
  95. // 当添加完一个节点后,右子树高度-左子树高度>1
  96. if (rightHeight() - leftHeight() > 1) {
  97. //当右子树的左子树高度大于它的右子树的高度
  98. if(right!=null&&right.leftHeight()>right.rightHeight()){
  99. right.rightRotate();
  100. }
  101. leftRotate();
  102. return;
  103. }
  104. //左子树高度>右子树高度
  105. if (leftHeight() - rightHeight() > 1) {
  106. //当左子树的右子树高度大于它的左子树高度
  107. if(left!=null&&left.rightHeight()>left.leftHeight()){
  108. left.leftRotate();
  109. }
  110. rightRotate();
  111. }
  112. }
  113. /**
  114. * 查找要删除的节点的值
  115. *
  116. * @param value 希望删除的值
  117. * @return 返回该节点,默认返回null
  118. */
  119. public Node search(int value) {
  120. if (value == this.value) {
  121. return this;
  122. } else if (value < this.value) {
  123. //查找的值小于当前节点的值
  124. if (this.left == null) {
  125. return null;
  126. }
  127. return this.left.search(value);
  128. } else {
  129. //查找的值大于当前节点的值
  130. if (this.right == null) {
  131. return null;
  132. }
  133. return this.right.search(value);
  134. }
  135. }
  136. /**
  137. * 查找要删除的父节点
  138. *
  139. * @param value
  140. * @return
  141. */
  142. public Node searchParent(int value) {
  143. // 如果当前节点就是要删除的节点的父节点,直接返回
  144. if ((this.right != null && this.right.value == value) ||
  145. (this.left != null && this.left.value == value)) {
  146. return this;
  147. } else {
  148. // 向左子树递归
  149. if (value < this.value && this.left != null) {
  150. return this.left.searchParent(value);
  151. } else if (value >= this.value && this.right != null) {
  152. //向右子树递归
  153. return this.right.searchParent(value);
  154. } else {
  155. return null;
  156. }
  157. }
  158. }
  159. /**
  160. * 中序遍历
  161. */
  162. public void infixOrder() {
  163. if (this.left != null) {
  164. this.left.infixOrder();
  165. }
  166. System.out.println(this);
  167. if (this.right != null) {
  168. this.right.infixOrder();
  169. }
  170. }
  171. @Override
  172. public String toString() {
  173. return "Node{" +
  174. "value=" + value +
  175. '}';
  176. }
  177. }
  1. public class AVLTree {
  2. private Node root;
  3. public void delNode(int value) {
  4. if (root == null) {
  5. return;
  6. }
  7. // 查找要删除的节点
  8. Node targetNode = search(value);
  9. // 如果没有找到要删除的节点
  10. if (targetNode == null) {
  11. return;
  12. } //二叉树只有一个节点,切删除的为此节点
  13. if (root.left == null && root.right == null) {
  14. root = null;
  15. return;
  16. }
  17. //查找父节点
  18. Node parentNode = searchParent(value);
  19. // 如果删除的是叶子节点
  20. if (targetNode.left == null && targetNode.right == null) {
  21. // 如果是父节点的左子节点
  22. if (parentNode.left != null && parentNode.left.value == value) {
  23. parentNode.left = null;
  24. } else if (parentNode.right != null && parentNode.right.value == value) {
  25. // 如果是父节点的右子节点
  26. parentNode.right = null;
  27. }
  28. } else if (targetNode.left != null && targetNode.right != null) {
  29. // 删除节点有左右两个子树(删除当前节点右节点的最小值,或者当前节点左节点的最大值)
  30. int minVal = delRightTreeMin(targetNode.right);
  31. targetNode.value = minVal;
  32. } else {
  33. // 只有一颗子树的节点
  34. // 如果要删除的节点有左子节点
  35. if (targetNode.left != null) {
  36. // 如果targetNode是parent的左子节点
  37. if (parentNode != null) {
  38. if (parentNode.left.value == value) {
  39. parentNode.left = targetNode.left;
  40. } else {
  41. parentNode.right = targetNode.left;
  42. }
  43. } else {
  44. root = targetNode.left;
  45. }
  46. } else {
  47. // 如果删除的节点有右子节点
  48. if (parentNode != null) {
  49. if (parentNode.left.value == value) {
  50. parentNode.left = targetNode.right;
  51. } else {
  52. parentNode.right = targetNode.right;
  53. }
  54. } else {
  55. root = targetNode.right;
  56. }
  57. }
  58. }
  59. }
  60. /**
  61. * 返回以node根节点的二叉排序树的最小节点的值
  62. * 删除最小节点,返回最小节点的值
  63. *
  64. * @param node
  65. * @return
  66. */
  67. public int delRightTreeMin(Node node) {
  68. Node target = node;
  69. // 循环找到左子节点,找到最小值
  70. while (target.left != null) {
  71. target = target.left;
  72. }
  73. // 删除最小节点
  74. delNode(target.value);
  75. return target.value;
  76. }
  77. /**
  78. * 查找要删除的节点
  79. *
  80. * @param value
  81. * @return
  82. */
  83. public Node search(int value) {
  84. if (root == null) {
  85. return null;
  86. } else {
  87. return root.search(value);
  88. }
  89. }
  90. /**
  91. * 查找父节点
  92. *
  93. * @param value
  94. * @return
  95. */
  96. public Node searchParent(int value) {
  97. if (root == null) {
  98. return null;
  99. } else {
  100. return root.searchParent(value);
  101. }
  102. }
  103. /**
  104. * 添加节点方法
  105. *
  106. * @param node 新节点
  107. */
  108. public void add(Node node) {
  109. if (root == null) {
  110. root = node;
  111. } else {
  112. root.add(node);
  113. }
  114. }
  115. /**
  116. * 创建二叉排序树
  117. */
  118. public void infixOrder() {
  119. System.out.println("中序遍历二叉排序树");
  120. if (root == null) {
  121. System.out.println("节点为空");
  122. } else {
  123. root.infixOrder();
  124. }
  125. }
  126. public Node getRoot() {
  127. return root;
  128. }
  129. }

四、测试 

  1. public class AVLTreeDemo {
  2. public static void main(String[] args) {
  3. //int[] arr = {4, 3, 6, 5, 7, 8};
  4. //int[] arr = {10,12,8,9,7,6};
  5. int[] arr = {10,11,7,6,8,9};
  6. //创建一个AVLTree对象
  7. AVLTree avlTree = new AVLTree();
  8. // 添加节点
  9. for (int i = 0; i < arr.length; i++) {
  10. avlTree.add(new Node(arr[i]));
  11. }
  12. // 遍历
  13. avlTree.infixOrder();
  14. System.out.println("树的高度;" + avlTree.getRoot().height());
  15. System.out.println("左子树的高度;" + avlTree.getRoot().leftHeight());
  16. System.out.println("右子树的高度;" + avlTree.getRoot().rightHeight());
  17. }
  18. }
  1. 中序遍历二叉排序树
  2. Node{value=6}
  3. Node{value=7}
  4. Node{value=8}
  5. Node{value=9}
  6. Node{value=10}
  7. Node{value=11}
  8. 树的高度;3
  9. 左子树的高度;2
  10. 右子树的高度;2

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/632105
推荐阅读
相关标签
  

闽ICP备14008679号