【數據結構】二叉排序樹(c風格、結合c++引用)

目錄

1 基本概念

結構體定義

各種接口

2?二叉排序樹的構建和中序遍歷

遞歸版單次插入

非遞歸版單次插入

3?二叉排序樹的查找

非遞歸版本

遞歸版本

4?二叉排序樹的刪除(難點)


1 基本概念

????????普通二叉排序樹是一種簡單的數據結構,節點的值根據特定順序(通常是升序或降序)排列。然而,如果普通二叉排序樹不平衡,即左、右子樹的高度相差很大時,查詢效率可能會降低。因此引出了avl樹、紅黑樹等一系列高階數據結構。

? ? ? ?基本性質:

  • 若它的左子樹不空,則左子樹上所有結點的值均小于根結點的值。
  • 若它的右子樹不空,則右子樹上所有結點的值均大于根結點的值。
  • 它的左、右子樹均為為?叉排序樹。
  • 二叉排序樹的查找時間復雜度為樹的高度,即為O(以2為底N的對數) ,下面全寫成O(logN)
  • 二叉排序樹的中序遍歷輸出是一個遞增的數列。

結構體定義

typedef struct BSTreeNode
{int val;struct BSTreeNode* left;struct BSTreeNode* right;
}BSTNode,*BiTree;

各種接口

???????

關于用到C++中的引用:

BSTNode是結構體struct BSTNode的別名,BiTree是結構體struct BSTNode指針。

在鏈表中,首次插入時需要修改頭節點,由于頭節點的定義也是一個指針,所以要修改一個一級指針,必須傳入二級指針或者一級指針的引用,二叉樹也是一樣,首次插入需要修改根節點的指向,所以這里用引用,當然也可以用二級指針,嚴蔚敏老師編寫的數據結構中也經常用到C++的引用。

而再次或多次進行插入時,我們用cur去遍歷鏈表或二叉樹,其實是修改鏈表和二叉樹的一個個結構體,這時我們只需要結構體指針,其實就只需要一級指針即可。

因此,我們直接用二級指針或一級指針的引用,就能解決所有的問題。?


2?二叉排序樹的構建和中序遍歷

?構建原則:

①根節點為空,先構建根節點。

②插入節點的值小于根節點的值,去根節點的左子樹尋找插入位置。

③插入節點的值大于根節點的值,去根節點的右子樹尋找插入位置。

void Create(BiTree& root,int* a,int n)
{for (int i = 0; i < n; ++i){BST_InsertR(root, a[i]);//BST_Insert(root, a[i]);}
}

遍歷數組O(N),數組每個元素插入O(logN),因此構建的時間復雜度是O(NlogN)

遞歸版單次插入

int BST_InsertR(BiTree& root, int x)
{//先申請節點BSTNode* newnode = (BiTree)malloc(sizeof(BSTNode));if (newnode == nullptr){perror("malloc fail");exit(-1);}newnode->val = x;newnode->left = newnode->right = nullptr;//進行插入if (root == nullptr)//空樹或者走到空{root = newnode;return 1;//插入成功}if (root->val == x)return -1;//插入失敗,節點元素值不能相同if (root->val > x)//x小于根節點的值,就去左子樹插入return BST_InsertR(root->left, x);if (root->val < x)//x大于于根節點的值,就去右子樹插入return BST_InsertR(root->right, x);
}

非遞歸版單次插入

?定義兩個指針,cur和prev,prev指向cur的根節點,cur最后走到空,對prev的左右指針進行操作,比對prev->val和x,如果val<x,就讓prev->right指向新節點,反之。

int BST_Insert(BiTree& root, int x)
{//二叉排序樹左孩子的值比根的值要小,右孩子的值比根的值要大BSTNode* newnode = (BiTree)malloc(sizeof(BSTNode));if (newnode == nullptr){perror("malloc fail");exit(-1);}newnode->val = x;newnode->left = newnode->right = nullptr;//第一次進來root為空if (root == nullptr){root = newnode;return 0;}//第二次開始往后遍歷BSTNode* cur = root;BSTNode* prev = nullptr;while (cur)//讓cur走到空{prev = cur;if (cur->val < x){cur = cur->right;}else if (cur->val > x){cur = cur->left;}else{return -1;//插入失敗,不能有元素相等的情況}}if (prev->val < x){prev->right = newnode;}if (prev->val > x){prev->left = newnode;}return 0;//插入成功
}

假設我們用這個數組去構建一棵樹:

結果是這樣的:

中序遍歷:

void InOrder(BiTree root)
{if (root == nullptr)//空樹或走到空return;InOrder(root->left);//左子樹printf("%d ", root->val);//根InOrder(root->right);//右子樹
}

輸出的結果一定是一個遞增序列,因此二叉排序樹的中序遍歷才有意義。

3?二叉排序樹的查找

查找原則:

①所查找的值比當前節點的值要小,就去左子樹找

②所查找的值比當前節點的值要大,就去右子樹找

③查找成功,返回結構體指針BSTNode*/BiTree

二叉排序樹的最大查找次數,就是樹的深度,類似于折半查找,每查一次排除一半的樹。

因此二叉排序樹的查找時間復雜度為O(logN) 。

非遞歸版本

BSTNode* BinarySearch(BiTree root,int x)
{BSTNode* cur = root;while (cur){if (cur->val < x){cur = cur->right;}else if (cur->val > x){cur = cur->left;}else{return cur;}}return nullptr;
}

遞歸版本

BSTNode* BinarySearchR(BiTree root, int x)
{if (root == nullptr)//空樹或者找到空了還沒找到return nullptr;if (x == root->val)return root;if (x > root->val)//大于就去右子樹找return BinarySearchR(root->right, x);if(x < root->val)//小于就去左子樹找return BinarySearchR(root->left, x);
}

4?二叉排序樹的刪除(難點)

刪除原則:

①刪除節點的右子樹為空,左子樹不為空,把左子樹頂上來。

②刪除節點的左子樹為空,右子樹不為空,把右子樹頂上來。

③刪除節點的左右子樹都不為空,要么在左子樹中找最大的數據和根的數據交換,要么在右子樹中找最小的數據和根的數據交換。

void DeleteNode(BiTree& root, int x)
{if (root == nullptr)//找不到或者根為空,直接返回{return;}//先找后刪除,遞歸if (x < root->val){DeleteNode(root->left, x);}if (x > root->val){DeleteNode(root->right, x);}//找到了,執行刪除if (root->val == x){if (root->left == nullptr)//左子樹為空,把右子樹頂上去{BiTree tmp = root;root = root->right;free(tmp);}else if (root->right == nullptr)//右子樹為空,把左子樹頂上去{BiTree tmp = root;root = root->left;free(tmp);}else//左右子樹均不為空,要么在左子樹中找最大的數據和根的數據交換,要么在右子樹中找最小的數據和根的數據交換//采用前者即可,左子樹的最大數據就是左子樹的最右結點{BiTree left = root->left;while (left->right){left = left->right;}root->val = left->val;//free(left);//不能這么做,萬一這個結點有左子樹怎么辦?//只能重新在T的左子樹找這個結點,復用遞歸刪除這個結點DeleteNode(root->left, left->val);}}
}

圖解何為“頂上來”?

由于函數傳參用到引用,因此root就是上一層函數root->left或者root->right的別名

定義指針tmp去指向root形參,root形參用root(1)表示一下:

這時我們想讓root->right變為root(1)->right,而root(1)就是root->right的別名,因此我們直接讓root(1)=root(1)->right,然后去free(tmp),用代碼表示就是這樣:


同理,右子樹為空,把左子樹頂上去:


當左右子樹都不為空時,要么去左子樹中找最大的數據去替換刪除節點,要么去右子樹中找最小的數據去替換刪除節點。

而左子樹中的最大數據位于左子樹的最右深處節點,右子樹中的最小數據位于右子樹的最左深處節點。

什么是“替換”:把要刪除的根節點的值與左子樹最右節點的值交換,然后“刪除”掉左子樹最右節點;或者把要刪除的根節點的值與右子樹最左節點的值交換,然后“刪除”掉右子樹最左節點。

何為刪除?真的是直接free掉嗎?

?刪除59,那它的左子樹咋辦?直接free就坑了!

復用函數去遞歸刪除59,讓59的左子樹頂上去:

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

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

相關文章

戲說二十三種設計模式_用故事的方式就是讓你一定能懂

創建型模式 1、FACTORY—追MM少不了請吃飯了&#xff0c;麥當勞的雞翅和肯德基的雞翅都是MM愛吃的東西&#xff0c;雖然口味有所不同&#xff0c;但不管你帶MM去麥當勞或肯德基&#xff0c;只管向服務員說“來四個雞翅”就行了。麥當勞和肯德基就是生產雞翅的Factory 工廠模式&…

Cortex-M與RISC-V區別

環境 Cortex-M以STM32H750為代表&#xff0c;RISC-V以芯來為代表 RTOS版本為RT-Thread 4.1.1 寄存器 RISC-V 常用匯編 RISC-V 關于STORE x4, 4(sp)這種寄存器前面帶數字的寫法&#xff0c;其意思為將x4的值存入sp4這個地址&#xff0c;即前面的數字表示偏移的意思 反之LOA…

【LM358AD運放方波振蕩器可控輸出幅值】2022-2-25

緣由仿真如何縮小方波振蕩電路方波幅值?-有問必答-CSDN問答

使用Pytorch從零開始構建LSTM

長短期記憶&#xff08;LSTM&#xff09;網絡已被廣泛用于解決各種順序任務。讓我們了解這些網絡如何工作以及如何實施它們。 就像我們一樣&#xff0c;循環神經網絡&#xff08;RNN&#xff09;也可能很健忘。這種與短期記憶的斗爭導致 RNN 在大多數任務中失去有效性。不過&a…

發送一個網絡數據包的過程解析

在 ip_queue_xmit 中&#xff0c;也即 IP 層的發送函數里面&#xff0c;有三部分邏輯。第一部分&#xff0c;選取路由&#xff0c;也即我要發送這個包應該從哪個網卡出去。 這件事情主要由 ip_route_output_ports 函數完成。接下來的調用鏈為&#xff1a;ip_route_output_port…

改進YOLOv8 | YOLOv5系列:RFAConv續作,即插即用具有任意采樣形狀和任意數目參數的卷積核AKCOnv

RFAConv續作,構建具有任意采樣形狀的卷積AKConv 一、論文yolov5加入的方式論文 源代碼 一、論文 基于卷積運算的神經網絡在深度學習領域取得了顯著的成果,但標準卷積運算存在兩個固有缺陷:一方面,卷積運算被限制在一個局部窗口,不能從其他位置捕獲信息,并且其采樣形狀是…

Matlab進階繪圖第33期—雙曲面圖

在《Matlab論文插圖繪制模板第56期—曲面圖&#xff08;Surf&#xff09;》中&#xff0c;我分享過曲面圖的繪制模板。 然而&#xff0c;有的時候&#xff0c;需要在一張圖上繪制兩個及以上的曲面圖&#xff0c;且每個曲面圖使用不同的配色方案。 在Matlab中&#xff0c;一張…

C++基礎入門(超詳細)

話不多說&#xff0c;序言搞起來&#xff1a; 自從開始學老師布置的任務后&#xff0c;目前還是OpenCV&#xff0c;哈~哈。我就莫名問老師&#xff1a;“以后編程是用C還是python&#xff1f;”&#xff0c;果然還是太年輕&#xff0c;老師說&#xff1a;“兩們都要精通”。唉&…

set和map + multiset和multimap(使用+封裝(RBTree))

set和map 前言一、使用1. set(1)、模板參數列表(2)、常見構造(3)、find和count(4)、insert和erase(5)、iterator(6)、lower_bound和upper_bound 2. multiset3. map(1)、模板參數列表(2)、構造(3)、modifiers和operations(4)、operator[] 4. multimap 二、封裝RBTree迭代器原理R…

9.輸出國際象棋盤【2023.11.24】

1.問題描述 要求輸出國際象棋棋盤。 2.解決思路 國際象棋棋盤由64個黑白相間的格子組成&#xff0c;分為8行*8列。用i控制行&#xff0c;j控制列&#xff0c;根據ij的和的變化來控制輸出黑方格還是白方格。 3.代碼實現 #include<stdio.h> int main(){for(int i0;i&…

各操作系統之間的關系

請移步知乎&#xff1a; 操作系統UNIX、WINDOWS、LINUX、MC OS的聯系與區別 - 知乎 (zhihu.com) 移動端的android操作系統就人盡皆知啦&#xff0c;基于linux內核。 完畢。 適用領域&#xff1a; windows,macos:主要面向個人計算機市場 Linux、Windows Server:隨著互聯網的…

基于廣義正態分布算法優化概率神經網絡PNN的分類預測 - 附代碼

基于廣義正態分布算法優化概率神經網絡PNN的分類預測 - 附代碼 文章目錄 基于廣義正態分布算法優化概率神經網絡PNN的分類預測 - 附代碼1.PNN網絡概述2.變壓器故障診街系統相關背景2.1 模型建立 3.基于廣義正態分布優化的PNN網絡5.測試結果6.參考文獻7.Matlab代碼 摘要&#xf…

網絡安全—自學

1.網絡安全是什么 網絡安全可以基于攻擊和防御視角來分類&#xff0c;我們經常聽到的 “紅隊”、“滲透測試” 等就是研究攻擊技術&#xff0c;而“藍隊”、“安全運營”、“安全運維”則研究防御技術。 2.網絡安全市場 一、是市場需求量高&#xff1b; 二、則是發展相對成熟…

深度學習之基于Pytorch照片圖像轉漫畫風格網絡系統

歡迎大家點贊、收藏、關注、評論啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代碼。 文章目錄 一項目簡介 二、功能三、系統四. 總結 一項目簡介 以下是一個基本的設計介紹&#xff1a; 數據準備&#xff1a;收集足夠的真實照片和漫畫圖像&#xff0c;用于訓練模…

typora中的快捷鍵shift enter 和 enter的交換

1 問題&#xff1a; 我最近在用 typora 進行寫作&#xff0c;但是在合格 typora 的 markdown 編輯器很奇怪&#xff0c;它的一個回車符是兩次換行&#xff0c;而用 shfit ent 找了半天都不知道怎么解決的這個問題&#xff0c;然后我就去了這個 typora 在 github 開源的問題倉庫…

hive 報錯return code 40000 from org.apache.hadoop.hive.ql.exec.MoveTask解決思路

參考學習 https://github.com/apache/hive/blob/2b57dd27ad61e552f93817ac69313066af6562d9/ql/src/java/org/apache/hadoop/hive/ql/ErrorMsg.java#L47 為啥學習error code 開發過程中遇到以下錯誤&#xff0c;大家覺得應該怎么辦&#xff1f;從哪方面入手呢&#xff1f; 1.百…

解決在Windows10或Windows11下無權限修改hosts文件

解決在Windows10或Windows11下無權限修改hosts文件&#xff0c;無法寫入內容 1、首先在開始菜單中找到這個 2、接著輸入&#xff1a; C:\Windows\System32\drivers\etc3、再次輸入以下命令行&#xff1a;notepad hosts &#xff0c;并回車&#xff1a; notepad hosts 4、然后…

DataFunSummit:2023年現代數據棧技術峰會-核心PPT資料下載

一、峰會簡介 現代數據棧&#xff08;Modern Data Stack&#xff09;是一種集合了多種技術和工具的軟件基礎設施&#xff0c;旨在更好地管理和處理數據&#xff0c;并為企業提供數據驅動的洞察和決策。包含以下幾個組件&#xff1a;數據采集、數據處理、數據存儲、數據查詢和分…

區塊鏈技術與應用 【全國職業院校技能大賽國賽題目解析】第四套區塊鏈應用后端開發

第四套區塊鏈應用后端開發 環境 : ubuntu20 fisco : 2.8.0 springboot 2.1.1 fisco-java-sdk: 2.7.2 maven 3.8.8 前言 這套后端樣題,只涉及調用fisco的系統接口,不涉及此食品溯源項目的業務接口,所以我就直接生成一個springboot項目進行完成此題目。 請提前準備好一…

Docker的項目資源參考

Docker的項目資源包括以下內容&#xff1a; Docker官方網站&#xff1a;https://www.docker.com/ Docker Hub&#xff1a;https://hub.docker.com/ Docker文檔&#xff1a;https://docs.docker.com/ Docker GitHub倉庫&#xff1a;https://github.com/docker Docker官方博客…