1,Node.java

 package com.cnblogs.mufasa.BalanceBinaryTree;

 public class Node {
Node parent;
Node leftChild;
Node rightChild;
int val;
public Node(Node parent, Node leftChild, Node rightChild,int val) {
super();
this.parent = parent;
this.leftChild = leftChild;
this.rightChild = rightChild;
this.val = val;
} public Node(int val){
this(null,null,null,val);
} public Node(Node node,int val){
this(node,null,null,val);
}
}

图1 Node.java结构图

2,BalanceBinaryTree.java

 package com.cnblogs.mufasa.BalanceBinaryTree;

 import java.util.LinkedList;
import java.util.Queue; public class BalanceBinaryTree {
private final static int LEFT=0;
private final static int RIGHT=1;
private Node root;
private int size;
public BalanceBinaryTree(){
super();
} //LL型非平衡树,右旋转
public Node rightRotation(Node node){
System.out.println(node.val+"右旋");
if(node != null){
Node leftChild = node.leftChild;// 用变量存储node节点的左子节点
node.leftChild = leftChild.rightChild;// 将leftChild节点的右子节点赋值给node节点的左节点
if(leftChild.rightChild != null){// 如果leftChild的右节点存在,则需将该右节点的父节点指给node节点
leftChild.rightChild.parent = node;
}
leftChild.parent = node.parent;
if(node.parent == null){// 即表明node节点为根节点
this.root = leftChild;
}else if(node.parent.rightChild == node){// 即node节点在它原父节点的右子树中
node.parent.rightChild = leftChild;
}else if(node.parent.leftChild == node){
node.parent.leftChild = leftChild;
}
leftChild.rightChild = node;
node.parent = leftChild;
return leftChild;
}
return null;
} //RR型非平衡树,左旋
public Node leftRotation(Node node){
System.out.println(node.val+"左旋");
if(node != null){
Node rightChild = node.rightChild;
node.rightChild = rightChild.leftChild;
if(rightChild.leftChild != null){
rightChild.leftChild.parent = node;
}
rightChild.parent = node.parent;
if(node.parent == null){
this.root = rightChild;
}else if(node.parent.rightChild == node){
node.parent.rightChild = rightChild;
}else if(node.parent.leftChild == node){
node.parent.leftChild = rightChild;
}
rightChild.leftChild = node;
node.parent = rightChild; }
return null;
} //添加新元素
public boolean put(int val){
return putVal(root,val);
}
private boolean putVal(Node node,int val){
if(node == null){// 初始化根节点
node = new Node(val);
root = node;
size++;
return true;
}
Node temp = node;
Node p;
int t;
/**
* 通过do while循环迭代获取最佳节点,
*/
do{
p = temp;
t = temp.val-val;
if(t > 0){
temp = temp.leftChild;
}else if(t < 0){
temp = temp.rightChild;
}else{
temp.val = val;//插入数值有相同数据,不符合要求
return false;
}
}while(temp != null); Node newNode = new Node(p, val);
if(t > 0){
p.leftChild = newNode;
}else if(t < 0){
p.rightChild = newNode;
}
rebuild(p);// 使二叉树平衡的方法,优化平衡
size++;
return true;
} //平衡二叉树优化节点
private void rebuild(Node p){
while(p != null){
if(calcNodeBalanceValue(p) == 2){// 说明左子树高,需要右旋或者 先左旋后右旋
fixAfterInsertion(p,LEFT);// 调整操作
}else if(calcNodeBalanceValue(p) == -2){// 说明右子树高
fixAfterInsertion(p,RIGHT);
}
p = p.parent;
}
} //计算二叉树平衡因子①
private int calcNodeBalanceValue(Node node){
if(node != null){
return getHeightByNode(node);
}
return 0;
} //计算二叉树平衡因子②
public int getHeightByNode(Node node){
if(node == null){//多余
return 0;
}
return getChildDepth(node.leftChild)-getChildDepth(node.rightChild);
} // 计算node节点的高度,递归调用
public int getChildDepth(Node node){
if(node == null){
return 0;
}
return 1+Math.max(getChildDepth(node.leftChild),getChildDepth(node.rightChild));
} /**
* 调整树结构,先后顺序需要换一下,先判断LR型和RL型进行二次旋转
* @param p
* @param type
*/
private void fixAfterInsertion(Node p, int type) {
if(type == 0){//需要右旋或者 先左旋后右旋
final Node leftChild = p.leftChild;
if(leftChild.rightChild != null){// 先左旋后右旋
leftRotation(leftChild);
rightRotation(p);
}else if(leftChild.leftChild != null){//右旋
rightRotation(p);
} }else{
final Node rightChild = p.rightChild;
if(rightChild.leftChild != null){// 先右旋,后左旋
rightRotation(p);
leftRotation(rightChild);
}else if(rightChild.rightChild != null){// 左旋
leftRotation(p);
}
}
} //删除元素
public boolean delete(int val){
Node node = getNode(val);//搜索这个节点的数值
if(node == null){
return false;
}
boolean flag = false;
Node p = null;
Node parent = node.parent;
Node leftChild = node.leftChild;
Node rightChild = node.rightChild;
//以下所有父节点为空的情况,则表明删除的节点是根节点
if(leftChild == null && rightChild == null){//没有子节点
if(parent != null){
if(parent.leftChild == node){
parent.leftChild = null;
}else if(parent.rightChild == node){
parent.rightChild = null;
}
}else{//不存在父节点,则表明删除节点为根节点
root = null;
}
p = parent;
node = null;
flag = true;
}else if(leftChild == null && rightChild != null){// 只有右节点
if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
parent.leftChild = rightChild;
}else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
parent.rightChild = rightChild;
}else{
root = rightChild;
}
p = parent;
node = null;
flag = true;
}else if(leftChild != null && rightChild == null){// 只有左节点
if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
parent.leftChild = leftChild;
}else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
parent.rightChild = leftChild;
}else{
root = leftChild;
}
p = parent;
flag = true;
}else if(leftChild != null && rightChild != null){// 两个子节点都存在
Node successor = getSuccessor(node);// 这种情况,一定存在后继节点
int temp = successor.val;
boolean delete = delete(temp);
if(delete){
node.val = temp;
}
p = successor;
successor = null;
flag = true;
}
if(flag){
rebuild(p);
}
return flag;
} /**
* 搜索节点
* @param val
* @return
*/
public Node getNode(int val){
Node temp = root;
int t;
do{//直接使用循环遍历的方法
t = temp.val-val;
if(t > 0){
temp = temp.leftChild;
}else if(t < 0){
temp = temp.rightChild;
}else{
return temp;
}
}while(temp != null);
return null;
} //获取后继节点
private Node getSuccessor(Node node){
if(node.rightChild != null){
Node rightChild = node.rightChild;
while(rightChild.leftChild != null){
rightChild = rightChild.leftChild;
}
return rightChild;
}
Node parent = node.parent;
while(parent != null && (node == parent.rightChild)){
node = parent;
parent = parent.parent;
}
return parent;
} /**
* 平衡二叉树节点遍历
* @param type 0前序,1中序,2后续,3层序
*/
public void print(int type){
if(type==0){//前序
printPre(root);
}else if(type==1){
printMid(root);
}else if(type==2){
printEnd(root);
}else if(type==3){
printLevel(root);
}
} //前序遍历
private void printPre(Node root){
if(root != null){
System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
printPre(root.leftChild);
printPre(root.rightChild);
}
} //中序遍历
private void printMid(Node root){
if(root != null){
printMid(root.leftChild);
System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
printMid(root.rightChild);
}
} //后序遍历
private void printEnd(Node root){
if(root != null){
printEnd(root.leftChild);
printEnd(root.rightChild);
System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
}
} //层次遍历
private void printLevel(Node root){
if(root == null){
return;
}
Queue<Node> queue = new LinkedList<>();
Node temp = null;
queue.add(root);
while(!queue.isEmpty()){
temp = queue.poll();
System.out.print("节点值:"+temp.val+",平衡值:"+calcNodeBalanceValue(temp)+"\n");
if(temp.leftChild != null){
queue.add(temp.leftChild);
}
if(temp.rightChild != null){
queue.add(temp.rightChild);
}
}
}
}

图2,BalanceBinaryTree.java结构图

3,JavaDemo.java

 package com.cnblogs.mufasa.BalanceBinaryTree;

 public class JavaDemo {
public static void main(String[] args) {
BalanceBinaryTree bbt=new BalanceBinaryTree();
// bbt.put(10);
// bbt.put(9);
// bbt.put(11);
// bbt.put(7);
// bbt.put(12);
// bbt.put(8);
// bbt.put(38);
// bbt.put(24);
// bbt.put(17);
// bbt.put(4);
// bbt.put(3); bbt.put(11);
bbt.put(7);
bbt.put(15);
bbt.put(4);
bbt.put(9);
bbt.put(10);
bbt.print(3);
}
}

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. Mac地址转换成long长整型 2

    数据之间的转换可以使用   System.Convert Mac地址转换成long长整型 /// <summary> /// 解析长整形的数据使其转换为macID /// </sum ...

  2. Hvie SQL 修改表名 注释 列名注释

    一.修改hive表注释 ALTER TABLE 数据库名.表名 SET TBLPROPERTIES('comment' = '新的表备注'); 二.修改hive表字段注释 ALTER TABLE 数据 ...

  3. MySQL格式化时间date_format

    select date_format(deal_date, '%Y年%m月%d日 %H时%i分%s秒'), date_format(deal_date, '%Y-%m-%d %H:%i:%s') fr ...

  4. SurfaceView动态背景效果实现

    package com.loaderman.customviewdemo; import android.content.Context; import android.graphics.*; imp ...

  5. 终极解决办法rvct Cannot obtain license for Compiler (feature compiler) with license version >= 3.1

    参考:https://blog.csdn.net/nic_r/article/details/7458038 ARM C/C++ Compiler, RVCT4. [Build ] armcc : e ...

  6. LeetCode_121. Best Time to Buy and Sell Stock

    121. Best Time to Buy and Sell Stock Easy Say you have an array for which the ith element is the pri ...

  7. 【Leetcode_easy】674. Longest Continuous Increasing Subsequence

    problem 674. Longest Continuous Increasing Subsequence solution class Solution { public: int findLen ...

  8. 第一次搭建redis集群

    #端口port 8003 #绑定IPbind 9.1.186.60 #redis 后台运行daemonize yes #开启集群cluster-enabled yes #指定集群配置文件nodes.c ...

  9. maven仓库里如何搜索三方包?查看流行软件

    问题 这个仓库提供了搜索,但是功能比较弱,不支持groupid/artfactid的联合搜索 https://mvnrepository.com/ 解决 直接在搜索的url里添加groupid和art ...

  10. Android SDK目录说明

    在SDK目录下有很多文件夹,了解这个文件夹都包含哪些内容,更有利于Android的开发,也是作为Android开发者应该了解的.本文就SDK目录进行说明. SDK目录如下: add-ones:Goog ...