【數據結構】之二叉樹

二叉樹是我們在數據結構中學到的第一個非線性結構,是后續學習更為復雜的樹、圖結構的基礎。本文整理了二叉樹的概念定義、基本操作、遍歷算法、偽代碼與代碼實現以及實例說明,方便大家隨時查找對應。

一、定義與基本術語

二叉樹是一種樹形結構,每個節點最多有兩個子節點,分別稱為左節點右節點

基本術語:

  • 根節點:樹的頂部節點。
  • 葉節點:沒有子節點的節點。
  • 父節點:某個節點的直接上級節點。
  • 子節點:某個節點的直接下級節點。
  • 兄弟節點:具有相同父節點的節點。
  • 深度:從根節點到某個節點的邊的數量。
  • 高度:從某個節點到最遠葉節點的邊的數量。

? ? ? ? A (Depth: 0, Root)
? ? ? ?/? ??
? ? ?B (Depth: 1)
? ? / ? \
?C1? ?C2(Depth: 2)
? ?\
? ? D (Depth: 3, Right)
? ? ?\
? ? ? E (Depth: 4, Right)
? ? ?/? \
? ? F1? ?F2(Depth: 4)?

二、主要特點

  1. 遞歸性質:二叉樹的許多操作可以通過遞歸實現。
  2. 動態集合:二叉樹可以用來實現動態集合,支持插入、刪除和查找操作。
  3. 層次結構:二叉樹具有明確的層次結構,適合表示具有層次關系的數據。

三、基本操作

1. 構建二叉樹:

① 構建節點:

struct TreeNode{int key;TreeNode* left;TreeNode* right;TreeNode(int k): key(k),left(nullptr),right(nullptr){}
};

② 插入節點:

插入操作會根據節點的值來決定插入的位置。例如,在二叉搜索樹(BST)中,插入操作遵循以下規則:

  • 如果當前節點的值大于插入值,則遞歸地插入到左子樹。
  • 如果當前節點的值小于插入值,則遞歸地插入到右子樹。
  • 如果當前節點的值等于插入值,則可以選擇不插入或插入到左/右子樹。
TreeNode* insert(TreeNode* node, int key){if(node == nullptr){return new TreeNode(key);}if(key < node->key){node->left = insert(node->left, key);}else if(key > node->key){node->right = insert(node->right,key);}return node;
}

③ 構建樹:

從一個空樹開始,通過多次插入節點,可以逐步構建二叉樹。

TreeNode* root = nullptr;
// 如果是基于一個給定數組構建二叉樹
for(int i = 0;i<length;i++){root = insert(root,nums[i]);
}
//手動輸入構建
root = insert(root,10);
root = insert(root,4);
root = insert(root, 7);
root = insert(root, 20);
root = insert(root, 34);
root = insert(root, 16);
root = insert(root, 8);

?2. 刪除節點:

TreeNode* deleteNode(TreeNode* node, int key){if(node == nullptr) return node;if(key < node->key){node->left = deleteNode(node->left, key);} else if (key > node->key) {node->right = deleteNode(node->right, key);}else{if(node->left == nullptr){TreeNode* tmp = node->right;delete node;return tmp;}else if(node->right == nullptr){TreeNode* tmp = node->left;delete node;return tmp;}TreeNode* temp = findMin(node->right);node->key = temp->key;node->right = deleteNode(node->right, temp->key);}return node;
}TreeNode* findMin(TreeNode* node){while(node->left != nullptr){node = node->left;}return node;
}

3. 查找節點:

TreeNode* searchNode(TreeNode* node, int key){if(node == nullptr||node->key = key) return node;if(key < node->key){return searchNode(node->left,key);}if(key > node->key){return searchNode(node->right, key);}
}

四、遍歷算法

需要了解:前序遍歷、中序遍歷、后序遍歷、層序遍歷

1. 前序遍歷:

? ? ? ? A
? ? ? ?/ \
? ? ? B ? C
? ? ?/ \ ? \
? ? D ? E ? F

遍歷順序:A->B->D->E->C->F

? ? ? ? 1
? ? ? ?/ \
? ? ? 2 ? 3
? ? ?/ \ ? \
? ? 4 ? 5 ? 6
? ?/ \
? 7 ? 8

遍歷順序:1->2->4->7->8->5->3->6

前序遍歷的訪問順序:根節點-->左子樹-->右子樹

// 以int整數型為例
vector<int> result
void preorder(TreeNode* node){if(node == nullptr){return;}// 如果題目要求的是前序遍歷打印節點值,那么可以直接:// cout<<node->key<<" ";// 如果題目要求前序遍歷將節點值存儲到數組中,需要先定義一個vector數組(如↑),再進行存儲result.push_back(node_key);preorder(node->left);preorder(nofe->right);
}

?2. 中序遍歷

? ? ? ? A
? ? ? ?/ \
? ? ? B ? C
? ? ?/ \ ? \
? ? D ? E ? F

遍歷順序:D->B->E->A->C->F

? ? ? ? 1
? ? ? ?/ \
? ? ? 2 ? 3
? ? ?/ \ ? \
? ? 4 ? 5 ? 6
? ?/ \
? 7 ? 8

遍歷順序:7->4->8->2->5->1->3->6?

? ? ? ? 10
? ? ? ?/? ? \
? ? ? 6 ? ?14
? ? ?/? \? ? /? ? \
? ? 4 ? 8 12 ?16

遍歷順序:4->6->8->10->12->14->16

中序遍歷的訪問順序:左子樹-->根節點-->右子樹

vector<int> result;
void inorder(TreeNode* node) {if (node == nullptr) return;inorder(node->left);visit(node);inorder(node->right);
}void visit(TreeNode* node){// cout<< node->key <<" ";result.push_back(node->key);
}

3. 后序遍歷

? ? ? ? A
? ? ? ?/ \
? ? ? B ? C
? ? ?/ \? ? ?\
? ? D ? E ? F

遍歷順序:D->E->B->F->C->A

? ? ? ? 1
? ? ? ?/ \
? ? ? 2 ? 3
? ? ?/? \? ? \
? ? 4 ? 5 ? 6
? ?/ \
? 7 ? 8

遍歷順序:7->8->4->5->2->6->3->1?

后序遍歷的訪問順序:左子樹->右子樹->根節點。

void postorder(TreeNode* node){if(node==nullptr) return;postorder(node->left);postorder(node->right);visit(node);
}
//visit函數要根據題目要求來定義,示例可參考中序遍歷的定義

4. 層序遍歷

? ? ? ? A
? ? ? ?/ \
? ? ? B ? C
? ? ?/ \? ? ?\
? ? D ? E ? F

遍歷順序:A->B->C->D->E->F

? ? ? ? 1
? ? ? ?/ \
? ? ? 2 ? 3
? ? ?/? ? /? \
? ? 4 ? 5 ? 6
? ? ? ? /
? ? ? 7?

遍歷順序:1->2->3->4->5->6->7

層序遍歷的順序是:從上到下,從左到右

層序遍歷的結果特別好寫,從上往下盯齊就沒問題,但是代碼是最長的。。

先來看看偽代碼:

LevelOrder(root)
? ? queue = new Queue()
? ? queue.enqueue(root)
? ? while not queue.isEmpty()
? ? ? ? node = queue.dequeue()
? ? ? ? visit(node)
? ? ? ? if node.left != null
? ? ? ? ? ? queue.enqueue(node.left)
? ? ? ? if node.right != null
? ? ? ? ? ? queue.enqueue(node.right)

void levelorder(TreeNode* root){if(root == nullptr) return;queue<TreeNode* > q; // 創建一個隊列,用于存儲待訪問的節點q.push(root); // 把現在的根節點存進去while(!q.empty()){TreeNode* node = q.front(); // 取出隊列的第一個節點q.pop(); // 將該節點從隊列中移除visit(node);if (node->left != nullptr) q.push(node->left);if (node->right != nullptr) q.push(node->right); // 這里加入隊列的順序是先左再右,隊列又是FIFO結構,遍歷得到的順序也就滿足了先左再右}
}

五、適用場景舉例

  1. 表達式樹:用于表示和計算算術表達式。
  2. 二叉搜索樹(BST):用于實現動態集合,支持高效的插入、刪除和查找操作。
  3. 哈夫曼樹:用于數據壓縮。
  4. :用于實現優先隊列。
  5. 線索二叉樹:用于高效地遍歷二叉樹。

六、Leetcode 二叉樹 練習題匯總

1.?初級題目

題號題目名稱知識點
94二叉樹的中序遍歷中序遍歷,遞歸與迭代
144二叉樹的前序遍歷前序遍歷,遞歸與迭代
145二叉樹的后序遍歷后序遍歷,遞歸與迭代
102二叉樹的層序遍歷層序遍歷,隊列的應用
226翻轉二叉樹遞歸,樹的翻轉
617合并二叉樹遞歸,樹的合并
589N叉樹的前序遍歷N叉樹,前序遍歷
897遞增順序搜索樹二叉搜索樹,中序遍歷的應用

2. 中級題目?

題號題目名稱知識點
98驗證二叉搜索樹二叉搜索樹的性質,遞歸
113路徑總和 II深度優先搜索,路徑求和
257二叉樹的所有路徑深度優先搜索,路徑記錄
114二叉樹展開為鏈表遞歸,樹的展開
116填充每個節點的下一個右側節點指針層序遍歷,隊列的應用
104二叉樹的最大深度深度優先搜索或層序遍歷
543二叉樹的直徑深度優先搜索,樹的直徑
236二叉樹的最近公共祖先遞歸,最近公共祖先

?希望對你有幫助!

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

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

相關文章

Honeyview:快速瀏覽各類圖像

Honeyview是一款免費、輕量級圖片查看工具?&#xff0c;專為快速瀏覽各類圖像設計&#xff0c;支持Windows系統?。其核心優勢在于?極速加載?與?廣泛格式兼容性?&#xff0c;可替代系統自帶的圖片查看工具&#xff0c;尤其適合需要處理專業圖像&#xff08;如PSD、RAW&…

Streamlit性能優化:緩存與狀態管理實戰

目錄 &#x1f4cc; 核心特性 &#x1f4cc; 運行原理 &#xff08;1&#xff09;全腳本執行 &#xff08;2&#xff09;差異更新 &#x1f4cc; 緩存機制 ?為什么使用緩存&#xff1f; 使用st.cache_data的優化方案 緩存適用場景 使用st.session_state的優化方案 &…

十七、TCP編程

TCP 編程是網絡通信的核心&#xff0c;其 API 圍繞面向連接的特性設計&#xff0c;涵蓋服務端和客戶端的交互流程。以下是基于 ?C 語言的 TCP 編程核心 API 及使用流程的詳細解析&#xff1a; 核心 API 概覽 ?函數?角色?描述socket()通用創建套接字&#xff0c;指定協議族…

將外網下載的 Docker 鏡像拷貝到內網運行

將外網下載的 Docker 鏡像拷貝到內網運行&#xff0c;可以通過以下步驟實現&#xff1a; 一、在有外網訪問權限的機器上操作 下載鏡像 使用docker pull命令下載所需的鏡像。例如&#xff0c;如果你需要下載一個名為nginx的鏡像&#xff0c;可以運行以下命令&#xff1a;docke…

《深入理解生命周期與作用域:以C語言為例》

&#x1f680;個人主頁&#xff1a;BabyZZの秘密日記 &#x1f4d6;收入專欄&#xff1a;C語言 &#x1f30d;文章目入 一、生命周期&#xff1a;變量的存在時間&#xff08;一&#xff09;生命周期的定義&#xff08;二&#xff09;C語言中的生命周期類型&#xff08;三&#…

Hqst的超薄千兆變壓器HM82409S在Unitree宇樹Go2智能機器狗的應用

本期拆解帶來的是宇樹科技推出的Go2智能機器狗&#xff0c;這款機器狗采用狗身體形態&#xff0c;前端設有激光雷達&#xff0c;攝像頭和照明燈。在腿部設有12個鋁合金精密關節電機&#xff0c;并配有足端力傳感器&#xff0c;通過關節運動模擬狗的運動&#xff0c;并可做出多種…

壹起航:15年深耕,引領中國工廠出海新征程

在全球化浪潮洶涌澎湃的當下&#xff0c;中國工廠正以前所未有的熱情和決心&#xff0c;將目光投向廣闊的海外市場。然而&#xff0c;出海之路并非一帆風順&#xff0c;建立品牌、獲取穩定詢盤、降低營銷成本等難題&#xff0c;如同橫亙在企業面前的高山&#xff0c;阻礙著他們…

【差分隱私相關概念】基礎合成定理和高級合成技術簡單關系

差分隱私中的合成定理用于分析多個機制組合時的隱私損失。基礎合成定理和高級合成技術分別在不同場景下提供了隱私預算增長的估計&#xff0c;其關系如下&#xff1a; 基礎合成定理&#xff08;線性增長&#xff09; 機制組合&#xff1a;當k個滿足(ε, δ)-DP的機制按順序組…

【異常處理】Clion IDE中cmake時頭文件找不到 頭文件飄紅

如圖所示是我的clion項目目錄 我自定義的data_structure.h和func_declaration.h在unit_test.c中無法檢索到 cmakelists.txt配置文件如下所示&#xff1a; cmake_minimum_required(VERSION 3.30) project(noc C) #設置頭文件的目錄 include_directories(${CMAKE_SOURCE_DIR}/…

MOS的驅動電流怎么計算?

一、MOS 驅動電流的計算方法 MOS 管在開關時&#xff0c;驅動電路主要是給柵極充放電。柵極電流 不是用來維持電流&#xff0c;而是用來克服電容的充放電需求&#xff0c;尤其是總柵極電荷 Qg。 驅動電流估算公式如下&#xff1a; I_drive Qg f_sw&#xff08;Qg&#xff…

GGML源碼逐行調試(下)

目錄 前言1. 簡述2. 預分配計算圖內存2.1 創建圖內存分配器2.2 構建最壞情況的計算圖2.3 預留計算圖內存 3. 分詞4. 模型推理與生成4.1 模型推理4.2 采樣 結語下載鏈接參考 前言 學習 UP 主 比飛鳥貴重的多_HKL 的 GGML源碼逐行調試 視頻&#xff0c;記錄下個人學習筆記&#x…

1.5-APP的架構\微信小程序的架構

1.5-APP的架構\微信小程序的架構 APP的三種開發架構&#xff1a; 原生態APP類型 APP-開發架構-原生態-IDEA 演示&#xff1a;remusic項目源碼 NP管理器&#xff1a; http://normalplayer.top/ HttpCanary&#xff1a;https://github.com/mingww64/HttpCanary-SSL-Magisk 安全影…

用css畫一條弧線

ui里有一條弧線&#xff0c;現在用css實現 關鍵代碼 border-bottom-left-radius: 100% 7px 兩個參數分別代表橫向和縱向的深度border-bottom-right-radius: 100% 7px

MSCKF及可觀性總結

可觀性 參考鏈接 真實VIO系統不能觀的維度是4&#xff08;位置和yaw角&#xff09;&#xff0c;由于EKF的轉移和觀測Jacobian矩陣的線性化點不同、不可觀方向噪聲的存在&#xff0c;實際MSCKF不能觀的維度變成了3&#xff0c;繞重力軸的旋轉&#xff08;yaw角&#xff09;被錯…

【Hotspot虛擬機創建對象的過程是什么樣的?】

1. 類加載檢查 觸發條件&#xff1a;當遇到 new 指令時&#xff0c;JVM首先檢查該指令的參數&#xff08;類符號引用&#xff09;是否已在常量池中。檢查內容&#xff1a; 類是否已被加載、解析和初始化。若未加載&#xff0c;則觸發類加載過程&#xff08;加載 → 驗證 → 準…

南墻WAF非標端口防護實戰解析——指定端口安全策略深度剖析

本文系統解析非標端口DDoS攻擊防護難點&#xff0c;重點闡述南墻WAF在指定端口防御中的技術突破。通過某金融機構真實攻防案例&#xff0c;結合Gartner最新防御架構模型&#xff0c;揭示如何構建基于智能流量建模的精準防護體系&#xff0c;為金融、政務等關鍵領域提供可落地的…

Context的全面解析:在不同技術應用中的通用作用與差異

Context的全面解析&#xff1a;在不同技術應用中的通用作用與差異 引言&#xff1a; 在軟件開發中&#xff0c;“Context”這個概念被廣泛使用。它不僅限于某個特定的技術或編程語言&#xff0c;實際上&#xff0c;Context 作為一種抽象的設計模式&#xff0c;貫穿在許多開發領…

尋找峰值 --- 二分查找

目錄 一&#xff1a;題目 二&#xff1a;算法原理 三&#xff1a;代碼實現 一&#xff1a;題目 題目鏈接&#xff1a;162. 尋找峰值 - 力扣&#xff08;LeetCode&#xff09; 二&#xff1a;算法原理 三&#xff1a;代碼實現 class Solution { public:int findPeakElemen…

基礎算法訓練7

目錄 庫存管理II 翻轉對 合并K個升序鏈表 存在重復元素II 字符串相乘 字符串解碼 在每個樹行中找最大值 數據流的中位數 被包圍的區域 為高爾夫比賽砍樹 庫存管理II LCR 159. 庫存管理 III - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;先進行排序&a…

從單機版到超級APP:MCP如何解鎖AI的超能力

MCP&#xff1a;AI界的“萬能充電寶”——讓AI從此告別“語言不通”的尷尬&#xff01; 開篇&#xff1a;AI咖啡館的尷尬日常 想象一下這樣的場景&#xff1a; 一位AI助手在咖啡館里手忙腳亂——它想幫用戶點杯咖啡&#xff0c;但需要先寫代碼調用天氣API&#xff08;“今天下…