日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构:关于AVL树的平衡旋转详解

發布時間:2025/3/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构:关于AVL树的平衡旋转详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

? 本文是基于你已經有一定的二叉排序樹知識。如果你還是小白,可以參考我之前的博客:《數據結構:二叉搜索樹(BST)的基本操作》。所以,在本文中不會再出現關于BST樹的基本知識。

?

版權說明

著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
作者:Q-WHai
發表日期: 2015年12月28日
鏈接:https://qwhai.blog.csdn.net/article/details/50393548
來源:CSDN
更多內容:分類 >> 算法與數學

?

概述

? AVL樹又叫做平衡二叉樹。前言部分我也有說到,AVL樹的前提是二叉排序樹(BST或叫做二叉搜索樹)。由于在生成BST樹的過程中可能會出現線型樹結構,比如插入的順序是:1, 2, 3, 4, 5, 6, 7..., n。在BST樹中,比較理想的狀況是每個子樹的左子樹和右子樹的高度相等,此時搜索的時間復雜度是log(N)。可是,一旦這棵樹演化成了線型樹的時候,這個理想的情況就不存在了,此時搜索的時間復雜度是O(N),在數據量很大的情況下,我們并不愿意看到這樣的結果。

? 現在我們要做的事就是讓BST在創建的過程中不要向線型樹發展。方法就是讓其在添加新節點的時候,不斷調整樹的平衡狀態。

? 定義:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹。

?

AVL樹實現

1.類圖

? 首先我們來看一下本文編寫代碼的類圖(見圖-1)。

? 因為考慮到圖片內容的篇幅問題,類圖中有一些地方的表述以eg.或getters(setters)省略掉了,詳細內容請以代碼為準。

? 知道策略模式或是看過我之前的博客《Java設計模式——策略模式》的都知道,這里我使用了策略模式來編寫代碼,4種不同的旋轉方式明顯的一個策略模式。這樣一來,代碼更加簡捷,邏輯也更加清晰了。

圖-1 AVL樹程序類圖

?

2.節點失衡

? 我們對于節點平衡有這樣的定義:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,并且左右兩個子樹都是一棵平衡二叉樹。而這里提到的高度差,就是我們下面會引入的平衡因子:BF

? 因為AVL樹說到底還是一個二叉樹,只有兩個子節點。而且節點失衡的發生,是因為有一個新節點的插入,這個新插入的節點導致了某些節點左右子節點高度的不一致。所以我們可以枚舉出以下4種情況的失衡狀態。

(1)在一個節點的左子樹的左子樹上插入一個新節點。即LL。在這種情況下,我們可以通過將節點右旋使其平衡。如圖-2所示;

圖-2 LL單右旋操作

(2)在一個節點的右子樹的右子樹上插入一個新節點。即RR。在這種情況下,我們可以通過將節點左旋使其平衡。如圖-3所示;

圖-3 RR單左旋操作

(3)在一個節點的左子樹的右子樹上插入一個新節點。即LR。在這種情況下,我們不能直接通過將節點左旋或右來使其平衡了。這里需要兩步來完成,先讓樹中高度較低的進行一次左旋,這個時候就變成了LL了。再進行一次單右旋操作即可。如圖-4所示;

圖-4 LR先左旋再右旋操作

(4)在一個節點的右子樹的左子樹上插入一個新節點。即RL。在這種情況下,我們不能直接通過將節點左旋或右來使其平衡了。這里需要兩步來完成,先讓樹中高度較低的進行一次右旋,這個時候就變成了RR了。再進行一次單左旋操作即可。如圖-5所示;

圖-5 RL先右旋再左旋操作

3.旋轉調節平衡

? 從上面對節點失衡的說明,以及圖解。我想你已經對旋轉的操作有了一個大概地認識了吧。從圖中我們也可以看出,LL型和RR型、LR型和RL型是兩個行為很相似地操作。其實他們互為對稱。所以在下面的講解中,我只針對LL型和LR型兩種操作進行詳細講解,另外兩種是類似的。

? 這里還有一點,可能讀者會有一些不是太明白。就是我們在旋轉的過程中,比如左旋,到底是怎么旋轉法,以哪個節點為中心點旋轉?

? 上面我們說到,失衡節點的平衡因子的絕對值是大于1的。AVL樹失衡類型的判斷都基于這個失衡節點的。也就是說LL型需要調整的是失衡節點的左子樹的左子樹,LR型需要調整的是失衡節點左子樹的右子樹。是不是有一點繞,看看上面的旋轉操作圖就應該知道了。那么,對于單旋轉操作也就很簡單了,就是以中間節點為中心旋轉。而雙旋轉中,因為不是一次旋轉,不能在一開始就確定旋轉中心點,我們在第一次旋轉的過程中,只是旋轉后面的兩個節點,并保證節點值的大小關系,如圖-4所示。后面的問題就轉化成了單旋轉操作了。

LL型:

? 針對圖-2所示的LL型失衡情況,可以看到節點15上是沒有右孩子的,這個時候轉成平衡之后,不用考慮節點15的右孩子與旋轉平衡調節之后的節點20是否有沖突。

? 關鍵代碼如下:

?

public class AdjustLL implements Adjustable {@Overridepublic void adjust(AVLTree tree, Node imbalanceNode) {Node parentNode = imbalanceNode.getParent();Node leftNode = imbalanceNode.getLeft(); // 新添加的節點resetImbalanceNode(imbalanceNode, leftNode);resetLeftNode(tree, leftNode, imbalanceNode, parentNode);resetParentNode(parentNode, leftNode);}/** 重置失衡節點* * @param imbalanceNode* 失衡節點*/private void resetImbalanceNode(Node imbalanceNode, Node leftNode) {... ...}/** 重置失衡節點的左節點* * @param leftNode* 左節點* @param imbalanceNode* 失衡節點* @param parentNode* 父節點*/private void resetLeftNode(AVLTree tree, Node leftNode, Node imbalanceNode, Node parentNode) {... ...}/** 重置父節點* * @param parentNode* 父節點* @param leftNode* 左節點*/private void resetParentNode(Node parentNode, Node leftNode) {... ...} }

?

RR型:

? 類似LL型,詳細代碼請參見下面的GitHub源碼。

RL型:

? 對于RL型的就比較麻煩一些了,比如我們現在插入的序列是這樣的:{20, 15, 30, 40, 25, 23}。那么在調整平衡之前,我們的樹結構是這樣的(如圖-6所示):

圖-6 RL型失衡

? 這時我們就不能直接進行一次左旋或是右旋就可以搞定的了。雖然我們不能一步直接達到我們的要求,但是分兩步就可以了呀。操作圖示參見圖-7.

圖-7 RL型失衡的旋轉過程

? 第一次右旋的關鍵代碼:

?

/** 第一次右旋* (此處方法調用的順序不要修改)* * @param tree* AVL樹* @param imbalanceNode* 失衡節點* @param rightChildNode* 失衡節點的右孩子* @param rightLeftNode* 失衡節點右孩子的左孩子*/private void firstRightAdjust(AVLTree tree, Node imbalanceNode, Node rightChildNode, Node rightLeftNode) {firstRightChildAdjust(rightChildNode, rightLeftNode);firstRightLeftAdjust(imbalanceNode, rightChildNode, rightLeftNode);firstImbalanceAdjust(imbalanceNode, rightLeftNode);}/** 調整失衡節點* * @param imbalanceNode* 失衡節點* @param rightLeftNode* 失衡節點右孩子的左孩子*/private void firstImbalanceAdjust(Node imbalanceNode, Node rightLeftNode) {imbalanceNode.setRight(rightLeftNode);imbalanceNode.resetHeight();imbalanceNode.resetBF();}/** 調整失衡節點的右孩子* * @param rightChildNode* 失衡節點的右孩子* @param rightLeftNode* 失衡節點右孩子的左孩子*/private void firstRightChildAdjust(Node rightChildNode, Node rightLeftNode) {rightChildNode.setParent(rightLeftNode);rightChildNode.setLeft(null);rightChildNode.resetHeight();rightChildNode.resetBF();}/** 調整失衡節點右孩子的左孩子* * @param imbalanceNode* 失衡節點* @param rightChildNode* 失衡節點的右孩子* @param rightLeftNode* 失衡節點右孩子的左孩子*/private void firstRightLeftAdjust(Node imbalanceNode, Node rightChildNode, Node rightLeftNode) {rightLeftNode.setRight(rightChildNode);rightLeftNode.setParent(imbalanceNode);rightLeftNode.resetHeight();rightLeftNode.resetBF();}

? 第二次左旋的關鍵代碼:

?

?

/** 第二次左旋* * @param tree* AVL樹* @param imbalanceNode* 失衡節點* @param rightChildNode* 失衡節點的右孩子* @param rightLeftNode* 失衡節點右孩子的左孩子*/private void secondLeftAdjust(AVLTree tree, Node imbalanceNode, Node rightChildNode, Node rightLeftNode) {Node parentNode = imbalanceNode.getParent();secondRightChildAdjust(rightChildNode);secondImbalanceAdjust(imbalanceNode, rightLeftNode);secondRightLeftAdjust(tree, imbalanceNode, rightLeftNode, parentNode);}/** 調整失衡節點* * @param imbalanceNode* 失衡節點* @param rightLeftNode* 失衡節點右孩子的左孩子*/private void secondImbalanceAdjust(Node imbalanceNode, Node rightLeftNode) {if (rightLeftNode.getLeft() != null) {imbalanceNode.setRight(rightLeftNode.getLeft());}imbalanceNode.setParent(rightLeftNode);imbalanceNode.resetHeight();imbalanceNode.resetBF();}/** 調整失衡節點的右孩子* * @param rightChildNode* 失衡節點的右孩子*/private void secondRightChildAdjust(Node rightChildNode) {rightChildNode.resetHeight();rightChildNode.resetBF();}/** 調整失衡節點右孩子的左孩子* * @param tree* AVL樹* @param imbalanceNode* 失衡節點* @param rightLeftNode* 失衡節點右孩子的左孩子* @param parentNode* 失衡節點的父節點*/private void secondRightLeftAdjust(AVLTree tree, Node imbalanceNode, Node rightLeftNode, Node parentNode) {rightLeftNode.setParent(parentNode);if (parentNode == null) {tree.resetRoot(rightLeftNode);}rightLeftNode.setLeft(imbalanceNode);rightLeftNode.resetHeight();rightLeftNode.resetBF();}

?

LR型:

? 類似RL型,詳細代碼請參見下面的GitHub源碼。

?

Ref

  • 數據結構(C語言版)--清華大學出版社
  • 大話數據結構--清華大學出版社

?

GitHub源碼下載

https://github.com/qwhai/simple-tree

總結

以上是生活随笔為你收集整理的数据结构:关于AVL树的平衡旋转详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。