1,Node.java

  1. package com.cnblogs.mufasa.BalanceBinaryTree;
  2.  
  3. public class Node {
  4. Node parent;
  5. Node leftChild;
  6. Node rightChild;
  7. int val;
  8. public Node(Node parent, Node leftChild, Node rightChild,int val) {
  9. super();
  10. this.parent = parent;
  11. this.leftChild = leftChild;
  12. this.rightChild = rightChild;
  13. this.val = val;
  14. }
  15.  
  16. public Node(int val){
  17. this(null,null,null,val);
  18. }
  19.  
  20. public Node(Node node,int val){
  21. this(node,null,null,val);
  22. }
  23. }

图1 Node.java结构图

2,BalanceBinaryTree.java

  1. package com.cnblogs.mufasa.BalanceBinaryTree;
  2.  
  3. import java.util.LinkedList;
  4. import java.util.Queue;
  5.  
  6. public class BalanceBinaryTree {
  7. private final static int LEFT=0;
  8. private final static int RIGHT=1;
  9. private Node root;
  10. private int size;
  11. public BalanceBinaryTree(){
  12. super();
  13. }
  14.  
  15. //LL型非平衡树,右旋转
  16. public Node rightRotation(Node node){
  17. System.out.println(node.val+"右旋");
  18. if(node != null){
  19. Node leftChild = node.leftChild;// 用变量存储node节点的左子节点
  20. node.leftChild = leftChild.rightChild;// 将leftChild节点的右子节点赋值给node节点的左节点
  21. if(leftChild.rightChild != null){// 如果leftChild的右节点存在,则需将该右节点的父节点指给node节点
  22. leftChild.rightChild.parent = node;
  23. }
  24. leftChild.parent = node.parent;
  25. if(node.parent == null){// 即表明node节点为根节点
  26. this.root = leftChild;
  27. }else if(node.parent.rightChild == node){// 即node节点在它原父节点的右子树中
  28. node.parent.rightChild = leftChild;
  29. }else if(node.parent.leftChild == node){
  30. node.parent.leftChild = leftChild;
  31. }
  32. leftChild.rightChild = node;
  33. node.parent = leftChild;
  34. return leftChild;
  35. }
  36. return null;
  37. }
  38.  
  39. //RR型非平衡树,左旋
  40. public Node leftRotation(Node node){
  41. System.out.println(node.val+"左旋");
  42. if(node != null){
  43. Node rightChild = node.rightChild;
  44. node.rightChild = rightChild.leftChild;
  45. if(rightChild.leftChild != null){
  46. rightChild.leftChild.parent = node;
  47. }
  48. rightChild.parent = node.parent;
  49. if(node.parent == null){
  50. this.root = rightChild;
  51. }else if(node.parent.rightChild == node){
  52. node.parent.rightChild = rightChild;
  53. }else if(node.parent.leftChild == node){
  54. node.parent.leftChild = rightChild;
  55. }
  56. rightChild.leftChild = node;
  57. node.parent = rightChild;
  58.  
  59. }
  60. return null;
  61. }
  62.  
  63. //添加新元素
  64. public boolean put(int val){
  65. return putVal(root,val);
  66. }
  67. private boolean putVal(Node node,int val){
  68. if(node == null){// 初始化根节点
  69. node = new Node(val);
  70. root = node;
  71. size++;
  72. return true;
  73. }
  74. Node temp = node;
  75. Node p;
  76. int t;
  77. /**
  78. * 通过do while循环迭代获取最佳节点,
  79. */
  80. do{
  81. p = temp;
  82. t = temp.val-val;
  83. if(t > 0){
  84. temp = temp.leftChild;
  85. }else if(t < 0){
  86. temp = temp.rightChild;
  87. }else{
  88. temp.val = val;//插入数值有相同数据,不符合要求
  89. return false;
  90. }
  91. }while(temp != null);
  92.  
  93. Node newNode = new Node(p, val);
  94. if(t > 0){
  95. p.leftChild = newNode;
  96. }else if(t < 0){
  97. p.rightChild = newNode;
  98. }
  99. rebuild(p);// 使二叉树平衡的方法,优化平衡
  100. size++;
  101. return true;
  102. }
  103.  
  104. //平衡二叉树优化节点
  105. private void rebuild(Node p){
  106. while(p != null){
  107. if(calcNodeBalanceValue(p) == 2){// 说明左子树高,需要右旋或者 先左旋后右旋
  108. fixAfterInsertion(p,LEFT);// 调整操作
  109. }else if(calcNodeBalanceValue(p) == -2){// 说明右子树高
  110. fixAfterInsertion(p,RIGHT);
  111. }
  112. p = p.parent;
  113. }
  114. }
  115.  
  116. //计算二叉树平衡因子①
  117. private int calcNodeBalanceValue(Node node){
  118. if(node != null){
  119. return getHeightByNode(node);
  120. }
  121. return 0;
  122. }
  123.  
  124. //计算二叉树平衡因子②
  125. public int getHeightByNode(Node node){
  126. if(node == null){//多余
  127. return 0;
  128. }
  129. return getChildDepth(node.leftChild)-getChildDepth(node.rightChild);
  130. }
  131.  
  132. // 计算node节点的高度,递归调用
  133. public int getChildDepth(Node node){
  134. if(node == null){
  135. return 0;
  136. }
  137. return 1+Math.max(getChildDepth(node.leftChild),getChildDepth(node.rightChild));
  138. }
  139.  
  140. /**
  141. * 调整树结构,先后顺序需要换一下,先判断LR型和RL型进行二次旋转
  142. * @param p
  143. * @param type
  144. */
  145. private void fixAfterInsertion(Node p, int type) {
  146. if(type == 0){//需要右旋或者 先左旋后右旋
  147. final Node leftChild = p.leftChild;
  148. if(leftChild.rightChild != null){// 先左旋后右旋
  149. leftRotation(leftChild);
  150. rightRotation(p);
  151. }else if(leftChild.leftChild != null){//右旋
  152. rightRotation(p);
  153. }
  154.  
  155. }else{
  156. final Node rightChild = p.rightChild;
  157. if(rightChild.leftChild != null){// 先右旋,后左旋
  158. rightRotation(p);
  159. leftRotation(rightChild);
  160. }else if(rightChild.rightChild != null){// 左旋
  161. leftRotation(p);
  162. }
  163. }
  164. }
  165.  
  166. //删除元素
  167. public boolean delete(int val){
  168. Node node = getNode(val);//搜索这个节点的数值
  169. if(node == null){
  170. return false;
  171. }
  172. boolean flag = false;
  173. Node p = null;
  174. Node parent = node.parent;
  175. Node leftChild = node.leftChild;
  176. Node rightChild = node.rightChild;
  177. //以下所有父节点为空的情况,则表明删除的节点是根节点
  178. if(leftChild == null && rightChild == null){//没有子节点
  179. if(parent != null){
  180. if(parent.leftChild == node){
  181. parent.leftChild = null;
  182. }else if(parent.rightChild == node){
  183. parent.rightChild = null;
  184. }
  185. }else{//不存在父节点,则表明删除节点为根节点
  186. root = null;
  187. }
  188. p = parent;
  189. node = null;
  190. flag = true;
  191. }else if(leftChild == null && rightChild != null){// 只有右节点
  192. if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
  193. parent.leftChild = rightChild;
  194. }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
  195. parent.rightChild = rightChild;
  196. }else{
  197. root = rightChild;
  198. }
  199. p = parent;
  200. node = null;
  201. flag = true;
  202. }else if(leftChild != null && rightChild == null){// 只有左节点
  203. if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
  204. parent.leftChild = leftChild;
  205. }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
  206. parent.rightChild = leftChild;
  207. }else{
  208. root = leftChild;
  209. }
  210. p = parent;
  211. flag = true;
  212. }else if(leftChild != null && rightChild != null){// 两个子节点都存在
  213. Node successor = getSuccessor(node);// 这种情况,一定存在后继节点
  214. int temp = successor.val;
  215. boolean delete = delete(temp);
  216. if(delete){
  217. node.val = temp;
  218. }
  219. p = successor;
  220. successor = null;
  221. flag = true;
  222. }
  223. if(flag){
  224. rebuild(p);
  225. }
  226. return flag;
  227. }
  228.  
  229. /**
  230. * 搜索节点
  231. * @param val
  232. * @return
  233. */
  234. public Node getNode(int val){
  235. Node temp = root;
  236. int t;
  237. do{//直接使用循环遍历的方法
  238. t = temp.val-val;
  239. if(t > 0){
  240. temp = temp.leftChild;
  241. }else if(t < 0){
  242. temp = temp.rightChild;
  243. }else{
  244. return temp;
  245. }
  246. }while(temp != null);
  247. return null;
  248. }
  249.  
  250. //获取后继节点
  251. private Node getSuccessor(Node node){
  252. if(node.rightChild != null){
  253. Node rightChild = node.rightChild;
  254. while(rightChild.leftChild != null){
  255. rightChild = rightChild.leftChild;
  256. }
  257. return rightChild;
  258. }
  259. Node parent = node.parent;
  260. while(parent != null && (node == parent.rightChild)){
  261. node = parent;
  262. parent = parent.parent;
  263. }
  264. return parent;
  265. }
  266.  
  267. /**
  268. * 平衡二叉树节点遍历
  269. * @param type 0前序,1中序,2后续,3层序
  270. */
  271. public void print(int type){
  272. if(type==0){//前序
  273. printPre(root);
  274. }else if(type==1){
  275. printMid(root);
  276. }else if(type==2){
  277. printEnd(root);
  278. }else if(type==3){
  279. printLevel(root);
  280. }
  281. }
  282.  
  283. //前序遍历
  284. private void printPre(Node root){
  285. if(root != null){
  286. System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
  287. printPre(root.leftChild);
  288. printPre(root.rightChild);
  289. }
  290. }
  291.  
  292. //中序遍历
  293. private void printMid(Node root){
  294. if(root != null){
  295. printMid(root.leftChild);
  296. System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
  297. printMid(root.rightChild);
  298. }
  299. }
  300.  
  301. //后序遍历
  302. private void printEnd(Node root){
  303. if(root != null){
  304. printEnd(root.leftChild);
  305. printEnd(root.rightChild);
  306. System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
  307. }
  308. }
  309.  
  310. //层次遍历
  311. private void printLevel(Node root){
  312. if(root == null){
  313. return;
  314. }
  315. Queue<Node> queue = new LinkedList<>();
  316. Node temp = null;
  317. queue.add(root);
  318. while(!queue.isEmpty()){
  319. temp = queue.poll();
  320. System.out.print("节点值:"+temp.val+",平衡值:"+calcNodeBalanceValue(temp)+"\n");
  321. if(temp.leftChild != null){
  322. queue.add(temp.leftChild);
  323. }
  324. if(temp.rightChild != null){
  325. queue.add(temp.rightChild);
  326. }
  327. }
  328. }
  329. }

图2,BalanceBinaryTree.java结构图

3,JavaDemo.java

  1. package com.cnblogs.mufasa.BalanceBinaryTree;
  2.  
  3. public class JavaDemo {
  4. public static void main(String[] args) {
  5. BalanceBinaryTree bbt=new BalanceBinaryTree();
  6. // bbt.put(10);
  7. // bbt.put(9);
  8. // bbt.put(11);
  9. // bbt.put(7);
  10. // bbt.put(12);
  11. // bbt.put(8);
  12. // bbt.put(38);
  13. // bbt.put(24);
  14. // bbt.put(17);
  15. // bbt.put(4);
  16. // bbt.put(3);
  17.  
  18. bbt.put(11);
  19. bbt.put(7);
  20. bbt.put(15);
  21. bbt.put(4);
  22. bbt.put(9);
  23. bbt.put(10);
  24. bbt.print(3);
  25. }
  26. }

4,特别鸣谢

https://www.cnblogs.com/qm-article/p/9349681.html

数据结构-平衡二叉树Java实现的更多相关文章

  1. 数据结构与算法——常用高级数据结构及其Java实现

    前文 数据结构与算法--常用数据结构及其Java实现 总结了基本的数据结构,类似的,本文准备总结一下一些常见的高级的数据结构及其常见算法和对应的Java实现以及应用场景,务求理论与实践一步到位. 跳跃 ...

  2. 什么是泛型?,Set集合,TreeSet集合自然排序和比较器排序,数据结构-二叉树,数据结构-平衡二叉树

    ==知识点== 1.泛型 2.Set集合 3.TreeSet 4.数据结构-二叉树 5.数据结构-平衡二叉树 ==用到的单词== 1.element[ˈelɪmənt] 要素 元素(软) 2.key[ ...

  3. 数据结构-堆 Java实现

    数据结构-堆 Java实现. 实现堆自动增长 /** * 数据结构-堆. 自动增长 * */ public class Heap<T extends Comparable> { priva ...

  4. 20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码

    20172332 2017-2018-2 <程序设计与数据结构>Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 哈夫曼树 1.路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子 ...

  5. 数据结构(java语言描述)

    概念性描述与<数据结构实例教程>大同小异,具体参考:http://www.cnblogs.com/bookwed/p/6763300.html. 概述 基本概念及术语 数据 信息的载体,是 ...

  6. 数据结构:JAVA实现二叉查找树

    数据结构:JAVA实现二叉查找树 写在前面 二叉查找树(搜索树)是一种能将链表插入的灵活性与有序数组查找的高效性结合在一起的一种数据结构. 观察二叉查找树,我们发现任何一个节点大于左子节点且小于其右子 ...

  7. 【数据结构】Java版

    有趣有内涵的文章第一时间送达! 喝酒I创作I分享 生活中总有些东西值得分享 @醉翁猫咪 想你吴亦凡;赵丽颖 - 想你 你是程序猿对吗?会写代码的那种? 我是打字猿?会打代码的那种? 现在告诉大家一个很 ...

  8. 数据结构-平衡二叉树 旋转过程平衡因子分析 c和java代码实现对比

    平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且 ...

  9. Java数据结构——平衡二叉树的平衡因子(转自牛客网)

    若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性.首先要找出插入新结点后失去平衡的最小子树根结点的指针.然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树.当失去平衡的最小子树被 ...

随机推荐

  1. Matlab 图像平移、旋转、缩放、镜像

    今天学习了用Matlab实现对图像的基本操作.在Matlab中,图像是按照二维矩阵的形式表示的.所以对图像的操作就是对矩阵的操作. 对图像进行缩放.平移.旋转,都可以转化为矩阵的运算. 关于变换矩阵的 ...

  2. Angular 自定义模块以及配置路由实现模块懒加载

    项目目录 创建模块 ng g module module/user --routing ng g module module/article --routing ng g module module/ ...

  3. mysqlcheck修复工具

    mysqlcheck工具可以检查.修复.优化和分析MyISAM引擎的表,实际上是集成了Mysql中的check.repair.analyze.tmpimize的功能. mysqlcheck共军存在于m ...

  4. 123457123456#0#-----com.twoapp.YiZhiPuzzle02--前拼后广--儿童日常拼图游戏jiemei

    com.twoapp.YiZhiPuzzle02--前拼后广--儿童日常拼图游戏jiemei

  5. 123457------com.threeapp.quWeiKaTongPinTu01----趣味卡通拼图游戏

    com.threeapp.quWeiKaTongPinTu01----趣味卡通拼图游戏

  6. Delphi中动态加载TreeView信息

    unit Unit3; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  7. expect自动登录

    .安装软件 yum install expect -y .查看expect命令位置 expect命令的位置也可能是在 /usr/local/bin/expect,使用前用户应确认工具是否存在(确认方法 ...

  8. vmware安装centos7.5、配置网卡、环境配置

    1.vmware安装centos7.5虚拟机    参考连接: https://blog.csdn.net/guo_ridgepole/article/details/78973763 可能遇到的问题 ...

  9. Linux 学习笔记 1 使用最小的系统,从分区安装系统开始

    我们常用的linux系统在安装过程中大多都省略了对系统进行分区的操作,以至于后期,不了解什么是分区以及分区当中最基本的一些概念, 我们不说最细的知识,只求了解这个过程,那直接步入正题,开始第一节的学习 ...

  10. 战术设计DDD

    可落地的DDD(5)-战术设计   摘要 本篇是DDD的战术篇,也就是关于领域事件.领域对象.聚合根.实体.值对象的讨论.也是DDD系列的完结篇.这一部分在我们团队争论最多的,也有很多月经贴,比如对资 ...