Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction 🤓
1.1.
Problem Statement 🤔
1.2.
Sample Example 🧐
2.
In-Order Traversal Approach 🧑‍💻✨
2.1.
Algorithm 🧑‍💻💫
2.2.
Implementation 🧑‍💻🌝
2.2.1.
Time Complexity ⏳
2.2.2.
Space Complexity 🌌
3.
Morris Traversal Approach 🧑‍💻✨
3.1.
Algorithm 🧑‍💻💫
3.2.
Implementation 🧑‍💻🌝
3.2.1.
Time Complexity ⏳
3.2.2.
Space Complexity 🌌
4.
Frequently Asked Questions 
4.1.
What are the characteristics of a binary search tree?
4.2.
What exactly is a key in a tree data structure?
4.3.
What is the threaded binary tree?
5.
Conclusion
Last Updated: Mar 27, 2024
Medium

Print BST Keys in the Given Valid Range

Introduction 🤓

The problem to print BST keys in the given valid range is a very basic BST problem. When you start BST, you usually come across this. 

introduction

This article will discuss how to print BST keys in the given valid range. We will use two approaches to find a solution to this problem. The interesting part is both of the approaches will have the same time complexity but different space complexities. This is the reason it is usually asked in interviews. So without any further ado. Let’s get started!

Print BST keys in the given valid range

Problem Statement 🤔

As a ninja of the hidden leaf village. You are going to get a task to retrieve a special scroll. But to prove that you are worthy to get that task. You need to solve a problem. You are given a BST and two keys which are the upper and lower limits of the range. The problem is to print BST keys in the given valid range. If you are able to print the key values. You’ll get the assignment.

problem statement

Let’s better understand the problem statement by the following example.

Sample Example 🧐

Example 1:

Input: Range of keys are, key1: 14 and key2: 23.

input

Output: 

output

Explanation: The keys are 13, 15, 17, 20, 23, 25, 30

So keys in range 14 to 23 are 15, 17, 20, and 23.

Example 2:

Input: Range of keys are, key1: 8 and key2: 15.

input

Output: 

output

Explanation: The keys are 8, 10, 12, 15, 18, 20, 25

So keys in range 8 to 15 are 8, 12, 10, and 15.

In-Order Traversal Approach 🧑‍💻✨

We will use an in-order traversal approach to print BST keys in the given valid range. In this approach, when the tree is traversed in an in-order fashion. The keys are traversed in increasing order. So when we find that the key lies in the range, then we will print it. Otherwise, we will skip it.

inorder approach

Algorithm 🧑‍💻💫

  1. Make a structure to store a BST node.
     
  2. Now create a function to do the in-order traversal of the tree.
     
  3. Now create a recursive function. It will take root as a parameter. And the range is (low, up)
    • If the value of the root’s key is greater than low, then recursively call in the left subtree.
    • If the value of the root’s key is in range, then print the root’s key.
    • Otherwise, recursively call the right subtree.
       
  4. Now modify the new tree accordingly.

Implementation 🧑‍💻🌝

#include<bits/stdc++.h>
#include <cmath>
#include<algorithm>
using namespace std;

#define FAST ios_base::sync_with_stdio(false); cin.tie(NULL);

//creating class Node
class Node
{
  public:
  int data;
  Node *left;
  Node *right;
};

//function to print values
//between low & up(low<up)
void Range(Node *root, int low, int Up)
{
  	if ( root==NULL )
    	return;
  
  	// traverse left subtree first
  	//If root->data > low, o/p the keys
  		if ( low < root->data )
    	Range(root->left, low, Up);
  
  	//similarly for data<=up
  		if ( low <= root->data && Up >= root->data )
    		cout<<root->data<<" ";
  
  	// traverse left subtree
  		Range(root->right, low, Up);
}


//----------------------------------Utility Function-----------------------------------//
Node* newNode(int data)
{
 	 Node *temp = new Node();
 	 temp->data = data;
 	 temp->left = NULL;
 	 temp->right = NULL;
  
 	 return temp;
}

//--------------------------------Main Function-------------------------------------//
int main()
{
  FAST;
  	Node *root = new Node();
  	int low = 15, Up = 30;
  
  //value for tree construction
  	root = newNode(25);
  	root->left = newNode(13);
  	root->right = newNode(27);
  	root->left->left = newNode(9);
  	root->left->right = newNode(17);
  
  Range(root, low,Up);
  	return 0;
}

Output:

output

Time Complexity ⏳

The time complexity of the above approach is O(n). Here, n is the total number of keys in the tree. A single traversal on the tree is needed in this approach. That’s why time complexity is O(n)

Space Complexity 🌌

The space complexity O(h). Here, the “h” is the height of the tree. This approach will need space proportional to the tree's height for the recursive function call..

Morris Traversal Approach 🧑‍💻✨

In In-order traversal we use recursion or a stack/queue operations. Both of them consume O(n) space. 

To overcome this space consumption problem. We use Morris Traversal. It is based on Threaded Binary trees.

Morris traversal does not use recursion or stacks/queues. Instead it stores information in the NULL pointers. Morris traversal uses no recursion operation or use of stack/queue. So it consumes constant extra memory O(1)

approach

In this approach, we will use Morris traversal to perform inorder traversal in the algorithm to print BST keys in the given valid range, which is memory efficient.

Algorithm 🧑‍💻💫

  1. Make a structure to store a BST node.
  2. Now create a function to do the in-order traversal of the tree.
  3. Initialise a node “current” as root node.
     
  4. Now when the root node value is not NULL :
    • If the root node has no left child
      • Check if the root node lies between the lower and upper values of the range.
        • If so, then visit the root node.
      • Otherwise, move it to the right child of the root node.
         
    • Else, we will have two cases:
      • Find the in-order predecessor of the node. The inorder predecessor is the rightmost node in the left subtree or left child itself.
      • If value of the right child of the inorder predecessor is NULL:
        • Set node value as the right child of its inorder predecessor.
        • Move the node to its left child.
           
      • Else, if the threaded link between the node and their inorder predecessor exists :
        • Set the right pointer of the in-order predecessor as NULL.
        • Again, check if the node lies between the range's lower and upper values.
        • If so, then visit the node.      
      • Now move the node to its right child.
         
  5. Now modify the new tree accordingly.

Implementation 🧑‍💻🌝

#include <bits/stdc++.h>
#include <cmath>
#include<algorithm>
using namespace std;

#define FAST ios_base::sync_with_stdio(false); cin.tie(NULL);

//creating struct Node
struct Node {
  int data;
  struct Node *left;
  struct Node *right;
};


// Function to print the keys in range
void Range(Node* root, int low, int up)
{
  Node* curr = root;


  if (!root)
    return;


  while (curr!=NULL) {
    if (curr->left == NULL)
    {
      // check if low <= node <= up
      if (curr->data <= up && curr->data >= low){
        cout << curr->data << " ";
      }
      curr = curr->right;
    }
    else {
      Node* temp = curr->left;
      // find the inorder predecessor 
      while (temp->right != curr && temp->right != NULL)
        temp = temp->right;


      if (temp->right == NULL){
        temp->right = curr;
        curr = curr->left;
      }


      else {
        temp->right = NULL;


        // check if low <= node <= up
        if (curr->data <= up && curr->data >= low){
          cout << curr->data << " ";
        }
        curr = curr->right;
      }
    }
  }
}


//----------------------------------Utility Function-----------------------------------//
Node* NodeVal(int data)
{
	  Node* temp = new Node;
	  temp->data = data;
	  temp->right = NULL;
	  temp->left = NULL;

  	return temp;
}


//--------------------------------Main Function-------------------------------------//
int main()
{
  	FAST;
  		Node* root = NodeVal(20);
  		root->left = NodeVal(15);
  		root->right = NodeVal(25);
  		root->left->left = NodeVal(13);
  		root->left->right = NodeVal(17);
  		root->right->left = NodeVal(23);
	  	root->right->right = NodeVal(30);

	  Range(root, 14, 23);
  
  return 0;
}

Output:

output

Time Complexity ⏳

The time complexity of the above approach is O(n). Here, n is the total number of keys in the tree. A single traversal on the tree is needed in this approach. That’s why time complexity is O(n)

Space Complexity 🌌

The space complexity of the above approach is O(1). Since no extra space has been used.

Frequently Asked Questions 

What are the characteristics of a binary search tree?

A binary search tree (BST) incorporates the following two features: Each node can have a maximum of two children. The values of each node's left descendent nodes are less than those of the current node, which are less than those of the right descendent nodes (if any).

What exactly is a key in a tree data structure?

In general, tree structures store a set of values known as keys. All of the numbers listed above are keys in the tree. Because trees frequently store key/value pairs, the term keys are appropriate, and the balancing and lookup logic only applies to keys.

What is the threaded binary tree?

The threaded binary tree is an idea to make inorder traversing faster, without using stack or recursion operation.

Conclusion

This article briefly discussed the problem to print BST keys in the given range. We used two approaches to do so. First by using an in-order traversal. And second by using Morris Traversal approach.

We hope that this blog have been helpful to you to enhance your knowledge about the above question and if you like to learn more, check out our articles Difference between binary tree and BSTInbuilt binary search in different languageswhy binary heap is better than BST for priority queue, and self-balancing BST.

You can also practice some relevant problems at the code studio, such as Count Univalue SubtreesSpecial Binary TreeRight View, and Binary Tree Pruning.

Refer to our Guided Path on Coding Ninjas Studio to upskill yourself in Data Structures and AlgorithmsCompetitive ProgrammingJavaScript, and many more! If you wish to test your competency in coding, you may check out the mock test series. You can also participate in the contests hosted on Coding Ninjas Studio! But suppose you have just started your learning process and are looking for questions asked by tech giants like Amazon, Microsoft, Uber, etc. In that case, you must look at the problemsinterview experiences, and interview bundle for placement preparations.

Nevertheless, you may consider our paid courses to give your career an edge over others!

Do upvote our blogs if you find them helpful and engaging!

Happy Learning!

Live masterclass