Depth-First Search (tree)
Algorithm · Core
Step through it: Binary Tree Traversal pattern
Step 1 of 5
A tree has no single first-to-last order, so we pick one. The three common orders differ only in when a node is visited compared with its children.
Step 2 of 5
Pre-order: the node first, then left, then right. Good for copying a tree.
Step 3 of 5
In-order: left, then the node, then right. On a binary search tree this gives the values in sorted order.
Step 4 of 5
Post-order: left, right, then the node. Children come before their parent, so it is the order for deleting a tree or adding up sizes.
Step 5 of 5
Your turn.
Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures. One starts at the root (selecting some arbitrary node as the root in the case of a graph) and explores as far as possible along each branch before backtracking.
Code
/**
* @typedef {Object} TraversalCallbacks
*
* @property {function(node: BinaryTreeNode, child: BinaryTreeNode): boolean} allowTraversal
* - Determines whether DFS should traverse from the node to its child.
*
* @property {function(node: BinaryTreeNode)} enterNode - Called when DFS enters the node.
*
* @property {function(node: BinaryTreeNode)} leaveNode - Called when DFS leaves the node.
*/
/**
* Extend missing traversal callbacks with default callbacks.
*
* @param {TraversalCallbacks} [callbacks] - The object that contains traversal callbacks.
* @returns {TraversalCallbacks} - Traversal callbacks extended with defaults callbacks.
*/
function initCallbacks(callbacks = {}) {
// Init empty callbacks object.
const initiatedCallbacks = {};
// Empty callback that we will use in case if user didn't provide real callback function.
const stubCallback = () => {};
// By default we will allow traversal of every node
// in case if user didn't provide a callback for that.
const defaultAllowTraversalCallback = () => true;
// Copy original callbacks to our initiatedCallbacks object or use default callbacks instead.
initiatedCallbacks.allowTraversal = callbacks.allowTraversal || defaultAllowTraversalCallback;
initiatedCallbacks.enterNode = callbacks.enterNode || stubCallback;
initiatedCallbacks.leaveNode = callbacks.leaveNode || stubCallback;
// Returned processed list of callbacks.
return initiatedCallbacks;
}
/**
* Recursive depth-first-search traversal for binary.
*
* @param {BinaryTreeNode} node - binary tree node that we will start traversal from.
* @param {TraversalCallbacks} callbacks - the object that contains traversal callbacks.
*/
export function depthFirstSearchRecursive(node, callbacks) {
// Call the "enterNode" callback to notify that the node is going to be entered.
callbacks.enterNode(node);
// Traverse left branch only if case if traversal of the left node is allowed.
if (node.left && callbacks.allowTraversal(node, node.left)) {
depthFirstSearchRecursive(node.left, callbacks);
}
// Traverse right branch only if case if traversal of the right node is allowed.
if (node.right && callbacks.allowTraversal(node, node.right)) {
depthFirstSearchRecursive(node.right, callbacks);
}
// Call the "leaveNode" callback to notify that traversal
// of the current node and its children is finished.
callbacks.leaveNode(node);
}
/**
* Perform depth-first-search traversal of the rootNode.
* For every traversal step call "allowTraversal", "enterNode" and "leaveNode" callbacks.
* See TraversalCallbacks type definition for more details about the shape of callbacks object.
*
* @param {BinaryTreeNode} rootNode - The node from which we start traversing.
* @param {TraversalCallbacks} [callbacks] - Traversal callbacks.
*/
export default function depthFirstSearch(rootNode, callbacks) {
// In case if user didn't provide some callback we need to replace them with default ones.
const processedCallbacks = initCallbacks(callbacks);
// Now, when we have all necessary callbacks we may proceed to recursive traversal.
depthFirstSearchRecursive(rootNode, processedCallbacks);
}References
Practice
Binary Tree Traversal
- Binary Tree Inorder TraversalEasy
- Binary Tree Preorder TraversalEasy
- Binary Tree Postorder TraversalEasy
- Same TreeEasy
- Symmetric TreeEasy
- Invert Binary TreeEasy
- Subtree of Another TreeEasy
- Merge Two Binary TreesEasy
- Construct Binary Tree from Preorder and Inorder TraversalMedium
- Construct Binary Tree from Inorder and Postorder TraversalMedium
- Validate Binary Search TreeMedium
- Kth Smallest Element in a BSTMedium
- Flatten Binary Tree to Linked ListMedium
- Lowest Common Ancestor of a Binary TreeMedium
- Binary Search Tree IteratorMedium
- Recover Binary Search TreeMedium
- Serialize and Deserialize Binary TreeHard
- Binary Tree Maximum Path SumHard
Depth-First Search
- Maximum Depth of Binary TreeEasy
- Path SumEasy
- Diameter of Binary TreeEasy
- Balanced Binary TreeEasy
- Find if Path Exists in GraphEasy
- Path Sum IIMedium
- Path Sum IIIMedium
- Clone GraphMedium
- Number of ProvincesMedium
- All Paths From Source to TargetMedium
- Course ScheduleMedium
- Pacific Atlantic Water FlowMedium
- Count Good Nodes in Binary TreeMedium
- Sum Root to Leaf NumbersMedium
- Reconstruct ItineraryMedium
- Is Graph Bipartite?Medium
- Binary Tree Maximum Path SumHard
- Longest Increasing Path in a MatrixHard
Spotted a mistake or something unclear? Report it on GitHub.