坐下,這些都是二叉樹的基本操做!

春招來了,辭了職在家裏準備再找份實習工做。相信你們,尤爲是大3、大四的同窗都常常在招聘要求上看到這樣一條要求:熟悉常見的數據結構與算法。常見的數據結構一般有:鏈表二叉樹,若是要求再高點,可能會讓你實現紅黑樹AVL樹這種高級的數據結構。因而可知,數據結構與算法仍是比較重要的,最近也是在複習這方面的知識。本篇爲複習過程當中遇到過的總結,同時也給各位跟我同樣準備面試的同窗一份參考。另外,因爲篇幅有限,本篇的重點在於二叉樹的常見算法以及實現。javascript

常見的二叉樹實現代碼

以前寫過相關的文章,是關於如何建立及遍歷二叉樹的,這裏再也不贅述。提供連接給各位感興趣的小夥伴,點此跳轉前端

翻轉二叉樹

對於一棵二叉樹,翻轉它的左右子樹,以下圖所示:java

下面來分析具體的實現思路:

  • 對於根結點爲空的狀況
    這種狀況須要排除,由於null不是一個對象,不可能存在左右子樹而且能夠翻轉的狀況
  • 對於一棵只有一個根結點的二叉樹
    emmm,這種狀況也能夠翻轉,由於此時根結點左右子樹爲null,交換左右子樹其實也就是在交換兩個null,理論上是翻轉了,但實際上咱們看到的和沒有翻轉以前的結果是同樣的
  • 對於一棵具備兩個或兩個以上結點的二叉樹,此時二叉樹能夠表示爲以下的圖像:


能夠看出,不管是隻有左子樹仍是隻有右子樹均可以進行翻轉。這句話等價於,爲空的子樹能夠和不爲空的子樹進行交換,也就是 不對爲空的子樹進行特殊處理

分析過程

其實這樣咱們仍是不知道二叉樹是如何翻轉的,咱們能夠用第一張圖的二叉樹爲例子,看一下翻轉的具體過程。面試

  1. 首先咱們須要對根結點進行判空處理,在根結點不爲空的狀況下存在左右子樹(即便左右子樹爲空),而後交換左右子樹;

2. 把根結點的左子樹當成左子樹的根結點,對當前根結點進行判空處理,不爲空時交換左右子樹;

3. 把根結的右子樹當成右子樹的根結點,對當前根結點進行判空處理,不爲空時交換左右子樹;

4. 重複步驟 23,最後二叉樹變爲原來的鏡像結構,結果能夠參考文章第一張示意圖。

示例代碼

根據上面的推理過程咱們能夠得出以下的代碼:算法

function reverseTree(root){
    if( root !== null){
        [root.left, root.right] = [root.right, root.left]
        reverseTree(root.left)
        reverseTree(root.right)
    }
}
複製代碼

雖然推理過程比較複雜(也多是寫的比較囉嗦。。),可是仔細觀察代碼,這和遍歷的代碼彷佛也沒多大差異,只是把輸出結點變爲了交換結點。微信

判斷二叉樹是否徹底對稱

一棵左右徹底對稱的二叉樹是這樣的: 數據結構

那到底如何判斷呢?

  • 根結點爲空時,此時爲一棵空二叉樹,知足對稱條件(-_-||)
  • 只有一個根結點時,左右子樹都爲null,知足左右對稱條件
  • 只有兩個結點時,此時左右子樹一定有一個爲空,不可能存在對稱的狀況
  • 結點數在三個及三個以上時,二叉樹有對稱的可能。

按照咱們正常的思惟,看對稱與否,首先看左邊,而後看右邊,最後比較左右是否相等。同時咱們注意到,在二叉樹深度比較大的時候,咱們光是比較左右是不夠的。能夠觀察到,咱們比較完左右之後還須要比較左的左右的右,比較左的右右的左post

分析過程

這麼看是比較繞,接下來咱們來看圖分析:spa

  1. 先比較根結點左右孩子
  2. 左子樹根結點的左孩子右子樹根結點的右孩子進行比較
  3. 左子樹根結點的右孩子右子樹根結點的左孩子進行比較
  4. 重複以上過程...

示例代碼

function isSymmetrical(pRoot) {
    // write code here
    if(!pRoot){
        return true
    }
    return funC(pRoot.left, pRoot.right)
}
 
function funC(left, right){
     
    if(!left){
        return right === null
    }
     
    if(!right){
        return false
    }
     
    if(left.val !== right.val){
        return false
    }
     
    return funC(left.right, right.left) && funC(left.left, right.right)
}
複製代碼

求二叉樹的深度

分析過程

  • 只有一個根結點時,二叉樹深度爲1
  • 只有左子樹時,二叉樹深度爲左子樹深度加1
  • 只有右子樹時,二叉樹深度爲右子樹深度加1
  • 同時存在左右子樹時,二叉樹深度爲左右子樹中深度最大者加1

示例代碼

function deep(root){
    if(!root){
        return 0
    }
    let left = deep(root.left)
    let right = deep(root.right)
    return left > right ? left + 1 : right + 1
}
複製代碼

求二叉樹的寬度

二叉樹的寬度是啥?我把它理解爲具備最多結點數的層中包含的結點數,好比下圖所示的二叉樹,其實它的寬度就是爲4: 3d

分析過程

根據上圖,咱們如何算出二叉樹的寬度呢?其實有個很簡單的思路:

  1. 算出第一層的結點數,保存
  2. 算出第二層的結點數,保存一二層中較大的結點數
  3. 重複以上過程

示例代碼

根據分析過程,咱們能夠利用隊列這種數據結構來實現這個算法,代碼以下:

function width(root){
    if(!root){
        return 0
    }
    let queue = [root], max = 1, deep = 1
    while(queue.length){
        while(deep--){
            let temp = queue.shift()
            if(temp.left){
                queue.push(temp.left)
            }
            if(temp.right){
                queue.push(temp.right)
            }
        }
        deep = queue.length
        max = max > deep ? max : deep
    }
    return max
}
複製代碼

重建二叉樹

常見的遍歷

  • 前序遍歷: 前序遍歷首先訪問根結點而後遍歷左子樹,最後遍歷右子樹

  • 中序遍歷: 中序遍歷首先訪問左子樹而後遍歷根節點,最後遍歷右子樹

  • 後序遍歷: 後序遍歷首先遍歷左子樹,而後遍歷右子樹,最後訪問根結點

題目描述

根據前序遍歷產生的序列和中序遍歷產生的序列生成一顆二叉樹

思路分析

假若有這麼一棵二叉樹:

能夠看出它 前序遍歷序列爲: 8 6 5 7 10 9 11中序遍歷序列爲: 5 6 7 8 9 10 11 其中有個很明顯的特徵,根結點的值爲 前序遍歷序列的第一個值,並且咱們在 中序遍歷序列中很容易看出,根結點左右兩邊的結點分別爲構成 左子樹右子樹的結點,因此咱們能夠獲得一種解決問題的思路:

  1. 獲取前序遍歷的第一個值,構建根結點
  2. 生成左子樹的前序遍歷序列和中序遍歷序列
  3. 生成右子樹的前序遍歷序列和中序遍歷序列
  4. 重複以上過程...

示例代碼

function reConstructBinaryTree(pre, vin) {
    if(!pre || !vin || !pre.length || !vin.length){
        return null
    }
    let root = new TreeNode(pre[0]),
        tIndex = vin.indexOf(pre[0]),
        leftIn = [],leftPre = [],rightIn = [],rightPre = []
    
    for(let i = 0; i < tIndex; i++){
        leftIn.push(vin[i])
        leftPre.push(pre[i+1])
    }
    for(let i = tIndex+1; i < pre.length; i++){
        rightIn.push(vin[i])
        rightPre.push(pre[i])
    }
    //遞歸
    root.left = reConstructBinaryTree(leftPre, leftIn)
    root.right = reConstructBinaryTree(rightPre, rightIn)
    return root
}
複製代碼

以上思路、代碼有錯漏請在評論區指出!

總結

代碼部分來自牛客網--劍指offer,相應的題目也均可以在上面找到。不過在這期間,我也是找到了份實習工做,年後就要去搬磚了。既然找到了,春招就不參與了(春招難度比秋招難太多了)但願看這篇文章的同窗們也能找到份合適的工做。

掃描下方的二維碼或搜索「tony老師的前端補習班」關注個人微信公衆號,那麼就能夠第一時間收到個人最新文章。

相關文章
相關標籤/搜索