【C++進階學習】第五彈——二叉搜索樹——二叉樹進階及set和map的鋪墊

二叉樹1:深入理解數據結構第一彈——二叉樹(1)——堆-CSDN博客

二叉樹2:深入理解數據結構第三彈——二叉樹(3)——二叉樹的基本結構與操作-CSDN博客

二叉樹3:深入理解數據結構第三彈——二叉樹(3)——二叉樹的基本結構與操作-CSDN博客

前言:


在之前我們用C語言實現數據結構時,已經對二叉樹進行了系統的學習,但還是有一些內容并沒有涉及到,比如今天要講的二叉搜索樹,因為二叉搜索樹在C++中有現成的模板庫——set和map,并且實現起來較為麻煩,所以我們放到這里來講,對前面二叉樹部分有所遺忘的同學可以在我的主頁搜一下之前的文章看一下

目錄

一、二叉搜索樹的概念

二、二叉搜索樹的基本操作

1. 插入節點

2. 查找節點

3. 刪除節點

三、二叉搜索樹的實現

四、二叉搜索樹的應用

五、總結


一、二叉搜索樹的概念

二叉搜索樹又稱二叉排序樹,它是一種具有特殊性質的二叉樹,它具有以下特點:

1. 有序性:對于樹中的每個節點,其左子樹中的所有節點的值都小于該節點的值,而其右子樹中的所有節點的值都大于該節點的值。

2. 唯一性:樹中的每個節點的值都是唯一的,不存在重復的值。

3. 遞歸性:它的子樹也都是二叉樹

上面這三種性質,最不好理解的應該是有序性,下面我們通過兩個例子來展現這三種性質:

二、二叉搜索樹的基本操作

1. 插入節點

插入節點的過程如下:

  • 從根節點開始,比較要插入的值與當前節點的值。
  • 如果要插入的值小于當前節點的值,則移動到左子節點;如果要插入的值大于當前節點的值,則移動到右子節點。
  • 重復上述過程,直到找到一個空位置,然后在該位置插入新節點。
2. 查找節點

查找節點的過程如下:

  • 從根節點開始,比較要查找的值與當前節點的值。
  • 如果要查找的值等于當前節點的值,則返回該節點。
  • 如果要查找的值小于當前節點的值,則移動到左子節點;如果要查找的值大于當前節點的值,則移動到右子節點。
  • 重復上述過程,直到找到目標節點或遍歷到空節點。
3. 刪除節點

刪除節點的過程相對復雜,需要考慮以下幾種情況:

  • 刪除葉子節點:直接刪除該節點。
  • 刪除只有一個子節點的節點:將其子節點替換到該節點的位置。
  • 刪除有兩個子節點的節點:找到該節點右子樹中的最小節點(或左子樹中的最大節點),將其值替換到該節點的位置,然后刪除該最小節點。

三、二叉搜索樹的實現

template<class T>
struct BSTNode
{BSTNode(const T& data = T()): _pLeft(nullptr) , _pRight(nullptr), _data(data){}BSTNode<T>* _pLeft;BSTNode<T>* _pRight;T _data;
};
template<class T>
class BSTree
{typedef BSTNode<T> Node;typedef Node* PNode;
public:BSTree(): _pRoot(nullptr){}// 自己實現,與二叉樹的銷毀類似~BSTree();// 根據二叉搜索樹的性質查找:找到值為data的節點在二叉搜索樹中的位置PNode Find(const T& data);bool Insert(const T& data){// 如果樹為空,直接插入if (nullptr == _pRoot){_pRoot = new Node(data);return true;}// 按照二叉搜索樹的性質查找data在樹中的插入位置PNode pCur = _pRoot;// 記錄pCur的雙親,因為新元素最終插入在pCur雙親左右孩子的位置PNode pParent = nullptr;while (pCur){pParent = pCur;if (data < pCur->_data)
比特就業課pCur = pCur->_pLeft;else if (data > pCur->_data)pCur = pCur->_pRight; ?// 元素已經在樹中存在elsereturn false;}// 插入元素pCur = new Node(data);if (data < pParent->_data)pParent->_pLeft = pCur;elsepParent->_pRight = pCur;return true;}bool Erase(const T& data){// 如果樹為空,刪除失敗if (nullptr == _pRoot)return false;// 查找在data在樹中的位置PNode pCur = _pRoot;PNode pParent = nullptr;while (pCur){if (data == pCur->_data)break;else if (data < pCur->_data){pParent = pCur;pCur = pCur->_pLeft;}else{pParent = pCur;pCur = pCur->_pRight;}}// data不在二叉搜索樹中,無法刪除if (nullptr == pCur)return false;// 分以下情況進行刪除,同學們自己畫圖分析完成if (nullptr == pCur->_pRight){// 當前節點只有左孩子或者左孩子為空---可直接刪除}else if (nullptr == pCur->_pRight){// 當前節點只有右孩子---可直接刪除}else{
// 當前節點左右孩子都存在,直接刪除不好刪除,可以在其子樹中找一個替代結點,
比如:// 找其左子樹中的最大節點,即左子樹中最右側的節點,或者在其右子樹中最小的節
點,即右子樹中最小的節點// 替代節點找到后,將替代節點中的值交給待刪除節點,轉換成刪除替代節點}return true;}
// 自己實現void InOrder();
private:PNode _pRoot;
};

四、二叉搜索樹的應用

在我們目前的學習中,二叉搜索樹最重要的用途就是key--val模型,KV模型就是每一個key值都對應一個val值,這樣就形成一個<key,val>鍵值對,這樣的應用在生活中是非常常見的

比如:在菜市場中不同的蔬菜對應著不同的價格;新華詞典中,不同的漢字對應著不同的拼音,這些都可以用KV模型來解決

下面是KV模型的實現(沒有主函數):

namespace kv
{template<class K,class V>struct BSTreeNode{BSTreeNode<K,V>* _left;BSTreeNode<K,V>* _right;K _key;V _value;BSTreeNode(const K& key,const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}};template<class K,class V>class BSTree{typedef BSTreeNode<K,V> Node;public://遍歷(中序)void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);cout << endl;}///bool Insert(const K& key,const V& value){if (_root == nullptr){_root = new Node(key,value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}cur = new Node(key,value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{// 準備刪除  20:15繼續if (cur->_left == nullptr){//左為空if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;}else if (cur->_right == nullptr){//右為空if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else{//左右都不為空// 右樹的最小節點(最左節點)Node* parent = cur;Node* subLeft = cur->_right;while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key);if (subLeft == parent->_left)parent->_left = subLeft->_right;elseparent->_right = subLeft->_right;delete subLeft;}return true;}}return false;}BSTree() = default;~BSTree(){Destroy(_root);}//遞歸版本bool InsertR(const K& key){return _InsertR(_root, key);}bool FindR(const K& key){return _FindR(_root, key);}bool EraseR(const K& key){return _EraseR(_root, key);}BSTree(const BSTree<K,V>& t){_root = Copy(t._root);}BSTree<K,V>& operator=(BSTree<K,V> t){swap(_root, t._root);return *this;}private:Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* newroot = new Node(root->_key);newroot->_left = Copy(root->_left);newroot->_right = Copy(root->_right);return newroot;}void Destroy(Node*& root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}bool _EraseR(Node*& root, const K& key){if (root == nullptr){return false;}if (root->_key < key){return _EraseR(root->_right, key);}else if (root->_key > key){return _EraseR(root->_left, key);}else{if (root->_left == nullptr){root = root->_right;return true;}else if (root->_right == nullptr){root = root->_left;return true;}else{Node* subLeft = root->_right;while (subLeft->_left){subLeft = subLeft->_left;}swap(root->_key, subLeft->_key);return _EraseR(root->_right, key);}}}bool _FindR(Node* root, const K& key){if (root == nullptr){return false;}if (root->_key < key){return root->_right;}else if (root->_key > key){return root->_left;}else{return true;}}bool _InsertR(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key < key){return _InsertR(root->_right, key);}else if (root->_key > key){return _InsertR(root->_left, key);}else{return false;}}Node* _root = nullptr;};
}

五、總結

以上就是二叉搜索樹的主要內容,在代碼實現上其實與之前講的二叉樹差別并不是很大,關鍵在于思路的梳理,這章就先到這了

感謝各位大佬觀看,創作不易,還請各位大佬點贊支持!!!

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

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

相關文章

想要打造超高性能的接口API?試試這12條小技巧。

1. 并行處理 簡要說明 舉個例子&#xff1a;在價格查詢鏈路中&#xff0c;我們需要獲取多種獨立的價格配置項信息&#xff0c;如基礎價、折扣價、商戶活動價、平臺活動價等等。 CompletableFuture 是銀彈嗎&#xff1f; 使用 CompletableFuture 的確能夠幫助我們解決許多獨…

走進IT的世界

引言 隨著高考的結束&#xff0c;對于即將踏入IT&#xff08;信息技術&#xff09;領域的新生而言&#xff0c;這個假期不僅是放松身心的時間&#xff0c;更是提前規劃、深化專業知識、為大學生活奠定堅實基礎的寶貴機會。以下是一份詳盡的高考假期預習與規劃指南&#xff0c;…

Android自動化測試實踐:uiautomator2 核心功能與應用指南

Android自動化測試實踐&#xff1a;uiautomator2 核心功能與應用指南 uiautomator2 是一個用于Android應用的自動化測試Python庫&#xff0c;支持多設備并行測試操作。它提供了豐富的API來模擬用戶對App的各種操作&#xff0c;如安裝、卸載、啟動、停止以及清除應用數據等。此外…

30個!2024重大科學問題、工程技術難題和產業技術問題發布

【SciencePub學術】中國科協自2018年開始&#xff0c;組織開展重大科技問題難題征集發布活動&#xff0c;引導廣大科技工作者緊跟世界科技發展大勢&#xff0c;聚焦國家重大需求&#xff0c;開展原創性、引領性研究&#xff0c;不斷夯實高質量發展的科技支撐。 自2024年征集活動…

飛書文檔轉markdown 超級快捷方法。

直接使用那個github的高贊官方的工具轉換&#xff0c;需要設置什么小應用那種東西&#xff0c;還要審批&#xff0c;社恐人表示怕了怕了。而且文檔我分享出去&#xff0c;是有權限的&#xff0c;反正無論如何生成不了 我的方法是 直接全選&#xff0c;然后粘貼進Arya - 在線 …

C#的五大設計原則-solid原則

什么是C#的五大設計原則&#xff0c;我們用人話來解釋一下&#xff0c;希望小伙伴們能學會&#xff1a; 好的&#xff0c;讓我們以一種幽默的方式來解釋C#的五大設計原則&#xff08;SOLID&#xff09;&#xff1a; 單一職責原則&#xff08;Single Responsibility Principle…

PCL 漸進形態過濾器實現地面分割

點云地面分割 一、代碼實現二、結果示例?? 概述 漸進形態過濾器:采用先腐蝕后膨脹的運算過程,可以有效濾除場景中的建筑物、植被、車輛、行人以及交通附屬設施,保留道路路面及路緣石點云。 一、代碼實現 #include <iostream> #include <pcl/io/pcd_io.h> #in…

【LeetCode】976. 三角形的最大周長

1. 題目 2. 分析 需要分析好再動手編程。 如果要構成三角形的最大周長&#xff0c;那么就需要盡可能用最長的邊構建。所以可以先對數組排個序&#xff0c;然后基于排序得到的結果從大往小的逐個檢查長度為3的窗口&#xff0c;判斷該窗口的值是否滿足三角形的構成條件&#x…

鴻蒙開發Ability Kit(程序訪問控制):【安全控件概述】

安全控件概述 安全控件是系統提供的一組系統實現的ArkUI組件&#xff0c;應用集成這類組件就可以實現在用戶點擊后自動授權&#xff0c;而無需彈窗授權。它們可以作為一種“特殊的按鈕”融入應用頁面&#xff0c;實現用戶點擊即許可的設計思路。 相較于動態申請權限的方式&am…

構造,析構,拷貝【類和對象(中)】

P. S.&#xff1a;以下代碼均在VS2019環境下測試&#xff0c;不代表所有編譯器均可通過。 P. S.&#xff1a;測試代碼均未展示頭文件stdio.h的聲明&#xff0c;使用時請自行添加。 博主主頁&#xff1a;LiUEEEEE ??????????????????? ?? …

Excel_VBA編程

在Excel中&#xff0c;VBA&#xff08;Visual Basic for Applications&#xff09;是一種強大的工具&#xff0c;可以用來自動化各種任務。下面介紹一些常用的VBA函數和程序結構&#xff1a; 常用函數 MsgBox&#xff1a;用于顯示消息框。 MsgBox "Hello, World!"In…

【python全棧系列】day07-python數據類型-集合

Python中的集合&#xff08;Set&#xff09;是一個無序的、不包含重復元素的數據結構。它主要用于數學上的集合操作&#xff0c;如并集、交集、差集和對稱差集等。集合的基本用途包括去重和關系測試。 1、集合的特性 無序性&#xff1a;集合中的元素是無序的&#xff0c;這意…

gin-vue -admin 初始化安裝后 進入 后臺首頁報錯

報錯原因&#xff1a; 因為 我是使用的phpstudy 小皮的數據庫 默認的是MySam 的引擎 mysql 引擎需要是 innoDB 解決辦法 &#xff1a; 在linux 的環境下 配置一個數據庫 &#xff0c; 我是用的是vmware 虛擬機

深入理解分布式搜索引擎 ElasticSearch,并能基于 ELK+Kafka 搭建分布式?志收集系統

Elasticsearch是一個基于Lucene的分布式、多租戶能力的全文搜索引擎。它提供了RESTful web接口和分布式多用戶能力的全文搜索引擎&#xff0c;基于Apache許可證發行。以下是對Elasticsearch的深入理解以及如何基于ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;加…

npm緩存深度解析:理解、使用與清除指南

&#x1f31f; npm緩存深度解析&#xff1a;理解、使用與清除指南 npm&#xff08;Node Package Manager&#xff09;是JavaScript編程語言的包管理器&#xff0c;廣泛用于Node.js應用程序。它不僅幫助我們安裝和管理項目依賴&#xff0c;還擁有一個強大的緩存機制來加速這一過…

[論文筆記] BlendedDataset blend goes out of bounds for list 34 for valid split

報錯&#xff1a; Traceback (most recent call last):File "/mnt/cpfs/kexin/dlc_code/qwen2/Pai-Megatron-Patch/examples/qwen2/pretrain_qwen.py", line 211, in <module> (<megatron.core.datasets.gpt_dataset.GPTDataset object at 0x7f491886bf10&…

《昇思25天學習打卡營第8天|CarpeDiem》

《昇思25天學習打卡營第8天|CarpeDiem》 模型訓練構建數據集定義神經網絡模型定義超參、損失函數和優化器超參損失函數優化器 訓練與評估 打卡 今天是昇思25天學習打卡營的第8天&#xff0c;終于迎來 模型訓練 的部分了&#xff01;&#xff01;&#xff01; 興奮 發癲 模型訓…

SSH遠程命令執行漏洞(CVE-2024-6387)驗證

0x01、漏洞名稱 OpenSSH遠程代碼執行漏洞 &#xff08;CVE-2024-6387&#xff09; 0x02、漏洞簡介 ? OpenSSH是SSH&#xff08;Secure SHell&#xff09;協議的開源實現&#xff0c;它通過不安全的網絡在兩個不受信任的主機之間提供安全的加密通信。OpenSSH 廣泛用于基于Un…

數據庫。

數據庫安全性 論述題5’ 編程題10’ sql語言實現權限控制 一、概述 1、不安全因素 &#xff08;1&#xff09;?授權對數據庫的惡意存取和破壞 &#xff08;2&#xff09;數據庫中重要的數據泄露 &#xff08;3&#xff09;安全環境的脆弱性 2、?主存取控制?法 gr…

【ajax實戰06】進行文章發布

本文章目標&#xff1a;收集文章內容&#xff0c;并提交服務器保存 一&#xff1a;基于form-serialize插件收集表單數據 form-serialize插件僅能收集到表單數據&#xff0c;除此之外的數據無法收集到 二&#xff1a;基于axios提交到服務器保存 三&#xff1a;調用alert警告…