數據結構與算法(樹)

首語

  • 樹(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+2
    n2。即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());
		}
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章