前言:
之前做百度前端練習題時,遇到二叉樹遍歷的問題,由于不了解二叉樹這種數(shù)據(jù)機構(gòu),自己只好學習一番并且總結(jié)如下。
樹的簡介
棧、隊列、鏈表等數(shù)據(jù)結(jié)構(gòu),都是順序數(shù)據(jù)結(jié)構(gòu)。而樹是非順序數(shù)據(jù)結(jié)構(gòu)。直觀地,樹型結(jié)構(gòu)是以分支關系定義的層次結(jié)構(gòu)。
基礎概念
樹的定義
樹(Tree)是n(n>=0)個結(jié)點的有限集。
在一顆非空樹里:
- 有且只有一個根節(jié)點(root)
- 當n>1時,其余結(jié)點可分為m(m>0)個互不相交的有限集T1,T2,T3,...Tm,其中每一個集合本身又是一棵樹,并且稱為根的子樹(Subtree)。
(a) 圖只有一個根節(jié)點A ,(b)A是根節(jié)點,13個子節(jié)點,13個子節(jié)點分成3個互不相交的子集:T1={B,E,F,K,L},t2={D,H,I,J,M};T1,T2和T3都是根A的子樹,且本身也是一棵樹。
樹的節(jié)點
樹中的每個元素,都叫做節(jié)點。
樹的結(jié)點包含一個數(shù)據(jù)元素及若干指向其子樹的分支。該節(jié)點的子樹被稱為該節(jié)點的孩子并且該節(jié)點同時也是孩子的雙親
度:節(jié)點擁有的子樹數(shù)目被稱為
度
例如(b)B節(jié)點的度為2,D節(jié)點的度為3,度為0的節(jié)點稱為葉子
或者終端結(jié)點,反之稱為非終端結(jié)點或分支結(jié)點。該樹的度為擁有節(jié)點的度的最大值
節(jié)點的層次
節(jié)點的層次(Level)從根開始定義起,根為第一層,然后為第二層,依次順序下去為n層。
深度: 樹中節(jié)點的最大層數(shù)被稱為樹的深度或高度
例如 (b)樹的深度為4
有序和無序樹
如果將樹中節(jié)點的各子樹看成從左至右是有次序的(即不能交換),則稱該樹為有序樹,否則稱為無序樹。在有序樹中最左邊的子樹的根稱為第一個孩子,最右邊的稱為最后一個孩子。
森林
森林(Forest)是m(m>=0)棵互不相交的樹的集合。對樹中每個結(jié)點而言,其子樹的集合即為森林。
二叉樹
二叉樹
(Binary Tree)是另一種樹型結(jié)構(gòu),它的特點是每個結(jié)點至多只有兩棵子樹(即二叉樹中不存在度大于2的結(jié)點),并且,二叉樹的子樹有左右之分(其次序不能任意顛倒。)
二叉樹的性質(zhì)
- 二叉樹的第i層上最多有2的(i-1)方個節(jié)點。(i>=1)
- 深度為k的樹最多有2的k次方-1個節(jié)點。(k>=1)
- 對任何一棵二叉樹T,如果其終端結(jié)點數(shù)為n0,度為2的結(jié)點數(shù)為n2,則n0 = n2 + 1;
- 一棵深度為k且有2的k次方-1個結(jié)點的二叉樹稱為
滿二叉樹
。 - 深度為k的,有n個結(jié)點的二叉樹,當且僅當其每一個結(jié)點都與深度為k的滿二叉樹中編號從1至n的結(jié)點一一對應時,稱之為
完全二叉樹
。
(我的理解是有限的節(jié)點個數(shù)里從左到右的編號要一一對應,否則不能稱為完全二叉樹)
注意:滿二叉樹一定是完全二叉樹,但完全二叉樹不一定是滿二叉樹。
二叉樹的5個基本形態(tài)
- 空二叉樹
- 只有一個根結(jié)點
- 根結(jié)點只有左子樹
- 根結(jié)點只有右子樹
- 根結(jié)點既有左子樹又有右子樹
二叉樹的存儲結(jié)構(gòu)
-
順序存儲結(jié)構(gòu)
用一維數(shù)組依照順序存儲樹的節(jié)點,編號為i節(jié)點依次存儲在數(shù)組下標i-1的元素里。i為0意味不存在此節(jié)點,這樣的順序存儲適合完全二叉樹。但是最壞的情況下,深刻為k并且只有k個節(jié)點的二叉樹(每個節(jié)點的度小于2),那么意味著需要長度為2的k次方-1的一維數(shù)組來存儲,非常浪費存儲空間。
-
鏈式存儲結(jié)構(gòu)
二叉樹的結(jié)點由一個數(shù)據(jù)元素和分別指向其左右子樹的兩個分支構(gòu)成,則表示二叉樹的鏈表中的結(jié)點至少包含三個域:數(shù)據(jù)域和左右指針域。有時,為了便于找到結(jié)點的雙親,則還可在結(jié)點結(jié)構(gòu)中增加一個指向其雙親結(jié)點的指針域。利用這兩種結(jié)構(gòu)所得的二叉樹的存儲結(jié)構(gòu)分別稱之為二叉鏈表和三叉鏈表。
在含有n個結(jié)點的二叉鏈表中有n+1個空鏈域,我們可以利用這些空鏈域存儲其他有用信息,從而得到另一種鏈式存儲結(jié)構(gòu)---線索鏈表。
二叉樹的遍歷
二叉樹的遍歷(traversing binary tree)是指從根結(jié)點出發(fā),按照某種次序依次訪問二叉樹中所有結(jié)點,使得每個結(jié)點被訪問一次且僅被訪問一次。
二叉樹的遍歷有三種方式,如下:
(1)前序遍歷(DLR),首先訪問根結(jié)點,然后遍歷左子樹,最后遍歷右子樹。簡記根-左-右。
(2)中序遍歷(LDR),首先遍歷左子樹,然后訪問根結(jié)點,最后遍歷右子樹。簡記左-根-右。
(3)后序遍歷(LRD),首先遍歷左子樹,然后遍歷右子樹,最后訪問根結(jié)點。簡記左-右-根。
前序遍歷(DLR)
算法思路
若二叉樹為空,則遍歷結(jié)束;否則
⑴ 訪問根結(jié)點;
⑵ 先序遍歷左子樹(遞歸調(diào)用本算法);
⑶ 先序遍歷右子樹(遞歸調(diào)用本算法)。
遍歷的順序為:A B D H I E J C F K G
算法實現(xiàn)
//先序遍歷
function preOrder(node){
if(!node == null){
putstr(node.show()+ " ");
preOrder(node.left);
preOrder(node.right);
}
}
中序遍歷(LDR)
算法思路
若二叉樹為空,則遍歷結(jié)束;否則
⑴ 中序遍歷左子樹(遞歸調(diào)用本算法);
⑵ 訪問根結(jié)點;
⑶ 中序遍歷右子樹(遞歸調(diào)用本算法)。
遍歷的順序為:A B D H I E J C F K G
算法實現(xiàn)
//使用遞歸方式實現(xiàn)中序遍歷
function inOrder(node){
if(!(node == null)){
inOrder(node.left);//先訪問左子樹
putstr(node.show()+ " ");//再訪問根節(jié)點
inOrder(node.right);//最后訪問右子樹
}
}
后序遍歷(LRD)
算法思路
若二叉樹為空,則遍歷結(jié)束;否則
⑴ 后序遍歷左子樹(遞歸調(diào)用本算法);
⑵ 后序遍歷右子樹(遞歸調(diào)用本算法) ;
⑶ 訪問根結(jié)點 。
遍歷的順序為:H I D J E B K F G C A
算法實現(xiàn)
//后序遍歷
function postOrder(node){
if(!node == null){
postOrder(node.left);
postOrder(node.right);
putStr(node.show()+ " ");
}
}
個人水平有限,如有錯誤,還望指正,感激不盡!!!
參考鏈接
javascript實現(xiàn)數(shù)據(jù)結(jié)構(gòu): 樹和二叉樹,二叉樹的遍歷和基本操作