前言
上一篇文章讲了 java 二叉搜索树的实现以及前序、中序、后续遍历实现 ,本文将讲述使用 java 实现自平衡二叉搜索树,以及自平衡二叉搜索树的前序、中序、后续遍历实现。
既然有了二叉搜索树,为什么又出现个 自平衡二叉搜索树呢?
试着把 1、2、3、4、5、6、7、8、9、10 这几个数字依次加入到二叉搜索树中你会发现,它是这样的
这样的树也是二叉搜索树,只不过它是一个链型,是一个不平衡的二叉搜索树,假如要获取10这个节点需要耗费的时间很长。
那么什么是平衡二叉搜索树呢,它是这样的:
有没有发现平衡二叉搜索树就很平衡,让查找每个节点的时间都尽量的缩短了。而自平衡二叉搜索树就是每次新增一个节点都检查二叉搜索树是否平衡,不平衡的话就自动转换为平衡二叉搜索树,这就是自平衡二叉搜索树。
一、平衡二叉搜索树与自平衡二叉搜索树
平衡二叉搜索树:简称 BST 树,平衡二叉树又称高度平衡二叉树,定义为任意节点左右子树高度相差不超过1的二叉树。
自平衡二叉搜索树:简称 AVL 树,自平衡二叉树就是每新加一个节点都自动进行变换调整让整棵树都保持为平衡二叉树。
二、自平衡二叉搜索树实现
算法主要分为两部分,当增加一个节点时:
1.检查整棵二叉搜索树是否平衡
- 任何节点的左子树和右子树的差不超过一
- 左子树是平衡的
- 右子树是平衡的
2.如果不平衡,把不平衡的二叉搜索树调整为平衡二叉搜索树
- 通过中序遍历二叉搜索树是有序的特点,获取所有排序好的节点并将结果存储在数组中
- 清空整棵树
- 递归,把数组中间的中位数作为根节点,中位数左边的数作为左子树,右边的数作为右子树
代码如下
import java.util.ArrayList;
import java.util.List;
public class BalanceBST {
/**
* 平衡二叉搜索树总的节点数
*/
private int size;
/**
* 根节点
*/
public Node root;
/**
* 不平衡二叉搜索树 调整为 平衡二叉搜索树 时用于记录节点数
*/
private int tempSize;
public class Node {
public int value;
private Node leftNode;
private Node rightNode;
private Node(int value, Node leftNode, Node rightNode) {
this.value = value;
this.leftNode = leftNode;
this.rightNode = rightNode;
}
}
/**
* 获取平衡二叉搜索树的总节点数
*/
public int size() {
return size;
}
/**
* 检查节点的左右子树是否平衡,不平衡则返回-1,平衡则返回树的高度
*/
public int balanceHeight(Node currentNode) {
if (currentNode == null) {
return 0;
}
// 检查左子树高度
int leftSubtreeHeight = balanceHeight(currentNode.leftNode);
if (leftSubtreeHeight == -1) return -1;
// 检查右子树高度
int rightSubtreeHeight = balanceHeight(currentNode.rightNode);
if (rightSubtreeHeight == -1) return -1;
//检查左右子树的高度相差是否超过1,超过则不平衡
if (Math.abs(leftSubtreeHeight - rightSubtreeHeight) > 1) {
return -1;
}
//如果平衡则返回树的高度
return (Math.max(leftSubtreeHeight, rightSubtreeHeight) + 1);
}
/**
* 向平衡二叉搜索树中增加节点
*/
public void add(int addValue) {
add(addValue, true);
}
/**
* 向平衡二叉搜索树中增加节点
*
* @param addValue 要添加的节点的值
* @param convert 是否检查该树是平衡二叉树
*/
public void add(int addValue, boolean convert) {
if (null == root) {
root = new Node(addValue, null, null);
} else {
add(addValue, root);
}
if (convert) {
size++;
}
//如果高度大于1则不平衡要转为AVL树
if (convert && balanceHeight(root) == -1) {
//利用中序遍历是有序的特点得到排好序的所有节点的值
List<Integer> allNodes = new ArrayList<>();
midTraverse(allNodes, root);
//清空二叉树
root = null;
//转为平衡二叉树
convertTONewTree(allNodes, 0, allNodes.size() - 1);
tempSize = 0;
}
}
/**
* 将有序的列表元素转化为一个平衡二叉树
*/
private void convertTONewTree(List<Integer> list, int start, int end) {
if (tempSize != size && start <= end && end >= 0) {
int sum = start + end;
int middle = sum % 2;
int middleIndex = middle == 0 ? sum / 2 : (sum / 2) + 1;
int middleValue = list.get(middleIndex);
add(middleValue, false);
tempSize++;
convertTONewTree(list, start, middleIndex - 1);
convertTONewTree(list, middleIndex + 1, end);
}
}
private void add(int addValue, Node node) {
if (null != node) {
int value = node.value;
if (addValue < value) {
if (null != node.leftNode) {
add(addValue, node.leftNode);
} else {
node.leftNode = new Node(addValue, null, null);
}
}
if (addValue >= value) {
if (null != node.rightNode) {
add(addValue, node.rightNode);
} else {
node.rightNode = new Node(addValue, null, null);
}
}
}
}
/**
* 前序遍历
*/
public List<Integer> preTraverse() {
return preTraverse(new ArrayList<>(), root);
}
private List<Integer> preTraverse(List<Integer> list, Node node) {
if (list.size() != size && null != node) {
list.add(node.value);
//遍历左节点
preTraverse(list, node.leftNode);
//遍历右节点
preTraverse(list, node.rightNode);
}
return list;
}
/**
* 中序遍历
*/
public List<Integer> midTraverse() {
return midTraverse(new ArrayList<>(), root);
}
private List<Integer> midTraverse(List<Integer> list, Node node) {
if (list.size() != size && null != node) {
//遍历左节点
midTraverse(list, node.leftNode);
list.add(node.value);
//遍历右节点
midTraverse(list, node.rightNode);
}
return list;
}
/**
* 后序遍历
*/
public List<Integer> afterTraverse() {
return afterTraverse(new ArrayList<>(), root);
}
private List<Integer> afterTraverse(List<Integer> list, Node node) {
if (list.size() != size && null != node) {
//遍历左节点
afterTraverse(list, node.leftNode);
//遍历右节点
afterTraverse(list, node.rightNode);
list.add(node.value);
}
return list;
}
/**
* 层序遍历
*/
public List<Integer> levelsTraverse() {
return levelsTraverse(new ArrayList<>(), root);
}
private List<Integer> levelsTraverse(List<Integer> list, Node root) {
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (list.size() != size) {
Node node = queue.poll();
list.add(node.value);
if (node.leftNode != null) {
queue.offer(node.leftNode);
}
if (node.rightNode != null) {
queue.offer(node.rightNode);
}
}
return list;
}
/**
* 清空二叉搜索树
*/
public void clear() {
size = 0;
root = null;
}
}
测试
public static void main(String[] args) {
BalanceBST binaryTree = new BalanceBST();
binaryTree.add(1);
binaryTree.add(2);
binaryTree.add(3);
binaryTree.add(4);
binaryTree.add(5);
binaryTree.add(6);
binaryTree.add(7);
binaryTree.add(8);
binaryTree.add(9);
binaryTree.add(10);
//输出根节点的值
BalanceBST.Node root = binaryTree.root;
System.out.println(root.value);
//检查树是否平衡,不平衡则返回-1,平衡则返回树的高度
System.out.println(binaryTree.balanceHeight(root));
//输出所有节点数量
System.out.println(binaryTree.size());
//前序遍历
System.out.println(binaryTree.preTraverse());
//中序遍历
System.out.println(binaryTree.midTraverse());
//后序遍历
System.out.println(binaryTree.afterTraverse());
//层序遍历
System.out.println(binaryTree.levelsTraverse());
}
输出
6
4
10
[6, 3, 2, 1, 5, 4, 9, 8, 7, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 4, 5, 3, 7, 8, 10, 9, 6]
[6, 3, 9, 2, 5, 8, 10, 1, 4, 7]
参考:
b+树详解
Balanced Binary Tree
Convert a normal BST to Balanced BST
Sorted Array to Balanced BST
Binary Search Tree