二叉树 & 平衡二叉树 算法(Java实现)
二叉树
比如我要依次插入10、3、1、8、23、15、28。先插入10作为根节点:
然后插入3,比10小,放在左边:
再插入1,比10和3小,放在3左边:
再插入8,比10小,比3大,放在3右边:
再插入23,比10大,放在10右边:
再插入15,比10大,比23小,放在23左边:
最后插入28,比10和23大,放在23右边:
代码实现:
package com.demo.tree; import java.util.LinkedList;
import java.util.Queue; public class BinaryTree { public static void main(String[] args){
BinaryTree tree = new BinaryTree();
tree.batchInsert(new int[]{10,3,1,8,23,15,28});
tree.prePrint();
tree.midPrint();
tree.postPrint();
tree.tierPrint();
tree.printDepth();
} private Node root; /**
* 节点
*/
private class Node{
int data; // 数据
Node left; // 左指针
Node right; // 右指针 private Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
} /**
* 插入
* @param data
*/
public void insert(int data){
Node newData = new Node(data);
if (root == null){
root = newData;
}else{
Node parent = root;
while (true){
if (data < parent.data){
// 如果左边为空,那新数据就直接放在这
if (parent.left == null){
parent.left = newData;
break;
}
// 进入左节点
parent = parent.left;
}else{
// 如果右边为空,那新数据就直接放在这
if (parent.right == null){
parent.right = newData;
break;
}
// 进入右节点
parent = parent.right;
}
}
}
} /**
* 批量插入
* @param arr
*/
public void batchInsert(int[] arr){
for (int data : arr){
insert(data);
}
} /**
* 前序遍历
*/
public void prePrint(){
System.out.print("前序遍历\t");
if (root != null){
pre(root);
}
System.out.println();
} private void pre(Node node){
if (node != null) {
System.out.print(node.data + "\t");
pre(node.left);
pre(node.right);
}
} /**
* 中序遍历
*/
public void midPrint(){
System.out.print("中序遍历\t");
if (root != null){
mid(root);
}
System.out.println();
} private void mid(Node node){
if (node != null) {
mid(node.left);
System.out.print(node.data + "\t");
mid(node.right);
}
} /**
* 后序遍历
*/
public void postPrint(){
System.out.print("后序遍历\t");
if (root != null){
post(root);
}
System.out.println();
} private void post(Node node){
if (node != null) {
post(node.left);
post(node.right);
System.out.print(node.data + "\t");
}
} /**
* 层序遍历,利用队列先进先出
*/
public void tierPrint(){
if (root != null){
Queue<Node> queue = new LinkedList<>();
queue.add(root);
System.out.print("层序遍历\t");
while (!queue.isEmpty()){
Node temp = queue.remove();
System.out.print(temp.data + "\t");
if (temp.left != null){
// 左节点不为空,放进队列
queue.add(temp.left);
}
if (temp.right != null){
// 右节点不为空,放进队列
queue.add(temp.right);
}
}
}
System.out.println();
} /**
* 求树高
*/
public void printDepth(){
if (root == null){
System.out.println(0);
}else{
System.out.println("树高\t" + getDepth(root));
}
} private int getDepth(Node node){
if (node == null){
return 0;
}
return Math.max(getDepth(node.left), getDepth(node.right))+1;
} }
测试:
平衡二叉树
前面的二叉树有个问题,如果我们按照顺序插入,那么这个树就会退化成一个线性链表,这个时候引入平衡二叉树来解决。
平衡二叉树要维持平衡需要旋转操作
LL型(在A的左孩子(L)的左子树(L)上插入新结点)
过程:
1. 将A的左孩子B提升为根节点
2. 将A降级为B的右孩子
3. 将B的右孩子调整为A的左孩子
RR型(在A的右孩子(R)的右子树(R)上插入新结点)
过程:
1. 将A的右孩子B提升为根节点
2. 将A降级为B的左孩子
3. 将B的左孩子调整为A的右孩子
LR型(在A的左孩子(L)的右子树(R)上插入新结点)【插入在C任意一颗子树都可以】
过程:
1. B、C节点左旋。
2. A、C节点右旋。
RL型(在A的右孩子(R)的左子树(L)上插入新结点)【插入在C任意一颗子树都可以】
过程:
1. B、C节点右旋。
2. A、C节点左旋。
插入步骤图解
平衡二叉树的插入,例如依次插入:8,6,3,4,5,20,15,23,28,1,2
插入8先作为根节点,插入6依然平衡,插入3不平衡,进行一次右旋(LL)
插入4依然平衡,插入5不平衡,进行左旋(RR)
插入20依然平衡,插入15不平衡,先右旋再左旋(RL)
插入23依然平衡,插入28不平衡,进行一次左旋(RR)
插入1依然平衡,插入2不平衡,先左旋再右旋(LR)
代码
package com.demo.tree; import java.util.LinkedList;
import java.util.Queue; public class BalancedBinaryTree { public static void main(String[] args){
BalancedBinaryTree tree = new BalancedBinaryTree();
tree.batchInsert(new int[]{8,6,3,4,5,20,15,23,28,1,2});
tree.tierPrint();
} private Node root; /**
* 节点
*/
private class Node{
int data; // 数据
Node left; // 左指针
Node right; // 右指针 private Node(int data) {
this.data = data;
this.left = null;
this.right = null;
}
} /**
* 右旋操作(左孩子的左子树插入节点)
* @param p
*/
private Node rightRotate(Node p){
Node temp = p.left; // temp指向p的左子树
p.left = temp.right; // p的左子树指向temp的右子树
temp.right = p;
return temp;
} /**
* 左旋操作(右孩子的右子树插入节点)
* @param p
*/
private Node leftRotate(Node p){
Node temp = p.right; // temp指向p的右子树
p.right = temp.left; // p的右子树指向temp的左子树
temp.left = p;
return temp;
} /**
* 先左旋再右旋(左孩子的右子树插入节点)
* @param p
*/
private Node leftRightRotate(Node p){
p.left = leftRotate(p.left);
return rightRotate(p);
} /**
* 先右旋再左旋(右孩子的左子树插入节点)
* @param p
*/
private Node rightLeftRotate(Node p){
p.right = rightRotate(p.right);
return leftRotate(p);
} /**
* 树高
* @param node
* @return
*/
private int getDepth(Node node){
if (node == null){
return 0;
}
return Math.max(getDepth(node.left), getDepth(node.right))+1;
} /**
* 平衡因子(左高:>1 等高:0 右高:<-1)
* @return
*/
public int balanceFactor(Node node){
if (node == null){
return 0;
}
return getDepth(node.left) - getDepth(node.right);
} /**
* 插入
* @param node
* @param data
*/
public Node insert(Node node, int data){
Node newData = new Node(data);
if (node == null){
return newData;
}
if (data < node.data){
node.left = insert(node.left, data);
}else if (data > node.data){
node.right = insert(node.right, data);
}else{
return node;
}
int bf = balanceFactor(node); if (bf > 1 && data < node.left.data){
// LL
System.out.println("LL" + data);
return rightRotate(node);
}else if (bf < -1 && data > node.right.data){
// RR
System.out.println("RR" + data);
return leftRotate(node);
}else if (bf > 1 && data > node.left.data){
// LR
System.out.println("LR" + data);
return leftRightRotate(node);
}else if (bf < -1 && data < node.right.data){
// RL
System.out.println("RL" + data);
return rightLeftRotate(node);
}
return node;
} /**
* 批量插入
* @param arr
*/
public void batchInsert(int[] arr){
for (int data : arr){
root = insert(root, data);
}
} /**
* 前序遍历
*/
public void prePrint(){
System.out.print("前序遍历\t");
if (root != null){
pre(root);
}
System.out.println();
} private void pre(Node node){
if (node != null) {
System.out.print(node.data + "\t");
pre(node.left);
pre(node.right);
}
} /**
* 中序遍历
*/
public void midPrint(){
System.out.print("中序遍历\t");
if (root != null){
mid(root);
}
System.out.println();
} private void mid(Node node){
if (node != null) {
mid(node.left);
System.out.print(node.data + "\t");
mid(node.right);
}
} /**
* 后序遍历
*/
public void postPrint(){
System.out.print("后序遍历\t");
if (root != null){
post(root);
}
System.out.println();
} private void post(Node node){
if (node != null) {
post(node.left);
post(node.right);
System.out.print(node.data + "\t");
}
} /**
* 层序遍历,利用队列先进先出
*/
public void tierPrint(){
if (root != null){
Queue<Node> queue = new LinkedList<>();
queue.add(root);
System.out.print("层序遍历\t");
while (!queue.isEmpty()){
Node temp = queue.remove();
System.out.print(temp.data + "\t");
if (temp.left != null){
// 左节点不为空,放进队列
queue.add(temp.left);
}
if (temp.right != null){
// 右节点不为空,放进队列
queue.add(temp.right);
}
}
}
} }
二叉树 & 平衡二叉树 算法(Java实现)的更多相关文章
- 找出 int 数组的平衡点 & 二叉树 / 平衡二叉树 / 满二叉树 / 完全二叉树 / 二叉查找树
找出 int 数组的平衡点 左右两边和相等, 若存在返回平衡点的值(可能由多个); 若不存在返回 -1; ``java int [] arr = {2,3,4,2,4}; ```js const ar ...
- 无向图的最短路径算法JAVA实现
一,问题描述 给出一个无向图,指定无向图中某个顶点作为源点.求出图中所有顶点到源点的最短路径. 无向图的最短路径其实是源点到该顶点的最少边的数目. 本文假设图的信息保存在文件中,通过读取文件来构造图. ...
- 无向图的最短路径算法JAVA实现(转)
一,问题描述 给出一个无向图,指定无向图中某个顶点作为源点.求出图中所有顶点到源点的最短路径. 无向图的最短路径其实是源点到该顶点的最少边的数目. 本文假设图的信息保存在文件中,通过读取文件来构造图. ...
- 归并排序算法 java 实现
归并排序算法 java 实现 可视化对比十多种排序算法(C#版) [直观学习排序算法] 视觉直观感受若干常用排序算法 算法概念 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Di ...
- 快速排序算法 java 实现
快速排序算法 java 实现 快速排序算法Java实现 白话经典算法系列之六 快速排序 快速搞定 各种排序算法的分析及java实现 算法概念 快速排序是C.R.A.Hoare于1962年提出的一种划分 ...
- 堆排序算法 java 实现
堆排序算法 java 实现 白话经典算法系列之七 堆与堆排序 Java排序算法(三):堆排序 算法概念 堆排序(HeapSort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,可以利用数组的特 ...
- Atitit 电子商务订单号码算法(java c# php js 微信
Atitit 电子商务订单号码算法(java c# php js 微信 1.1. Js版本的居然钱三爷里面没有..只好自己实现了. 1.2. 订单号标准化...长度16位 1.3. 订单号的结构 前 ...
- 关于Leetcode上二叉树的算法总结
二叉树,结构很简单,只是比单链表复杂了那么一丢丢而已.我们先来看看它们结点上的差异: /* 单链表的结构 */ struct SingleList{ int element; struct Singl ...
- 基于FP-Tree的关联规则FP-Growth推荐算法Java实现
基于FP-Tree的关联规则FP-Growth推荐算法Java实现 package edu.test.ch8; import java.util.ArrayList; import java.util ...
随机推荐
- 浅谈华为验厂对MES系统的要求
众所周知,华为对供应商在管理.防错.品控.追溯等方面的要求都非常严格.在华为验厂时,对供应商的信息系统,尤其是MES系统的评估也是有非常具体的要求.那么我们今天就来谈谈华为验厂时,对MES系统有哪些具 ...
- SpringCloud学习第三章-springcloud 父项目创建
父项目 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns=" ...
- PAT 乙级 1039.到底买不买 C++/Java
题目来源 小红想买些珠子做一串自己喜欢的珠串.卖珠子的摊主有很多串五颜六色的珠串,但是不肯把任何一串拆散了卖.于是小红要你帮忙判断一下,某串珠子里是否包含了全部自己想要的珠子?如果是,那么告诉她有多少 ...
- 使用log4Net输出调试信息
在上一篇搭建服务器端的项目基础上,使用log4Net进行调试信息输出 http://www.cnblogs.com/fzxiaoyi/p/8439769.html 1.先分析下Photo 自带的服务器 ...
- Sonarqube C#静态代码规范检查(一)
使用说明 代码规范对于每个开发来说重要也重要,说不重要其实也没那么重要,简单点的vs的code analysis也能提供很多的建议,重量级一点的Resharper不仅能提供建议,还提供了更方便快捷的一 ...
- 学习:CC断点
断点介绍: shark恒老师说有四种说法,但是其实都是相同的 第一个读法:普通断点 第二个读法:F2断点 第三个读法:INT3断点( int3其实就是汇编指令 ) 第四个读法:CC断点 (CC其实就是 ...
- 简述 gevent模块的作用和应用场景。
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成, 再在适当的时候切换回来继续执行.由于IO操作非常耗时,经常使程序处于等待状态, 有了geve ...
- MacOS下IDEA设置智能提示不区分大小写
本文只针对,IDEA-2019.2.3版本 目录地址: Edit -> General -> Code Completion -> Match case -> 勾选去掉 截图如 ...
- 虚拟机中Windows激活「很抱歉,程序无法在非MBR引导分区上进行激活」
虚拟机激活 Windows 出现如下错误提示: 很抱歉,程序无法在非MBR引导分区上进行激活 没错,是小马Oem7F7激活工具. 最后使用 KMS 激活成功,下载链接: 链接:https://pan. ...
- three.js 打包为一个组-几个单独的模型
代码: <!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl ...