Table of contents
1.
Introduction
2.
Problem Statement
2.1.
Sample Examples
3.
Approach
4.
Optimum approach
4.1.
Algorithm
4.2.
Implementation in Java
4.2.1.
Complexity Analysis 
4.3.
Implementation using Recursion
4.3.1.
Complexity Analysis 
5.
Frequently Asked Questions
5.1.
Mention the properties of tree data structure that are used while solving problems.
5.2.
What is a Threaded Binary Tree?
5.3.
What are the advantages of using the Threaded Binary Tree data structure?
6.
Conclusion
Last Updated: Mar 27, 2024
Medium

Print leaf nodes from preorder of a BST

Author Rupal Saluja
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

In this blog, we will understand a very interesting problem of a Binary Search Tree data structure. We have already learned that there are three ways in which we can traverse a tree. These are, namely, preorder, inorder, and postorder. In this problem, we will print leaf nodes from the preorder of a BST. 

Basic idea of preorder

Through this problem, we will learn the approach to solve any such problem of a Binary Search Tree. Firstly, we will examine the problem statement, learn about the Binary Search tree data structure, and decide on what will be the optimum approach. Then we will proceed toward the implementation in the programming languages.

Notion of coding

What is a Binary Search Tree?

A Binary Search Tree is a type of Binary tree data structure. A Binary Tree is one in which elements have the utmost two children nodes. Since elements in this data structure have only two child nodes, we name them the left child and the right child. Any node of Binary contains the following information. These are its data and pointers to its left and right child.

For Example, if we consider the tree below, 20 is the root node, and the rest of the nodes are its children nodes. We pick any node, say 17, so 13 will be its left child, and 19 will be its right child. 17 is the parent node to children nodes 13 and 19.

Binary Search Tree

Three properties of a Binary Search Tree that differentiates it from a normal Binary Tree. These properties are mentioned below in the list.

  • The left subtree of any node will contain only those whose value is lesser than that node’s value.
  • The right subtree of any node will contain only those whose value is greater than that node’s value.
  • All the subtrees must also be binary search trees.

Problem Statement

We are given a preorder of a binary search tree with n nodes. We have to find and print leaf nodes from the preorder of a BST. There may be any number of leaf nodes in the BST.

Here, we assume that all the nodes’ values are positive. Let us understand this with the help of an example.

Suppose we have a BST preordered, as seen in the examples below. We have to print leaf nodes from them. We will use multiple examples so that you can get a better understanding of the problem statement.

Sample Examples

🌷 Example 1:

Input: 30 27 23 19 26 29 32 31 35 42

Output: 19 26 29 31 42

Explanation

In the above example, we can see a preorder of a binary search tree. Using the given preorder, we will output the leaf nodes of that BST. If you are familiar with the basic terminologies of the tree, this problem will not be difficult for you.

You might know that preorder traversal goes from root to left subtree and then to right subtree.

  1. In the given preorder, observe the decreasing order from 30 to 19.
  2. This decreasing order breaks when we get 26. As a result, 19 is pushed onto the stack.
  3. The same happens for 26 and 29. They are pushed to the stack because the value ahead of them is greater.
  4. 32 is not pushed because the consecutive value is less.
  5. We check that 32 is greater than the top of the stack. If this case is true, we will pop the stack. 19 will be printed as a result.

This way, the process continues, and every leaf node value will be popped out of the stack. You can use the BST created using the preorder for a better grab.

Sample Example

 

🌷 Example 2

Input: 45 30 26 19 13 34 40 50 60 55 52

Output: 13 40 52

Explanation

  1. In the given preorder, observe the decreasing order from 45 to 13.
  2. This decreasing order breaks when we get 34. As a result, 13 is pushed onto the stack.
  3. The same happens for 34, 40, 50, and 52. They are pushed to the stack because the value ahead of them is greater.
  4. 55 is not pushed because the consecutive value is less.
  5. We check if 34 is greater than the top of the stack. If this case is true, we will pop the stack. 13 will be printed as a result.

This way, the process continues, and every leaf node value will be popped out of the stack one by one. You can use the BST created using the preorder for a better grab.

Sample example

🌷 Example 3

Input: 15 10 8 11 27 23 31 29 37

Output: 8 11 23 29 37

Explanation

  1. In the given preorder, observe the decreasing order from 15 to 8.
  2. This decreasing order breaks when we get 11. As a result, 8 is pushed onto the stack.
  3. The same happens for 11, 23, 29, and 37. They are pushed to the stack because the value ahead of them is greater.
  4. 27 is not pushed because the consecutive value is less.
  5. We check that 11 is greater than the top of the stack. If this case is true, we will pop the stack. 8 will be printed as a result.

This way, the process continues, and every leaf node value will be popped out of the stack. You can use the BST created using the preorder for a better grab.

sample example

Approach

The Naive Approach for this problem can be to find the inorder of the array provided to you. Now, traverse the preorder array and while traversing, find each element in the inorder array using Binary Search. We can use Binary Search here because inorder traversal of the Binary Search Tree is always sorted. If the element from both arrays match, we print it as a leaf node.

This approach is very simple. Still, we don’t use it because the time complexity is O(n log n), which is not acceptable. 

Optimum approach

The Optimum Approach for this problem will use the Stack and Binary Search Tree properties.

We will traverse the preorder array using two pointers, x=0 and y=1. It is implied that the preorder traversal starts from the root to the leftmost node. By each passing value, we compare two consecutive nodes. The preorder will be in the decreasing order first. After decreasing order ends, you will get a node greater than the previous node. This node will be pushed onto the stack. Whenever we get a value greater than the peek of the stack, we pop an element. The popped element will be printed as a leaf node.

Algorithm

Now, when you know every aspect of this problem, have a look at the algorithm given below.

  1. Set two pointers, say x and y, at index 0 and 1, respectively.
  2. Traverse the pointers through the preorder array at two consecutive indices.
  3. If arr[x] > arr[y], arr[x] will be pushed to stack.
  4. Else arr[y] > top of element, pop an element.
  5. Print all the elements popped.

Implementation in Java

import java.util.*;
class Main
{
    public static void main(String[] args)
    {
        int pre[] = {5, 2, 1, 3, 4, 7, 6, 8, 9};
        int len = pre.length;
        Node(pre, len);
    }
    
    static void Node(int pre[], int len)
    {
        Stack<Integer> stack = new Stack<Integer> ();
        for (int x = 0, y = 1; y < len; x++, y++)
        {
            boolean search = false;
 
            if (pre[x] > pre[y])
                stack.push(pre[x]);
 
            else
            {
                while (!stack.isEmpty())
                {
                    if (pre[y] > stack.peek())
                    {
                        stack.pop();
                        search = true;
                    }
                else
                    break;
                }
            }
 
            if (search)
                System.out.print(pre[x] + " ");
        }
        System.out.println(pre[len - 1]);
    }
}


Input: 

5, 2, 1, 3, 4, 7, 6, 8, 9

 

Output: 

1, 4, 6, 9


Complexity Analysis
 

🍉 Time Complexity
In the implementation above, the pointer may have to traverse all the nodes before finding the required node. Therefore, in this case, the time complexity will be O(n).

🍉 Space Complexity
Since the space scales 1:1 with changes to the size of n, that is n increases by 1 every time a new iteration is performed. Therefore, the space complexity would be O(n).

Implementation using Recursion

We have used a simple recursive approach here. The concept is to use two variables for minimum and maximum values. We will recursively create a root node and check if that node has a child or not using two boolean variables. If the root node created has no child nodes, both the boolean variables return false. It will be printed as a leaf node.

import java.util.*;
class Main
{
    static int a = 0;
    public static void main(String[] args)
    {
        int pre[] = {5, 2, 1, 3, 4, 7, 6, 8, 9};
        int len = pre.length;
        print(pre, len);
    }
    
    static boolean Leaf(int pre[], int len, int minimum, int maximum)
    {
        if (a >= len)
        {
            return false;
        }
        if (pre[a] > minimum && pre[a] < maximum)
        {
            a++;
            boolean left = Leaf(pre, len, minimum, pre[a - 1]);
            boolean right = Leaf(pre, len, pre[a - 1], maximum);
            if (!left && !right)
            {
                System.out.print(pre[a - 1] + " ");
            }
            return true;
        }
        return false;
    }
    static void print(int pre[], int len)
    {
        Leaf(pre, len, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }
}


Complexity Analysis
 

🍉 Time Complexity
In the implementation above, the pointer will traverse only the required nodes using recursion. Therefore, in this case, the time complexity will be O(log n).

🍉 Space Complexity
Since the space scales 1:1 with changes to the size of n, that is n increases by 1 every time a new iteration is performed. Therefore, the space complexity would be O(n).

Frequently Asked Questions

Mention the properties of tree data structure that are used while solving problems.

Some properties of tree data structure which we use while solving problems are mentioned below.

  • Number of Edges
  • Depth of a node
  • Height of a node
  • Height of the tree
  • Degree of a node

What is a Threaded Binary Tree?

Such a tree in which all right child pointers would be null and pointing towards the inorder successor of the node is known as a threaded binary tree. Similarly, all left child pointers would also be null and pointing towards the inorder predecessor of the node.

What are the advantages of using the Threaded Binary Tree data structure?

A few advantages of using Threaded Binary Tree data structure are:

  • Traversal becomes much faster.
  • No stack overhead would occur.
  • Every node becomes accessible.
  • Easy implementation of insertion and deletion.

Conclusion

To summarize the article, we looked at the problem statement, looked at every possible condition that could occur, understood the approach, went through the Pseudocode, saw the implementation, tested the code against an example output, and did time and space complexities analysis.

We hope the above discussion helped you understand and solve the problem better.

This will also help you learn how to approach any problem like this in the future.

For coders who want to solve more such questions, refer to the list below.


Enroll in our courses, go for mock tests, solve problems available, and interview puzzles. Also, you can focus on interview stuff- interview experiences and an interview bundle for placement preparations. Do upvote our blog to help other ninjas grow.

thanks image

 

Happy Coding!

Live masterclass