在筆者的『基礎資料結構 3 --- 樹狀結構與二元樹』的這篇文章中,我們介紹了樹的基本概念,也學習了如何遍歷樹的方法,在之前的文章中,我們有說到,如果要遍歷樹大至上有以下三種方法 :
-
中序追蹤 (in-order)
: 先走訪左子樹,然後在根,最後在右子樹。(DBEAFCG) -
前序追蹤 (pre-order)
: 先走訪根,然後在左子樹,最後在右子樹。(ABDECFG) -
後序追蹤 (post-order)
: 先走訪左子樹,然後在右子樹,最後是根。(DEBFGCA)

那為什麼我們這裡要在拿來說一次呢 ?
因為我們之前實作的方法是用『 Recursion 』來實作。
有寫過程式的人大概會知道,在使用 recursion
實作程式碼,常常有可能會發生 memory leak
事件,所以我們這篇將要來說明,如何不使用它,來實作以上三種 traversal。
中序追蹤 (in-order)
左 => 根 => 右
iteration
- 直接先深入最深的左子樹,並將行經的節點,存放到 stack 中。
- 然後深入到最後時,發現是 null ,開始從 stack 中 pop 東西出來。
- 接下來在從 pop 出的節點的右子樹開始重複第一個步驟。
/** * Tree inordrTraversal (no recursive) * Tip: 左根右 */ BinarySearchTree.prototype.inorderTraversal = function(){ let stack = []; let isEnd = false; let current = this.root; while (!isEnd) { if(current != null){ stack.push(current); current = current.left; } else{ if(stack.length > 0){ current = stack.pop(); console.log(current.data); current = current.right; }else{ isEnd = true; } } } }
recursion
BinaryTree.prototype.inOrderTraverse = function(callback) { inOrderTraverseNode(this.root,callback); function inOrderTraverseNode(node,callback) { if(node !== null){ inOrderTraverseNode(node.left,callback); callback(node.data); inOrderTraverseNode(node.right,callback); } } };
前序追蹤 (pre-order)
根 => 左 => 右
iteration
- 先將 root 存放到 stack 中。
- 然後因為pre-order 是先根在子樹,所以直接從 stack pop 出節點輸出。
- 接下來在將左右子樹放入 stack。
- 重複第二個步驟。
/** * Tree preorderTraversal (no recursive) * Tip: 根左右 */ BinarySearchTree.prototype.preorderTraversal = function(){ let stack = []; stack.push(this.root); let current; while (stack.length > 0) { current = stack.pop(); console.log(current.data); if(current.right){ stack.push(current.right); } if(current.left){ stack.push(current.left); } } }
recursion
BinaryTree.prototype.preOrderTraverse = function(callback) { preOrderTraverseNode(this.root,callback); function preOrderTraverseNode(node,callback) { if(node !== null){ callback(node.data); preOrderTraverseNode(node.left,callback); preOrderTraverseNode(node.right,callback); } } };
後序追蹤 (post-order)
左 => 右 => 根
iteration
- 將第一個節點丟到 stack 中。
- 然後在進行 while
- pop 出節點,然後丟到 temp 陣列中。
- 在將該節點的左右子樹丟到 stack 中。
- 重複 while
- 最後在將 temp 陣列中的節點取出。
/** * Tree postOrder Traversal (no recursive) * Tip: 左右根 */ BinarySearchTree.prototype.postOrderTraversal = function() { let stack = []; let temp = []; let current = this.root; let isEnd = false; stack.push(current); while(stack.length > 0){ current = stack.pop(); temp.push(current); if(current.left != null){ stack.push(current.left); } if(current.right != null){ stack.push(current.right); } } while(temp.length > 0){ current = temp.pop(); console.log(current.data); } }
recursion
BinaryTree.prototype.postOrderTraverse = function(callback) { postOrderTraverseNode(this.root,callback); function postOrderTraverseNode(node,callback) { if(node !== null){ postOrderTraverseNode(node.left,callback); postOrderTraverseNode(node.right,callback); callback(node.data); } } };
參考資料
注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。