Open In App

Tree Traversal Techniques – Data Structure and Algorithm Tutorials

Last Updated : 29 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Tree Traversal techniques include various ways to visit all the nodes of the tree. Unlike linear data structures (Array, Linked List, Queues, Stacks, etc) which have only one logical way to traverse them, trees can be traversed in different ways. In this article, we will discuss about all the tree traversal techniques along with their uses.

Tree-Traversal-Techniques-(1)

Tree Traversal Meaning:

Tree Traversal refers to the process of visiting or accessing each node of the tree exactly once in a certain order. Tree traversal algorithms help us to visit and process all the nodes of the tree. Since tree is not a linear data structure, there are multiple nodes which we can visit after visiting a certain node. There are multiple tree traversal techniques which decide the order in which the nodes of the tree are to be visited.

Tree Traversal Techniques:

Tree-Traversal-Techniques

A Tree Data Structure can be traversed in following ways:

  • Depth First Search or DFS
    • Inorder Traversal
    • Preorder Traversal
    • Postorder Traversal
  • Level Order Traversal or Breadth First Search or BFS

Inorder Traversal:

Inorder traversal visits the node in the order: Left -> Root -> Right

Preorder-Traversal-of-Binary-Tree


Algorithm for Inorder Traversal:

Inorder(tree)

  • Traverse the left subtree, i.e., call Inorder(left->subtree)
  • Visit the root.
  • Traverse the right subtree, i.e., call Inorder(right->subtree)

Uses of Inorder Traversal:

  • In the case of binary search trees (BST), Inorder traversal gives nodes in non-decreasing order.
  • To get nodes of BST in non-increasing order, a variation of Inorder traversal where Inorder traversal is reversed can be used.
  • Inorder traversal can be used to evaluate arithmetic expressions stored in expression trees.

Code Snippet for Inorder Traversal:

C++
// Given a binary tree, print its nodes in inorder
void printInorder(struct Node* node)
{
    if (node == NULL)
        return;

    // First recur on left child
    printInorder(node->left);

    // Then print the data of node
    cout << node->data << " ";

    // Now recur on right child
    printInorder(node->right);
}
C
// Given a binary tree, print its nodes in inorder
void printInorder(struct node* node)
{
    if (node == NULL)
        return;

    // First recur on left child
    printInorder(node->left);

    // Then print the data of node
    printf("%d ", node->data);

    // Now recur on right child
    printInorder(node->right);
}
Java
void printInorder(Node node)
{
    if (node == null)
        return;

    // First recur on left child
    printInorder(node.left);

    // Then print the data of node
    System.out.print(node.key + " ");

    // Now recur on right child
    printInorder(node.right);
}
Python3
# A function to do inorder tree traversal
def printInorder(root):

    if root:

        # First recur on left child
        printInorder(root.left)

        # Then print the data of node
        print(root.val, end=" "),

        # Now recur on right child
        printInorder(root.right)
C#
// Given a binary tree, print
// its nodes in inorder
void printInorder(Node node)
{
    if (node == null)
        return;

    // First recur on left child
    printInorder(node.left);

    // Then print the data of node
    Console.Write(node.key + " ");

    // Now recur on right child
    printInorder(node.right);
}
Javascript
// Given a binary tree, print its nodes in inorder
function printInorder(node) {
    if (node == null)
        return;

    // First recur on left child */
    printInorder(node.left);

    // Then print the data of node
    console.log(node.key + " ");

    // Now recur on right child
    printInorder(node.right);
}

Output
Inorder traversal of binary tree is 
4 2 5 1 3 

Time Complexity: O(N)
Auxiliary Space: If we don’t consider the size of the stack for function calls then O(1) otherwise O(h) where h is the height of the tree. 

Preorder Traversal:

Preorder traversal visits the node in the order: Root -> Left -> Right

Inorder-Traversal-of-Binary-Tree

Algorithm for Preorder Traversal:

Preorder(tree)

  • Visit the root.
  • Traverse the left subtree, i.e., call Preorder(left->subtree)
  • Traverse the right subtree, i.e., call Preorder(right->subtree) 

Uses of Preorder Traversal:

  • Preorder traversal is used to create a copy of the tree.
  • Preorder traversal is also used to get prefix expressions on an expression tree.

Code Snippet for Preorder Traversal:

C++
// Given a binary tree, print its nodes in preorder
void printPreorder(struct Node* node)
{
    if (node == NULL)
        return;

    // First print data of node
    cout << node->data << " ";

    // Then recur on left subtree
    printPreorder(node->left);

    // Now recur on right subtree
    printPreorder(node->right);
}
C
// Given a binary tree, print its nodes in preorder
void printPreorder(struct node* node)
{
    if (node == NULL)
        return;

    // First print data of node
    printf("%d ", node->data);

    // Then recur on left subtree
    printPreorder(node->left);

    // Now recur on right subtree
    printPreorder(node->right);
}
Java
// Given a binary tree, print its nodes in preorder
void printPreorder(Node node)
{
    if (node == null)
        return;

    // First print data of node
    System.out.print(node.key + " ");

    // Then recur on left subtree
    printPreorder(node.left);

    // Now recur on right subtree
    printPreorder(node.right);
}
Python3
# A function to do preorder tree traversal
def printPreorder(root):

    if root:

        # First print the data of node
        print(root.val, end=" "),

        # Then recur on left child
        printPreorder(root.left)

        # Finally recur on right child
        printPreorder(root.right)
C#
// Given a binary tree, print
// its nodes in preorder
void printPreorder(Node node)
{
    if (node == null)
        return;

    // First print data of node
    Console.Write(node.key + " ");

    // Then recur on left subtree
    printPreorder(node.left);

    // Now recur on right subtree
    printPreorder(node.right);
}
Javascript
// Given a binary tree, print its nodes in preorder
function printPreorder(node) {
    if (node == null)
        return;

    // First print data of node
    document.write(node.key + " ");

    // Then recur on left subtree
    printPreorder(node.left);

    // Now recur on right subtree
    printPreorder(node.right);
}

Output
Preorder traversal of binary tree is 
1 2 4 5 3 

Time Complexity: O(N)
Auxiliary Space: If we don’t consider the size of the stack for function calls then O(1) otherwise O(h) where h is the height of the tree. 

Postorder Traversal

Postorder traversal visits the node in the order: Left -> Right -> Root

Postorder-Traversal-of-Binary-Tree

Algorithm for Postorder Traversal:

Algorithm Postorder(tree)

  • Traverse the left subtree, i.e., call Postorder(left->subtree)
  • Traverse the right subtree, i.e., call Postorder(right->subtree)
  • Visit the root

Uses of Postorder Traversal:

  • Postorder traversal is used to delete the tree. See the question for the deletion of a tree for details.
  • Postorder traversal is also useful to get the postfix expression of an expression tree.
  • Postorder traversal can help in garbage collection algorithms, particularly in systems where manual memory management is used.

Code Snippet for Postorder Traversal:

C++
// Given a binary tree, print its nodes according to the
// "bottom-up" postorder traversal.
void printPostorder(struct Node* node)
{
    if (node == NULL)
        return;

    // First recur on left subtree
    printPostorder(node->left);

    // Then recur on right subtree
    printPostorder(node->right);

    // Now deal with the node
    cout << node->data << " ";
}
C
// Given a binary tree, print its nodes according to the
// "bottom-up" postorder traversal.
void printPostorder(struct node* node)
{
    if (node == NULL)
        return;

    // First recur on left subtree
    printPostorder(node->left);

    // Then recur on right subtree
    printPostorder(node->right);

    // Now deal with the node
    printf("%d ", node->data);
}
Java
// Given a binary tree, print its nodes according to the
// "bottom-up" postorder traversal.
void printPostorder(Node node)
{
    if (node == null)
        return;

    // First recur on left subtree
    printPostorder(node.left);

    // Then recur on right subtree
    printPostorder(node.right);

    // Now deal with the node
    System.out.print(node.key + " ");
}
Python3
# A function to do postorder tree traversal
def printPostorder(root):

    if root:

        # First recur on left child
        printPostorder(root.left)

        # The recur on right child
        printPostorder(root.right)

        # Now print the data of node
        print(root.val, end=" "),
C#
// Given a binary tree, print its nodes according to
// the "bottom-up" postorder traversal.
void printPostorder(Node node)
{
    if (node == null)
        return;

    // First recur on left subtree
    printPostorder(node.left);

    // Then recur on right subtree
    printPostorder(node.right);

    // Now deal with the node
    Console.Write(node.key + " ");
}
Javascript
// Given a binary tree, print its nodes according 
// to the "bottom-up" postorder traversal
function printPostorder(node) {
    if (node == null)
        return;

    // First recur on left subtree
    printPostorder(node.left);

    // Then recur on right subtree
    printPostorder(node.right);

    // Now deal with the node
    console.log(node.key + " ");
}

Output
Postorder traversal of binary tree is 
4 5 2 3 1 

Level Order Traversal:

Level Order Traversal visits all nodes present in the same level completely before visiting the next level.

Level-Order-Traversal-of-Binary-Tree

Algorithm for Level Order Traversal:

LevelOrder(tree)

  • Create an empty queue Q
  • Enqueue the root node of the tree to Q
  • Loop while Q is not empty
    • Dequeue a node from Q and visit it
    • Enqueue the left child of the dequeued node if it exists
    • Enqueue the right child of the dequeued node if it exists

Uses of Level Order:

Code Snippet for Level Order Traversal:

C++
// Iterative method to find height of Binary Tree
void printLevelOrder(Node* root)
{
    // Base Case
    if (root == NULL)
        return;

    // Create an empty queue for level order traversal
    queue<Node*> q;

    // Enqueue Root and initialize height
    q.push(root);

    while (q.empty() == false) {

        // Print front of queue and remove it from queue
        Node* node = q.front();
        cout << node->data << " ";
        q.pop();

        // Enqueue left child
        if (node->left != NULL)
            q.push(node->left);

        // Enqueue right child
        if (node->right != NULL)
            q.push(node->right);
    }
}
C
// Given a binary tree, print its nodes in level order
// using array for implementing queue
void printLevelOrder(struct node* root)
{
    int rear, front;
    struct node** queue = createQueue(&front, &rear);
    struct node* temp_node = root;

    while (temp_node) {
        printf("%d ", temp_node->data);

        // Enqueue left child
        if (temp_node->left)
            enQueue(queue, &rear, temp_node->left);

        // Enqueue right child
        if (temp_node->right)
            enQueue(queue, &rear, temp_node->right);

        // Dequeue node and make it temp_node
        temp_node = deQueue(queue, &front);
    }
}
Java
// Given a binary tree. Print
// its nodes in level order
// using array for implementing queue
void printLevelOrder()
{
    Queue<Node> queue = new LinkedList<Node>();
    queue.add(root);
    while (!queue.isEmpty()) {

        // poll() removes the present head.
        Node tempNode = queue.poll();
        System.out.print(tempNode.data + " ");

        // Enqueue left child
        if (tempNode.left != null) {
            queue.add(tempNode.left);
        }

        // Enqueue right child
        if (tempNode.right != null) {
            queue.add(tempNode.right);
        }
    }
}
Python3
# Iterative Method to print the
# height of a binary tree


def printLevelOrder(root):

    # Base Case
    if root is None:
        return

    # Create an empty queue
    # for level order traversal
    queue = []

    # Enqueue Root and initialize height
    queue.append(root)

    while(len(queue) > 0):

        # Print front of queue and
        # remove it from queue
        print(queue[0].data, end=" ")
        node = queue.pop(0)

        # Enqueue left child
        if node.left is not None:
            queue.append(node.left)

        # Enqueue right child
        if node.right is not None:
            queue.append(node.right)
C#
// Given a binary tree. Print
// its nodes in level order using
// array for implementing queue
void printLevelOrder()
{
    Queue<Node> queue = new Queue<Node>();
    queue.Enqueue(root);
    while (queue.Count != 0) {

        Node tempNode = queue.Dequeue();
        Console.Write(tempNode.data + " ");

        // Enqueue left child
        if (tempNode.left != null) {
            queue.Enqueue(tempNode.left);
        }

        // Enqueue right child
        if (tempNode.right != null) {
            queue.Enqueue(tempNode.right);
        }
    }
}
JavaScript
// Function to perform level order traversal of a binary tree
function printLevelOrder(root) {
    // Create a deque to store nodes for traversal
    const queue = new Deque();
    // Add the root node to the queue
    queue.enqueue(root);
    // Continue traversal until the queue is empty
    while (!queue.isEmpty()) {
        // Remove and get the first node from the queue
        const tempNode = queue.dequeue();
        // Print the data of the current node
        console.log(tempNode.data + " ");

        // Enqueue the left child if it exists
        if (tempNode.left !== null) {
            queue.enqueue(tempNode.left);
        }
        // Enqueue the right child if it exists
        if (tempNode.right !== null) {
            queue.enqueue(tempNode.right);
        }
    }
}

Other Tree Traversals:

  1. Boundary Traversal
  2. Diagonal Traversal

1. Boundary Traversal:

Boundary Traversal of a Tree includes:

  • left boundary (nodes on left excluding leaf nodes)
  • leaves (consist of only the leaf nodes)
  • right boundary (nodes on right excluding leaf nodes)

Algorithm for Boundary Traversal:

BoundaryTraversal(tree)

  • If root is not null:
    • Print root’s data
    • PrintLeftBoundary(root->left) // Print the left boundary nodes
    • PrintLeafNodes(root->left) // Print the leaf nodes of left subtree
    • PrintLeafNodes(root->right) // Print the leaf nodes of right subtree
    • PrintRightBoundary(root->right) // Print the right boundary nodes

Uses of Boundary Traversal:

  • Boundary traversal helps visualize the outer structure of a binary tree, providing insights into its shape and boundaries.
  • Boundary traversal provides a way to access and modify these nodes, enabling operations such as pruning or repositioning of boundary nodes.

2. Diagonal Traversal

In the Diagonal Traversal of a Tree, all the nodes in a single diagonal will be printed one by one.

Algorithm for Diagonal Traversal:

DiagonalTraversal(tree):

  • If root is not null:
    • Create an empty map
    • DiagonalTraversalUtil(root, 0, M) // Call helper function with initial diagonal level 0
    • For each key-value pair (diagonalLevel, nodes) in M:
      • For each node in nodes:
      • Print node’s data

DiagonalTraversalUtil(node, diagonalLevel, M):

  • If node is null:
  • Return
  • If diagonalLevel is not present in M:
    • Create a new list in M for diagonalLevel
  • Append node’s data to the list at M[diagonalLevel]
  • DiagonalTraversalUtil(node->left, diagonalLevel + 1, M) // Traverse left child with increased diagonal level
  • DiagonalTraversalUtil(node->right, diagonalLevel, M) // Traverse right child with same diagonal level

Uses of Diagonal Traversal:

  • Diagonal traversal helps in visualizing the hierarchical structure of binary trees, particularly in tree-based data structures like binary search trees (BSTs) and heap trees.
  • Diagonal traversal can be utilized to calculate path sums along diagonals in a binary tree.

Frequently Asked Questions (FAQs) on Tree Traversal Techniques:

1. What are tree traversal techniques?

Tree traversal techniques are methods used to visit and process all nodes in a tree data structure. They allow you to access each node exactly once in a systematic manner.

2. What are the common types of tree traversal?

The common types of tree traversal are: Inorder traversal, Preorder traversal, Postorder traversal, Level order traversal (Breadth-First Search)

3. What is Inorder traversal?

Inorder traversal is a depth-first traversal method where nodes are visited in the order: left subtree, current node, right subtree.

4. What is preorder traversal?

Preorder traversal is a depth-first traversal method where nodes are visited in the order: current node, left subtree, right subtree.

5. What is postorder traversal?

Postorder traversal is a depth-first traversal method where nodes are visited in the order: left subtree, right subtree, current node.

6. What is level order traversal?

Level order traversal, also known as Breadth-First Search (BFS), visits nodes level by level, starting from the root and moving to the next level before traversing deeper.

7. When should I use each traversal technique?

Inorder traversal is often used for binary search trees to get nodes in sorted order.

Preorder traversal is useful for creating a copy of the tree.

Postorder traversal is commonly used in expression trees to evaluate expressions.

Level order traversal is helpful for finding the shortest path between nodes.

8. How do I implement tree traversal algorithms?

Tree traversal algorithms can be implemented recursively or iteratively, depending on the specific requirements and programming language being used.

9. Can tree traversal algorithms be applied to other tree-like structures?

Yes, tree traversal algorithms can be adapted to traverse other tree-like structures such as binary heaps, n-ary trees, and graphs represented as trees.

10. Are there any performance considerations when choosing a traversal technique?

Performance considerations depend on factors such as the size and shape of the tree, available memory, and specific operations being performed during traversal. In general, the choice of traversal technique may affect the efficiency of certain operations, so it’s important to choose the most suitable method for your specific use case.

Some other important Tutorials:



Previous Article
Next Article

Similar Reads

Construct Full Binary Tree using its Preorder traversal and Preorder traversal of its mirror tree
Given two arrays that represent Preorder traversals of a full binary tree and its mirror tree, we need to write a program to construct the binary tree using these two Preorder traversals.A Full Binary Tree is a binary tree where every node has either 0 or 2 children. Note: It is not possible to construct a general binary tree using these two traver
12 min read
Pre Order, Post Order and In Order traversal of a Binary Tree in one traversal | (Using recursion)
Given a binary tree, the task is to print all the nodes of the binary tree in Pre-order, Post-order, and In-order in one iteration. Examples: Input: Output: Pre Order: 1 2 4 5 3 6 7 Post Order: 4 5 2 6 7 3 1 In Order: 4 2 5 1 6 3 7 Input: Output: Pre Order: 1 2 4 8 12 5 9 3 6 7 10 11 Post Order: 12 8 4 9 5 2 6 10 11 7 3 1 In Order: 8 12 4 2 9 5 1 6
9 min read
Level order traversal of Binary Tree using Morris Traversal
Given a binary tree, the task is to traverse the Binary Tree in level order fashion.Examples: Input: 1 / \ 2 3 Output: 1 2 3 Input: 5 / \ 2 3 \ 6 Output: 5 2 3 6 Approach: The idea is to use Morris Preorder Traversal to traverse the tree in level order traversal.Observations: There are mainly two observations for the traversal of the tree using Mor
11 min read
Static Data Structure vs Dynamic Data Structure
Data structure is a way of storing and organizing data efficiently such that the required operations on them can be performed be efficient with respect to time as well as memory. Simply, Data Structure are used to reduce complexity (mostly the time complexity) of the code. Data structures can be two types : 1. Static Data Structure 2. Dynamic Data
4 min read
Efficiently find first repeated character in a string without using any additional data structure in one traversal
Implement a space efficient algorithm to check First repeated character in a string without using any additional data structure in one traversal. Use additional data structures like count array, hash, etc is not allowed. Examples : Input : abcfdeacf Output : char = a, index= 6Recommended: Please solve it on “PRACTICE ” first, before moving on to th
5 min read
Find postorder traversal of BST from preorder traversal
Given an array representing preorder traversal of BST, print its postorder traversal. Examples: Input : 40 30 35 80 100 Output : 35 30 100 80 40 Input : 40 30 32 35 80 90 100 120 Output : 35 32 30 120 100 90 80 40 Prerequisite: Construct BST from given preorder traversal Simple Approach: A simple solution is to first construct BST from a given preo
9 min read
Basic Algorithm Techniques Not Taught in Academics
We generally study most of the algorithmic techniques in academics like Searching, Sorting, Dynamic Programming, Greedy Algorithms, Divide and Conquer, Backtracking, etc. But below techniques are generally not taught and used a lot to solve questions in interviews and competitive programming. Prefix Sum Technique In this technique we preprocess the
3 min read
Cartesian tree from inorder traversal | Segment Tree
Given an in-order traversal of a cartesian tree, the task is to build the entire tree from it. Examples: Input: arr[] = {1, 5, 3} Output: 1 5 3 5 / \ 1 3 Input: arr[] = {3, 7, 4, 8} Output: 3 7 4 8 8 / 7 / \ 3 4 Approach: We have already seen an algorithm here that takes O(NlogN) time on an average but can get to O(N2) in the worst case.In this art
13 min read
Check if a binary tree is subtree of another binary tree using preorder traversal : Iterative
Given two binary trees S and T, the task is the check that if S is a subtree of the Tree T. For Example: Input: Tree T - 1 / \ 2 3 / \ / \ 4 5 6 7 Tree S - 2 / \ 4 5 Output: YES Explanation: The above tree is the subtree of the tree T, Hence the output is YES Approach: The idea is to traverse both the tree in Pre-order Traversal and check for each
11 min read
Given level order traversal of a Binary Tree, check if the Tree is a Min-Heap
Given the level order traversal of a Complete Binary Tree, determine whether the Binary Tree is a valid Min-Heap Examples: Input : level = [10, 15, 14, 25, 30] Output : True The tree of the given level order traversal is 10 / \ 15 14 / \ 25 30 We see that each parent has a value less than its child, and hence satisfies the min-heap property Input :
6 min read
three90RightbarBannerImg