1.主要功能
平衡二叉树的构造、遍历、节点的删除(有规则)、节点的添加、二叉排序树的平衡化
2.代码实现
1.节点
public class Nodes {
public int value; // 节点值
public Nodes left; // 节点的左指针
public Nodes right; // 节点的右指针
public Nodes() {
}
public Nodes(int value) {
this.value = value;
}
@Override
public String toString() {
return "{" +
"value=" + value +
'}';
}
/*------------计算以某个节点为根节点的树高度-----------*/
public int Tree_height() {
return Math.max(left == null ? 0 : left.Tree_height(), right == null ? 0 : right.Tree_height()) + 1;
}
/*-----------计算以某个节点为根节点的左子树的高度---------*/
public int LeftChild_height() {
if (left == null) {
return 0;
}
return left.Tree_height();
}
/*----------计算以某个节点为根节点的右子树的高度-----------*/
public int RightChild_height() {
if (right == null) {
return 0;
} else {
return right.Tree_height();
}
}
/*-------------------------平衡处理-----------------------*/
/*------------------------1.左旋转(右子树高度大于左子树高度)------------------------*/
public void LeftRotate() {
// 创建一个新节点,存储当前根节点的值
Nodes newNode = new Nodes(value);
// 新节点的左子节点设置为当前节点的左子节点
newNode.left = left;
// 新节点的右子节点设置为当前节点的右子节点的左子节点
newNode.right = right.left;
// 把当前节点的值设置为它的右子节点的值
value = right.value;
// 把当前节点的右子树设置为右子树的右子树
right = right.right;
// 把当前节点的左子节点设置为新节点
left = newNode;
}
/*------------------------2.右旋转(左子树高度大于右子树高度)------------------------*/
public void RightRotate() {
// 创建一个新节点,存储当前根节点的值
Nodes newNode = new Nodes(value);
// 新节点的右子节点设置为当前节点的右子节点
newNode.right = right;
// 新节点的左子节点设置为当前节点的左子节点的右子节点
newNode.left = left.right;
// 把当前节点的值设置为它的左子节点的值
value = left.value;
// 把当前节点的左子树设置为左子树的左子树
left = left.left;
// 把当前节点的右子节点设置为新节点
right = newNode;
}
/* ------------------------添加节点--------------------------*/
public void AddNodes(Nodes nodes) {
// 添加的节点为空
if (nodes == null) {
return;
}
// 判断要添加的节点和当前树的根节点比较
if (nodes.value < this.value) {
// 如果当前节点的左子节点为空,就直接插入
if (this.left == null) {
this.left = nodes;
} else { // 递归向左子树添加节点
this.left.AddNodes(nodes);
}
}
if (nodes.value > this.value) {
// 如果当前节点的右子节点为空,就直接插入
if (this.right == null) {
this.right = nodes;
} else { // 递归向右子树添加节点
this.right.AddNodes(nodes);
}
}
/*---------------平衡处理------------*/
// 1.(右子树的高度-左子树的高度) > 1 ----------> 左旋转
if (RightChild_height() - LeftChild_height() > 1) {
// 如果当前节点的右节点的左子树的高度大于当前节点的右节点的右子树的高度
// 先对当前节点的右节点进行右旋转
if (right != null && right.LeftChild_height() > right.RightChild_height()) {
right.RightRotate();
LeftRotate();
} else {
LeftRotate();
}
return;
}
// 2.(左子树的高度-右子树的高度) > 1 ----------> 右旋转
if (LeftChild_height() - RightChild_height() > 1) {
// 如果当前节点的左节点的右子树的高度大于当前节点的左节点的右子树的高度
// 先对当前节点的左子节点进行左旋转
if (left != null && left.RightChild_height() > left.RightChild_height()) {
left.LeftRotate();
// 再对当前节点进行右旋转
RightRotate();
} else { // 否则,直接对当前节点进行右旋转
RightRotate();
}
}
}
/*-------------------------中序遍历---------------------------*/
public void MidOrderTraverse() {
if (this.left != null) {
this.left.MidOrderTraverse();
}
System.out.print(this + "");
if (this.right != null) {
this.right.MidOrderTraverse();
}
}
/*---------------查找要删除的节点(根据节点权值)------------------*/
public Nodes SearchNodes(int value) {
// 直接找到,就返回当前节点
if (this.value == value) {
return this;
} else if (value < this.value) { // 如果查找的值小于当前节点的值,查找左子节点
// 如果当前节点的左子树为空,则查找失败
if (this.left == null) {
return null;
}
// 否则,递归查找左子树
return this.left.SearchNodes(value);
} else { // 如果要查找的值大于当前节点的值,查找右子节点
// 如果当前节点的右子节点为空,则查找失败
if (this.right == null) {
return null;
}
// 否则,递归查找右子树
return this.right.SearchNodes(value);
}
}
/*---------------查找要删除节点的父节点-------------*/
/**
* @param value 要删除的节点的值
* @return 要查找的节点的父节点
*/
public Nodes SearchParentNode(int value) {
// 当前节点是要查找节点的父节点,就直接返回当前节点
if ((this.left != null && this.left.value == value) || (this.right != null && this.right.value == value)) {
return this;
} else {
// 如果要查找的节点小于当前节点,并且当前节点的左子节点不为空,递归左子树查找
if (value < this.value && this.left != null) {
return this.left.SearchParentNode(value);
} else if (value > this.value && this.right != null) { // 如果要查找的节点大于当前节点,并且当前节点的右子节点不为空,递归右子树查找
return this.right.SearchParentNode(value);
} else {
return null; // 没有找到父节点
}
}
}
}
2.二叉树
public class AVL {
private Nodes root; // 二叉树的根节点
public Nodes getRoot() {
return root;
}
public void setRoot(Nodes root) {
this.root = root;
}
/*-------------添加节点-----------*/
public void AddNode(Nodes nodes) {
// 如果二叉树为空,则直接将要添加的节点作为根节点
if (root == null) {
root = nodes;
} else {
root.AddNodes(nodes);
}
}
/*------------删除最小节点---------*/
/**
* 删除以node为根节点的二叉排序树的最小值
*
* @param node 根节点
* @return 最小值
*/
public int DelMinNode(Nodes node) {
// 设置一个辅助指针,用于遍历
Nodes temp = node;
// 直到找到最小值
while (node.left != null) {
temp = temp.left;
}
// 找到了最小值对应的节点
DelNode(temp.value);
return temp.value;
}
/*------------查找要删除的节点--------*/
public Nodes SearchNode(int value) {
if (root == null) {
System.out.println("树为空,无法查找");
return null;
} else {
return root.SearchNodes(value);
}
}
/*-----------查找要删除节点的父节点------*/
public Nodes SearchParent(int value) {
if (root == null) {
System.out.println("树为空,无法查找");
return null;
} else {
return root.SearchParentNode(value);
}
}
/*-----------删除节点----------------*/
public void DelNode(int value) {
if (root == null) {
System.out.println("树为空,无法删除");
return;
} else {
// 1.先找到要删除的节点
Nodes target = SearchNode(value);
// 没有找到
if (target == null) {
return;
}
// 如果只有一个节点
if (root.left == null && root.right == null) {
// 删除这个节点
root = null;
return;
}
// 2.找到要删除节点的父节点
Nodes target_parentNode = SearchParent(value);
// ------------------->如果要删除的节点是叶子节点<---------------------
if (target.left == null && target.right == null) {
// 直接删除
// 如果要删除的节点是左子节点
if (target_parentNode.left != null && target_parentNode.left.value == value) {
// 直接删除
target_parentNode.left = null;
// 如果要删除的节点是右子节点
} else if (target_parentNode.right != null && target_parentNode.right.value == value) {
target_parentNode.right = null;
}
} else if (target.left != null && target.right != null) { // -------------->要删除的节点有两个子树<-----------------
// 找到目标节点右子树的最小值
int i = DelMinNode(target.right);
// 用这个值替代目标值
target.value = i;
} else { // -------------->要删除的节点有一个子树<-----------------
// 目标节点只有左子树
if (target.left != null) {
// 如果目标节点是父节点的左子节点
if (target_parentNode.left == target) {
target_parentNode.left = target.left;
}
// 如果目标节点是父节点的右子节点
if (target_parentNode.right == target) {
target_parentNode.right = target.left;
}
} else { // 目标节点只有右子树
// 如果目标节点是父节点的右子节点
if (target_parentNode.right == target) {
target_parentNode.right = target.right;
}
// 如果目标节点是父节点的左子节点
if (target_parentNode.left == target) {
target_parentNode.left = target.right;
}
}
}
}
}
/*------------中序遍历------------*/
public void MidTraverse() {
if (root != null) {
root.MidOrderTraverse();
} else {
System.out.println("树为空,无法遍历");
}
}
}
3.入口
public class Input {
public static void main(String[] args) {
// 创建一个数组,使用数组元素创建一个二叉排序树
int[] Array = {10, 12, 8, 9, 7, 6};
AVL avl = new AVL();
// 创建一个二叉树
BinarySortTree(Array, avl);
// 中序遍历二叉排序树
MidTraverse(avl);
// 测试计算树的高度
System.out.println("进行平衡处理:");
System.out.println("树的高度为:" + avl.getRoot().Tree_height());
System.out.println("左子树的高度为:" + avl.getRoot().LeftChild_height());
System.out.println("右子树的高度为:" + avl.getRoot().RightChild_height());
MidTraverse(avl);
// // 删除叶子节点 ---- 10
// int Branch = AVL.DelMinNode(new Nodes(10));
// System.out.println();
// System.out.printf("删除的叶子节点是:%d", Branch);
//
// MidTraverse(AVL);
// // 删除只有一个子节点的节点 ---- 8
// int Branch = AVL.DelMinNode(new Nodes(8));
// System.out.printf("删除的节点是:%d", Branch);
// System.out.println();
// MidTraverse(AVL);
// 删除右有两个子节点的节点 ---- 6
// int Branch = avl.DelMinNode(new Nodes(6));
System.out.printf("删除的节点是:%d", Branch);
System.out.println();
MidTraverse(avl);
}
// 创建一个二叉树
private static void BinarySortTree(int[] Arr, AVL AVL) {
for (int i = 0; i < Arr.length; i++) {
AVL.AddNode(new Nodes(Arr[i]));
}
}
// 中序遍历二叉排序树
private static void MidTraverse(AVL AVL) {
System.out.println("中序遍历:");
AVL.MidTraverse(); // 2 4 5 6 8 10
System.out.println();
}
}