樹 是一種常常用到的數據結構,用來模擬具備樹狀結構性質的數據集合。node
二叉樹是一種更爲典型的樹狀結構。如它名字所描述的那樣,二叉樹是每一個節點最多有兩個子樹的樹結構,一般子樹被稱做「左子樹」和「右子樹」。數據結構
所謂的縱向遍歷二叉樹,一般指的是前序遍歷、中序遍歷、後序遍歷。ide
下面會介紹這三種遍歷中的遞歸寫法與迭代寫法。post
迭代寫法就是用一個棧來存下每次遍歷的左右子節點。this
假設樹的定義以下:遞歸
// Definition for a binary tree node. function TreeNode(val, left, right) { this.val = (val===undefined ? 0 : val) this.left = (left===undefined ? null : left) this.right = (right===undefined ? null : right) }複製代碼
前序遍歷的順序就是:根節點 -> 左子節點 -> 右子節點it
注意:棧是先入後出的,可是前序遍歷是先遍歷左子節點,再遍歷右子節點,因此須要先把右子節點先入棧io
那麼前序遍歷的 遞歸寫法 與 迭代寫法 以下:function
// 遞歸 var preorderTraversal = functioån(root) { let arr = [] const preNode = (point) => { if (point) { arr.push(point.val) preNode(point.left) preNode(point.right) } } preNode(root) return arr }; // 迭代 var preorderTraversal = function(root) { let arr = [] let stack = [] if (root) stack.push(root) while (stack.length) { let point = stack.pop() arr.push(point.val) if (point.right) stack.push(point.right) if (point.left) stack.push(point.left) } return arr };複製代碼
中序遍歷的順序就是:左子節點 -> 根節點 -> 右子節點class
那麼中序遍歷的 遞歸寫法 與 迭代寫法 以下:
// 遞歸 var inorderTraversal = function(root) { let arr = [] const midRoot = (point) => { if (point) { midRoot(point.left) arr.push(point.val) midRoot(point.right) } } midRoot(root) return arr }; // 迭代 var inorderTraversal = function(root) { let arr = [] let stack = [] while(root || stack.length) { while (root) { stack.push(root) root = root.left } root = stack.pop() arr.push(root.val) root = root.right } return arr };複製代碼
後序遍歷的順序就是:左子節點 -> 右子節點 -> 根節點
這裏解析一下後序遍歷的迭代寫法: 一樣是用一個棧來存遍歷的左右子節點,跟前序與中序遍歷不同的是,這裏我在存子節點的時候存多一個狀態來記錄,判斷是否遍歷過左右子節點了 默認是false,沒有遍歷過,當咱們遍歷過以後設置爲 true
那麼後序遍歷的 遞歸寫法 與 迭代寫法 以下:
// // 遞歸 var postorderTraversal = function(root) { let arr = [] const nextR = (point) => { if (point) { nextR(point.left) nextR(point.right) arr.push(point.val) } } nextR(root) return arr }; // 迭代 var postorderTraversal = function(root) { let arr = [] let stack = [] if (root) stack.push([root, false]) while(stack.length) { let point = stack.pop() if (point[1]) { arr.push(point[0].val) } else { if (!point[0].left && !point[0].right) { arr.push(point[0].val) } else { stack.push([point[0], true]) } if (point[0].right) stack.push([point[0].right, false]) if (point[0].left) stack.push([point[0].left, false]) } } return arr };複製代碼
以上就是二叉樹的縱向遍歷的幾種寫法。後續會繼續出二叉樹的橫向遍歷的幾種常見的場景以及寫法。