二叉查找樹 _ 二叉排序樹 _ 二叉搜索樹_C++

来源:http://www.cnblogs.com/hadilo/archive/2016/07/31/5724118.html
-Advertisement-
Play Games

二叉查找樹,又名二叉排序樹,亦名二叉搜索樹,一種常用的樹形數據結構 ...


一、數據結構背景+代碼變數介紹

  二叉查找樹,又名二叉排序樹,亦名二叉搜索樹

  它滿足以下定義:

    1、任意節點的子樹又是一顆二叉查找樹,且左子樹的每個節點均小於該節點,右子樹的每個節點均大於該節點。

    2、由1可推出,任意節點的左孩子小於該節點,右孩子大於該節點

      以上討論的是左(右)孩子(子樹)存在的情況

  它的中序遍歷是一個升序的排序

  在參考代碼中,我們定義有:

    主程式中,k代表插入或刪除或查找的節點的值

    root,根節點位置;a[i],第 i 號節點的值;cl[i],第 i 號節點左孩子的位置;cr[i],第 i 號節點右孩子的位置;fa[i],父親節點位置;


二、中序遍歷

   中序遍歷的求法採用遞歸,先遞歸它的左孩子,然後列印當前節點,最後遞歸它的右孩子(當左或右孩子存在時才進行遞歸)

  

  如上圖的中序遍歷為 DBEAFC

  時間複雜度O(n)

1 void mid(int x)
2 {
3     if (time[cl[x]]!=0) mid(cl[x]);
4     cout<<a[x]<<" ";
5     if (time[cr[x]]!=0) mid(cr[x]);
6 }
7 
8 主程式中:mid(root);

 


三、插入節點

  我們採用遇到相同的節點,使該節點計數器+1的辦法

  先從根節點出發:

    1、若當前節點小於插入的數,則遞歸進入其左兒子

                   若左兒子計數器為0,即不存在左兒子,則直接將數插入到左兒子

    2、若當前節點大於插入的數,則遞歸進入其右兒子

                   若右兒子計數器為0,即不存在右兒子,則直接將數插入到右兒子

    3、若當前節點等於插入的數,則直接將該節點計數器+1

 

樣例一

  如上圖,將6插入該二叉樹

    1、與根節點比較,小於根節點,進入左兒子

    2、與2比較,大於2,進入右兒子

    3、與5比較,大於5,進入右兒子,但因右兒子不存在,所以將6作為其右兒子

樣例二

  如上圖,將1插入該二叉樹:

    1、與根節點比較,小於8,進入左兒子

    2、與2比較,小於2,進入左兒子,但因其左兒子不存在,所以將1作為其左兒子

  時間複雜度O(log2n)

 1 void ins(int i,int x)
 2 {
 3     if (root==0)
 4     {
 5         a[1]=x;
 6         time[1]=root=1;
 7         return;
 8     }
 9     if (x<a[i])
10     {
11         if (time[cl[i]]==0)
12         {
13             cl[i]=top>0?s[top--]:++tail;14             a[cl[i]]=x;
15             fa[cl[i]]=i;
16             time[cl[i]]++;
17             cr[cl[i]]=cl[cl[i]]=0;
18         }
19         else ins(cl[i],x);
20     }
21     else if (x>a[i])
22     {
23         if (time[cr[i]]==0)
24         {
25             cr[i]=top>0?s[top--]:++tail;26             a[cr[i]]=x;
27             fa[cr[i]]=i;
28             time[cr[i]]++;
29             cr[cr[i]]=cl[cr[i]]=0;
30         }
31         else ins(cr[i],x);
32     }
33     else
34     {
35         time[i]++;
36     }
37 }
38 
39 主程式中:ser(root,k); root代表起始位置,k代表插入的值

 


四、查找節點

  查找類似於插入

  同樣從根節點出發,如果遇到了空節點,即計數器等於0的節點,直接返回0,表示未查找到

  若該節點等於查找的值,則返回該節點的位置

  若該節點大於查找的值,則向左兒子遞歸查找

  若該節點小於查找的值,則向右兒子遞歸查找

  此處說明,若當前節點為空節點,則說明小於(大於)該節點父親的值不存在,即未查找到

  查找類似於線段樹思想,是一步步向下把範圍縮小,直到找到期望的值或無結果

 

樣例一

 

  如上圖,需查找的值為5

    1、查找根節點,5<8,進入左兒子

    2、5>2,進入右兒子

    3、5=5,查找到該節點,返回該節點的位置

  若需查找的值為4時,在第3步會進入其左兒子,又因左兒子為空節點,則返回0,說明未查找到

  時間複雜度O(log2n)

1 int sea(int i,int x)
2 {
3     if (time[i]==0) return 0;
4     if (a[i]==x) return i;
5     else if (a[i]>x) return ser(cl[i],x);
6     else return ser(cr[i],x);
7 }
8 
9 主程式中:sea(root,k); root代表查找的起始位置,k代表查找的值

 

 


五、刪除節點

  當需要刪除節點時,先查找改值所在的位置,然後再進行刪除

  如果該節點計數器大於1,則只用把計數器-1

  如果計數器等於1,即刪除後該節點不再存在,則根據兒子的數目分為三種情況:

    1、沒有兒子:直接將該節點刪除

    2、一個兒子:將該節點父親的左(右)兒子直接指向該節點的唯一的那個兒子

    3、兩個兒子:在該節點的右子樹中尋找一個最小的值,然後用最小的那個節點替代該節點,最後刪除最小的節點

            尋找最小節點具體方法:先將目前節點指向右兒子,然後尋找不斷指向目前節點的左兒子,直到沒有左兒子為止

            因為需要刪除的最小節點肯定沒有左兒子,所以只需遞歸執行第1或第2種情況,即 del(最小節點位置,最小節點的值)具體請參考代碼

樣例一

  刪除9節點:調用查找,查找到9的位置,因為它沒有兒子,可直接刪除

 

樣例二

  刪除5節點:同樣查找5節點的位置,發現其有1個孩子,則將 5節點 的 父親2節點 的 右孩子 指向 5節點 的 孩子6節點,這樣就自動刪除了5節點

 

樣例三

  刪除2節點:

    1、查找到2節點的位置

    2、把最小節點指向其右孩子

    3、不斷尋找目前最小節點的左孩子,直到盡頭,找到最小節點

    4、將最小節點的信息賦給2節點

    5、按照刪除節點的方法刪除最小節點4節點

  時間複雜度O(log2n)

 1 void del(int k,int x)
 2 {
 3     int ct=0;
 4     if (cl[k]!=0) ct++;
 5     if (cr[k]!=0) ct++;
 6     time[k]--;
 7     if (time[k]==0)
 8     {
 9         if (ct==1)
10         {
11             s[++top]=k;12             if (k==root)
13             {
14                 root=time[cr[k]]==0?cl[k]:cr[k];
15                 return;
16             }
17             if (x<a[fa[k]]) cl[fa[k]]=time[cr[k]]==0?cl[k]:cr[k];
18             else cr[fa[k]]=time[cr[k]]==0?cl[k]:cr[k];
19         }
20         else if (ct==2)
21         {
22             int s=cr[k];
23             if (time[cl[s]]!=0) s=cl[s];
24             time[k]=time[s];
25             a[k]=a[s];
26             del(s,a[s]);
27         }
28         else s[++top]=k;29     }
30 }
31 
32 主程式中:del(sea(root,k),k); 先查找到需刪除的節點的位置,然後刪除k

 


 

六、空節點位置棧

  在刪除節點的時候,會產生許多空節點

  為了節省空間,我們會開一個棧來保存空節點的位置,當刪除某個節點後,把它空出來的位置壓入棧中

  當插入節點時,先詢問棧頂top是否大於0,若棧中有元素,則把棧中的位置彈出,用該位置存放節點

                      若棧中沒有元素,表示前面沒有空的位置,則新開一個空間來存放節點,通過保存最大位置數的變數tail來控制最大位置

 


 

七、特殊情況

  對於二叉查找樹會產生如下圖的情況

 

   則所有操作的時間往往會被卡成線性O(n),而利用平衡二叉樹、伸展樹、紅黑樹等等數據結構便會幫我們解決這個問題

 

 

版權所有,轉載請聯繫作者,違者必究

QQ:740929894


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說明:本文是個人翻譯文章,由於個人水平有限,有不對的地方請大家幫忙更正。 原文: "dotnet run" 翻譯: "dotnet run" 名稱 dotnet run 沒有任何明確的編譯或啟動命令運行“就地”(即運行命令的目錄)源代碼。 概要 `dotnet run [ framework] [ ...
  • 發現很少有集中討論C#可變性限制的中文博文(要麼就是一大段文字中夾雜很多凌亂的部分),所以寫發篇博文,集中討論,這些限制基本是基於安全考慮,亦或者根本難以實現而產生的。 註:本文不再解釋什麼是可變性,以及本文所討論的問題都基於.NET 4至.NET 4.5。所有地方我都力求簡潔。 好了,廢話不說了, ...
  • 隨著互聯網項目用戶訪問量不斷上升,單點web伺服器是無法滿足大型高併發高負載的業務處理的,為了給web伺服器做負載均衡方案,打算採用Nginx搭建負載均衡伺服器,把用戶請求分配到N個伺服器來緩解伺服器壓力。 Nginx簡介: Nginx (“engine x”) 是一個高性能的 HTTP 和 反向代 ...
  • 前段時間,一直有練習ASP.NET MVC與Web API交互,接下來,Insus.NET再做一些相關的練習,Web API與文件操作,如POST文件至Web API,更新或是刪除等。不管怎樣,先在資料庫創建一張表,用來存儲上傳的文件。本實例中是把文件存儲過資料庫的。 CREATE TABLE Ap ...
  • 1.continue,break,ruturn eg:1-100的和 結果為:5050 換為break,查看結果 結果為:10 結論一:break:跳出整個迴圈體 換為continue看一下結果又是多少? 結果為:5045,(除5之外都執行) 結論二:continue跳過當前條件的迴圈 return ...
  • 目錄索引 【無私分享:ASP.NET CORE 項目實戰】目錄索引 簡介 本章我們來介紹下Asp.net Core 使用 CodeFirst 創建資料庫和表,通過 控制台 和 dotnet ef 兩種方式 修改EF上下文對象,添加測試類 我修改了一下名字,Domains 改為了 wkmvc.Data ...
  • 字元串操作大概是電腦程式中最常見的操作了,Java中表示字元串的類是String,它有哪些方法?內部是如何實現的?如何處理各種不同的編碼?不可變性意味著什麼?字元串常量到底是什麼?hashCode是如何實現的?... ...
  • lambda是一種匿名函數,python lambda可以使簡單的函數簡潔的表達,,C++的lambda使類似嵌套函數的功能得以實現 python的lambda VC++14的lambda lambda是vc++獨有的,在vc++11以後,擴展這個功能主要是為了使代碼書寫簡潔,gcc沒有這個功能 直 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...