本文基于二叉排序树(BST)创作,若对二叉排序树不了解建议先掌握二叉排序树再学习文本
本文完整代码下载
一、介绍
- 平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树, 可以保证查询效率较高。
- 具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。
例:
二、二叉排序树 问题分析
将数列{1,2,3,4,5,6} 创建为一颗二叉排序树(BST)
创建后的效果
问题
- 左子树全部为空,从形式上看,更像一个单链表。
- 插入速度没有影响。
- 查询速度明显降低(因为需要依次比较), 不能发挥BST的优势,因为每次还需要比较左子树,其查询速度比单链表还慢。
三、解决思路
AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法。但是要进行预先或随后做一次或多次所谓的"AVL 旋转"。
旋转
左旋转
右旋转
双旋转
双旋转就是先进行左旋转,再进行右旋转或先进行右旋转,在进行左旋转
例
旋转过后依然不符合条件
问题分析
在满足右旋转条件时,要判断
(1)如果 是 左子树的 右子树高度 大于左子树的左子树时:
(2)就是 对 当前根节点的左子树,先进行 左旋转,
(3)然后, 在对当前根节点进行右旋转即可。
否则,直接对当前节点(根节点)进行右旋转.即可。
四、代码实现
1.求树的高度
class Node {
int value;
Node left;
Node right;
/**
* @return 以该节点为根节点的树的高度
*/
public int height() {
return Math.max(left == null ? 0 : left.height(), right == null ? 0 : right.height()) + 1;
}
/**
* @return 左子树的高度
*/
public int leftHeight() {
if (left == null) {
return 0;
}
return left.height();
}
/**
* @return 右子树的高度
*/
public int rightHeight() {
if (right == null) {
return 0;
}
return right.height();
}
}
2.左旋转
class Node {
/**
* 左旋转方法
*/
private void leftRotate() {
//创建新的结点,以当前根结点的值
Node newNode = new Node(value);
//把新的结点的左子树设置成当前结点的左子树
newNode.left = left;
//把新的结点的右子树设置成当前结点右子树的左子树
newNode.right = right.left;
//把当前结点的值替换成右子结点的值
value = right.value;
//把当前节点的右子树设置成当前节点右子树的右子树
right = right.right;
//把当前结点的左子树(左子结点)设置成新的结点
left = newNode;
}
}
3.右旋转
class Node {
/**
* 右旋转
*/
private void rightRotate() {
Node newNode = new Node(value);
newNode.right = right;
newNode.left = left.right;
value = left.value;
left = left.left;
right = newNode;
}
}
4.添加结点
/**
* 添加结点
*
* @param node 结点
*/
public void add(Node node) {
if (node == null) {
return;
}
//添加的结点的值 小于 当前结点的值
if (node.value < this.value) {
//若当前结点的左子结点为空
if (this.left == null) {
this.left = node;
} else {
//递归向左子树添加
this.left.add(node);
}
} else {
//添加的结点的值 大于等于 当前结点的值
if (this.right == null) {
this.right = node;
} else {
//递归向左子树添加
this.right.add(node);
}
}
//当添加完成一个结点后,若(右子树的高度-左子树的高度)>1,左旋转
if (rightHeight() - leftHeight() > 1) {
//如果它的右子树的左子树的高度大于右子树的右子树的高度
if (right != null && right.leftHeight() > right.rightHeight()) {
//新对右子结点进行右旋转
right.rightRotate();
//再对当前结点进行左旋转
leftRotate();
} else {
//直接进行左旋转
leftRotate();
}
return;
}
//当添加完成一个结点后,若(左子树的高度-右子树的高度)>1,右旋转
//当添加完成一个结点后,若(右子树的高度-左子树的高度)>1,左旋转
if (leftHeight() - rightHeight() > 1) {
//如果它的左子树的右子树的高度大于右子树的左子树的高度
if (left != null && left.rightHeight() > left.leftHeight()) {
//新对右子结点进行右旋转
left.leftRotate();
//再对当前结点进行左旋转
rightRotate();
} else {
//直接进行左旋转
rightRotate();
}
}
}
本文完整代码下载