C++實現基礎二叉搜索樹(并不是AVL和紅黑樹)

本次實現的二叉搜索樹并不是AVL數和紅黑樹,只是了解流程和細節。

目錄

  • 二叉搜索樹的概念
  • K模型二叉搜索樹的實現
    • 二叉搜索樹的架構
    • insert插入
    • find 查找
    • 中序遍歷Inorder
    • 刪除earse
      • 替換法的思路
      • 情況一 :假如要刪除節點左邊是空的。
        • 在左邊時
        • 在右邊時
      • 情況二:假如要刪除節點右邊是空的。
        • 是父親的右邊時
        • 是父親的左邊時
      • 情況三:兩邊都有值
        • 左邊
        • 右邊
        • 代碼實現

二叉搜索樹的概念

二叉搜索樹并不是單純存儲數據。所以他有規則:
①.左子樹比根小,右子樹比根大。

②.搜索二叉樹不建議用遞歸。

二叉搜索樹一定要遵循這個規律!否則他都不能算是二叉搜索樹!

K模型二叉搜索樹的實現

二叉搜索樹的架構

我們之前也學過二叉樹,二叉樹的結構是節點里面放了左右指針和值,所以節點就是一下結構。 而二叉樹的本身就是又一個根節點連接起來的

template<class T>
struct BinarySearchTreeNode
{BinarySearchTreeNode(T& key):_key(key), _left(nullptr), _right(nullptr){}T _key;BinarySearchTreeNode* _left;BinarySearchTreeNode* _right;
};template<class T>class BinarySearchTree{public:typedef BinarySearchTreeNode<T> Node;		private:Node* _root=nullptr;};

insert插入

插入一定要遵循規則:
①.左子樹比根小,右子樹比根大。
不是這個規則都不是二叉搜索樹。

(1). 當你插入第一個值的時候,他就是根,所以我們要特殊處理,當_root==nullptr時,要把第一個插入的值變成根。
(2).除第一個值之后的值就要遵行規則。

bool insert(T& x)
{if (_root == nullptr){Node* noeNode = new Node(x);_root = noeNode;return true;}Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key < x){//大于在右邊parent = cur;cur = cur->_right;}else if (cur->_key > x){//小于在左邊parent = cur;cur = cur->_left;}else{//等于,二叉搜索樹不允許冗余,所以直接返回false。return false;}}Node* newNode = new Node(x);if (newNode->_key > parent->_key)parent->_right = newNode;elseparent->_left = newNode;return true;
}

find 查找

查找就很簡單,只要把前面的代碼復制一半,當查找到了,我們就返回true,到空了都沒找到就返回false。

bool find(const T& x)
{Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key < x){//大于在右邊parent = cur;cur = cur->_right;}else if (cur->_key > x){//小于在左邊parent = cur;cur = cur->_left;}else{//等于,找到了return true;}}return false;
}

中序遍歷Inorder

中序遍歷我們都很了解了,但是問題是,我們要把根傳入,根一定是私有的,你在類外訪問不了。這個時候我們就可以套一層。

publicvoid Inorder()
{_Inorder(_root);cout << endl;
}
private:void _Inorder(Node* _root){if (_root == nullptr) return;_Inorder(_root->_left);cout << _root->_key<< " ";_Inorder(_root->_right);}Node* _root=nullptr;

刪除earse

刪除其實很麻煩,有很多種情況。因為二叉搜索數一定是滿足規則的,所以我們刪除不能混亂了規則,而是繼續保持規則。所以我們要用替換法,保證規則不亂

替換法的思路

因為我們要保證規則不亂,那么我們可以用替換法,讓左樹的最大值/右樹的最小值與當前值替換,因為當前節點的左邊一定比他小,右邊一定比他大,那么當我們用左邊最大值,替換了當前節點,也不會改變規則;右邊同理。

情況一 :假如要刪除節點左邊是空的。

在左邊時

假如我要刪除9這個節點。并且左側是空,那么我們是不是可以直接讓他父親的左邊指向他的右邊?思考一下!

為什么?左側為空,當前刪除節點的左側一定是什么都沒有的,右邊可有可無,但是右邊沒有也沒關系,一樣置空,有的話,我們就需要讓他的父親鏈接他的孩子。
在這里插入圖片描述
并且我們發現并不用替換法,就可以直接鏈接后刪除。
在這里插入圖片描述

在右邊時

其實在右邊也是一樣的,只不是我們要特殊判斷一下,刪除節點時父親的左邊還是右邊,方便我們鏈接。
在這里插入圖片描述

情況二:假如要刪除節點右邊是空的。

是父親的右邊時

那么他右邊一定是沒有值的,左邊的值可有可無,那么我們就需要讓它的父親指向他的左值就可以了。
在這里插入圖片描述

是父親的左邊時

在這里插入圖片描述

情況三:兩邊都有值

如果這棵樹是這樣的,那么我要刪除9怎么做呢?就需要替換法,我們需要找左邊最大值或者右邊最小值,我們假設要找是右邊最小值
在這里插入圖片描述

從當前節點開始找,右邊最小值是10(藍色標記)。

問:為什么要從當前節點找,而不是從根開始?
答:如果從根開始找,你會發現,當我們交換后,不滿足條件了。圖中右邊最小值是13,如果換到最左邊那就不滿足二叉搜索的要求了,所以要從當前節點找,因為當前節點的右邊跟當前這個位置換一定是比大,比其他節點小的。

在這里插入圖片描述
當我們都找到了,我們就要用交換法。將兩個值交換后,左邊最小的那個節點就是我們要刪除的。那么我們就需要把最小節點的右邊給它的右邊。
在這里插入圖片描述

左邊

這里給大家道個歉,因為數字太過緊湊,所以湊不出數,只能讓整型和浮點數混合了,在實際場景中是不可能有的,只是舉個例子

假設我們交換后,發現要刪除的節點右邊還有值,

問題:我怎么讓被刪除節點的父親知道是左邊還是右邊的節點間接我的右節點呢
答:需要判斷一下,如果被刪除的節點是父親的左邊,就需要讓左邊指向被刪的右邊,如果是父親的右邊就讓父親的右邊指向被刪的右邊。

在這里插入圖片描述
在這里插入圖片描述

右邊

這種情況,就是他在父親的右邊,所以我們需要讓父親的右邊鏈接被刪的右邊。
在這里插入圖片描述

代碼實現

雖然刪除的代碼很復雜,但是要注意的細節很多。
(1).在我們找到了當前被刪節點,情況三的時候,能不能讓Node* rightMinParent = nullptr;? 答:不可以,因為當我們刪除這種情況的時候,就會導致空指針訪問,因為循環我們沒有進去,但是鏈接值的時候,就會導致空指針訪問。

(2).在我們交換后,能不能遞歸把他刪了?不能!我問你交換后還滿足二叉搜索數的要求嗎?不滿足,你永遠都不會找到!

在這里插入圖片描述

		bool erase(const T& x){Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key < x){//大于在右邊parent = cur;cur = cur->_right;}else if (cur->_key > x){//小于在左邊parent = cur;cur = cur->_left;}else{//等于,找到了if (cur->_left == nullptr){//沒有值直接刪,把右邊給父親if (cur == parent->_left){parent->_left = cur->_right;delete cur;}else if(cur == parent->_right){parent->_right = cur->_right;delete cur;}}else if (cur->_right == nullptr){if (cur == parent->_left){parent->_left = cur->_left;delete cur;}else if (cur == parent->_right){parent->_right = cur->_left;delete cur;}}else{Node* rightMin = cur->_right;Node* rightMinParent = cur;//這里要讓父親是cur,刪根的時候就會出問題while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}std::swap(cur->_key, rightMin->_key);if (rightMinParent->_left == rightMin)rightMinParent->_left = rightMin->_right;elserightMinParent->_right = rightMin->_right;delete rightMin;}return true;}}return false;}

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

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

相關文章

文心智能體,零代碼構建情感表達大師智能體

前言 隨著智能體技術的突飛猛進&#xff0c;各行各業正迎來前所未有的變革與機遇。智能體&#xff0c;作為人工智能領域的重要分支&#xff0c;以其自主性、智能性和適應性&#xff0c;正逐步滲透到我們生活的每一個角落&#xff0c;成為推動社會進步和科技發展的新動力。 為了…

軟考 系統架構設計師系列知識點之雜項集萃(20)

接前一篇文章&#xff1a;軟考 系統架構設計師系列知識點之雜項集萃&#xff08;19&#xff09; 第28題 在單元測試中&#xff0c;&#xff08; &#xff09;。 A. 驅動模塊用來調用被測模塊&#xff0c;自頂向下的單元測試中不需要另外需要編寫驅動模塊 B. 樁模塊用來模擬被…

visual studio 2022 ssh 主機密鑰算法失敗問題解決

 Solution - aengusjiang 問題&#xff1a; I follow the document, then check sshd_config, uncomment“HostKey /etc/ssh/ssh_host_ecdsa_key” maybe need add the key algorithms: #HostKeyAlgorithms ssh-ed25519[Redacted][Redacted]rsa-sha2-256,rsa-sha2-512 Ho…

Redis常用命令——String篇

前面我們講解了一些 Redis 的全局命令&#xff08;Redis常用基本全局命令&#xff09;。所謂全局命令&#xff0c;就是可以匹配任意一個數據結構進行使用。但是不同的數據結構&#xff0c;也有自己的操作命令。本篇文章主要講解的是 String 的操作命令&#xff0c;希望會對你有…

ClickHouse課件

列式存儲數據庫&#xff1a;hbase clickhouse 簡介 ClickHouse入門 ClickHouse是俄羅斯的Yandex于2016年開源的列式存儲數據庫&#xff08;DBMS&#xff09;&#xff0c;使用C語言編寫&#xff0c;主要用于在線分析處理查詢&#xff08;OLAP&#xff09;&#xff0c;能夠使用…

2024年電工杯B題論文首發+問題一論文代碼分享

問題一論文代碼鏈接&#xff1a;https://pan.baidu.com/s/1kDV0DgSK3E4dv8Y6x7LExA 提取碼&#xff1a;sxjm --來自百度網盤超級會員V5的分享 基于數據分析的大學生平衡膳食食譜的優化設計及評價 摘要 大學時期不僅是學術學習和身體成長的關鍵階段&#xff0c;更是青年學生…

supermind讀寫自選股的功能來了

python custom_sector() # 返回所有板塊的dataframecustom_sector(板塊1) # 返回 板塊1 的屬性和股票custom_sector(板塊1, append, [000001.SZ]) # 增加板塊1的股票列表custom_sector(板塊1, pop, [000001.SZ]) # 移除板塊1的股票custom_sector(板塊1, remove) # 刪除板塊1zxg…

Hsql每日一題 | day03

前言 就一直向前走吧&#xff0c;沿途的花終將綻放~ 題目&#xff1a;打折日期交叉問題 如下為平臺商品促銷數據&#xff1a;字段為品牌&#xff0c;打折開始日期&#xff0c;打折結束日期 brand stt edt oppo,2021-06-05,2021-06-09 oppo,2021-06-11,2021-06-21 vivo,…

Java中流的概念細分

按流的方向分類&#xff1a; 輸入流&#xff1a;數據流向是數據源到程序&#xff08;以InputStream、Reader結尾的流&#xff09;。 輸出流&#xff1a;數據流向是程序到目的地&#xff08;以OutputStream、Writer結尾的流&#xff09;。 按處理的數據單元分類&#xff1a; 字…

PVE 虛擬機環境下刪除 local-lvm分區

1、刪除邏輯卷 lvremote pve/data 2、擴展邏輯卷 lvextend -l 100%FREE -r pve/root 3、 修改存儲目錄內容 點擊 Datacenter - Storage &#xff08;1&#xff09;刪除local-lvm分區 &#xff08;2&#xff09;編輯local分區&#xff0c;在內容一項中勾選所有可選項。

mysql 兩個不同字段的表導入數據

下面這個場景就是A表的字段和B表的字段不一樣&#xff0c;但是現在我想把b表中的數據導入到A表里面&#xff0c;下面是導入公式如下&#xff1a; 語法&#xff1a; 將SYS_ORG表中的數據導入到sys_depart&#xff0c;但是這兩個表的字段不一樣&#xff0c;在()里面填寫要新增數據…

Spring Boot 3.3 正式發布,王炸級更新,應用啟動速度直接起飛!

最新消息&#xff0c;Spring Boot 一次性發布了 3 個版本&#xff1a; 3.3.0 3.2.6 3.1.13 Spring Boot 3.3 正式發布了&#xff0c;3.1.x 在前幾天也停止維護了。 最新的支持版本如下&#xff1a; 從路線圖可以看到每個版本的終止時間&#xff0c;每個版本的生命周期只有…

安徽大學數學科學學院教授陳昌昊

男&#xff0c;本&#xff08;2005-2009&#xff09;、碩&#xff08;2009-2012&#xff09;學位都在湖北大學獲得&#xff0c;博士學位在芬蘭獲得&#xff08;2012-2016&#xff09;&#xff0c;博士后分別在澳大利亞&#xff08;2016-2019&#xff09;、香港&#xff08;2020…

vue3中el-form表單校驗,再點擊提交按鈕的時候通過校驗才進行提交

vue3中el-form表單校驗&#xff0c;再點擊提交按鈕的時候通過校驗才進行提交 一、前言1、案例 一、前言 在 Vue 3 中&#xff0c;可以使用 Element UI 的 <el-form> 組件配合 <el-form-item> 來實現表單的必填項校驗&#xff0c;并在提交時根據校驗結果來決定是否…

clickhouse 中的數組(array)和元組(Tuple)—— clickhouse 基礎篇(二)

文章目錄 數組判斷是否為空計算數組長度獲取數組元素判斷某個元素是否存在數組切片數組元素展開數組元素去重刪除連續重復元素連接多個數組數組倒序數組拍平數組元素映射數組元素過濾數組聚合分析計算數組交集計算數組并集計算數組差集SQL 子查詢進行集合操作 元組創建元組獲取…

LeetCode刷題之HOT100之二叉樹的直徑

2024/5/25 陰天。這幾天睡眠質量都非常好&#xff0c;一切似乎都在慢慢上升。先把題做了 1、題目描述 2、邏輯分析 題目要求就是給一個二叉樹&#xff0c;求出兩個節點之間的最大長度即為二叉樹的直徑。怎么做呢&#xff1f;我想不出來。看一下題解吧。題解給出的解法是深度優…

Swagger2 和 Swagger3 的不同

Swagger2 和 Swagger3 的不同 SpringBoot 整合 Swagger3 和 Swagger2 的主要區別如下&#xff1a; 區別一&#xff1a;引入不同的依賴 如果使用的是 Swagger 3 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter<…

Linux——Docker容器虛擬化平臺

安裝docker 安裝 Docker | Docker 從入門到實踐https://vuepress.mirror.docker-practice.com/install/ 不需要設置防火墻 docker命令說明 docker images #查看所有本地主機的鏡像 docker search 鏡像名 #搜索鏡像 docker pull 鏡像名 [標簽] #下載鏡像&…

學習java第八十天

ApplicationContext有哪些常見實現&#xff1f; FileSystemXmlApplicationContext容器從XML文件加載bean的定義。XML bean配置文件的完整路徑必須提供給構造函數。 ClassPathXmlApplicationContext容器也從XML文件加載bean的定義。這里&#xff0c;你需要正確設置classpath因…

mybatis-plus 優雅的寫service接口中方法(3)

多表聯查 上文講過了自定義sql &#xff0c;和wrapper的使用&#xff0c;但是我們可以發現 我們查詢的都是數據庫中的一張表&#xff0c;那么怎么進行多表聯查呢&#xff0c;當然也是用自定義sql來進行實現 比如說 查詢 id 為 1 2 4 的用戶 并且 地址在北京 的 用戶名稱 普…