数据结构-平衡二叉树Java实现
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实现的更多相关文章
- 数据结构与算法——常用高级数据结构及其Java实现
前文 数据结构与算法--常用数据结构及其Java实现 总结了基本的数据结构,类似的,本文准备总结一下一些常见的高级的数据结构及其常见算法和对应的Java实现以及应用场景,务求理论与实践一步到位. 跳跃 ...
- 什么是泛型?,Set集合,TreeSet集合自然排序和比较器排序,数据结构-二叉树,数据结构-平衡二叉树
==知识点== 1.泛型 2.Set集合 3.TreeSet 4.数据结构-二叉树 5.数据结构-平衡二叉树 ==用到的单词== 1.element[ˈelɪmənt] 要素 元素(软) 2.key[ ...
- 数据结构-堆 Java实现
数据结构-堆 Java实现. 实现堆自动增长 /** * 数据结构-堆. 自动增长 * */ public class Heap<T extends Comparable> { priva ...
- 20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码
20172332 2017-2018-2 <程序设计与数据结构>Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 哈夫曼树 1.路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子 ...
- 数据结构(java语言描述)
概念性描述与<数据结构实例教程>大同小异,具体参考:http://www.cnblogs.com/bookwed/p/6763300.html. 概述 基本概念及术语 数据 信息的载体,是 ...
- 数据结构:JAVA实现二叉查找树
数据结构:JAVA实现二叉查找树 写在前面 二叉查找树(搜索树)是一种能将链表插入的灵活性与有序数组查找的高效性结合在一起的一种数据结构. 观察二叉查找树,我们发现任何一个节点大于左子节点且小于其右子 ...
- 【数据结构】Java版
有趣有内涵的文章第一时间送达! 喝酒I创作I分享 生活中总有些东西值得分享 @醉翁猫咪 想你吴亦凡;赵丽颖 - 想你 你是程序猿对吗?会写代码的那种? 我是打字猿?会打代码的那种? 现在告诉大家一个很 ...
- 数据结构-平衡二叉树 旋转过程平衡因子分析 c和java代码实现对比
平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且 ...
- Java数据结构——平衡二叉树的平衡因子(转自牛客网)
若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性.首先要找出插入新结点后失去平衡的最小子树根结点的指针.然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树.当失去平衡的最小子树被 ...
随机推荐
- base64和hex
base64和hex 我们知道,字符分为二种:一种是可见字符:另一种是不可见字符. 1)三种编码方式 hex也称为base16,意思是使用16个可见字符来表示一个二进制数组,编码后数据大小将翻倍,因为 ...
- (四)OpenCV-Python学习—形态学处理
通过阈值化分割可以得到二值图,但往往会出现图像中物体形态不完整,变的残缺,可以通过形态学处理,使其变得丰满,或者去除掉多余的像素.常用的形态学处理算法包括:腐蚀,膨胀,开运算,闭运算,形态学梯度,顶帽 ...
- Tosca new project Repository as MS SQL Server
# 然后对应的服务器就能自己给创建对应的数据库
- npm如何更新安装包?
方法一手动跟新:修改package.json中依赖包版本,执行npm install --force 方法二使用第三方插件:npm install -g npm-check-updatesncu // ...
- [Java复习] 设计模式 Design Pattern
设计模式的六大原则 1.开闭原则(Open Close Principle) 对扩展开放,对修改关闭. 2.里氏代换原则(Liskov Substitution Principle) 任何基类可以出现 ...
- lua日期处理函数
function day_step(old_day,step) local y,m,d if("0" ~= string.sub(old_day,6,6)) then ...
- Centos7安装zabbix3.4.0以及配置和使用
一.安装ZABBIX 1.环境和软件版本 注:此次是采用的rpm包方式安装,所以服务器必须要能连接互联网通过yum方式解决依赖关系 ①系统: [root@zabbix ~]# cat /etc/red ...
- Python - Django - 添加作者
在 book_list.html 的页面下方加上 “添加作者” 的链接 <!DOCTYPE html> <html lang="en"> <head& ...
- pip3快速下载paddle
安装百度的paddle paddle时很慢,后来采用国内的源,速度嗖嗖滴 pip3 install -U paddlepaddle -i https://pypi.douban.com/simple/ ...
- CentOS 7启动与切换图形界面
安装图形界面 默认情况下是不会安装图形界面的,所以需要自己手动安装,步骤如下: 1.开启系统,以root身份进入 安装X(X Window System),命令如下: yum groupinstall ...