Java深入分析了解平衡二叉樹(shù)
AVL樹(shù)的引入
搜索二叉樹(shù)有著極高的搜索效率,但是搜索二叉樹(shù)會(huì)出現(xiàn)以下極端情況:

這樣的二叉樹(shù)搜索效率甚至比鏈表還低。在搜索二叉樹(shù)基礎(chǔ)上出現(xiàn)的平衡二叉樹(shù)(AVL樹(shù))就解決了這樣的問(wèn)題。當(dāng)平衡二叉樹(shù)(AVL樹(shù))的某個(gè)節(jié)點(diǎn)左右子樹(shù)高度差的絕對(duì)值大于1時(shí),就會(huì)通過(guò)旋轉(zhuǎn)操作減小它們的高度差。
基本概念
AVL樹(shù)本質(zhì)上還是一棵二叉搜索樹(shù),它的特點(diǎn)是:
- 本身首先是一棵二叉搜索樹(shù)。
- 每個(gè)結(jié)點(diǎn)的左右子樹(shù)的高度之差的絕對(duì)值(平衡因子)最多為1。也就是說(shuō),AVL樹(shù),本質(zhì)上是帶了平衡功能的二叉查找樹(shù)(二叉排序樹(shù),二叉搜索樹(shù))。
- 當(dāng)插入一個(gè)節(jié)點(diǎn)或者刪除一個(gè)節(jié)點(diǎn)時(shí),導(dǎo)致某一個(gè)節(jié)點(diǎn)的左右子樹(shù)高度差的絕對(duì)值大于1,這時(shí)需要通過(guò)左旋和右旋的操作使二叉樹(shù)再次達(dá)到平衡狀態(tài)。
平衡因子(balanceFactor)
- 一個(gè)結(jié)點(diǎn)的左子樹(shù)與右子樹(shù)的高度之差。
- AVL樹(shù)中的任意結(jié)點(diǎn)的BF只可能是-1,0和1。
基礎(chǔ)設(shè)計(jì)
下面是AVL樹(shù)需要的簡(jiǎn)單方法和屬性:
public class AVLTree <E extends Comparable<E>>{
class Node{
E value;
Node left;
Node right;
int height;
public Node(){}
public Node(E value){
this.value = value;
height = 1;
left = null;
right = null;
}
public void display(){
System.out.print(this.value + " ");
}
}
Node root;
int size;
public int size(){
return size;
}
public int getHeight(Node node) {
if(node == null) return 0;
return node.height;
}
//獲取平衡因子(左右子樹(shù)的高度差,大小為1或者0是平衡的,大小大于1不平衡)
public int getBalanceFactor(){
return getBalanceFactor(root);
}
public int getBalanceFactor(Node node){
if(node == null) return 0;
return getHeight(node.left) - getHeight(node.right);
}
//判斷一個(gè)樹(shù)是否是一個(gè)平衡二叉樹(shù)
public boolean isBalance(Node node){
if(node == null) return true;
int balanceFactor = Math.abs(getBalanceFactor(node.left) - getBalanceFactor(node.right));
if(balanceFactor > 1) return false;
return isBalance(node.left) && isBalance(node.right);
}
public boolean isBalance(){
return isBalance(root);
}
//中序遍歷樹(shù)
private void inPrevOrder(Node root){
if(root == null) return;
inPrevOrder(root.left);
root.display();
inPrevOrder(root.right);
}
public void inPrevOrder(){
System.out.print("中序遍歷:");
inPrevOrder(root);
}
}
RR(左旋)
往一個(gè)樹(shù)右子樹(shù)的右子樹(shù)上插入一個(gè)節(jié)點(diǎn),導(dǎo)致二叉樹(shù)變得不在平衡,如下圖,往平衡二叉樹(shù)中插入5,導(dǎo)致這個(gè)樹(shù)變得不再平衡,此時(shí)需要左旋操作,如下:

代碼如下:
//左旋,并且返回新的根節(jié)點(diǎn)
public Node leftRotate(Node node){
System.out.println("leftRotate");
Node cur = node.right;
node.right = cur.left;
cur.left = node;
//跟新node和cur的高度
node.height = Math.max(getHeight(node.left),getHeight(node.right)) + 1;
cur.height = Math.max(getHeight(cur.left),getHeight(cur.right)) + 1;
return cur;
}
LL(右旋)
往一個(gè)AVL樹(shù)左子樹(shù)的左子樹(shù)上插入一個(gè)節(jié)點(diǎn),導(dǎo)致二叉樹(shù)變得不在平衡,如下圖,往平衡二叉樹(shù)中插入2,導(dǎo)致這個(gè)樹(shù)變得不再平衡,此時(shí)需要左旋操作,如下:

代碼如下:
//右旋,并且返回新的根節(jié)點(diǎn)
public Node rightRotate(Node node){
System.out.println("rightRotate");
Node cur = node.left;
node.left = cur.right;
cur.right = node;
//跟新node和cur的高度
node.height = Math.max(getHeight(node.left),getHeight(node.right)) + 1;
cur.height = Math.max(getHeight(cur.left),getHeight(cur.right)) + 1;
return cur;
}
LR(先左旋再右旋)
往AVL樹(shù)左子樹(shù)的右子樹(shù)上插入一個(gè)節(jié)點(diǎn),導(dǎo)致該樹(shù)不再平衡,需要先對(duì)左子樹(shù)進(jìn)行左旋,再對(duì)整棵樹(shù)右旋,如下圖所示,插入節(jié)點(diǎn)為5.

RL(先右旋再左旋)
往AVL樹(shù)右子樹(shù)的左子樹(shù)上插入一個(gè)節(jié)點(diǎn),導(dǎo)致該樹(shù)不再平衡,需要先對(duì)右子樹(shù)進(jìn)行右旋,再對(duì)整棵樹(shù)左旋,如下圖所示,插入節(jié)點(diǎn)為2.

添加節(jié)點(diǎn)
//添加元素
public void add(E e){
root = add(root,e);
}
public Node add(Node node, E value) {
if (node == null) {
size++;
return new Node(value);
}
if (value.compareTo(node.value) > 0) {
node.right = add(node.right, value);
} else if (value.compareTo(node.value) < 0) {
node.left = add(node.left, value);
}
//跟新節(jié)點(diǎn)高度
node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1;
//獲取當(dāng)前節(jié)點(diǎn)的平衡因子
int balanceFactor = getBalanceFactor(node);
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在左子樹(shù)的左子樹(shù)上,此時(shí)需要進(jìn)行右旋
if (balanceFactor > 1 && getBalanceFactor(node.left) >= 0) {
return rightRotate(node);
}
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在右子樹(shù)子樹(shù)的右子樹(shù)上,此時(shí)需要進(jìn)行左旋
else if (balanceFactor < -1 && getBalanceFactor(node.right) <= 0) {
return leftRotate(node);
}
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在左子樹(shù)的右子樹(shù)上,此時(shí)需要先對(duì)左子樹(shù)左旋,在整個(gè)樹(shù)右旋
else if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
//balanceFactor < -1 && getBalanceFactor(node.left) > 0
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在右子樹(shù)的左子樹(shù)上,此時(shí)需要先對(duì)右子樹(shù)右旋,再整個(gè)樹(shù)左旋
else if(balanceFactor < -1 && getBalanceFactor(node.right) > 0) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
return node;
}
刪除節(jié)點(diǎn)
//刪除節(jié)點(diǎn)
public E remove(E value){
root = remove(root,value);
if(root == null){
return null;
}
return root.value;
}
public Node remove(Node node, E value){
Node retNode = null;
if(node == null)
return retNode;
if(value.compareTo(node.value) > 0){
node.right = remove(node.right,value);
retNode = node;
}
else if(value.compareTo(node.value) < 0){
node.left = remove(node.left,value);
retNode = node;
}
//value.compareTo(node.value) = 0
else{
//左右節(jié)點(diǎn)都為空,或者左節(jié)點(diǎn)為空
if(node.left == null){
size--;
retNode = node.right;
}
//右節(jié)點(diǎn)為空
else if(node.right == null){
size--;
retNode = node.left;
}
//左右節(jié)點(diǎn)都不為空
else{
Node successor = new Node();
//尋找右子樹(shù)最小的節(jié)點(diǎn)
Node cur = node.right;
while(cur.left != null){
cur = cur.left;
}
successor.value = cur.value;
successor.right = remove(node.right,value);
successor.left = node.left;
node.left = node.right = null;
retNode = successor;
}
if(retNode == null)
return null;
//維護(hù)二叉樹(shù)平衡
//跟新height
retNode.height = Math.max(getHeight(retNode.left),getHeight(retNode.right));
}
int balanceFactor = getBalanceFactor(retNode);
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在左子樹(shù)的左子樹(shù)上,此時(shí)需要進(jìn)行右旋
if (balanceFactor > 1 && getBalanceFactor(retNode.left) >= 0) {
return rightRotate(retNode);
}
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在右子樹(shù)子樹(shù)的右子樹(shù)上,此時(shí)需要進(jìn)行左旋
else if (balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0) {
return leftRotate(retNode);
}
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在左子樹(shù)的右子樹(shù)上,此時(shí)需要先對(duì)左子樹(shù)左旋,在整個(gè)樹(shù)右旋
else if (balanceFactor > 1 && getBalanceFactor(retNode.left) < 0) {
retNode.left = leftRotate(retNode.left);
return rightRotate(retNode);
}
//該子樹(shù)不平衡且新插入節(jié)點(diǎn)(導(dǎo)致不平衡的節(jié)點(diǎn))在右子樹(shù)的左子樹(shù)上,此時(shí)需要先對(duì)右子樹(shù)右旋,再整個(gè)樹(shù)左旋
else if(balanceFactor < -1 && getBalanceFactor(retNode.right) > 0) {
retNode.right = rightRotate(retNode.right);
return leftRotate(retNode);
}
return retNode;
}
到此這篇關(guān)于Java深入分析了解平衡二叉樹(shù)的文章就介紹到這了,更多相關(guān)Java平衡二叉樹(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA創(chuàng)建Java項(xiàng)目保姆級(jí)教程(超詳細(xì)!)
這篇文章主要給大家介紹了關(guān)于IDEA創(chuàng)建Java項(xiàng)目保姆級(jí)教程的相關(guān)資料,Java是一種廣泛使用的編程語(yǔ)言,廣泛用于Web應(yīng)用程序和客戶端應(yīng)用程序的開(kāi)發(fā),文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
詳解Spring Boot使用系統(tǒng)參數(shù)表提升系統(tǒng)的靈活性
Spring Boot項(xiàng)目中常有一些相對(duì)穩(wěn)定的參數(shù)設(shè)置項(xiàng),其作用范圍是系統(tǒng)級(jí)的或模塊級(jí)的,這些參數(shù)稱為系統(tǒng)參數(shù)。這些變量以參數(shù)形式進(jìn)行配置,從而提高變動(dòng)和擴(kuò)展的靈活性,保持代碼的穩(wěn)定性2021-06-06
IDEA配置Tomcat創(chuàng)建web項(xiàng)目的詳細(xì)步驟
Tomcat是一個(gè)Java?Web應(yīng)用服務(wù)器,實(shí)現(xiàn)了多個(gè)Java?EE規(guī)范(JSP、Java?Servlet等),這篇文章主要給大家介紹了關(guān)于IDEA配置Tomcat創(chuàng)建web項(xiàng)目的詳細(xì)步驟,需要的朋友可以參考下2023-12-12
Java獲取此次請(qǐng)求URL以及服務(wù)器根路徑的方法
這篇文章主要介紹了Java獲取此次請(qǐng)求URL以及服務(wù)器根路徑的方法,需要的朋友可以參考下2015-08-08
解決Java中由于數(shù)據(jù)太大自動(dòng)轉(zhuǎn)換成科學(xué)計(jì)數(shù)法的問(wèn)題
今天小編就為大家分享一篇解決Java中由于數(shù)據(jù)太大自動(dòng)轉(zhuǎn)換成科學(xué)計(jì)數(shù)法的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
利用Java實(shí)現(xiàn)更改Word中的頁(yè)面大小和頁(yè)面方向
這篇文章主要為大家詳細(xì)介紹了一種高效便捷的方法——通過(guò)Java應(yīng)用程序,以編程方式更改Word中的頁(yè)面大小和頁(yè)面方向,感興趣的可以了解一下2023-03-03

