「樹的遍歷」 指按照必定規則不重複地訪問樹中全部節點的過程。
「訪問」指針對節點的操做,如打印節點的值,更新節點的值等。函數
本文討論二叉樹的遍歷,對節點的訪問經過打印節點的值體現出來。
從二叉樹的根節點出發,遍歷可分爲三個環節:post
不一樣環節執行的前後順序產生了不一樣的遍歷方式。this
「前序遍歷」指先訪問節點,再遍歷節點的左子樹,最後遍歷節點的右子樹,按照這種規則不重複地訪問樹中全部節點的過程。
「中序遍歷」指先遍歷節點的左子樹,再訪問節點,最後遍歷節點的右子樹,按照這種規則不重複地訪問樹中全部節點的過程。
「後序遍歷」指先遍歷節點的左子樹,再遍歷節點的右子樹,最後訪問節點,按照這種規則不重複地訪問樹中全部節點的過程。spa
上圖展示了前序遍歷的整個過程,其中樹的結構用代碼表示以下(存儲爲變量root
)翻譯
function Node(value) { this.value = value this.left = null this.right = null }
root { value: 'A', left: { value: 'B', left: { value: 'D', left: { value: 'H', left: null, right: null }, right: { value: 'I', left: null, right: null } }, right: { value: 'E', left: null, right: null } }, right: { value: 'C', left: { value: 'F', left: null, right: null }, right: { value: 'G', left: null, right: null } } }
設計一個函數,用於遍歷二叉樹,傳入的參數是二叉樹的根節點,函數會先訪問節點(打印節點的值),再遍歷節點的左子樹,最後遍歷節點的右子樹。
上述代碼翻譯成代碼片斷就是設計
/** * 函數的做用是遍歷二叉樹 * 傳入的參數是二叉樹的根節點 * @param {object} root */ function preOrderTraverse(root){ console.log(root.value) // 訪問節點(打印節點的值) ... // 遍歷節點的左子樹 ... // 遍歷節點的右子樹 }
... 處應該是遍歷節點的左,右子二叉樹的代碼。遍歷二叉樹不正是這個函數的做用嗎?故想到了遞歸指針
function preOrderTraverse(root){ console.log(root.value) // 訪問節點(打印節點的值) preOrderTraverse(root.left) // 遍歷節點的左子樹 preOrderTraverse(root.right) // 遍歷節點的右子樹 }
添加遞歸的終止條件,即訪問到葉節點就中止調用函數code
const preOrderTraverse = root => { console.log(root.value) // 訪問節點(打印節點的值) root.left && preOrderTraverse(root.left) // 若節點的左子樹存在,則遍歷節點的左子樹 root.right && preOrderTraverse(root.right) // 若節點的右子樹存在,則遍歷節點的右子樹 } preOrderTraverse(root) // A B D H I E C F G
中序遍歷blog
const inOrderTraverse = root => { root.left && inOrderTraverse(root.left) // 若節點的左子樹存在,則遍歷節點的左子樹 console.log(root.value) // 訪問節點(打印節點的值) root.right && inOrderTraverse(root.right) // 若節點的右子樹存在,則遍歷節點的右子樹 } inOrderTraverse(root) // H D I B E A F C G
後序遍歷遞歸
const postOrderTraverse = root => { root.left && postOrderTraverse(root.left) // 若節點的左子樹存在,則遍歷節點的左子樹 root.right && postOrderTraverse(root.right) // 若節點的右子樹存在,則遍歷節點的右子樹 console.log(root.value) // 訪問節點(打印節點的值) } postOrderTraverse(root) // H I D E B F G C A
隨着被調用次數的增長,遞歸函數會線性地增長棧空間的使用。至於二叉樹的非遞歸遍歷,且聽下回分解。