大話數據結構——樹

一、樹的定義

樹(Tree)是n(n>=0)個結點的有限集。 n=0又稱為空樹。在任意一課非空的樹中:(1)有且僅有一個特定的稱為跟(Root)的結點;(2)當n>1時,其余結點可分為m(m>0)個互不相交的有限集,其中每一個集合本身又是一棵樹,并且稱為根的子樹(SubTree)。
樹是一種一對多的數據結構。
需要注意的是:
(1)當n>0時根結點是惟一的,不可能存在多個根結點。
(2)m>0時,子樹的個數沒有限制,但它們一定是互不相交的。如果相交,就不符合樹的定義。
結點分類
結點擁有的子樹稱為結點的度。度為0的結點稱為葉結點或終端結點;度不為0的結點稱為非終端結點或分支結點。除根結點外,分支結點也稱為內部結點。樹的度是樹內各結點的度的最大值。如圖所示,樹的最大結點是D的度,為3,則樹的度也為3.
結點分類
樹中結點最大的層次稱為樹的深度或高度
如果將樹中結點的各子樹看成從左到右是有次序的,不能互換的,則稱該樹為有序樹,否則稱為無序樹
森林是m(m>=0)棵互不相交的樹的集合。

二、樹的存儲結構

簡單的順序存儲結構和鏈式存儲結構表示不了樹一對多的關系。試想,數據元素挨個的存儲,誰是誰的雙親,誰是誰的孩子呢?
樹有自己的三種不同表示法:雙親表示法、孩子表示法、孩子兄弟表示法。
1. 雙親表示法
在每個結點中,附設一個指示器指示雙親結點在數組中的位置。結點結構表如下。

dataparent

其中,data是數據域,存儲結點的數據信息。而parent是指針域,存儲該結點的雙親在數組的下標。
標出雙親,左右結點則構成樹。
雙親表示法
2. 孩子表示法
先介紹一種多種鏈表表示法:每個結點有多個指針域,其中每個指針指向一棵子樹的根結點。
方案一:
指針域的個數就等于樹的度。

datachild1child2child3……childd

其中data是數據域,child1到childd是指針域,用來指向該結點的孩子結點。對于圖6-4-1的樹來說,樹的度是3,所以指針域的個數是3。如下圖。
多重鏈表表示法
這種方法對于樹中各結點的度相差很大是,顯然是浪費空間的,因為有很多的結點,它的指針域都是空的。不過如果樹的各結點度相差很小時,那就意味著開辟的空間被充分利用了,這時存儲結構的缺點反而變成了優點。
為了按需分配空間,我們考慮方案二。
方案二:
每個結點指針域的個數等于該結點的度。

datadegreechild2child2……childd

其中data是數據域,degree為度域,也就是存儲該結點的孩子結點的個數,child1到childd為指針域,指向該結點的各孩子結點。如下圖。
多重鏈表表示法
這種方案也有缺點,就是會給結點的維護帶來麻煩。所以,我們提出孩子表示法。
孩子表示法: 把每個結點的孩子結點排列起來,以單鏈表作存儲結構,則n個結點有n個孩子鏈表,如果是葉子結點則次單鏈表為空。然后n個頭指針又組成一個線性表,采用順序存儲結構,存放進一個一維數組中。如下圖。
孩子表示法
為此,設計兩種結點結構,一個是孩子鏈表的孩子結點,如下圖。

childnext

其中child是數據域,用來存儲某個結點在表頭數組的下標。next是指針域,用來存儲指向某結點的下一個孩子結點的指針。
另一個是表頭數組的表頭結點,如下表。

datafirstchild

其中data是數據域,存儲某結點的數據信息。firstchild是頭指針域,存儲該結點的孩子鏈表頭指針。
但是,這種方法也找不到某個結點的雙親。于是有了雙親孩子表示法。如下圖。
雙親孩子表示法
3. 孩子兄弟表示法
任意一棵樹,它的結點的第一個孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我們設置兩個指針,分別指向該結點的第一個孩子和詞結點的右兄弟。

datafirstchildrightsib

其中data是數據域,firstchild為指針域,存儲該結點的第一個孩子結點的存儲地址,rightsib是指針域,存儲該結點的右兄弟結點的存儲地址。如下圖。
孩子兄弟表示法

三、二叉樹的定義

二叉樹(Binary Tree)是n(n>=0)個結點的有限集合,該集合或者為空集(稱為空二叉樹),或者由一個根結點和兩棵互不相交的、分別稱為根結點的左子樹和右子樹的二叉樹組成。
二叉樹的特點:

  • 每個結點最多有兩棵子樹,所以二叉樹中不存在大于2的結點。注意不是只有兩棵子樹,而是最多有。沒有子樹或者有一棵子樹都是可以的。
  • 左子樹和右子樹是有順序的,次序不能顛倒。就像人的左右手。
  • 即使樹中某結點只有一棵子樹,也要區分它是左子樹還是右子樹。

    二叉樹有5種基本形態:

    1. 空二叉樹。
    2. 只有一個根結點。
    3. 根結點只有左子樹。
    4. 根結點只有右子樹。
    5. 根結點既有左子樹又有右子樹。

    斜樹:只有左子樹或者只有右子樹。是一種特殊的線性表。

    滿二叉樹:所有分支結點都存在左子樹和右子樹,并且所有葉子都在同一層上。
    滿二叉樹的特點有:

    1. 葉子只能在最下一層。出現在其他層就不可能達到平衡。
    2. 非葉子結點的度一定是2。否則就是“缺胳膊少腿了”。
    3. 在同樣深度的二叉樹中,滿二叉樹的結點個數越多,葉子樹越多。

    完全二叉樹:

    1. 葉子結點只能在最下兩層。
    2. 最下層的葉子一定集中在左部連續的位置。
    3. 倒數第二層,若有葉子結點,一定都在右部連續位置。
    4. 如果結點度為1,則該結點只有左孩子,即不存在右子樹的情況。
    5. 同樣結點數從二叉樹,完全二叉樹的深度最小。

    判斷一棵樹是否是完全二叉樹,心中默默給每個結點按照滿二叉樹的結構逐層順序編號,如果編號出現空檔,就不是完全二叉樹,否則就是。
    滿二叉樹是特殊的完全二叉樹。
    完全二叉樹必須先滿足左后滿足右,缺的元素只能是滿二叉樹最下一層的,高度差小于或等于1。

四、二叉樹的存儲結構

(一)順序存儲結構
一般只有完全二叉樹才考慮順序存儲結構,因為完全二叉樹的嚴格性,可以充分利用順序存儲空間。其他二叉樹都會造成空間的浪費,特別是右斜樹。
(二)二叉鏈表
二叉樹每個結點最多有兩個孩子,所以為它設計一個數據域和兩個指針域,稱為二叉鏈表。

lchilddatarchild

其中data是數據域,lchild和rchild都是指針域,分別存放指向左孩子和右孩子的指針。
二叉鏈表

五、遍歷二叉樹

二叉樹的遍歷(traversing binary tree)是指從根結點出發,按照某種次序一次訪問樹中所有結點,使得每個結點被訪問一次且僅被訪問一次。

  1. 前序遍歷
    根–左子樹–右子樹
    前

  2. 中序遍歷
    左子樹–根–右子樹
    中

  3. 后序遍歷
    左子樹–右子樹–根
    后

  4. 層序遍歷
    根–第一層從左到右–第一層從左到右……
    層

已知前序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹。
已知后序遍歷序列和中序遍歷序列,可以唯一確定一棵二叉樹。
已知前序遍歷序列和后序遍歷序列,不可以唯一確定一棵二叉樹。

六、線索二叉樹

為了充分利用二叉鏈表的空指針,把空指針指向前驅和后繼,這種指向前驅和后繼的指針稱為線索,加上線索的二叉鏈表稱為線索鏈表,相應的二叉樹就稱為線索二叉樹。
對二叉樹一某種次序比那里時期變為線索二叉樹的過程稱作是線索化。線索化的過程就是在遍歷的過程中修改空指針的過程。
為了判別某一結點的lchild是指向左孩子還是前驅,rchild是指向右孩子還是后繼,引入ltag和rtag兩個標志域。

lchildltagdatartagrchild

其中,ltag為0時指向該結點的左孩子,為1時指向該結點的前驅;rtag為0時指向該結點的右孩子,為1時指向該結點的后繼;因為對6-10-1的圖的二叉鏈表圖可以修改如下圖。
線索二叉樹
如果所用的二叉樹需經常遍歷或查找結點時需要某種遍歷序列中的前驅和后繼,那么采用線索二叉鏈表的存儲結構就是不錯的選擇。

七、二叉樹的性質

  1. 在一棵高度為k的二叉樹中,結點總數為至多為2k(k次方)-1

八、樹、森林與二叉樹的轉換

(一)樹轉化為二叉樹
1. 加線。在所有兄弟結點之間加一條連線。
2. 去線。對樹中每個結點,只保留它與第一個孩子結點的連線,刪除它與其他孩子結點之間的連線。
3. 層次調整。以樹的根結點為軸心,將整棵樹瞬時間旋轉一定的角度。使之結構層次分明。之一第一個孩子是二叉樹結點的左孩子,兄弟轉換過來的孩子是結點的右孩子。
樹轉換為二叉樹
(二)森林轉換為二叉樹
森林是由若干棵樹組成的,所以完全可以理解為,森林中的每一棵樹都是兄弟,可以按照兄弟的處理辦法來操作,如下:
1. 把每個樹轉換為二叉樹;
2. 第一棵樹不動,從第二棵二叉樹開始,依次把后一棵二叉樹的根結點作為前一棵二叉樹的根結點的右孩子,用連線連接起來。當多有的二叉樹連接起來后就得到森林轉化的二叉樹。
森林轉換為二叉樹
(三)二叉樹轉換為樹
二叉樹轉換為樹是樹轉換為二叉樹的逆過程。
1. 加線。若某結點的左孩子結點存在,則將這個左孩子的右孩子結點、右孩子的右孩子結點、右孩子的右孩子的右孩子的結點……哈,反正就是左孩子的n個右孩子結點都作為此結點的孩子。將該結點與這些右孩子結點用線連接起來。
2. 去線。刪除原二叉樹中所有結點與其右孩子結點的連線。
3. 層次調整。使之結構層次分明。
二叉樹轉換為森林
(四)二叉樹轉換為森林
判斷一棵樹是否能轉換為一棵樹還是森林,就看它是否有右結點,若有,就可以轉為森林,否則,就是一棵樹。
1. 從根結點開始,若右孩子存在,則把與右孩子結點的連線刪除,再查看分離后的二叉樹,若右孩子存在,則連線刪除……,直到所有右孩子連線都刪除為止,得到分離的二叉樹。
2. 再將每棵分離后的二叉樹轉換為樹即可。
二叉樹轉換為樹
(五)樹與森林的遍歷
樹的遍歷分為兩種方式:
1. 一種是先根遍歷樹,即先訪問樹的根結點,然后依次先根遍歷根的每棵子樹。
2. 另一種是后根遍歷,即先依次后根遍歷每棵子樹,然后再訪問根結點。
森里的遍歷方式也分為兩種方式:
1. 前序遍歷:先訪問森林中第一棵樹的根結點,然后再依次先跟遍歷根的每棵子樹,再依次用同樣方式遍歷除去每一棵樹的剩余樹構成的森林。
2. 后序遍歷:先訪問森林中第一棵樹,后根遍歷的方式遍歷每棵子樹,然后再訪問根結點,再依次同樣方式遍歷除去第一棵樹的剩余樹構成的森林。
樹和森林的遍歷可參看(三)(四)圖中的筆記。
神奇的是,森林的前序遍歷和二叉樹的前序遍歷結果相同,森林的后序遍歷和二叉樹的中序遍歷結果相同。這也就告訴我們,當以二叉鏈表作樹的存儲結構時,樹的先根遍歷和后根遍歷完全可以借用二叉樹的前序遍歷和中序遍歷的算法來實現。

九、赫夫曼樹

赫夫曼樹:帶全路徑長度WPL最小的二叉樹。
先取最小權值的結點作為葉子結點,逐級遞增就能構造出哈夫曼樹。把左結點標為0,右結點標為1,就能構造出赫夫曼編碼。

十、題目

  1. 某棵完全二叉樹上有699個節點,則該二叉樹的葉子節點數為(350)。
    解析:n0=n2+1;
    n=n0+n1+n2=n0+n1+n0-1=699
    由于完全二叉樹中度為1的節點只有0個或1個兩種情況,所以,將0或1帶入上面公式,整理后得: n0=(n+1)/2或者n0=n/2; 看看n是否能被2整除,能則用n0=n/2。否則用n0=(n+1)/2 既葉子節點為n0=(n+1)/2=350。
  2. 一棵有124個葉節點的完全二叉樹,最多有(248 )個節點。
    解析:n0 = n2 + 1,于是度為2的結點個數123個
    完全二叉樹中度為1結點個數最多1個
    因此該完全二叉樹中結點最多有123 + 1 + 124 = 248個

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

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

相關文章

大話數據結構——圖

圖(Graph)是由定點的又窮非空集合和頂點之間邊的集合組成,通常表示為:G(V,E),其中,G表示一個圖,V是圖G中頂點的集合,E是圖G中邊的集合。 一、各種圖的定義 …

【工作感悟】達內java大數據課程

前言 其實前幾篇文章已經寫了好多有關于Spring源碼的文章,事實上,很多同學雖然一直在跟著閱讀、學習這些Spring的源碼教程,但是一直都很迷茫,這些Spring的源碼學習,似乎只是為了面試吹逼用,我大概問過一些…

大話數據結構——查找

查找(Searching)是根據給定的某個值,在查找表中確定一個其關鍵字等于給定值的數據元素(或記錄)。 一、順序表查找 順序查找又叫線性查找,是最基本的查找技術,它的查找過程是:從表中…

【工作經驗分享】java圖片轉文字

前言 又到一年金九銀十之際。 Java作為目前用戶最多,使用范圍最廣的軟件開發技術之一。 Java的技術體系主要由支撐Java程序運行的虛擬機,提供各開發領域接口支持的Java,Java編程語言及許多第三方Jvav框架構成。 其中,以Java的虛擬器為今天的著…

數據挖掘工程師的面試問題與答題思路

一個Java程序可以認為是一系列對象的集合,而這些對象通過調用彼此的方法來協同工作。下面簡要介紹下類、對象、方法和實例變量的概念。 對象:對象是類的一個實例,有狀態和行為。例如,一條狗是一個對象,它的狀態有&…

【干貨】java課程實戰培訓

開頭 消息隊列 RocketMQ 是阿里巴巴集團基于高可用分布式集群技術,自主研發的云正式商用的專業消息中間件,既可為分布式應用系統提供異步解耦和削峰填谷的能力,同時也具備互聯網應用所需的海量消息堆積、高吞吐、可靠重試等特性,…

Java的幾個特點

Java語言是簡單的: Java語言的語法與C語言和C語言很接近,使得大多數程序員很容易學習和使用。另一方面,Java丟棄了C中很少使用的、很難理解的、令人迷惑的那些特性,如操作符重載、多繼承、自動的強制類型轉換。特別地&#xff0c…

【干貨】mysql建表語句注釋

前言 難道程序員的職業生命線是青春飯?答案是的。 35歲考慮轉行,然后35歲又成了一個新人,而外國可以做到60歲,啥也不說了,可能是覺得中年大叔油膩,不及小鮮肉便宜,唉,可嘆市場更新…

軟件測試知識整理

在一個測試計劃匯總能包含哪些內容? 答:在一個測試計劃中可以包含需要測試的產品的特點和主要功能模塊,列出需要測試的功能點,并標明側重點;測試的策略和記錄(測試工具的確認,測試用例等文檔模…

【干貨】mysql查詢重復數據sql

前言 本系列的目的是明明白白、徹徹底底的搞定日期/時間處理的幾乎所有case。上篇文章鋪設所有涉及到的概念解釋,例如GMT、UTC、夏令時、時間戳等等,若你還沒看過,不僅強烈建議而是強制建議你前往用花5分鐘看一下,因為日期時間處…

【微信小程序】java最簡單觀察者模式

開頭 對于一個Java程序員而言,能否熟練掌握并發編程是判斷他優秀與否的重要標準之一。因為并發編程是Java語言中最為晦澀的知識點,它涉及操作系統、內存、CPU、編程語言等多方面的基礎能力,更為考驗一個程序員的內功。 那到底應該怎么學習并…

操作系統知識點整理

作業 用戶在一次解題或一個事務處理過程中要求計算機系統所做工作的集合。它包括用戶程序、所需要的數據及控制命令等。作業是由一系列有序的步驟組成的。 進程 一個程序在一個數據集合上的一次運行過程。所以一個程序在不同數據集合上運行,乃至一個程序在同樣數…

【性能優化實戰】java驗證碼識別訓練

前言 今天剛好有空,跟大家聊聊如何學好算法進大廠。 前兩天一個讀者和我說,他堅持刷算法題2個月,薪資翻番去了他夢寐以求的大廠,期間面字節跳動還遇到了原題…其實據我所知目前國內的大廠和一些獨角獸,已經越來越效仿…

計算機網絡知識整理

OSI七層 物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層。 物理層涉及信道上傳輸的比特流。 數據鏈路層的主要任務是加強物理層傳輸原始比特流的功能,是指對應的網路層顯現為一條無錯線路。發送包把數據封裝在數據幀,按順序傳送出去并處…

吸水間最低動水位標高_體驗長安逸動EV460:再也不用為電動車續駛里程焦慮了...

文| 車突突車圖騰出品,未經許可,謝絕轉載● ● ●人們都在期待碧水藍天,而且越來越多的消費者也開始踐行環保理念,在買車時關注起了純電動汽車。不過遺憾的是,純電動汽車目前還沒能成為主流。一方面,是因為…

java開發工具包jdk包括哪些

害怕干不過SpringBoot?莫慌,我送你套神級pdf文檔 隨著 Spring Boot 使用越來越廣泛,Spring Boot 已經成為 Java 程序員面試的知識點,很多同學對 Spring Boot 理解不是那么深刻,經常就會被幾個連環追問就給干趴下了&am…

微信計步器怎么不計步_難以關閉的微信朋友圈廣告

太難關掉了。”試圖關閉朋友圈廣告的小曾,在對照著騰訊視頻上的一個長達6分鐘的視頻演示之后,通過14次操作才得以關閉。這14步操作具體如下:點擊“我”—點擊“設置”—點擊“關于微信”—點擊“微信隱私保護指引”—下拉兩個屏幕的面積—點擊…

java開發工具有哪些

前言 Netty 是一款基于 Java 的網絡編程框架,能為應用程序管理復雜的網絡編程、多線程處理以及并發。Netty 隱藏了樣板和底層代碼,讓業務邏輯保持分離,更加易于復用。使用 Netty 可以得到一個易于使用的 API,讓開發人員可以專注自…

經典冒泡排序及其優化

經典排序算法 - 冒泡排序Bubble sort 原理是臨近的數字兩兩進行比較,按照從小到大或者從大到小的順序進行交換,這樣一趟過去后,最大或最小的數字被交換到了最后一位,然后再從頭開始進行兩兩比較交換,直到倒數第二位時結束,其余類似…

expdp導出 schema_記錄一則expdp任務異常處理案例

在XTTS遷移測試階段,遇到執行幾個expdp的導出任務,遲遲沒有返回任何信息,對應日志無任何輸出。環境:AIX 6.1 Oracle 10.2.0.4現象:在XTTS遷移測試階段,遇到執行幾個expdp的導出任務,遲遲沒有返…