数据结构 非线性结构 树 介绍及存储方法
?????????? 所謂樹, 其實跟鏈表有類似的地方,? 就是都是由節點和指針構成的數據結構.
?????????? 在鏈表中,? 每1個節點(尾節點除外)只有1個指針指向下1個節點. 所以鏈表各個節點可以由一條線鏈接起來, 就是一種線性結構.
?????????? 而在樹中, 每1個節點可以有1個或多個指針指向下1個節點,? 如下圖:
????????????? 所以樹是一種非線性結構, 對于這種結構, 有很多算法都要依賴遞歸來實現, 否則就相當復雜, 所以很多教程都把遞歸作為1個專題放在樹這章之前講解, 就是這個原因.
????????????? 其實樹也可以利用連續存儲來實現, 也就是說節點不需具有指向別的節點的指針, 但是這種樹必須是完全二叉樹。 下面會詳細提到。
1. 樹的定義
???????? 樹的定義有兩種, 一種是專業的定義, 跟遞歸有關.
???????? 專業定義:
???????????????? 1. 只有1個稱為根的節點.
???????????????? 2. 有若干個互不相交的子樹, 這些子樹本身也是樹.
???????????????? 解析下,子樹本身也是樹, 就如上上圖的樹A, 根就是是A了, 它具有2個子樹, 分別是B1 和 B2, 而B1和B2也是1棵樹啊, 所以, 這個定義跟遞歸有關.
?????????? 通俗定義:
???????????????? 1. 樹是有節點和邊組成.(為什么不用指針這個字眼,用邊?因為樹是可以利用連續存儲來實現的,下面會提到)
???????????????? 2. 每1個節點只有1個父節點, 但是可以有多個子節點.
???????????????? 3. 但是有1個節點例外, 該節點沒有父節點, 此節點就是根節點.
2. 樹的一些專業術語.
??????????? 節點:? ? ? ? ? ? ? ? ? ? 構成樹的元素, 通常節點里會包含指向其他節點的指針.? 在C語言中, 節點通常是由結構體來表示的.
???????????? 父節點:
??????????????????? 節點的上1級節點,? 通常1個節點有且只有1個父節點, 根節點例外, 根節點沒有父節點.
???????????? 子節點:
??????????????????? 節點的下一級節點, 1個節點可以有1個或多個子節點, 也可以沒有子節點.
????????????? 子孫:
??????????????????? 1個節點的子節點或者子節點的子節點....,等所有下級節點都可以成為這個節點的子孫,? 1棵樹的所有節點都是根節點的子孫.?? 上圖C2 是B1的子孫, 但不是B2的子孫.
????????????? 兄弟:
??????????????????? 擁有同1個父節點的若干個節點成為兄弟, 上圖B1 就是 B2的兄弟
????????????? 堂兄弟:
???????????????????? 不屬于同1個父節點, 但是它們的父節點屬與同1個父節點的若干個節點就是堂兄弟. 上圖C1 就是 C3的堂兄弟.
????????????? 深度:
???????????????????? 1棵樹從根節點到最底層節點的層數稱之為深度.?? 根節點是第1層.
?????????????? 葉子節點:
????????????????????? 沒有子節點的節點, 因為葉子不同于樹干, 不能再分叉了.? 當1個棵樹只有1個節點, 那么這個節點是根節點. 也是葉子節點.
?????????????? 非終端節點:
?????????????????????? 實際就是非葉子節點,? 就是具有子節點的節點.
??????????????? 度:
??????????????????????? 1個節點的子節點個數成為這個節點的度
??????????????????????? 1個樹中擁有最大度的節點的度就是這個樹的度.
???????????????
? ? ? ? ? ? ?? 森林:
? ? ? ? ? ? ? ? ? ? ? ? ? n個互不相交的樹的集合, 成為森林. ????????
3. 樹的分類
??????????????? 一般的樹:
????????????????????????? 任意1個節點的子節點的個數都不受限制的樹.
??????????????? 二叉樹: (binary tree)
?????????????????????????? 任意1個節點的個數最多有連個, 且子節點的位置不能被更改, 這種樹就是二叉樹.
?
??????????????????????????? 第一句容易理解, 關鍵是第二句, 子節點的位置不能更改??? 其實意思就是二叉樹是有序的, 它的節點最多只有2個子節點, 分別是左子節點和右子節點,? 它們的順序不能被更改. 也不能更改節點的父子點(移動子樹),我們稱為這種樹是有序的樹
??????????????????????????? 一般的樹沒有這種要求, 可以是有序的樹, 也可以是無序的樹(子節點位置可更改),??? 但是2叉樹必須是有序的樹.
??????????????
???????????????????????????? 二叉樹還有分類
???????????????
???????????????????????????滿二叉樹: (full binary tree)
????????????????????????????????????? 在不增加層數的情況下,? 無法再多添加1個節點的二叉樹, 就是滿二叉樹. 例如上圖那個樹就是非滿2叉樹, 因為還可以添加1個C4節點在B2節點下.
????????????????????????
??????????????????????????????????????? 添加了C4節點后, 就是1個滿二叉樹, 如下圖:
???????????????????????????????????????? 假如1個滿二叉樹的層數是k, 那么它的節點個數必定是 (2^k-1).
???????????????????????????????????????? 這里順便貼個等比數列求和的推導公式:
(1)Sn=a1+a2+a3+...+an(公比為q) (2)q*Sn=a1*q+a2*q+a3*q+...+an*q =a2+a3+a4+...+a(n+1) (3)Sn-q*Sn=a1-a(n+1) (4)(1-q)Sn=a1-a1*q^n (5)Sn=(a1-a1*q^n)/(1-q) (6)Sn=(a1-an*q)/(1-q) (7)Sn=a1(1-q^n)/(1-q)
????????????????????? 完全二叉樹: (Complete binary tree)
???????????????????????????????? 完全二叉樹就厲害了,之前提到滿二叉樹的目的就是為了引出完全二叉樹. 滿二叉樹是完全二叉樹的一種。
???????????????????????????????? 若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。
???????????????????????????????? 又有1個通俗定義: 當1棵層數為k滿二叉樹, 從它的最底層的最右邊的節點開始,連續向左刪除n個節點(2k >= n >= 0), 得到的樹就是1棵完全二叉樹.
???????????????????????????????? 如下圖, 左邊兩個是完全二叉樹, 而右邊那個不是,因為最下層的節點不是向右連續的啊!
??????????????????????????? 這里補充一點:完全二叉樹是效率很高的數據結構,堆是一種完全二叉樹,所以效率極高,像十分常用的排序算法、Dijkstra算法、Prim算法等都要用堆才能優化,幾乎每次都要考到的二叉排序樹的效率也要借助平衡性來提高,而平衡性基于完全二叉樹。
??????????????????????????? 這里為什么要特別提到完全二叉樹呢?? 因為完全二叉樹是一種重要的數據結構, 跟棧,對列一樣, 二叉樹也可以用鏈式和數組內核來實現, 但是因為數組必須是連續存儲的, 所以數組實現的二叉樹必須是完全二叉樹。
??????????????????????????? 完全二叉樹的性質:
?????????????????????????????????? 1. 如果知道完全二叉樹的節點個數, 就必然可以退出完全二叉樹的形狀(包括層數, 最后一層的節點排布)。? 也就是說兩個節點樹相同的完全二叉樹的形狀是一樣的。
?????????????????????????????????? 2. 根據第1個性質, 只需要知道1個確定節點個數的完全二叉樹的節點編號, 就可以推出這個節點的父節點和字節點! 這個是1個非常重要的優點!
???????????????????????????
3. 樹的存儲(內存)
????? ??? 3.1 二叉樹的存儲:
??????????????? 3.1.1. 連續存儲 :
?????????????????????? 上面提過了, 要利用連續存儲(數組)來實現的二叉樹必須是完全二叉樹, 因為它們的節點必須是連續的啊! 如果要利用連續存儲來存儲普通的二叉樹, 就必須把這個二叉樹轉化為完全二叉樹。
?????????????????????? 關鍵是如何轉化? 很簡單, 就是添加必要的空節點把1個非完全二叉樹補成1個完全二叉樹, 如下圖:
????????????????????? 藍色的樹就是1個普通的2叉樹,? 白色的節點就是必要的不存放實際數據的節點, 添加上去組成1個完全二叉樹, 就可以利用連續存儲了。
????????????????????? 至于要轉成完全二叉樹的原因:
????????????????????? 假如只按一定的順序只存儲有效的節點,? 內存物理上是1個線性結構, 如果把非線性的樹存放在線性的內存中,存放后就變成線性結構了,例如上圖中的藍色樹在內存里存放: A,B1,C1,C2,D3,D4? 的確是能存放, 但是不能將存放的數據還原成原來的樹啊! 所以就必須添加一些無效的節點令它轉化成1個完全二叉樹!
????????????????????? 缺點:
??????????????????????? 其實也可以看出, 如過利用連續存儲來存放普通的二叉樹, 首先需要一定量的連續內存空間,而且必然會造成1些空間浪費。 而且普通二叉樹的層數越大, 耗費的內存越大!
??????????????????? ? 優點:
??????????????????????? 就是上面完全二叉樹的第2個性質,? 只需要知道1個節點在數組的位置, 就可以推出它的父節點和子節點, 時間復雜度是0啊!
????????????? 3.1.2. 鏈式存儲 :
???????????????????? 這個跟鏈表有點類似。
???????????????????? 我們會把每1個節點分成4個域, 分別是數據域, 父節點指針域, 左子節點指針域, 右字節域指針域。(或者不包含父節點指針域,則只有3個域)
???????????????????? 如下圖:
???????????????????? 可以見到,這種存儲方式浪費的空間很少, 無非就是一些子節點的空指針, 但是這些空指針個數仍是線性增長的, 但是我們認為浪費的空間已經很少啦, 比起連續存儲來講, 因為鏈式存儲不需存儲多余的節點啊。
????????????????????
??????????????????
????????
????? 3.2 一般樹的存儲:
????????????? 一般樹的特點是節點的度(子節點個數)無限制, 用上面連續存儲根本沒可能, 如果用鏈式存儲也很困難, 因為無法決定子節點的子節點指針域的個數啊!
??????????? 3.2.1 雙親表示法(數組):
??????????????????? 雙親表示法實際上也是利用連續存儲的, 只不過數組內的元素必須分為兩個域, 1個是數據域, 另1個是父節點的下標(注意不是指針啊). 根節點的父節點下標是·-1.
??????????????????? 雙親表示法對于元素(節點)在數組內的順序無要求。
? ? ? ? ? ? ? ? ? ? 如下圖:
???????????????? 如上圖右邊的數組, 基本上可以把1棵樹的結構表示出來了, 但是有個問題, 就是無法通過數組得到同1個父子點兄弟之間的順序, 例如無法知道C1,C2,C3這個3兄弟在樹中的順序, 所以雙親表示法只適合表示無序的樹。
? ? ? ? ? ? ? ?? 優點:
? ? ? ? ? ? ? ? ? ?? 幾乎不浪費內存空間, 查找父節點很容易。
? ? ? ? ? ? ? ?? 缺點:
? ? ? ? ? ? ? ? ? ?? 不能表示有序的樹, 查找子節點相對困難, 查找任何1個節點的子節點都必須遍歷整個數組。 不能表示有序的樹。
? ? ? ? ??
?????????? 3.2.2 孩子表示法(數組):
???????????????? 孩子表示法也是利用連續存儲來實現的, 它的節點同樣具有兩個域, 1個是數據域, 另1個是1個子節點下標鏈表的頭節點地址。
???????????????? 關鍵就是這個鏈表了, 鏈表的節點有兩個域, 1個是int類型,用于表示節點下標, 另1個是指針。
???????????????? 如下圖:
??????????? 可以見到, 因為可以利用子節點下標鏈表的順序來表示子節點兄弟的順序, 所以這種表示法是能表示有序樹的。
??????????? 優點:
????????????????? 查找子節點算法很方便, 可以表示有序樹
??????????? 缺點:
???????????????? 查找父節點算法很困難, 必須遍歷每1個節點的子節點下標鏈表, 如上圖, 甚至判斷哪個是根節點都需要遍歷啊(O(n^2))!?
??????????
??????? 3.2.3 雙親孩子表示法(數組):
???????? 由上面的例子可以看出, 其實雙親表示法和孩子表示法的優缺點是互補的, 所以把它們合拼在一起就是雙親孩子表示法了。
???????? 所謂雙親孩子法就是指表示樹的數組內的節點有3個域, 數組域, 父節點下標域,及子節點下標鏈表域。
???????? 如下圖:
????????
???????? 優點:
????????????? 具有雙親表示法和孩子表示法的所有優點, 關鍵是方便地查找父節點和子節點。
???????? 缺點:
????????????? 占用相對更多的內存空間。
???????
?????? 3.2.4 二叉樹表示法 :
??????? 這個的原理就是把一般樹轉化為二叉樹, 然后再利用二叉樹的存儲方法來存儲。
??????? 關鍵是如何把1個一般樹轉化為二叉樹?? 一句話:? 每個子節點的左子節點指向它原來的第1個子節點,?右子節點指向它原來的下1個兄弟。
??????? 所以這個方法又叫孩子兄弟鏈表表示法
??????? 如下圖:
??????? 可以看到, 轉換后層數增加了, 而且某個子樹的度越大, 轉化后所需的層數越多, 畢竟是利用層數來表示兄弟的個數啊。
??????? 而且有個特點, 就是轉化后的二叉樹, 對于根節點來講, 是沒有右字數的, 因為根節點沒有兄弟嘛。
??????? 優點:
???????????? 能使用一些二叉樹的算法。
??????? 缺點:
???????????? 查找真正的父節點和子節點的算法有點復雜,? 例如上圖轉化后的二叉樹, 如果求C3的父節點, 則必須反方向先求出C2和C1..
???????
???????? 3.3 森林的存儲:
? ? ? ? ??? 所謂森林上面也提到過了, 就是互不相交(沒有公共節點)的n棵樹的集合。
? ? ? ? ? ? 例如下圖中的三棵樹就可以組成1個森林。
? ? ????????
?????????? 一般來講,
?????????? 首先: 我們會先把森林的所有樹轉化為二叉樹(孩子兄弟鏈表表示法)
?????????? 然后: 把轉化后的二叉樹合成1個新的二叉樹, 怎么合成? 就是把各個二叉樹視為兄弟, 然后新增1個根節點作為它們的父子點。
?????????? 其實不難理解的啦, 轉化后如圖:
??????? 然后就按照二叉樹的方法存儲就ok了。
總結
以上是生活随笔為你收集整理的数据结构 非线性结构 树 介绍及存储方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Oracle 系统改变号SCN详解
- 下一篇: 数据结构 二叉树的遍历