本篇爲複習過程當中遇到過的總結,同時也給準備面試的同窗一份參考。另外,因爲篇幅有限,本篇的重點在於二叉樹的常見算法以及實現。
以前寫過相關的文章,是關於如何建立及遍歷二叉樹的,這裏再也不贅述。提供連接給各位感興趣的小夥伴,點此跳轉javascript
對於一棵二叉樹,翻轉它的左右子樹,以下圖所示: 前端
下面來分析具體的實現思路:java
這種狀況須要排除,由於null不是一個對象,不可能存在左右子樹而且能夠翻轉的狀況面試
emmm,這種狀況也能夠翻轉,由於此時根結點左右子樹爲null,交換左右子樹其實也就是在交換兩個null,理論上是翻轉了,但實際上咱們看到的和沒有翻轉以前的結果是同樣的算法
能夠看出,不管是隻有左子樹仍是隻有右子樹均可以進行翻轉。這句話等價於,爲空的子樹能夠和不爲空的子樹進行交換,也就是不對爲空的子樹進行特殊處理微信
其實這樣咱們仍是不知道二叉樹是如何翻轉的,咱們能夠用第一張圖的二叉樹爲例子,看一下翻轉的具體過程。數據結構
根據上面的推理過程咱們能夠得出以下的代碼:post
function reverseTree(root){ if( root !== null){ [root.left, root.right] = [root.right, root.left] reverseTree(root.left) reverseTree(root.right) } }
雖然推理過程比較複雜(也多是寫的比較囉嗦。。),可是仔細觀察代碼,這和遍歷的代碼彷佛也沒多大差異,只是把輸出結點變爲了交換結點。spa
一棵左右徹底對稱的二叉樹是這樣的:
那到底如何判斷呢?3d
按照咱們正常的思惟,看對稱與否,首先看左邊,而後看右邊,最後比較左右是否相等。同時咱們注意到,在二叉樹深度比較大的時候,咱們光是比較左右是不夠的。能夠觀察到,咱們比較完左右之後還須要比較左的左和右的右,比較左的右和右的左
這麼看是比較繞,接下來咱們來看圖分析:
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) }
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:
根據上圖,咱們如何算出二叉樹的寬度呢?其實有個很簡單的思路:
根據分析過程,咱們能夠利用隊列這種數據結構來實現這個算法,代碼以下:
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
其中有個很明顯的特徵,根結點的值爲前序遍歷序列的第一個值,並且咱們在中序遍歷序列中很容易看出,根結點左右兩邊的結點分別爲構成左子樹和右子樹的結點,因此咱們能夠獲得一種解決問題的思路:
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老師的前端補習班」關注個人微信公衆號,那麼就能夠第一時間收到個人最新文章。