[Algorithms] Build a Binary Tree in JavaScript and Several Traversal Algorithms
A binary tree is a tree where each node may only have up to two children. These children are stored on the left
and right
properties of each node.
When traversing a binary tree, we have three common traversal algorithms: in order, pre-order, and post-order. In this lesson, we write each of these algorithms and explore their differences.
// Binary Trees and Tree Traversal // Binary trees are trees whose nodes can only have up to two children function createBinaryNode(key) { return { key, left: null, right: null, addLeft(leftKey) { const newLeft = createBinaryNode(leftKey) this.left = newLeft return newLeft }, addRight(rightKey) { const newRight = createBinaryNode(rightKey) this.right = newRight return newRight } } } const TRAVERSALS = { /** * Javascript Call stack is Last in, First Out, * So it keep calling * TRAVERSALS.IN_ORDER(node.left, visitFn) * Until it reach the bottom left node 'h' (b- d- h) * h - visitFn get called * h - TRAVERSALS.IN_ORDER(node.right, visitFn) get called * * d - visitFn get called * d - left * d - right * * b - visitFn * b - left * b - right */ IN_ORDER: (node, visitFn) => { if (node !== null) { console.log('left', node.left && node.left.key) TRAVERSALS.IN_ORDER(node.left, visitFn) console.log('call', node.key) visitFn(node) console.log('right', node.right && node.right.key) TRAVERSALS.IN_ORDER(node.right, visitFn) } }, PRE_ORDER: (node, visitFn) => { if (node !== null) { visitFn(node) TRAVERSALS.PRE_ORDER(node.left, visitFn) TRAVERSALS.PRE_ORDER(node.right, visitFn) } }, POST_ORDER: (node, visitFn) => { if (node !== null) { TRAVERSALS.POST_ORDER(node.left, visitFn) TRAVERSALS.POST_ORDER(node.right, visitFn) visitFn(node) } } } function createBinaryTree(rootKey) { const root = createBinaryNode(rootKey) return { root, print(traversalType = 'IN_ORDER') { let result = '' const visit = node => { result += result.length === 0 ? node.key : ` => ${node.key}` } TRAVERSALS[traversalType](this.root, visit) return result } } } const tree = createBinaryTree('a') const b = tree.root.addLeft('b') const c = tree.root.addRight('c') const d = b.addLeft('d') const e = b.addRight('e') const f = c.addLeft('f') const g = c.addRight('g') const h = d.addLeft('h') const i = d.addRight('i') console.log('IN_ORDER: ', tree.print())// IN_ORDER: h => d => i => b => e => a => f => c => g
//console.log('PRE_ORDER: ', tree.print('PRE_ORDER')) // PRE_ORDER: a => b => d => h => i => e => c => f => g
//console.log('POST_ORDER: ', tree.print('POST_ORDER')) // POST_ORDER: h => i => d => e => b => f => g => c => a
exports.createBinaryNode = createBinaryNode exports.createBinaryTree = createBinaryTree
Time complexity: O(n),
Space Complexity O(h) for average cases; h = logN -- this is because we need to stack all the function calls. worse cases: O(n)