數據結構:二叉樹

數據結構分類中有一種很常見的結構,那就是樹,樹的分類不少種,包括二叉樹、二叉搜索樹、紅黑樹、B+樹等等,但大多數都是基於二叉樹的衍生結構,因此今天來學習下二叉樹。java

本文的目錄結構以下:node

什麼是二叉樹

定義:二叉樹是每一個結點最多有兩個子樹的樹結構。一般子樹被稱做 「左子樹」(left subtree)和 「右子樹」(right subtree),最頂層的節點叫作 「根」 。web

邏輯上,二叉樹能夠分紅五種形態,分別是:算法

1) 空二叉樹 數據結構

2) 只有一個根節點的二叉樹svg

3)只有跟和左子樹 學習

4)只有跟和右子樹 spa

5)根和左右子樹 (徹底二叉樹)
這裏寫圖片描述.net

注:二叉樹是遞歸定義的,也就是理論上每一個節點均可以無限延伸二叉樹的結構,因此每一個節點都有左右子樹子分,上面的形態只是一種簡單的展現。code

二叉樹的性質

性質1:二叉樹中全部結點的度數均不大於2

性質2:二叉樹第i層上的結點數目最多爲2i-1(i>=1)

性質3:深度爲k的二叉樹至多有2k-1個結點(k>=1)

性質4:包含n個結點的二叉樹的高度至少爲(log2n)+1

性質5:在任意一棵二叉樹中,若終端結點的個數爲n0,度爲2的結點數爲n2,則n0=n2+1

性質4的證實:

(1) 基於性質1,咱們知道二叉樹的節點度數最多不大於2,因此這裏假設n0表示度爲0的結點個數, n1表示度爲1的結點個數,n2表示度爲2的結點個數。三類結點加起來爲總結點個數,因而即可獲得:n=n0+n1+n2

(2) 基於性質1,咱們又能夠得出,樹的總度數爲度數0,1,2的度數加上根節點,也就是 n=n0 * 0 + n1 * 1 + n2* 1 + 1

結合上面的(1) 和 (2)的證實就能夠得出 n0=n2+1 。

二叉樹的遍歷

在將二叉樹的遍歷前,咱們須要先實現二叉樹,根據二叉樹的特色,其包含了節點自己的數據,左子樹和右子樹,用Java代碼能夠這樣表示

public class Node {

    /* * 一個二叉樹包括 數據、左右孩子 三部分 */ 
    private int mData; 
    private Node mLeftChild; 
    private Node mRightChild; 

    public Node(int data, Node leftChild, Node rightChild) {
        mData = data;
        mLeftChild = leftChild;
        mRightChild = rightChild;
    }

    public int getData() {
        return mData;
    }

    public void setData(int data) {
        mData = data;
    }

    public Node getLeftChild() {
        return mLeftChild;
    }

    public void setLeftChild(Node leftChild) {
        mLeftChild = leftChild;
    }

    public Node getRightChild() {
        return mRightChild;
    }

    public void setRightChild(Node rightChild) {
        mRightChild = rightChild;
    }
}

每個二叉樹的節點均可以用 Node 類表示,下面開始講述其遍歷方式。

前面說了,二叉樹是一種遞歸的結構,每一個節點均可以有左右子樹的結構,而二叉樹的遍歷也是個遞歸遍歷的過程,使得每一個節點有且只有被訪問一次。

按照遍歷結構的順序,通常將二叉樹的遍歷分爲三種:

  • 先序遍歷
  • 中序遍歷
  • 後序遍歷

先序遍歷

遍歷方式:

  • 先訪問根節點
  • 再先序遍歷左子樹
  • 再先序遍歷右子樹

代碼實現:

public void firstOrder(Node node){
    if (node == null){
        return;
    }
    showData(node);
    firstOrder(node.getLeftChild());
    firstOrder(node.getRightChild());
}

//輸出節點數據
public void showData(Node node){
    if (node == null){
        return;
    }
    System.out.println(node.getData());
}

中序遍歷

遍歷方式:

  • 先中序遍歷左子樹
  • 再訪問根節點
  • 再中序遍歷右子樹

代碼實現:

public void MediumOrder(Node node){
    if (node == null){
        return;
    }
    MediumOrder(node.getLeftChild());
    showData(node);
    MediumOrder(node.getRightChild());
}

後序遍歷

遍歷方式:

  • 前後序遍歷左子樹
  • 再後序遍歷右子樹
  • 最後訪問根節點

代碼實現:

public void LastOrder(Node node){
    if (node == null){
        return;
    }
    LastOrder(node.getLeftChild());
    LastOrder(node.getRightChild());
    showData(node);
}

如下面的二叉樹爲例,三種不一樣的遍歷結果爲

先序遍歷: 1 2 4 5 7 3 6

中序遍歷: 4 2 7 5 1 3 6

後序遍歷: 4 7 5 2 6 3 1

這裏寫圖片描述

說完二叉樹的基本知識後,下面介紹下二叉樹的幾種延伸結構。

特殊的二叉樹

下面介紹兩種特殊的二叉樹,分別是滿二叉樹、徹底二叉樹。

滿二叉樹

定義:一顆高度爲k,擁有2^k-1 個節點。就是說除了葉子節點,每一個節點都有左右子樹。

示意圖以下:
這裏寫圖片描述

徹底二叉樹

徹底二叉樹跟滿二叉樹很相似,但有些許不一樣,須要知足如下的條件:

  • 全部葉子節點都出如今 k 或者 k-1 層,並且從 1 到 k-1 層必須達到最大節點數;
  • 第 k 層能夠不是滿的,可是第 k 層的全部節點必須集中在最左邊。

給張示意圖看下二者的區別:
這裏寫圖片描述

最後

瞭解兩種特殊的二叉樹後,咱們來作一道算法題鞏固一下。

在筆試過程當中常常會見到的,就是問你怎麼判斷一顆二叉樹爲徹底二叉樹?

思路:根據徹底二叉樹的特色,咱們知道最後一層的全部節點都在最左邊,所以能夠按照這樣的思路來解題,那就是:在層序遍歷的過程當中,找到第一個非滿節點。滿節點指的是同時擁有左右孩子的節點。在找到第一個非滿節點以後,剩下的節點不該該有孩子節點;若是有,那麼該二叉樹就不是徹底二叉樹。

根據這樣的思路,咱們能夠藉助隊列,對徹底二叉樹作廣度遍歷的方式,下面展現一下代碼實現:

public class CompleteTreeChecker { 
 
   
   //輔助空間,隊列
   private LinkedList<Node> queue = new LinkedList<Node>();
   //第n層最右節點的標誌
   private boolean leftMost = false;

   public boolean processChild(Node child) {
      if(child != null) {
         if(!leftMost) {
            queue.addLast(child);
         } else {
            return false;
         }
      } else {
         leftMost = true;
      }
      return true;
   }

   public boolean isCompleteTree(Node root) {
      //空樹也是徹底二叉樹
      if(root == null) return true;

      //首先根節點入隊列
      queue.addLast(root);

      while(!queue.isEmpty()) {
         Node node = queue.removeFirst();

         //處理左子結點
         if(!processChild(node.getLeftChild()))
            return false;
         //處理右子結點
         if(!processChild(node.getRightChild()))
            return false;
      }
      //廣度優先遍歷完畢,此樹是徹底二叉樹
      return true;
   }

本文分享 CSDN - 鄙人薛某。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索