數據結構:生成 (Generating) 一棵 AVL 樹

目錄

搭建“創世”的舞臺

注入序列,觀察演化

注入 10

注入 20

注入 30

注入 40

注入 50

注入 25

再次審視


上一講,我們已經從最根本的邏輯出發,推導出了 AVL 樹失衡時所必需的修復操作——旋轉 (Rotation)。

現在,我們將進入一個非常實踐性的環節:如何從無到有地生成 (Generating) 一棵 AVL 樹?

這個問題的本質,其實是一個思想實驗:

如果我們擁有一臺“AVL 插入機”(也就是我們上一講實現的 insert 函數),我們把一堆數字一個一個地扔給它,這臺機器內部會發生什么?最終會得到一個什么樣的產品?

搭建“創世”的舞臺

在開始之前,我們需要三樣東西:

1. 一個起點 (The Starting Point): 一個空的世界,也就是一棵空樹。在 C/C++ 代碼中,我們用一個 NULL 指針來表示。

// 我們的宇宙之初,只有一個指向虛空的根指針
AVLTreeNode* root = NULL;

2. 一套基本法則 (The Rules): 這就是我們上一講嘔心瀝血推導出的 insert 函數。它內部封裝了 BST 的插入邏輯、高度 (Height) 的更新、平衡因子 (Balance Factor, BF) 的檢查,以及四種旋轉 (Rotation) 修復機制。

3. 一串生命序列 (The Sequence): 我們將要注入的數字。為了充分展示樹的演化過程,我們需要一個能觸發各種情況的序列。我們選用這個經典的序列:[10, 20, 30, 40, 50, 25]

我們的整個“生成”過程,在代碼層面其實非常簡潔,就是一個循環,不斷地調用我們的基本法則 insert 函數。

數據結構:利用旋轉在AVL樹中維持平衡(Inserting in AVL with Rotation)-CSDN博客

// 引入頭文件,以便我們可以打印輸出觀察每一步
#include <iostream>// ... 此處省略我們之前已經定義的 AVLTreeNode 結構體、
// createNode, getHeight, max, leftRotate, rightRotate, insert 等函數 ...// 主程序,也就是我們的“創世”過程
int main() {AVLTreeNode* root = NULL; // 1. 起點:空樹int keys[] = {10, 20, 30, 40, 50, 25}; // 3. 生命序列int n = sizeof(keys) / sizeof(keys[0]);std::cout << "Starting to generate the AVL tree..." << std::endl;std::cout << "------------------------------------" << std::endl;for (int i = 0; i < n; ++i) {std::cout << "\n>>> Inserting " << keys[i] << "..." << std::endl;// 2. 反復調用我們的基本法則root = insert(root, keys[i]);// 為了便于觀察,我們可以在這里加上一個打印樹結構的函數(此處省略其實現)// printTree(root); std::cout << ">>> ... " << keys[i] << " inserted. Tree is now balanced." << std::endl;}std::cout << "\n------------------------------------" << std::endl;std::cout << "Generation complete." << std::endl;return 0;
}

代碼框架已經搭好,現在,讓我們進入核心環節,手動模擬上面這段代碼的執行過程,觀察樹的每一步演化。


注入序列,觀察演化

注入 10
  • 演化過程: 樹為空,insert 函數直接創建一個新節點作為根。

  • 最終形態:樹誕生了,它是平衡的。

(10) {h=0, BF=0}  // h 是 Height(高度), BF 是 Balance Factor(平衡因子)
注入 20
  • 演化過程:

    1. 根據 BST 法則, 20 > 10,插入到 10 的右側。

    2. 插入后回溯,更新路徑上的節點。節點 10 的高度 h 更新為 1,其平衡因子 BF 變為 height(left) - height(right) = -1 - 0 = -1

    3. |BF| <= 1,樹依然平衡。

  • 最終形態:

  (10) {h=1, BF=-1}\(20) {h=0, BF=0}
注入 30
  • 演化過程:

    1. 根據 BST 法則, 30 > 10 (向右) -> 30 > 20 (向右),插入到 20 的右側。

    2. 回溯更新:

      • 20 節點:h 更新為 1, BF 更新為 -1。平衡。

      • 10 節點:h 更新為 2, BF 更新為 height(left) - height(right) = -1 - 1 = -2

    3. 警報! 節點 10BF 絕對值變為 2樹失衡 (Unbalanced)!

  • 診斷與修復:

    • 失衡節點 A10 (BF=-2)。

    • 失衡是由于在 A 的右 (Right)子樹 (B=20) 的右 (Right)側插入新節點導致的。

    • 這是典型的 RR (右-右) 失衡。

    • 根據我們的法則,需要對失衡節點 10 執行一次 左旋 (Left Rotation)。

  • 修復后形態:

  (20) {h=1, BF=0}/  \
(10) (30) {h=0, BF=0}
注入 40
  • 演化過程: 40 根據 BST 法則插入為 30 的右孩子。回溯檢查,所有節點的 BF 均在 [-1, 1] 區間內。

  • 最終形態: 無需旋轉。

  (20) {h=2, BF=-1}/  \
(10) (30) {h=1, BF=-1}\(40) {h=0, BF=0}
注入 50
  • 演化過程:

    1. 50 插入為 40 的右孩子。

    2. 回溯更新,當檢查到 30 節點時,其 h 變為 2,BF 變為 -2失衡!

  • 診斷與修復:

    • 失衡節點 A30 (BF=-2)。

    • 失衡路徑是 右-右 (RR)。

    • 修復操作:對 30 執行 左旋 (Left Rotation)。40 會取代 30 的位置,成為 20 的右孩子。

  • 修復后形態:

      (20) {h=2, BF=-1}/  \(10) (40) {h=1, BF=0}/  \(30) (50)

系統再次自我修復,恢復平衡。

注入 25
  • 演化過程:

    1. 根據 BST 法則: 25>20 (右) -> 25<40 (左) -> 25<30 (左)。25 插入為 30 的左孩子。

    2. 回溯更新:

      • 30 節點: h 變為 1, BF 變為 1。平衡。

      • 40 節點: h 變為 2, BF 變為 1。平衡。

      • 20 節點: h 變為 3, BF 變為 height(left) - height(right) = 0 - 2 = -2。 失衡!

  • 診斷與修復:

    • 失衡節點 A20 (BF=-2)。

    • 失衡發生在 A右 (Right)子樹 (根為 40)。

    • 新節點 25 是插入在該子樹的左 (Left)側

    • 這是一個 RL (右-左) 的“拐角”型失衡。

    • 根據法則,需要兩步操作:

      1. “拉直”拐角: 對 A 的孩子節點 40,執行一次右旋 (Right Rotation)。

      2. 整體修復: 對 A 節點 20,執行一次左旋 (Left Rotation)。

  • 修復后最終形態:

      (30)/    \(20)    (40)/  \      \
(10) (25)    (50)

經歷了一次復雜的重構后,系統演化出了一個極為穩定和平衡的最終形態。


再次審視

我們完成了整個生成過程。回過頭看,我們得到了什么結論?

  • 自組織性 (Self-Organization): 我們從未規劃過最終那棵樹長什么樣。我們只定義了最基本的、局部的交互規則(插入和旋轉)。一個高度平衡的、優美的全局結構,是自發涌現出來的。

  • 動態平衡 (Dynamic Equilibrium): AVL 樹不是靜止的。每次有新的元素加入,都會暫時打破它的平衡,然后系統會通過一系列的調整,迅速回歸到一個新的平衡狀態。這是一種動態的、有彈性的穩定。

  • 局部決定全局 (Local Actions, Global Consequences): 每次修復操作(旋轉)都只涉及兩到三個節點。然而,就是這樣微小的局部調整,確保了整棵樹的全局屬性——對數級別的高度,從而保證了 O(logn) 的操作效率。

這就是從第一性原理理解“生成 AVL 樹”——它不是一個按圖索驥的建造過程,而是一個遵循簡單規則、不斷演化的創生過程。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93849.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93849.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93849.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

github 上傳代碼步驟

登錄GitHub → 點擊右上角 ?? → New Repository??。填寫倉庫名稱&#xff08;建議與本地項目同名&#xff09;&#xff0c;選擇 ??Public/Private??。??關鍵&#xff1a;不要勾選?? “Initialize with README”&#xff08;避免與本地倉庫沖突&#xff09;。點擊 …

陪診小程序系統開發:開啟智慧就醫新時代

在數字化浪潮的推動下&#xff0c;智慧醫療正逐漸成為現實。陪診小程序系統的開發&#xff0c;作為智慧醫療領域的一次重要創新&#xff0c;正以其獨特的魅力與優勢&#xff0c;引領著就醫新時代的到來。它不僅改變了傳統就醫模式&#xff0c;更以科技的力量&#xff0c;讓醫療…

朝花夕拾(七)--------從混淆矩陣到分類報告全面解析?

目錄 ??機器學習模型評估指南&#xff1a;從混淆矩陣到分類報告全面解析?? ??1. 引言?? ??2. 混淆矩陣&#xff1a;模型評估的基石?? ??2.1 什么是混淆矩陣&#xff1f;?? 2.2二分類問題的混淆矩陣 ??二分類場景下的具體案例? ?分析案例: 1.??案例…

Python讀取和設置PNG圖片的像素值

在Python中&#xff0c;可以使用Pillow庫或OpenCV庫來讀取和寫入PNG圖片的像素值。以下是兩種方法的詳細說明&#xff1a;1. 使用Pillow庫Pillow是Python中常用的圖像處理庫&#xff0c;支持多種圖像格式&#xff0c;包括PNG。讀取像素值from PIL import Imageimg Image.open(…

SkyWalking + Elasticsearch8 容器化部署指南:國內鏡像加速與生產級調優

SkyWalking Elasticsearch8 Docker 部署文檔本文提供在 Ubuntu 服務器上&#xff0c;使用 Docker Compose 部署 SkyWalking&#xff08;OAPUI&#xff09;與 Elasticsearch 8 的完整步驟&#xff0c;數據/日志落地到 /media/disk2 前置條件 Ubuntu&#xff0c;已具備 sudo 權限…

有符號和無符號的區別

有符號&#xff08;Signed&#xff09;和無符號&#xff08;Unsigned&#xff09;是計算機編程中用來描述整數數據類型能否表示負數的兩個概念。它們的主要區別在于能否表示負數以及數值的表示范圍。以下是它們的核心區別&#xff1a;1. 能否表示負數有符號&#xff08;Signed&…

8月21日作業

1、Makefile中頭文件發生過修改的解決&#xff1a; 處插入*.h依賴&#xff0c;對.h文件打的時間戳進行檢查2、頭刪和輸出//五、頭刪 void delete_head(seq_p s) {empty(s);for(int i1;i<s->len;i){s->data[i-1]s->data[i];}s->len--; }//六、輸出 void output(s…

Lucene 8.5.0 的 `.pos` 文件**邏輯結構**

Lucene 8.5.0 的 .pos 文件**邏輯結構**&#xff08;按真實實現重新整理&#xff09; .pos 文件 ├─ Header (CodecHeader) ├─ TermPositions TermCount ← 每個 term 一段&#xff0c;順序由詞典隱式決定 │ ├─ PackedPosDeltaBlock N ← 僅當 **無 payl…

基于Matlab多技術融合的紅外圖像增強方法研究

紅外圖像在低照度、強干擾和復雜環境下具有較強的成像能力&#xff0c;但受傳感器噪聲、成像條件及大氣衰減等因素影響&#xff0c;原始紅外圖像往往存在對比度低、細節模糊及光照不均等問題。本文針對紅外圖像質量退化的特點&#xff0c;提出了一種基于多算法融合的紅外圖像增…

【時時三省】集成測試 簡介

山不在高,有仙則名。水不在深,有龍則靈。 ----CSDN 時時三省 目錄 1,集成測試含義 2,集成測試 驗證方法 3,集成測試 用例設計方法 4,集成測試輸出物 5,集成測試注意點 1,集成測試含義 單元測試在以V模型的流程中,對應的是架構設計階段。在 單元測試 和 架構設計…

leetcode 76 最小覆蓋子串

一、題目描述二、解題思路整體思路&#xff1a;模擬尋找最小覆蓋子集的過程&#xff0c;由于可借助同向雙指針且可以做到指針不回退&#xff0c;所以可以用滑動窗口的思想來解決這個問題。具體思路&#xff1a;(1)數組hash1用于統計t中每一個字符出現的頻次&#xff0c;變量kin…

阿里云ECS服務器的公網IP地址

文章目錄環境背景查詢公網IP地址阿里云控制臺阿里云客戶端工具&#xff08;圖形界面&#xff09;阿里云CLI工具&#xff08;命令行&#xff09;其它方法元數據服務器ipinfo.io參考注&#xff1a;本文介紹了如何獲取阿里云ECS服務器的公網IP地址&#xff0c;可以順便了解一下和阿…

IPSec 與 IKE 核心知識點總結

一、IPSec 安全基礎IPSec 是保障 IP 數據傳輸安全的核心協議&#xff0c;其核心圍繞密鑰管理和安全策略約定展開&#xff0c;具體包括以下關鍵內容&#xff1a;1. 對稱密鑰的作用與要求對稱密鑰是 IPSec 實現加密、驗證的基礎&#xff0c;主要用于三個場景&#xff1a;加密 / 解…

C2ComponentStore

1. C2ComponentStore這是 Codec 2.0 HAL 的抽象接口&#xff08;frameworks/av/media/codec2/core/include/C2ComponentStore.h&#xff09;。代表一個「組件工廠」&#xff0c;負責&#xff1a;枚舉當前可用的 Codec2 組件&#xff08;解碼器、編碼器&#xff09;。創建組件&a…

AI 在醫療領域的應用與挑戰

引言介紹 AI 技術迅猛發展的大背景&#xff0c;引出其在醫療領域的重要應用。闡述研究 AI 醫療應用及挑戰對推動醫療行業進步的重要意義。AI 在醫療領域的應用現狀疾病診斷輔助&#xff1a;描述 AI 影像識別技術在識別 X 光、CT、MRI 影像中疾病特征的應用&#xff0c;如對肺癌…

【GPT入門】第51課 Conda環境遷移教程:將xxzh環境從默認路徑遷移到指定目錄

【GPT入門】第51課 Conda環境遷移教程&#xff1a;將xxzh環境從默認路徑遷移到指定目錄步驟1&#xff1a;創建目標目錄&#xff08;若不存在&#xff09;步驟2&#xff1a;克隆環境到新路徑步驟3&#xff1a;驗證新環境可用性步驟4&#xff1a;刪除舊環境&#xff08;可選&…

應急響應-模擬服務器掛馬后的應急相關操作

工具&#xff1a;攻擊機&#xff1a; kail:192.168.108.131 kail下載地址&#xff1a;https://mirrors.aliyun.com/kali-images/kali-2021.3/kali-linux-2021.3-live-i386.iso靶機&#xff1a;windows 7: 192.168.108.1321、在kali中制作木馬文件&#xff1a;vhost.exe&#xf…

記一次 .NET 某光譜檢測軟件 內存暴漲分析

一&#xff1a;背景 1. 講故事 訓練營里的一位學員找到我&#xff0c;說他們的系統會出現內存暴漲的情況&#xff0c;看了下也不是托管堆的問題&#xff0c;讓我協助一下到底怎么回事&#xff1f;既然有dump了&#xff0c;那就開始分析之旅吧。 二&#xff1a;內存暴漲分析 1. …

基于OpenCV的物體識別與計數

在計算機視覺領域&#xff0c;利用圖像處理技術進行物體識別和計數是一項基礎且重要的任務。本文將介紹一種使用OpenCV庫實現的高效物體識別與計數方法&#xff0c;并提供一些代碼片段以幫助理解各個步驟。 這是前幾年做過傳統圖像處理計數的項目&#xff0c;通過傳統圖像處理之…

算法題打卡力扣第34題:在排序數組中查找元素的第一個和最后一個位置(mid)

題目描述提示&#xff1a; 0 < nums.length < 105 -109 < nums[i] < 109 nums 是一個非遞減數組 -109 < target < 109 解題思路一 暴力解 頭到尾遍歷整個數組。 用一個變量 first 記錄第一次遇到 target 的索引。 繼續遍歷&#xff0c;用另一個變量 last 不斷…