当前位置:   article > 正文

算法其实很简单—平衡二叉树的构建_创建平衡二叉树

创建平衡二叉树

目录

 

1. 基本概念

2. 整体思路

3. 代码实现


1. 基本概念

平衡二叉树的本质其实也是二叉排序树,具体可参考:

算法其实很简单—二叉排序树的构建

算法其实很简单—二叉排序树的删除

平衡二叉树的特点是任意节点的子树的高度差都小于等于1。

2. 整体思路

平衡二叉树的构建基本分为三种情况,左旋转、右旋转、双旋转

1、当根节点的右子树的高度比左子树高度大于1时,即高度相差2以上,则进行左旋转,思路如下图:

 

2、当根节点的左子树的高度比右子树高度大于1时,则进行右旋转:

 

3、如下图,复合右旋转条件,但是右旋转后还不是平衡二叉树,则分以下两种情况

3.1 当符合右旋条件,并且根节点的左子节点的右子树高度大于左子树的时候,先进行一次左旋转

3.2 当符合左旋转条件,并且根节点的右子树的左子树节点大于右子树节点的时候,先进行一次右旋转

 

3. 代码实现

  1. /**
  2. * @author 浪子傑
  3. * @version 1.0
  4. * @date 2020/6/2
  5. */
  6. public class AVLTreeDemo {
  7. public static void main(String[] args) {
  8. // int[] arr = {4, 3, 6, 5, 7, 8};
  9. // int[] arr = {10, 12, 8, 9, 7, 6};
  10. int[] arr = {10, 11, 7, 6, 8, 9};
  11. AVLTree avlTree = new AVLTree();
  12. for (int i : arr) {
  13. avlTree.add(new Node(i));
  14. }
  15. System.out.println(avlTree.root.height());
  16. System.out.println(avlTree.root.leftHeight());
  17. System.out.println(avlTree.root.rightHeight());
  18. }
  19. }
  20. class Node {
  21. int value;
  22. Node left;
  23. Node right;
  24. public Node(int value) {
  25. this.value = value;
  26. }
  27. /**
  28. * 左旋转
  29. */
  30. public void leftRotate() {
  31. // 创建一个新的节点,值为当前节点的值
  32. Node newNode = new Node(value);
  33. // 把新节点的左子树设为当前节点的左子树
  34. newNode.left = left;
  35. // 把新节点的右子树设为当前右子节点的左子树
  36. newNode.right = right.left;
  37. // 把当前节点的值换位右子节点的值
  38. this.value = right.value;
  39. // 把当前节点的右子树设为右子节点的右子树
  40. right = right.right;
  41. // 把当前节点的左子树设为新节点
  42. left = newNode;
  43. }
  44. /**
  45. * 右旋转
  46. */
  47. public void rightRotate() {
  48. // 创建一个新的节点并将当前值赋给新节点
  49. Node newNode = new Node(value);
  50. // 把新节点的右子树设为当前节点的右子树
  51. newNode.right = right;
  52. // 把新节点的左子树设为当前节点左子节点的右子树
  53. newNode.left = left.right;
  54. // 把当前值设为左子树节点的值
  55. this.value = left.value;
  56. // 把当前节点的左子树设为左子节点的左子树
  57. this.left = left.left;
  58. // 把当前节点的右子树设为新节点
  59. this.right = newNode;
  60. }
  61. /**
  62. * 返回右子树的高度
  63. *
  64. * @return
  65. */
  66. public int rightHeight() {
  67. if (right == null) {
  68. return 0;
  69. } else {
  70. return right.height();
  71. }
  72. }
  73. /**
  74. * 返回左子树的高度
  75. *
  76. * @return
  77. */
  78. public int leftHeight() {
  79. if (left == null) {
  80. return 0;
  81. } else {
  82. return left.height();
  83. }
  84. }
  85. /**
  86. * 获取以当前节点为根节点的树的高度
  87. *
  88. * @return
  89. */
  90. public int height() {
  91. return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
  92. }
  93. /**
  94. * 查询要删除的节点
  95. *
  96. * @param value
  97. * @return
  98. */
  99. public Node search(int value) {
  100. // 如果要查找的值==当前节点的值,返回当前节点
  101. // 如果要查找的值 < 当前节点,则向该节点的左子树查找
  102. // 否则向该节点的右子树查找
  103. if (this.value == value) {
  104. return this;
  105. } else if (value < this.value) {
  106. // 如果该节点的左子节点为null,直接返回null
  107. if (this.left == null) {
  108. return null;
  109. }
  110. return this.left.search(value);
  111. } else {
  112. if (this.right == null) {
  113. return null;
  114. }
  115. return this.right.search(value);
  116. }
  117. }
  118. /**
  119. * 查找要删除节点的父节点
  120. *
  121. * @param value
  122. * @return
  123. */
  124. public Node searchParent(int value) {
  125. // 如果当前节点的子节点不为空,并且当前节点子节点的值 == value,则返回当前节点
  126. // 如果当前节点的左子节点不为null,并且当前节点的值 > value,则向该节点的左子节点遍历
  127. // 如果当前节点的右子节点不为null,并且当前节点的值不> value,则向该节点的右子节点遍历
  128. // 否则没有找到,返回null
  129. if ((this.left != null && this.left.value == value) ||
  130. (this.right != null && this.right.value == value)) {
  131. return this;
  132. } else if (this.left != null && this.value > value) {
  133. return this.left.searchParent(value);
  134. } else if (this.right != null && this.value <= value) {
  135. return this.right.searchParent(value);
  136. } else {
  137. return null;
  138. }
  139. }
  140. /**
  141. * 添加节点
  142. *
  143. * @param node
  144. */
  145. public void add(Node node) {
  146. // 如果该节点为null,直接返回
  147. if (node == null) {
  148. return;
  149. }
  150. // add的节点小于当前节点,说明应该在当前节点的左边
  151. // 否则放在当前节点的右边
  152. if (node.value < this.value) {
  153. // 如果当前节点的左边没有子节点,则直接把add节点放在当前节点的左子节点
  154. // 否则的话,遍历当前左子节点,直到找到合适位置
  155. if (this.left == null) {
  156. this.left = node;
  157. } else {
  158. this.left.add(node);
  159. }
  160. } else {
  161. if (this.right == null) {
  162. this.right = node;
  163. } else {
  164. this.right.add(node);
  165. }
  166. }
  167. // 如果当前节点的右节点比左节点的高度 > 1,则进行左旋转
  168. // 如果当前节点的左节点比右节点的高度 > 1,则进行右旋转
  169. if (rightHeight() - leftHeight() > 1) {
  170. // 如果当前节点的右子节点的左子树高度大于右子树的高度,则先进行右旋转
  171. if (right != null && right.leftHeight() > right.rightHeight()) {
  172. right.leftRotate();
  173. }
  174. leftRotate();
  175. } else if (leftHeight() - rightHeight() > 1) {
  176. // 如果当前节点的左子节点的右子树高度大于左子树的高度,则先进行左旋转
  177. if (left != null && left.rightHeight() > left.leftHeight()) {
  178. left.leftRotate();
  179. }
  180. rightRotate();
  181. }
  182. }
  183. /**
  184. * 中序遍历
  185. */
  186. public void middleOrder() {
  187. if (this.left != null) {
  188. this.left.middleOrder();
  189. }
  190. System.out.println(this);
  191. if (this.right != null) {
  192. this.right.middleOrder();
  193. }
  194. }
  195. @Override
  196. public String toString() {
  197. return "Node{" +
  198. "value=" + value +
  199. '}';
  200. }
  201. }
  202. class AVLTree {
  203. Node root;
  204. /**
  205. * 删除节点
  206. *
  207. * @param value
  208. */
  209. public void delete(int value) {
  210. // 如果父节点为null,直接返回
  211. if (root == null) {
  212. return;
  213. } else {
  214. Node targetNode = search(value);
  215. // 如果要删除的节点为null,直接返回
  216. if (targetNode == null) {
  217. return;
  218. }
  219. // 如果父节点的左右节点都为null,说明只有一个节点,直接将root设为null即可
  220. if (root.left == null && root.right == null) {
  221. root = null;
  222. return;
  223. }
  224. Node parentNode = searchParent(value);
  225. // 如果要删除节点的左右节点都为null,说明该要删除的节点为子节点
  226. if (targetNode.left == null && targetNode.right == null) {
  227. // 如果父节点的左子节点不为null并且是要删除的节点,则将父节点的左子节点设为null
  228. // 如果父节点的右子节点不为null并且是要删除的节点,则将父节点的右子节点设为null
  229. if (parentNode.left != null && parentNode.left.value == value) {
  230. parentNode.left = null;
  231. } else if (parentNode.right != null && parentNode.right.value == value) {
  232. parentNode.right = null;
  233. }
  234. } else if (targetNode.left != null && targetNode.right != null) {
  235. // 如果要删除的左右子节点都不为null,则查找要删除节点右子节点的最小值,删除最小节点并将值赋给要删除节点
  236. int treeMin = delRightTreeMin(targetNode.right);
  237. System.out.println("最小的为---" + treeMin);
  238. targetNode.value = treeMin;
  239. } else {
  240. // 如果要删除的节点左右子节点有一个为null
  241. // 如果要删除的子节点为root节点
  242. if (parentNode == null) {
  243. // 如果左子节点不为null,则将左子节点赋给root
  244. // 否则将右子节点赋给root
  245. if (targetNode.left != null) {
  246. root = targetNode.left;
  247. } else {
  248. root = targetNode.right;
  249. }
  250. } else if (parentNode.left.value == value) {
  251. // 如果要删除的节点为parentNode的左子节点
  252. // 如果要删除的节点的左子节点不为null,则将parentNode的左子节点指向要删除节点的左子节点
  253. // 否则则指向要删除节点的右子节点
  254. if (targetNode.left != null) {
  255. parentNode.left = targetNode.left;
  256. } else {
  257. parentNode.left = targetNode.right;
  258. }
  259. } else {
  260. if (targetNode.right != null) {
  261. parentNode.right = targetNode.right;
  262. } else {
  263. parentNode.right = targetNode.left;
  264. }
  265. }
  266. }
  267. }
  268. }
  269. /**
  270. * 返回以node节点为根节点的二叉排序树的最小值
  271. *
  272. * @param node
  273. * @return
  274. */
  275. public int delRightTreeMin(Node node) {
  276. Node target = node;
  277. while (target.left != null) {
  278. target = target.left;
  279. }
  280. delete(target.value);
  281. return target.value;
  282. }
  283. /**
  284. * 查找要删除的节点
  285. *
  286. * @param value
  287. * @return
  288. */
  289. public Node search(int value) {
  290. if (root == null) {
  291. return null;
  292. } else {
  293. return root.search(value);
  294. }
  295. }
  296. /**
  297. * 查询要删除的父节点
  298. *
  299. * @param value
  300. * @return
  301. */
  302. public Node searchParent(int value) {
  303. if (root == null) {
  304. return null;
  305. } else {
  306. return root.searchParent(value);
  307. }
  308. }
  309. /**
  310. * 添加子节点
  311. *
  312. * @param node
  313. */
  314. public void add(Node node) {
  315. if (root == null) {
  316. root = node;
  317. } else {
  318. root.add(node);
  319. }
  320. }
  321. /**
  322. * 中序遍历
  323. */
  324. public void infixOrder() {
  325. if (root != null) {
  326. root.middleOrder();
  327. } else {
  328. System.out.println("当前root为空");
  329. }
  330. }
  331. }

 

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

闽ICP备14008679号