首語
- 疫情嚴重,需要多多注意,做好防範!戴口罩,勤洗手。獻上→新型冠狀病毒感染防護手冊!
樹
- 樹(Tree)是n(n≥0)個結點的有限集。n=0時稱爲空樹。在任意一顆非空樹中:(1)有且僅有一個特定的稱爲根(Root)的結點;(2)當n>1時,其餘結點可分爲m(m>0)個互不相交的有限集T1、T2、…Tm,其中每一個集合本身又是一棵樹,並且稱爲根的子樹(SubTree)。
結點的度
- 結點擁有的子樹數稱爲結點的度。度爲0的節點稱爲葉子結點或終端結點,度不爲0的結點稱爲非終端結點或分支結點。除根結點以外,分支結點也稱爲內部結點。樹的度是樹內各節點的度的最大值。
層次與深度
- 結點的層次(Level)從根開始定義起,根爲第一層,根的孩子爲第二層。若某結點在第一層,則其子樹的根就在l+1層。其雙親在同一層的結點互爲堂兄弟。顯然圖中的D、E、F是堂兄弟,而G、H、I、J也是。樹中結點的最大層次稱爲樹的深度(Depth)或高度,當前樹的深度爲4。
有序與無序樹
- 如果將樹中結點的各子樹看成從左至右是有次序的,不能互換的,則稱該樹爲有序樹,否則稱爲無序樹。
森林
- 森林(Forest)是m(m≥0)棵互不相交的樹的集合。
樹的存儲結構
- 簡單的順序存儲不能滿足樹的實現。
- 結合順序存儲和鏈式存儲來實現。
三種表示方法
1、雙親表示法
- 在每個結點中,附設一個指示器指示其雙親結點到鏈表中的位置。
2、孩子表示法
- 方案一
- 方案二
- 最終方案
把每個結點的孩子結點排列起來,以單鏈表作爲存儲結構,則n個結點有n個孩子鏈表,如果是葉子結點則此單鏈表爲空,然後n個頭指針又組成一個線性表,採用順序存儲結構,存放在一個一維數組中。
3、孩子兄弟表示法
- 任意一棵樹,它的結點的第一個孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此,我們設置兩個指針,分別指向該結點的第一個孩子和此結點的右兄弟。
二叉樹
- 二叉樹(Binary Tree)是n(n≥0)個結點的有限集合,該集合或者爲空集(稱爲二叉樹),或者由一個根節點和兩顆互不相交的、分別稱爲根節點的左子樹和右子樹的二叉樹組成。
斜樹(特殊二叉樹)
- 所有的結點都只有左子樹的叫做左斜樹。所有結點都是右子樹的二叉樹叫右斜樹。這兩者統稱爲斜樹。
滿二叉樹
- 在一顆二叉樹中,如果所有分支結點都存在左子樹和右子樹,並且所有葉子都在同一層上,這樣的二叉樹稱爲滿二叉樹。
完全二叉樹
- 對一顆具有n個結點的二叉樹按層序編號,如果編號爲i(1≤i≤n)的結點與同樣深度的滿二叉樹找那個編號爲i的結點在二叉樹中位置相同,則這棵二叉樹稱爲完全二叉樹。
二叉樹的性質
- 性質1:在二叉樹的第i層上至多有2的i-1次方個結點(i≥1)。
- 性質2:深度爲k的二叉樹至多有2的k-1次方個結點(k≥1)。
- 性質3:對任何一棵二叉樹T,如果其終端結點數爲n0,度爲2的結點爲n2,則n0=n2+1。
證明: 設n爲總結點數,n1爲度爲1的結點樹,n2位度爲2 的結點樹,n0爲終端結點樹。
n=n0+n1+n2,而分支線總數=n-1=n1+2n2。
推出n0+n1+n2-1=n1+2n2。即n0=n2+1。
- 性質4:具有n個結點的完全二叉樹深度[㏒2ⁿ]+1([x]表示不大於x的最大整數)。
- 性質5:如果對一顆有n個結點的完全二叉樹(其深度爲[㏒2ⁿ]+1)的結點按層序編號(從第1層到第
[㏒2ⁿ]+1層,每層從左到右),對任意一個結點i(1≤i≤n)有:
1、如果i=1,則結點i是二叉樹的根,無雙親;如果i>1,則其雙親是結點[i/2].
2、如果2i>n,則結點i無左孩子(結點i爲葉子結點);否則其左孩子是結點2i。
3、如果2i+1>n,則結點i無右孩子;否則其右孩子是結點2i+1。
順序存儲
- 完全二叉樹
- 一般二叉樹
二叉鏈表
- lchild—>data—>rchild
二叉樹的遍歷
- 前序遍歷(根左右)
規則是若二叉樹爲空,則空操作返回,否則先訪問跟結點,然後前序遍歷左子樹,再前序遍歷右子樹。
- 中序遍歷(左根右)
規則是若樹爲空,則空操作返回,否則從根結點開始(注意並不是先訪問根結點),中序遍歷根結點的左子樹,然後是訪問根結點,最後中序遍歷右子樹。
- 後序遍歷(左右根)
規則是若樹爲空,則空操作返回,否則從左到右先葉子後結點的方式遍歷訪問左右子樹,最後是訪問根結點。
- 層序遍歷
規則是若樹爲空,則空操作返回,否則從樹的第-一層,也就是根結點開始訪問,從上而下逐層遍歷,在同一層,按從左到右的順序對結點逐個訪問。
代碼實現
- 構建二叉樹
private TreeNode root = null;
public BinaryTree(){
root = new TreeNode(1, "A");
}
/**
* 構建二叉樹
* A
* B C
* D E F
*/
public void createBinaryTree(){
TreeNode nodeB = new TreeNode(2, "B");
TreeNode nodeC = new TreeNode(3, "C");
TreeNode nodeD = new TreeNode(4, "D");
TreeNode nodeE = new TreeNode(5, "E");
TreeNode nodeF = new TreeNode(6, "F");
root.leftChild = nodeB;
root.rightChild = nodeC;
nodeB.leftChild = nodeD;
nodeB.rightChild = nodeE;
nodeC.rightChild = nodeF;
}
public class TreeNode{
private int index;
private String data;
private TreeNode leftChild;
private TreeNode rightChild;
public TreeNode(int index,String data){
this.index = index;
this.data = data;
this.leftChild = null;
this.rightChild = null;
}
}
- 求二叉樹的高度
/**
* 求二叉樹的高度
* @author yhj
*
*/
public int getHeight(){
return getHeight(root);
}
private int getHeight(TreeNode node) {
if(node == null){
return 0;
}else{
int i = getHeight(node.leftChild);
int j = getHeight(node.rightChild);
return (i<j)?j+1:i+1;
}
}
- 獲取二叉樹的結點樹
/**
* 獲取二叉樹的結點數
* @author yhj
*
*/
public int getSize(){
return getSize(root);
}
private int getSize(TreeNode node) {
if(node == null){
return 0;
}else{
return 1+getSize(node.leftChild)+getSize(node.rightChild);
}
}
- 前序遍歷(迭代與非迭代)
/**
* 前序遍歷――迭代
* @author yhj
*
*/
public void preOrder(TreeNode node){
if(node == null){
return;
}else{
System.out.println("preOrder data:"+node.getData());
preOrder(node.leftChild);
preOrder(node.rightChild);
}
}
/**
* 前序遍歷――非迭代
*/
public void nonRecOrder(TreeNode node){
if(node == null){
return;
}
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(node);
while(!stack.isEmpty()){
//出棧和進棧
TreeNode n = stack.pop();//彈出根結點
//壓入子結點
System.out.println("nonRecOrder data"+n.getData());
if(n.rightChild!=null){
stack.push(n.rightChild);
}
if(n.leftChild!=null){
stack.push(n.leftChild);
}
}
}
- 中序遍歷
/**
* 中序遍歷――迭代
* @author yhj
*
*/
public void midOrder(TreeNode node){
if(node == null){
return;
}else{
midOrder(node.leftChild);
System.out.println("midOrder data:"+node.getData());
midOrder(node.rightChild);
}
}
- 後序遍歷
/**
* 後序遍歷――迭代
* @author yhj
*
*/
public void postOrder(TreeNode node){
if(node == null){
return;
}else{
postOrder(node.leftChild);
postOrder(node.rightChild);
System.out.println("postOrder data:"+node.getData());
}
}