平衡二叉樹
平衡二叉樹又叫AVL樹,它是在二叉排序樹的基礎上進行了樹結構的調整,使其根節點的左右子樹的高度差一致。可以保證查詢效率更加高效。
平衡二叉樹涉及到左旋轉、右旋轉和雙旋轉,接下來分別用圖解分析一下:
左旋轉
右旋轉
雙旋轉
代碼如下:
package com.avl;
/*
* 平衡二叉樹:
* 1.左旋轉
* 2.右旋轉
* 3.雙旋轉
*/
public class AVLTreeDemo2 {
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 };// 雙旋轉
AVLTree2 avlTree2 = new AVLTree2();
for (int i = 0; i < arr.length; i++) {
avlTree2.add(new Node2(arr[i]));
}
System.out.println("樹的高度=" + avlTree2.getRoot().height());
System.out.println("左子樹的高度=" + avlTree2.getRoot().leftHeight());
System.out.println("右子樹的高度=" + avlTree2.getRoot().rightHeight());
System.out.println("前序遍歷");
avlTree2.preList();
System.out.println("中序遍歷");
avlTree2.infixList();
}
}
//創建平衡二叉樹
class AVLTree2 {
Node2 root;
public Node2 getRoot() {
return root;
}
// 前序遍歷
public void preList() {
if (root == null) {
System.out.println("空樹無法遍歷!");
return;
}
root.preList();
}
// 中序遍歷
public void infixList() {
if (root == null) {
System.out.println("空樹無法遍歷!");
return;
}
root.infixList();
}
/**
* 添加節點
*
* @param node
*/
public void add(Node2 node) {
if (root == null) {
root = node;
return;
}
root.add(node);
}
}
//創建節點類
class Node2 {
int value;
Node2 left;
Node2 right;
public Node2(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node2 [value=" + value + "]";
}
// 前序遍歷
public void preList() {
System.out.println(this);
if (this.left != null) {
this.left.preList();
}
if (this.right != null) {
this.right.preList();
}
}
// 中序遍歷
public void infixList() {
if (this.left != null) {
this.left.infixList();
}
System.out.println(this);
if (this.right != null) {
this.right.infixList();
}
}
// 以當前節點爲根節點,求其樹的高度
public int height() {
return Math.max(this.left == null ? 0 : this.left.height(), this.right == null ? 0 : this.right.height()) + 1;
}
// 求當前節點左子樹的高度
public int leftHeight() {
if (this.left == null) {
return 0;
}
return this.left.height();
}
// 求當前節點右子樹的高度
public int rightHeight() {
if (this.right == null) {
return 0;
}
return this.right.height();
}
/**
* 左旋轉
*/
public void leftRotate() {
// 1.以當前節點爲根結點,創建一個新的節點,值爲當前節點的值
Node2 newNode = new Node2(this.value);
// 2.將新節點的左子節點設置成當前節點的左子樹
newNode.left = this.left;
// 3.將新節點的右子節點設置成當前節點右子節點的左子樹
newNode.right = this.right.left;
// 4.將當前節點的值替換成其右子節點的值
this.value = this.right.value;
// 5.將當前節點的右子節點設置成當前節點右子節點的右子樹
this.right = this.right.right;
// 6.將當前節點的左子節點設置成新節點
this.left = newNode;
}
/**
* 右旋轉
*/
public void rightRotate() {
// 1.以當前節點爲根節點,創建一個新的節點,值爲當前節點的值
Node2 newNode = new Node2(this.value);
// 2.將新節點的右子節點設置成當前節點的右子樹
newNode.right = this.right;
// 3.將新節點的左子節點設置成當前節點左子節點的右子樹
newNode.left = this.left.right;
// 4.將當前節點的值替換成其左子節點的值
this.value = this.left.value;
// 5.將當前節點的左子節點設置成當前節點左子節點的左子樹
this.left = this.left.left;
// 6.將當前節點的右子節點設置成新節點
this.right = newNode;
}
/**
* 添加節點
*
* @param node
*/
public void add(Node2 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.如果當前節點的左子樹高度-右子樹高度>1,那麼需要進行右旋轉
if (this.leftHeight() - this.rightHeight() > 1) {
// !!!這裏有種情況:如果以當前節點的左子節點爲根節點,其右子樹的高度>其左子樹的高度時,需要局部進行左旋轉。
if (this.left != null && this.left.rightHeight() > this.left.leftHeight()) {
// 以當前節點的左子節點爲根節點,進行局部左旋轉
this.left.leftRotate();
}
// 然後以當前節點爲根節點,進行右旋轉
this.rightRotate();
// 旋轉完就可以退出了
return;
}
// 2.如果當前節點的右子樹高度-左子樹高度>1,那麼需要進行左旋轉
if (this.rightHeight() - this.leftHeight() > 1) {
// !!!這裏有種情況:如果以當前節點的右子節點爲根節點,其左子樹的高度>其右子樹的高度時,需要進行局部右旋轉
if (this.right != null && this.right.leftHeight() > this.right.rightHeight()) {
// 以當前節點的右子節點爲根結點,進行局部右旋轉
this.right.rightHeight();
}
// 然後以當前節點爲根結點,進行左旋轉
this.leftRotate();
}
}
}
如有錯誤之處,還望指出,定會及時改正!