- 平衡二叉树也叫平衡二叉搜索树(Self-balancing binary search tree)又被称为 AVL 树, 可以保证查询效率较高。
- 具有以下特点:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过 1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。
获取树高度
// 返回以当前节点为根节点的树的高度, 此处假设根节点高度为1
public int height() {
return Math.max(this.left==null? 0: this.left.height(), this.right==null? 0: this.right.height()) + 1;
}
左旋转
/*
原因: 左旋转后的根节点是现在根节点的右子节点,而这个右子节点成为新根节点后,
其右边的值必须大于新根结点的值,但这个右子节点的左子节点的值小于这个右子节点,
所以要将这个节点的左节点挂到左边去,而又因为这个右子节点的左子节点肯定比原先根节点的值大,
所以将其挂到原先根节点(新创建的一个节点)右子节点的位置
*/
public void leftRotate(){
// 另新节点的值为当前节点的值
Node newNode = new Node(value);
// 新节点的左子节点指向当前节点的左子节点
newNode.left = left;
// 新节点的右子节点指向当前节点的右子节点的左子节点
newNode.right = right.left;
// 令当前根节点的值为其右子节点的值
this.value = right.value;
// 将新节点挂到当前根节点的左边
this.left = newNode;
// 令当前节点的右子节点指向原先右子节点的右子节点
right = right.right;
}
右旋转
// 右旋转
public void rightRotate(){
// 创建新节点
Node newNode = new Node(value);
// 令新节点的值等于当前根节点的值
newNode.value = this.value;
// 令新节点的右子节点指向当前根节点的右子节点
newNode.right = right;
// 令新节点的左子节点指向根节点的左子节点的右子节点
newNode.left = left.right;
// 将当前根节点的值更新为其左子节点的值
value = left.value;
// 将当前节点的右子节点指向新节点
right = newNode;
// 将当前节点的左子节点指向原左子节点的左子节点
left = left.left;
}
特殊情况下的双向旋转
在add中
// 右子树高度比左子树的高度大于1
if (rightHeight() - leftHeight() > 1){
// 如果当前节点的右子节点的左子节点高度大于右子节点的右子节点的高度, 先让右子树进行右旋转
if (right!=null && (right.left.height() > right.right.height())){
right.rightRotate();
leftRotate();
}else {
leftRotate();
}
return;
}
// 左子树高度比右子树的高度大于1
if (leftHeight() - rightHeight() > 1){
// 如果当前节点的左子节点的右子节点高度大于左子节点的左子节点的高度, 先让左子树进行左旋转
if (left!=null && (left.right.height() > left.left.height())){
left.leftRotate();
rightRotate();
}else {
rightRotate();
}
}
完整代码
public class AVLTreeDemo {
public static void main(String[] args) {
// int[] arr = {4, 3, 6, 5, 7, 8};
// int[] arr = {10, 12, 8, 9, 7, 6};
int[] arr = { 10, 11, 7, 6, 8, 9 };
AVLTree avltree = new AVLTree();
//循环的添加结点到二叉排序树
for(int i = 0; i< arr.length; i++) {
avltree.add(new Node(arr[i]));
}
avltree.infixOrder();
System.out.println(avltree.getRoot().height());
System.out.println(avltree.getRoot().leftHeight());
System.out.println(avltree.getRoot().rightHeight());
}
}
class AVLTree{
private Node root;
public Node getRoot(){
return root;
}
// 查找要删除的节点
public Node search(int value){
if (root==null){
return null;
}else {
return root.search(value);
}
}
// 查找父节点
public Node searchParent(int value){
if (root==null){
return null;
}else {
return root.searchParent(value);
}
}
// 返回以node节点为根结点的子树的最小的节点
public int delRightTreeMin(Node node){
while (node.left!=null){
node = node.left;
}
// 删除最小节点并返回其值
delNode(node.value);
return node.value;
}
public void delNode(int value){
if (root==null){
return;
}else {
Node targetNode = search(value);
if (targetNode==null){
return;
}
if (root.left==null && root.right==null){
root = null;
return;
}
// 查找要删除节点的父节点
Node parent = searchParent(value);
if (targetNode.right==null&&targetNode.left==null){ // 待删除的节点为子节点
if (parent.left!=null&&parent.left.value==value){
parent.left = null;
}else if (parent.right!=null&&parent.right.value==value){
parent.right = null;
}
}else if (targetNode.left!=null&&targetNode.right!=null){ // 待删除的节点有两个子树
int minVal = delRightTreeMin(targetNode.right);
targetNode.value = minVal;
}else { // 待删除的节点只有一个子树
if (targetNode.left!=null){ // 待删除的节点的左子树不为空,则将其挂到父节点上
if (parent!=null){
if (parent.left.value==value){
parent.left = targetNode.left;
}else {
parent.right = targetNode.left;
}
}else { // 如果待删除节点的父节点为空,则说明删除的是根节点
root = targetNode.left;
}
}else { // 待删除的节点的右子树不为空,则将其挂到父节点上
if (parent!=null){
if (parent.left.value==value){
parent.left = targetNode.right;
}else {
parent.right = targetNode.right;
}
}else {
root = targetNode.right;
}
}
}
}
}
public void add(Node node){
if (root == null){
root = node;
}else {
root.add(node);
}
}
public void infixOrder(){
if (root != null){
root.infixOrder();
}else {
System.out.println("二叉树为空");
}
}
}
class Node{
int value;
Node left;
Node right;
public Node(int value){
this.value = value;
}
// 返回左子树的高度
public int leftHeight(){
if (this.left==null){
return 0;
}
return left.height();
}
// 返回右子树的高度
public int rightHeight(){
if (this.right==null){
return 0;
}
return right.height();
}
/*
原因: 左旋转后的根节点是现在根节点的右子节点,而这个右子节点成为新根节点后,
其右边的值必须大于新根结点的值,但这个右子节点的左子节点的值小于这个右子节点,
所以要将这个节点的左节点挂到左边去,而又因为这个右子节点的左子节点肯定比原先根节点的值大,
所以将其挂到原先根节点(新创建的一个节点)右子节点的位置
*/
public void leftRotate(){
// 另新节点的值为当前节点的值
Node newNode = new Node(value);
// 新节点的左子节点指向当前节点的左子节点
newNode.left = left;
// 新节点的右子节点指向当前节点的右子节点的左子节点
newNode.right = right.left;
// 令当前根节点的值为其右子节点的值
this.value = right.value;
// 将新节点挂到当前根节点的左边
this.left = newNode;
// 令当前节点的右子节点指向原先右子节点的右子节点
right = right.right;
}
// 右旋转
public void rightRotate(){
// 创建新节点
Node newNode = new Node(value);
// 令新节点的值等于当前根节点的值
newNode.value = this.value;
// 令新节点的右子节点指向当前根节点的右子节点
newNode.right = right;
// 令新节点的左子节点指向根节点的左子节点的右子节点
newNode.left = left.right;
// 将当前根节点的值更新为其左子节点的值
value = left.value;
// 将当前节点的右子节点指向新节点
right = newNode;
// 将当前节点的左子节点指向原左子节点的左子节点
left = left.left;
}
// 返回以当前节点为根节点的树的高度, 此处假设根节点高度为1
public int height() {
return Math.max(this.left==null? 0: this.left.height(), this.right==null? 0: this.right.height()) + 1;
}
// 查找要删除的节点
public Node search(int value){
if (this.value==value){
return this;
}else {
if (value<this.value&&this.left!=null){
return this.left.search(value);
}else if (value>=this.value&&this.right!=null){
return this.right.search(value);
}else {
return null;
}
}
}
// 查找要删除节点的父节点
public Node searchParent(int value){
if ((this.left!=null&&this.left.value==value)||(this.right!=null&&this.right.value==value)){
return this;
}
if (value<this.value&&this.left!=null){
return this.left.searchParent(value);
}else if (value>=this.value&&this.right!=null){
return this.right.searchParent(value);
}else {
return null;
}
}
public void add(Node node){
if (node==null){
return;
}
if (node.value<this.value){
if (this.left!=null){
this.left.add(node);
}else {
this.left = node;
}
}else {
if (this.right!=null){
this.right.add(node);
}else {
this.right = node;
}
}
// 右子树高度比左子树的高度大于1
if (rightHeight() - leftHeight() > 1){
// 如果当前节点的右子节点的左子节点高度大于右子节点的右子节点的高度, 先让右子树进行右旋转
if (right!=null && (right.left.height() > right.right.height())){
right.rightRotate();
leftRotate();
}else {
leftRotate();
}
return;
}
// 左子树高度比右子树的高度大于1
if (leftHeight() - rightHeight() > 1){
// 如果当前节点的左子节点的右子节点高度大于左子节点的左子节点的高度, 先让左子树进行左旋转
if (left!=null && (left.right.height() > left.left.height())){
left.leftRotate();
rightRotate();
}else {
rightRotate();
}
}
}
public String toString() {
return " " + this.value;
}
// 中序遍历
public void infixOrder(){
if (this.left!=null){
this.left.infixOrder();
}
System.out.println(this);
if (this.right!=null){
this.right.infixOrder();
}
}
}