數據結構總結


什么是數據結構?

數據結構是指存在特定相互關系的數據元素的集合。元素之間的相互關系稱為數據的邏輯結構,數據元素及元素之間關系的存儲稱為存儲結構或物理結構。通常情況下,精心選擇的數據結構可以帶來更高的運行或者存儲效率。

數據結構的分類

數據結構的邏輯結構主要分為線性結構與非線性結構兩大類。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/1F84B8C9F748468E820CF0E1AF7F333E/16026
 
存儲結構主要分為順序存儲、鏈式存儲、索引存儲、散列存儲
順序存儲:采用一組地址連續的存儲單元依次進行存儲(例如:數組)。
鏈式存儲:用通過指針鏈接起來的結點進行存儲,結點的地址不要求連續(例如:鏈表)。
索引存儲:建立索引表,通過索引表的索引號還確定結點存儲地址。
散列存儲:散列存儲,又稱hash存儲,是一種力圖將數據元素的存儲位置與關鍵碼之間建立確定對應關系的查找技術。散列法存儲的基本思想是:由結點的關鍵碼值決定結點的存儲地址。除了用來查找之外還可以用來存儲。

線性表

線性表的定義

線性結構是一種基本的數據結構,主要用於對客觀世界中具有單一前驅和后繼的數據關系進行描述。線性結構的特點是數據元素之間呈現一種線性關系,即元素“ 一個接一個地排列 ”。
線性表是最簡單、最基本、也是最常用的一種線性結構。通常采用順序存儲和鏈式存儲,主要的基本操作是插入、刪除和查找等。
線性表是n(n>=0)個具有相同特性的數據元素的有限序列。非空線性表的特點如下。
(1)存在唯一的一個稱作“ 第一個 ”的元素。
      (2)存在唯一的一個稱作“ 最后一個 ”的元素。
       (3)除第一個元素外,序列中的每個元素均只有一個直接前驅。
       (4)除最后一個元素外,序列中的每個元素均只有一個直接后繼。
 

線性表的存儲結構

線性表的存儲結構分為順序存儲和鏈式存儲。
線性表的順序存儲是指用一組地址連續的存儲單元依次存儲線性表中的數據元素,從而使得邏輯上相鄰的兩個元素在物理位置上也相鄰,如圖:
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/551F06FE7F3045D99B13B93A3BC890DC/16033
 
線性表采用順序存儲結構的優點是可以隨機存取表中的元素,缺點是插入和刪除操作需要移動元素。
 
線性表的鏈式存儲是用結點來存儲數據元素,基本的結點結構如下所示:
 
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/2F3AEA40ED994B85B7BFC2BF2E62F131/16032
其中,數據域用於存儲數據元素的值,指針域則存儲當前元素的直接前驅和直接后繼信息,指針域中的信息稱為指針(或鏈)。
     存儲各數據元素的結點的地址並不要求是連續的,因此存儲數據元素的同時必須存儲元素之間的邏輯關系。
     另外,結點空間只有在需要的時候才申請,無需事先分配。
    結點之間通過指針域構成一個鏈表,若結點中只有一個指針域,則稱為線性鏈表(或單鏈表),如圖所示:
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/2DA8B4F1A63041B186AD85C91EE4617F/16027
在鏈表的存儲結構中,只需要一個指針(稱為頭指針,如上圖中的 head)指向第一個結點,就可以順序訪問到表中的任一個元素。
在鏈式存儲結構下進行插入和刪除,其實質都是對相關指針的修改。
線性表采用鏈表作為存儲結構時,不能對數據元素進行隨機訪問(需要對數據元素進行遍歷),但是插入和刪除操作不需要移動元素。
 
根據結點中指針域的設置方式,還有其他幾種鏈表結構。
  雙向鏈表。每個結點包含兩個指針,分別指出當前結點元素的直接前驅和直接后繼。其特點是可從表中任意的元素結點出發,從兩個方向遍歷鏈表。
循環鏈表。在單項鏈表(或雙向鏈表的基礎上),令表尾結點的指針指向表中的第一個結點,構成循環鏈表。 其特點是可以從表中任意結點開始遍歷整個鏈表。
靜態鏈表。借助數組來描述線性表的鏈式存儲結構。用數組元素的下標表表示元素所在結點的指針。
 

棧的定義

棧是只能通過訪問它的一端來實現數據存儲和檢索的一種線性數據結構。也就是說,棧是按“ 后進先出 ”的規則進行操作。因此,棧又稱為后進先出(Last In First Out,LIFO)的線性表。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/C3C088956CFE4A678FD04D2FDEE2682C/16023
在棧中進行插入和刪除操作的一端稱為棧頂(top),相應地,另一端稱為棧底(bottom)。不含數據元素的棧稱為空棧。
 

棧的基本運算

① 初始化棧 InitStack(S):創建一個空棧S。
② 判棧空 StackEmpty(S):當棧 S 為空時返回“ 真 ”值,否則返回“ 假 ”值。
③ 入棧 Push(S,x):將元素 x 加入棧頂,並更新棧頂指針。
④ 出棧 Pop(S):將棧頂元素從棧中刪除,並更新棧頂指針。若需要得到棧頂元素的值,可將 Pop(S)定義為一個返回棧頂元素值的函數。
⑤ 讀棧頂元素 Top(S):返回棧頂元素的值,但不修改棧頂指針。
 

棧的存儲結構

順序存儲(順序棧):棧的順序存儲是指用一組地址連續的存儲單元依次存儲自棧頂到棧底的數據元素,同時附設指針 top 指示棧頂元素的位置。在該存儲方式下,需要預先定義(或申請)棧的存儲空間,棧空間的容量是有限的。因此,在順序棧中,當一個元素入棧時,需要判斷是否棧滿(棧空間中沒有空閑單元),若棧滿,則元素入棧發生上溢現象。
鏈式存儲(鏈棧):棧的鏈式存儲是指用鏈表存儲棧中的數據元素,它解決了可能發生上溢的不足。由於棧中元素的插入和刪除僅在棧頂一端進行,因此不必設置頭結點,鏈表的頭指針就是棧頂指針。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/96D2D6A09B54430AA0489F4DB54069C9/16029

棧的應用

  棧的典型應用包括表達式求值、括號匹配等,在計算機語言的實現以及遞歸過程轉變為非遞歸過程的處理中,棧有重要作用

 

隊列

隊列的定義

隊列式一種先進先出(First In First Out,FIFO)的線性表,它只允許在表的一端插入元素,而在表的另一端刪除元素。在隊列中,允許插入元素的一端稱為隊尾(rear),允許刪除元素的一端稱為隊頭(front)。
 

隊列的基本運算

① 初始化隊 InitQueue(Q):創建一個空的隊列 Q。
② 判隊空 Empty(Q):當隊列為空時返回“ 真 ”值,否則返回“ 假 ”值。
③ 入隊 EnQueue(Q,x):將元素 x 加入到隊列Q的隊尾,並更新隊尾指針。
④  出隊 DeQueue(Q):將隊頭元素從隊列Q中刪除,並更新隊頭指針。
⑤  讀取隊頭元素FrontQue(Q):返回隊頭元素的值,但不更新隊頭指針。

隊列的存儲結構

順序存儲:隊列的順序存儲結構又稱為順序隊列,它也是利用一組地址連續的存儲單元存放隊列中的元素。由於隊列中元素的插入和刪除限定在表的兩端進行,因此設置隊頭和隊尾指針,分別指示出當前的隊首元素和隊尾元素。
在順序隊列中,為了降低運算的復雜度,元素入隊時只修改隊尾指針,元素出隊時只修改隊頭指針。下面設順序隊列 Q 的容量為 6,其隊頭指針 為 front,隊尾指針為 rear,頭、尾指針和隊列中的元素之間的關系如圖:
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/CD5BA96012AD459686B7B524EB01981F/16024
由於順序隊列的存儲空間是提前設定的,所以隊尾指針會有一個上限值,當隊尾指針達到該上限時,就不能只通過修改隊尾指針來實現新元素的入隊操作了。此時,可通過除取余運算順序隊列假想成一個環狀結構,稱之為循環隊列。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/6D922BECEE4B483185E729F1C1ED7D99/16028
設置循環隊列Q的容量 MAXSIZE,初始時隊列為空,且Q.rear 和 Q.front 都等於 0。
元素入隊時,修改隊尾指針 Q.rear = (Q.rear+1)%MAXSIZE。
元素出隊時,修改隊頭指針 Q.front = (Q.front+1)%MAXSIZE。
在隊列空和隊列滿的情況下,循環隊列的隊頭、隊尾指針指向的位置是相同的,此時僅僅根據 Q.rear 和 Q.front之間的關系無法判定隊列的狀態。
為了區別隊空和隊滿的情況,可采用以下兩種處理方式:
其一,是設置一個標志位,以區別頭、尾指針的值相同時隊列式空還是滿;
其二,是犧牲一個存儲單元,約定以“ 隊列的尾指針所指位置的下一個位置是隊頭指針 ”表示隊列滿,而頭、尾指針的值相同時表示隊列為空。
 
鏈式存儲: 隊列的鏈式存儲也稱為鏈隊列。這里為了便於操作,給鏈隊列添加一個頭結點,並令頭指針指向頭結點。因此,隊列為空的判定條件是:頭指針和尾指針的值相同,且均指向頭結點。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/32CF28CC8F954F7B8D98C08C8AAE27EB/16031
 

隊列的應用

隊列結構常用於處理需要排隊的場合,如操作系統中處理打印任務的打印隊列、離散事件的計算機模擬等。
 
 

串的定義

串(字符串)是一種特殊的線性表,其數據元素為字符。計算機中非數值問題處理的對象經常是字符串數據。串是僅由字符構成的有限序列,是取值范圍受限的線性表。一般記為 S=‘a1a2...an’,其中 S 是串名,單引號括起來的字符序列是串值。
 

串的幾個基本概念

空串:長度為零的串,空串不包含任何字符。
空格串:由一個或多個空格組成的串。雖然空格是一個空白字符,但它也是一個字符,計算串長度時要將其計算在內。
子串:由串中任意長度的連續字符構成的序列稱為子串。含有子串的串稱為主串。子串在主串中的位置是指子串首次出現時,該子串的第一個字符在主串中的位置。空串是任意串的子串。
串相等:指兩個串長度相等且對應位置上的字符也相同。
串比較:兩個串比較大小時以字符的ASCII碼值(或其他字符編碼集合)作為依據。比較操作從兩個串的第一個字符開始進行,字符的碼值大者所在的串為大;若其中一個串先結束,則以串長較大者為大。
 

串的基本操作

① 賦值操作 StrAssign(s,t):將串 s 的值賦給串 t。
② 聯接操作 Concat(s,t):將串 t 接續在 s 的尾部,形成一個新串。
③ 求串長 StrLength(s):返回串 s 的長度。
④ 串比較 StrCompare(s,t):比較兩個串的大小。返回值 -1、0 和 1 分別表示 s<t、s=t 和 s>t 三種情況。
⑤ 求子串 SubString(s,start,len):返回串 s 中從 start 開始的、長度為 len 的字符串序列。
 

串的存儲結構

順序存儲:串的順序存儲結構是指用一組地址連續的存儲單元來存儲串值的字符序列。由於串中的元素為字符,所以可通過程序語言提供的字符數組定義串的存儲空間,也可以根據串長的需要動態申請字符串的空間。
鏈式存儲:當鏈表存儲串中的字符時,每個結點中可以存儲一個字符,也可以存儲多個字符,此時要考慮存儲密度問題。在鏈式存儲結構中,結點大小的選擇和順序存儲方法中數組空間大小的選擇一樣重要,它直接影響對串的處理效率。
 

串的模式匹配

子串的定位操作通常稱為串的模式匹配,它是各種串處理系統中最重要的運算之一。子串也稱為模式串。
(1)朴素的模式匹配算法:
該算法也稱為布魯特-福斯算法,其基本思想是從主串的第一個字符起與模式串的第一個字符比較,若相等,則繼續逐對字符串后續的比較,否則從主串第二個字符起與模式串的第一個字符重新比較,直至模式串中每個字符依次和主串中一個連續的字符序列相等時為止,此時稱為匹配成功。如果不能在主串中找到與模式串相同的子串,則匹配失敗。
(2)改進的模式匹配算法:
改進的模式匹配算法又稱為 KMP 算法,其改進之處在於:每當匹配過程中出現相比較的字符不相等時,不需要回溯主串的字符串位置指針,而是利用已經得到的“ 部分匹配 ”結果,將模式串向右“ 滑動 ”盡可能遠的距離,再繼續進行比較。
設模式串為“ P0... Pm-1 ”,KMP 匹配算法的思想是:當模式串中的字符 Pj 與主串中相應的字符 Si不相等時,因其前 j個字符(“P0...Pj-1”)已經獲得了匹配,所以若模式串中的“P0...Pk-1”與“Pj-k...Pj-1”相同,這時可令Pk與Si進行比較,從而是 i 無需回退。
在 KMP 算法中,依據模式串的 next 函數值實現了子串的滑動。若令 next[j] = k,則 next[j] 表示當模式串中的Pj 與主串中相應字符不相等時,令模式串的 Pk 與主串的相應字符進行比較。
       next 函數的定義如下:       
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/CFA218FC6AF14238B63D2527EC8C4B84/16030
 

樹的定義

樹結構是一種非常重要的非線性結構,該結構中一個數據元素可以有兩個或兩個以上的直接后繼元素,樹可以用來描述客觀世界中廣泛存在的層次結構關系。
樹是 n(n≥0)個結點的有限集合,當 n=0 時稱為空樹。在任一非空樹(n>0)中,有且僅有一個稱為根的結點;其余結點可分為 m(m≥0)個互不相交的有限集 T1,T2,...,Tm,其中每個 Ti又都是一棵樹,並且稱為根結點的子樹。
樹的定義是遞歸的,它表明了樹本身的固有特性,也就是一棵樹由若干棵子樹構成,而子樹又由更小的子樹構成。
 

樹的基本概念

   (1)雙親、孩子和兄弟:結點的子樹的根稱為該結點的孩子;相應地,該結點稱為其子結點的雙親。具有相同雙親的結點互為兄弟。
   (2)結點的度:一個結點的子樹的個數記為該結點的度。
   (3)葉子結點:也稱為終端結點,指度為 0 的結點。
   (4)內部結點:度不為 0 的結點稱為分支結點或非終端結點。出根結點之外,分支結點稱為內部結點。
   (5)結點的層次:根為第一層,根的孩子為第二層,以此類推,若某結點在第 i 層,則其孩子結點在第 i+1 層。
   (6)樹的高度:一棵樹的最大層次樹記為樹的高度(或深度)。
   (7)有序(無序)樹:若樹中結點的各子樹看成是從左到右具有次序的,即不能交換,則稱該樹為有序樹,否則稱為無序樹。
 

二叉樹

二叉樹的定義

二叉樹是 n (n≥0)個結點的有限集合,它或者是空樹(n = 0),或者是由一個根結點及兩棵不相交的且分別成為左、右子樹的二叉樹所組成。
樹和二叉樹之間最主要的區別是:二叉樹結點的子樹要區分左子樹和右子樹,即使在結點只有一顆子樹的情況下,也要明確指出該子樹是左子樹還是右子樹。另外,二叉樹結點最大度為2,而樹中不限制結點的度數。
 
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/3BC442F1389F4337AD2D6638517A86E1/16025
 

二叉樹的性質

(1)二叉樹第 i 層(i≥1)上至多有 2^{i-1}個結點。
(2)高度為 k 的二叉樹至多有 2^{k}-1個結點(k≥1)。
(3)對任何一棵二叉樹,若其終端結點數為 n_{0},度為2的結點數 為n_{2},則n_{0}=n_{2}+1。
(4)具有 n 個結點的完全二叉樹的深度為log₂n+1。
 
若深度為k的二叉樹有 個結點,則稱其為滿二叉樹。對滿二叉樹的結點進行連續編號:約定編號從根結點起,自上而下、自左而右依次進行。深度為k、有n 個結點的二叉樹,當且僅當其每一個結點都與深度為 k的滿二叉樹中編號從 1 至 n 的結點一一對應時,稱之為完全二叉樹。滿二叉樹和完全二叉樹的示意圖如圖所示
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/7AD65E9307DE4A44BA723A4E61462751/16020

二叉樹的存儲結構

順序存儲:用一組地址連續的存儲單元存儲二叉樹的結點,必須把結點排成一個適當的線性序列,並且結點在這個序列中的相互位置能反映出結點之間的邏輯關系。
對於深度為 k 的完全二叉樹,除第 k 層外,其余各層中含有最大的結點數,即每一層的結點數恰為其上一層結點數的兩倍,由此從一個結點的編號可推知其雙親、左孩子和右孩子的編號。
假設有編號為 i 的結點,則有:
若 i=1 ,該結點為根結點,無雙親;若 i>1 ,該結點的雙親結點為i/2(取整數)。
若 2i≤ n,則該結點的左孩子編號為2i,否則無左孩子。
若 2i+1 ≤ n,則該結點的右孩子編號為 2i+1,否則無右孩子。
 
二叉樹的順序存儲結構如圖所示
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/D5BF6E4A54B343DFB6BA303CBDD39D75/16022
完全二叉樹采用順序存儲結構既簡單又節省空間,對於一般的二叉樹,則不宜采用順序存儲結構。因為一般的二叉樹也必須按照完全二叉樹的形式存儲,也就是要添上一些實際並不存在的“虛結點”,這將造成空間的浪費。
 
鏈式存儲:由於二叉樹的結點中包含有數據元素、左子樹的根、右子樹的根及雙親等信息,因此可以用三叉鏈表或二叉鏈表(即一個結點含有三個指針或兩個指針)來存儲二叉樹,鏈表的頭指針指向二叉樹的根結點。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/8B76BF104D704D04B2903BEB67E3B0CB/16021
 

二叉樹的遍歷

遍歷是按某種策略訪問樹中的每個結點,且僅訪問一次的過程。由於二叉樹所具有的的遞歸性質,一棵非空的二叉樹可以看作是由根結點、左子樹和右子樹三部分構成的,因此若能依次遍歷這三部分,也就遍歷了整棵二叉樹。按照先遍歷左子樹后遍歷右子樹的約定,根據訪問根結點位置的不同,可得到二叉樹的先序、中序和后序三種遍歷方法。
先序遍歷:按照根-左-右的順序進行遍歷。
中序遍歷:按照左-根-右的順序進行遍歷。
后序遍歷:按照左-右-根的順序進行遍歷。
二叉樹的遍歷實質上是對一個非線性結構進行線性化的過程,它使得每個結點(除第一個和最后一個外)在這些線性序列中有且僅有一個直接前驅和直接后繼。
 

最優二叉樹

最優二叉樹的定義

最優二叉樹又稱為哈夫曼樹,是一類帶權路徑長度最短的樹。 路徑是從樹中一個結點到另一個結點之間的通路,路徑上的分支數目稱為路徑長度。
樹的路徑長度是從樹根到每一個葉子之間的路徑長度之和。結點的帶權路徑長度為從該結點到樹根之間的路徑長度與該結點帶權的乘積。
樹的帶權路徑長度為樹中所有葉子結點的帶權路徑長度之和,記為
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/EB185358FC844D3DBC05F2989B100191/16035
其中, n 為帶權葉子結點數目,w_{k}為葉子結點的權值,l_{k}為葉子 結點到根的路徑長度。
 
下圖所示的具有 4 個葉子結點的二叉樹,其中以圖(b)所示二叉樹帶權路徑長度最小。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/61BDA448BF1445F4A98A3C062F4F3002/16044
 
構造最優二叉樹的哈夫曼算法如下:
           (1)根據給定的 n 個權值{ w1,w2,...,wn },構成 n 棵二叉樹的集合 F={T1,T2,...,Tn  },其中每棵樹Ti中只有一個帶權為wi的根結點,其左右子樹均空。
           (2)在 F 中選取兩棵權值最小的樹作為左、右子樹構造一棵新的二叉樹,置新構造二叉樹的根結點的權值為其左、右子樹根結點的權值之和。
           (3)從 F 中刪除這兩棵樹,同時將新得到的二叉樹加入到 F 中。
         重復 (2)、(3)步,直到 F 中只含一棵樹時為止,這棵樹便是最優二叉樹(哈夫曼樹)。

哈夫曼編碼

若對每個字符編制相同長度的二進制碼,則稱為等長編碼。例如,英文字符集中的 26個字符采用 5 位二進制串表示,按等長編碼格式構造一個字符編碼表。發送方按照編碼表對信息原文進行編碼后送出電文,接收方對接收到的二進制代碼按每 5 位一組進行分割,通過查字符的編碼表即可得到對應字符,實現譯碼。
等長編碼方案的實現方法比較簡單,但對通信中的原文進行編碼后,所得電文的碼串過長,不利於提高通信效率,因此希望縮短碼串的總長度。如果對每個字符設計長度不等的編碼,且讓電文出現次數較多的采用盡可能短的編碼,那么傳送的電文碼串總長度則可減少。
要設計長度不等的編碼,必須滿足下面的條件:任一字符的編碼都不是另一個字符的編碼的前綴,這種編碼也稱為前綴碼。
對給定的字符集 D及字符的使用頻率 W,構造其最優前綴碼的方法為:以 D作為葉子結點,W 作為葉子結點的權值,構造出一棵最優二叉樹,然后將樹中每個結點的左分支標上 0,右分支標上 1,則每個葉子結點代表的字符的編碼就是從根到葉子的路徑上的 0、1組成的串。
利用哈夫曼譯碼的過程為:從根結點出發,按二進制位串(編碼序列)中的 0 和 1 確定是進入左分支還是右分支(當前編碼為0進入當前結點的左子樹,為1則進入右子樹),當到達葉子結點時譯出一個字符。若位串未結束,則回溯到根結點接續上述譯碼過程。
例如,設有字符集{a,b,c,d,e}及對應的權值集合{0.3,0.25,0.15,0.22,0.08},按照構造最優二叉樹的哈夫曼算法構建最優二叉樹后得到
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/96F44405F8234A12BC2751B95AF16F51/16081
若編碼序列為101110000100,翻譯出的字符序列為"edaac"。
 
 

二叉排序樹

二叉排序樹的定義

二叉排序樹又稱二叉查找樹,它或者是一棵空樹,或者是具有以下性質的二叉樹。
(1)若它的左子樹非空,則左子樹上所有結點的值均小於根結點的值。
(2〉若它的右子樹非空,則右子樹上所有結點的值均大於根結點的值。
(3)左、右子樹本身是二叉排序樹。
如圖:
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/0258C8FE00004B3689EC9D2740B6C006/16143

二叉排序樹的查找過程

二叉排序樹非空時,將給定值與根結點的關鍵字值相比較,若相等,則查找成功;若不相等,則當根結點的關鍵字值大於給定值時,下一步到根的左子樹中進行查找,否則到根的右子樹中進行查找。若查找成功,則查找過程是走了一條從樹根到所找到結點的路徑;否則,查找過程終止於一棵空的子樹。
 

在二叉樹中插入結點

二叉排序樹是通過依次輸入數據元素並把它們插入到二叉樹的適當位置構造起來的,具體的過程是:每讀入一個元素,建立一個新結點。若二叉排序樹非空,則將新結點的值與根結點的值相比較,如果小於根結點的值,則插入到左子樹中,否則插入到右子樹中;若二叉排序樹為空,則新結點作為二叉排序樹的根結點。設關鍵字序列為{46,25,54,13,29,91},則整個二叉排序樹的構造過程如圖所示。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/C0936CCDD45C4881BB323D992BD46A80/16154
 

在二叉樹中刪除結點

在二叉排序樹中刪除一個結點,不能把以該結點為根的子樹都刪除,只能刪除這個結點並仍舊保持二叉排序樹的特性。也就是說,在二叉排序樹上刪除一個結點相當於在有序序列中刪除一個元素。刪去葉子結點后需要修改其雙親結點已經左右子樹的指針保證不破壞整棵樹的結構。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/1B3795A536514DB7825D0A2CE1E91804/16169
 

平衡二叉樹

平衡二叉樹又稱為AVL樹,它或者是一棵空樹,或者是具有下列性質的二叉樹。它的左子樹和右子樹都是平衡二叉樹,且左子樹和右子樹的高度之差的絕對值不超過1。若將二叉樹結點的平衡因子(Balance Factor,BF)定義為該結點左子樹的高度減去其右子樹的高度,則平衡二叉樹上所有結點的平衡因子只可能是-1、0和1。只要樹上有一個結點的平衡因子的絕對值大於1,則該二叉樹就是不平衡的。
分析二叉排序樹的查找過程可知,只有在樹的形態比較均勻的情況下,查找效率才能達到最佳。因此,希望在構造二叉排序樹的過程中,保持其為一棵平衡二叉樹。
使二叉排序樹保持平衡的基本思想是:每當在二叉排序樹中插入一個結點時,首先檢查是否因插入破壞了平衡。若是,則找出其中的最小不平衡二叉樹,在保持二叉排序樹特性的情況下,調整最小不平衡子樹中結點之間的關系,以達到新的平衡。所謂最小不平衡子樹,是指離插入結點最近且以平衡因子的絕對值大於1的結點作為根的子樹。
 

平衡二叉樹上的插入操作

假設由於在二叉排序樹上插入結點而失去平衡的最小子樹根結點的指針為a,也就是說,a所指結點是離插入結點最近且平衡因子的絕對值超過1的祖先結點,那么,失去平衡后進行調整的規律可歸納為以下4種情況。
(1) LL型單向右旋平衡處理。如下圖所示,由於在*a(即結點A)的左子樹的左子樹上插入新結點,使*a的平衡因子由1增至2,導致以*a為根的子樹失去平衡,因此需進行一次向右的順時針旋轉操作。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/2CC43DA3B6ED424BBEA2400042B36048/16183
(2)RR型單向左旋平衡處理。如下圖所示,由於在*a(即結點A)的右子樹的右子樹上插入新結點,使*a的平衡因子由-1變為-2,導致以*a為根的子樹失去平衡,因此需進行一次向左的逆時針旋轉操作。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/65AEB13C898D46A19C28BE25B47B8398/16189
(3)LR型先左后右雙向旋轉平衡處理。如下圖所示,由於在*a(即結點A)的左子樹的右子樹上插入新結點,使*a的平衡因子由1增至2,導致以*a為根結點的子樹失去平衡,因此需進行兩次旋轉(先左旋后右旋)操作。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/A407C104A441495784C6CDD7FAF19BDB/16194
(4)RL型先右后左雙向旋轉平衡處理。如下圖所示,由於在*a(即結點A)的右子樹的左子樹上插入新結點,使*a的平衡因子由-1變為-2,導致以*a為根結點的子樹失去平衡,因此需進行兩次旋轉(先右旋后左旋)操作。
https://note.youdao.com/yws/public/resource/0ccf1e0892bc9f9f7a1444921ed746d7/xmlnote/F2DDFBEB971F4DAEA100179DC1D537A8/16198
 

平衡二叉樹上的刪除操作

在平衡二叉樹上進行刪除操作比插入操作更復雜。若待刪結點的兩個子樹都不為空,就用該結點左子樹上的中序遍歷的最后一個結點(或其右子樹上的第一個結點)替換該結點,將情況轉化為待刪除的結點只有一個子樹后再進行處理。當一個結點被刪除后,從被刪結點到樹根的路徑上所有結點的平衡因子都需要更新。對於每一個位於該路徑上的平衡因子為+-2的結點來說,都要進行平衡處理。
 
 
參考資料:《軟件設計師教程(第5版)》 電子書鏈接:https://pan.baidu.com/s/1OEQJ6TLd1FzcFT852UBc-A 提取碼:7za7
ps:數據結構還有部分內容未總結,后續有時間會把其余內容補充完整
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM