【C++高階一】二叉搜索樹

【C++高階一】二叉搜索樹剖析

  • 1.什么是二叉搜索樹
  • 2.二叉搜索樹非遞歸實現
    • 2.1插入
    • 2.2刪除
      • 2.2.1刪除分析一
      • 2.2.2刪除分析二
    • 2.3查找
  • 3.二叉搜索樹遞歸實現
    • 3.1插入
    • 3.2刪除
    • 3.3查找
  • 4.完整代碼

1.什么是二叉搜索樹

任何一個節點,他的左子樹的所有節點都比他小,右子樹的所有節點都比他大

在這里插入圖片描述

二叉搜索樹是有序的,中序遍歷這棵二叉搜索樹剛好是升序
時間復雜度為O(N),因為會出現這種極端情況
在這里插入圖片描述
二叉搜索樹中不能出現值相同的節點

2.二叉搜索樹非遞歸實現

大致框架

template<class K>
struct BSTreeNode //二叉搜索樹節點
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};template<class K>
class BSTree//二叉搜索樹
{typedef BSTreeNode<K> Node;
public:private:Node* _root = nullptr;
};

2.1插入

插入的值比根大就往右走,比根小就往左走,如果遇見和插入值相同的值就返回false

bool insert(const k& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else {parent->_right = cur;}return true;}

parent保存每一步的父節點,在插入之后起到父子節點連接作用

2.2刪除

2.2.1刪除分析一

  1. 被刪除節點無孩子:
    直接將此節點刪除,不用做特殊處理
  2. 被刪除節點只有左孩子:
    此節點被刪除后,將此節點的左孩子連接到此節點的父親節點
  3. 被刪除節點只有右孩子:
    此節點被刪除后,將此節點的右孩子連接到此節點的父親節點
bool erase(const k& key)
{Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if(cur->_key > key){parent = cur;cur = cur->_right;}else//找到了{if (cur->_left == nullptr)//左孩子為空{if (cur == _root)_root = cur->_right;else{if (cur == parent->_right)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr)//右孩子為空{if (cur == _root)_root = cur->_left;else{if (cur == parent->_right)parent->_right = cur->_leftelseparent->_left = cur->_left;}delete cur;}//第四種情況 //else{}}}return false}

表面只寫了兩種情況,其實已經把無孩子的情況包括了

2.2.2刪除分析二

當被刪除的節點存在左右孩子時,我們要使用替換法
被替換的節點一定要滿足一個條件:
是左子樹的最大值 || 是右子樹的最小值
在這里插入圖片描述

假設使用右子樹中最小的節點來替換,其左孩子為空,但右孩子未知,還需要分情況討論

else//左右孩子都不為空
{//用右子樹最小值來替換Node* Temp_parent = cur;//臨時父節點Node* R_subtree_min = cur->_right;//右子樹最小值while (R_subtree_min->_left){Temp_parent = R_subtree_min;R_subtree_min = R_subtree_min->_left;}swap(cur->_key, R_subtree_min->_key);if (R_subtree_min == Temp_parent->_left){Temp_parent->_left = R_subtree_min->_right;}else{Temp_parent->_right = R_subtree_min->_right;}delete R_subtree_min;
}

2.3查找

bool find(const K& key)
{Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;
}

3.二叉搜索樹遞歸實現

遞歸實現全都使用了函數嵌套的方式,是為了使用_root這個定義在類中的成員變量

3.1插入

插入的基本思路一樣,但遞歸到空時構建新節點的鏈接有三種方式:
1.多傳一個參數,記錄父節點
2.遞歸到空節點的上一層,比如if(root->_left==NULL) 開始構建節點
3.傳引用
前兩個方法和循環寫法沒什么區別,下面都使用傳引用

bool Re_insert(const K& key)
{return _Re_insert(_root, key);
}bool _Re_insert(Node*& root, const K& key)
{if (root == nullptr){root = new Node(key);return true;}if (root->_key > key){return _Re_insert(root->_left, key);}else if (root->_key < key){return _Re_insert(root->_right, key);}else{return false;}
}

3.2刪除

bool Re_erase(const K& key)
{return _Re_erase(_root, key);
}
bool _Re_erase(Node*& root, const K& key)
{if (root == nullptr)return false;if (root->_key > key){return _Re_erase(root->_left, key);}else if (root->_key < key){return _Re_erase(root->_right, key);}else//找到了,準備刪除{if (root->_left == nullptr)//左孩子為空{Node* temp = root;root = root->_right;delete temp;return true;}else if (root->_right == nullptr)//右孩子為空{Node* temp = root;root = root->_left;delete temp;return true;}else//左右孩子都不為空{//找右子樹的最小值Node* temp = root->_right;while (temp->_left){temp = temp->_left;}swap(root->_key, temp->_key);return _Re_erase(root->_right, key);}}
}

3.3查找

bool Re_find(const K& key)
{return _Re_find(_root, key);
}
private:
bool _Re_find(Node* root,const K& key)
{if (root == nullptr)return false;if (root->_key > kry){return _Re_find(root->_left, key);}else if (root->_key < kry){return _Re_find(root->_right, key);}else{return true;}
}

4.完整代碼

template<class K>
struct BSTreeNode //二叉搜索樹節點
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};template<class K>
class BSTree//二叉搜索樹
{typedef BSTreeNode<K> Node;
public:bool insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{return false;}}cur = new Node(key);if (parent->_key > key){parent->_left = cur;}else {parent->_right = cur;}return true;}bool erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if(cur->_key < key){parent = cur;cur = cur->_right;}else//找到了,準備刪除{if (cur->_left == nullptr)//左孩子為空{if (cur == _root)_root = cur->_right;else{if (cur == parent->_right)parent->_right = cur->_right;elseparent->_left = cur->_right;}delete cur;}else if (cur->_right == nullptr)//右孩子為空{if (cur == _root)_root = cur->_left;else{if (cur == parent->_right)parent->_right = cur->_leftelseparent->_left = cur->_left;}delete cur;}else//左右孩子都不為空{//用右子樹最小值來替換Node* Temp_parent = cur;//臨時父節點Node* R_subtree_min = cur->_right;//右子樹最小值while (R_subtree_min->_left){Temp_parent = R_subtree_min;R_subtree_min = R_subtree_min->_left;}swap(cur->_key, R_subtree_min->_key);if (R_subtree_min == Temp_parent->_left){Temp_parent->_left = R_subtree_min->_right;}else{Temp_parent->_right = R_subtree_min->_right;}delete R_subtree_min;}return true;}}return false;}bool find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;}bool Re_insert(const K& key){return _Re_insert(_root, key);}bool Re_erase(const K& key){return _Re_erase(_root, key);}bool Re_find(const K& key){return _Re_find(_root, key);}
private:bool _Re_insert(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key > key){return _Re_insert(root->_left, key);}else if (root->_key < key){return _Re_insert(root->_right, key);}else{return false;}}bool _Re_erase(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key > key){return _Re_erase(root->_left, key);}else if (root->_key < key){return _Re_erase(root->_right, key);}else//找到了,準備刪除{if (root->_left == nullptr)//左孩子為空{Node* temp = root;root = root->_right;delete temp;return true;}else if (root->_right == nullptr)//右孩子為空{Node* temp = root;root = root->_left;delete temp;return true;}else//左右孩子都不為空{//找右子樹的最小值Node* temp = root->_right;while (temp->_left){temp = temp->_left;}swap(root->_key, temp->_key);return _Re_erase(root->_right, key);}}}bool _Re_find(Node* root,const K& key){if (root == nullptr)return false;if (root->_key > kry){return _Re_find(root->_left, key);}else if (root->_key < kry){return _Re_find(root->_right, key);}else{return true;}}
private:Node* _root = nullptr;
};

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

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

相關文章

前端面試熱門知識點總結

URL從輸入到頁面展示的過程 版本1 1.用戶在瀏覽器的地址欄輸入訪問的URL地址。瀏覽器會先根據這個URL查看瀏覽器緩存-系統緩存-路由器緩存&#xff0c;若緩存中有&#xff0c;直接跳到第6步操作&#xff0c;若沒有&#xff0c;則按照下面的步驟進行操作。 2.瀏覽器根據輸入的UR…

Swagger | 解決Springboot2.x/3.x不兼容和依賴報錯等問題

目錄 不兼容報錯提醒 1. 修改Spring Boot版本 2. 修改application.yml配置文件 3. 使用其他替代方案 依賴兼容 配置 Yaml 文件 依賴報錯提醒 解決方法 1. 選擇一個庫 2. 移除springfox依賴 3. 添加springdoc依賴 4. 配置springdoc 5. 清理項目 6. 啟動項目 示例代…

C++默認構造函數、普通構造函數、拷貝構造、移動構造、委托構造及析構函數深度解析

目錄 一、默認構造函數&#xff08;Default Constructor&#xff09;二、普通構造函數&#xff08;General Constructor&#xff09;三、拷貝構造函數&#xff08;Copy Constructor&#xff09;四、移動構造函數&#xff08;Move Constructor&#xff0c;C11&#xff09;五、委…

JVM 深度解析

一、JVM 概述 1.1 什么是 JVM&#xff1f; JVM&#xff08;Java Virtual Machine&#xff0c;Java 虛擬機&#xff09;是 Java 程序運行的核心引擎。它像一個“翻譯官”&#xff0c;將 Java 字節碼轉換為機器能理解的指令&#xff0c;并管理程序運行時的內存、線程等資源。 …

OpenCV CUDA 模塊圖像過濾-----創建一個計算圖像導數的濾波器函數createDerivFilter()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 cv::cuda::createDerivFilter 是 OpenCV CUDA 模塊中的一個工廠函數&#xff0c;用于創建一個計算圖像導數的濾波器。這個濾波器可以用來計算圖像…

Spring Boot 接口開發實戰指南

Spring Boot 接口開發實戰指南 一、基礎接口開發步驟 1.1 添加必要依賴 <!-- pom.xml --> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></depen…

題目 3325: 藍橋杯2025年第十六屆省賽真題-2025 圖形

題目 3325: 藍橋杯2025年第十六屆省賽真題-2025 圖形 時間限制: 2s 內存限制: 192MB 提交: 494 解決: 206 題目描述 小藍要畫一個 2025 圖形。圖形的形狀為一個 h w 的矩形&#xff0c;其中 h 表示圖形的高&#xff0c;w 表示圖形的寬。當 h 5,w 10 時&#xff0c;圖形如下所…

UML 時序圖 使用案例

UML 時序圖 UML 時序圖 (Sequence Diagram)時序圖的主要元素消息類型詳解時序圖示例時序圖繪制步驟時序圖的應用場景 UML 時序圖 (Sequence Diagram) 時序圖是UML(統一建模語言)中用于展示對象之間交互行為的動態視圖&#xff0c;它特別強調消息的時間順序。 時序圖的主要元素…

PPT連同備注頁(演講者模式)一塊轉為PDF

首先&#xff0c;進入創建PDF/XPS&#xff1a; 然后進入選項&#xff1a; 發布選項-發布內容里選備注頁&#xff1a; 導出的原始結果是這樣的&#xff1a; 這個時候裁剪一下&#xff0c;范圍為所有頁面&#xff1a; 最終結果&#xff1a; 如果導出不選“備注頁”而是只勾選“包…

AI時代新詞-多模態(Multimodal)

一、什么是多模態&#xff08;Multimodal&#xff09;&#xff1f; 多模態&#xff08;Multimodal&#xff09;是指在人工智能中&#xff0c;融合多種不同類型的信息&#xff08;如文本、圖像、語音、視頻等&#xff09;進行處理和分析的技術。與傳統的單一模態&#xff08;例…

【圖像大模型】Stable Diffusion XL:下一代文本到圖像生成模型的技術突破與實踐指南

Stable Diffusion XL&#xff1a;下一代文本到圖像生成模型的技術突破與實踐指南 一、架構設計與技術演進1.1 核心架構革新1.2 關鍵技術突破1.2.1 雙文本編碼器融合1.2.2 動態擴散調度 二、系統架構解析2.1 完整生成流程2.2 性能指標對比 三、實戰部署指南3.1 環境配置3.2 基礎…

圖像分割技術的實現與比較分析

引言 圖像分割是計算機視覺領域中的一項基礎技術&#xff0c;其目標是將數字圖像劃分為多個圖像子區域&#xff08;像素的集合&#xff09;&#xff0c;以簡化圖像表示&#xff0c;便于后續分析和理解。在醫學影像、遙感圖像分析、自動駕駛、工業檢測等眾多領域&#xff0c;圖…

摩爾線程S4000國產信創計算卡性能實戰——Pytorch轉譯,多卡P2P通信與MUSA編程

簡介 MTT S4000 是基于摩爾線程曲院 GPU 架構打造的全功能元計算卡&#xff0c;為千億規模大語言模型的訓練、微調和推理進行了定制優化&#xff0c;結合先進的圖形渲染能力、視頻編解碼能力和超高清 8K HDR 顯示能力&#xff0c;助力人工智能、圖形渲染、多媒體、科學計算與物…

「從0到1」構建工業物聯網監控系統:ARM+Quarkus+Prometheus技術棧全記錄

在工業4.0浪潮中&#xff0c;邊緣計算正成為智能制造的核心基礎設施。ARM架構邊緣計算機憑借其低功耗、高能效比和模塊化設計優勢&#xff0c;正在重塑工業物聯網&#xff08;IIoT&#xff09;的監控體系。當Java的跨平臺能力與Prometheus的實時監控體系相結合&#xff0c;為工…

【HW系列】—web常規漏洞(文件上傳漏洞)

文章目錄 一、簡介二、危害三、文件檢測方式分類四、判斷文件檢測方式五、文件上傳繞過技術六、漏洞防御措施 一、簡介 文件上傳漏洞是指Web應用程序在處理用戶上傳文件時&#xff0c;未對文件類型、內容、路徑等進行嚴格校驗和限制&#xff0c;導致攻擊者可上傳惡意文件&…

如何設計ES的冷熱數據分離架構?Elasticsearch 集群如何實現高可用?如何避免腦裂問題?如果出現腦裂如何恢復?

以下為Elasticsearch架構設計與高可用方案詳細說明&#xff1a; 冷熱架構 一、冷熱數據分離架構設計&#xff08;文字描述模擬架構圖&#xff09; [Hot Layer] │ ├─ SSD節點組&#xff08;3節點&#xff09; │ ├─ 角色&#xff1a;ingest/data/hot │ ├─ 存…

Trivy 鏡像漏洞掃描:從零入門到實戰指南

&#x1f525;「炎碼工坊」技術彈藥已裝填&#xff01; 點擊關注 → 解鎖工業級干貨【工具實測|項目避坑|源碼燃燒指南】 ——手把手帶你掌握容器安全核心工具 一、安裝配置&#xff1a;三步完成 Trivy 部署 Trivy 是由 Aqua Security 開發的開源容器安全工具&#xff0c;支持…

SQL基礎概念以及SQL的執行方式

1. SQL入門 1.1. SQL語言功能 可以把 SQL 語言按照功能劃分成以下的 4 個部分&#xff1a; DDL&#xff0c;英文叫做 Data Definition Language&#xff0c;也就是數據定義語言&#xff0c;它用來定義我們的數據庫對象&#xff0c;包括數據庫、數據表和列。通過使用 DDL&…

Rust 1.0 發布十周年,夢想再度揚帆起航!

目錄 引言&#xff1a;發布十周年&#xff0c;鋒芒露今朝 一、Rust的誕生&#xff1a;源于安全的初心 二、Rust 1.0&#xff1a;十年耕耘&#xff0c;碩果累累 三、核心利器&#xff1a;安全、并發與性能的十年錘煉 四、生態與應用&#xff1a;十年拓展&#xff0c;遍地開…

x86 與 ARM 匯編深度對比:聚焦 x86 匯編的獨特魅力

一、引言 匯編語言是硬件與軟件的橋梁&#xff0c;x86 和 ARM 作為兩大主流架構&#xff0c;其匯編語言在設計理念、指令集、編程風格上差異顯著。本文以 x86 匯編為核心&#xff0c;結合與 ARM 的對比&#xff0c;解析 x86 匯編的技術細節與應用場景&#xff0c;助力開發者深…