C++ Program to Implement Interval Tree



What is an Interval Tree?

An interval tree is a tree data structure that stores intervals. It helps us to efficiently find all intervals that overlap with a specific interval or point.

The purpose is to enhance a self-balancing Binary Search Tree (BST) known as Interval Tree, which is similar to Red Black Tree, AVL Tree, and so on, with a set of intervals so that all operations can be performed in O(log n) time.

Every node of interval trees stores the following details:

  • i: An interval which is represented as a pair [start, end].
  • max: The maximum height in subtree rooted with this node.
The low value of an interval provides a key to maintaining order in BST. The insert and delete operation are similar as those used in self-balancing BST.

Let's see an Interval Tree Diagram to understand precisely:

interval-tree

Implement Interval Tree in C++

We have given a set of intervals where each interval contains two values low and high, which specify the start and end time of the interval. Our task is to perform the following operation in the interval tree:

  • Add an Interval
  • Remove an Interval
  • Given an interval y, find if y overlaps with any of the existing intervals.

How to find if the given interval overlaps with existing interval?

  • If y overlaps with root's interval, return the root's interval.
  • If the left child of the root is not empty and the maximum in the left child is greater than the minimum value of y, then recurse to the left child.
  • Else recurse for right child.

Algorithm

Let the interval be searched for y. We need to prove this in for following two cases:

Case 1: One of the following conditions must be true. When we visit the right subtree.

  • There is an overlap in the right subtree: This is fine as we need to return one overlapping interval.
  • There is no overlap in either subtree: We go to the right subtree only when either the left is NULL or the maximum value in the left is smaller than x.low. So the interval cannot be present in the left subtree.

Case 2: One of the following conditions must be true. When we visit the left subtree.

  • There is an overlap in the left subtree: This is fine as we need to return one overlapping interval.
  • There is no overlap in either subtree: This is the most important part. We need to look over the following facts:
  1. We went to the left subtree because x.low <= max in the left subtree.
  2. max in the left subtree is a high of one of the intervals let us say [a, max] in the left subtree.
  3.  
  4. Since x doesn't overlap with any node in the left subtree x.high must be smaller than 'a'.
  5.  
  6. All nodes in BST are ordered by low value, so all nodes in right subtree must have a low value greater than 'a'.
  7. From the above two facts, we can say all intervals in the right subtree have a low value greater than x.high. So x cannot overlap with any interval in the right subtree.

Implementation of Interval Tree

The following C++ example demonstrates the implementation of the interval tree:

#include <iostream>
using namespace std;

// Structure to represent an interval
struct Interval {
   int low, high;
};

// Structure to represent a node in Interval Search Tree
struct Node {
   Interval * i;
   int max;
   Node * left, * right;
};

Node * newNode(Interval i) {
   Node * temp = new Node;
   temp -> i = new Interval(i);
   temp -> max = i.high;
   temp -> left = temp -> right = nullptr;
   return temp;
};

Node * insert(Node * root, Interval i) {

   // Base case: Tree is empty, new node becomes root
   if (root == nullptr)
      return newNode(i);

   // Get low value of interval at root
   int l = root -> i -> low;

   // If root's low value is smaller, 
   // then new interval goes to left subtree
   if (i.low < l)
      root -> left = insert(root -> left, i);

   // Else, new node goes to right subtree.
   else
      root -> right = insert(root -> right, i);

   // Update the max value of this ancestor if needed
   if (root -> max < i.high)
      root -> max = i.high;

   return root;
}

bool isOverlapping(Interval i1, Interval i2) {
   if (i1.low <= i2.high && i2.low <= i1.high)
      return true;
   return false;
}

Interval * overlapSearch(Node * root, Interval i) {

   // Base Case, tree is empty
   if (root == nullptr) return nullptr;

   // If given interval overlaps with root
   if (isOverlapping( * (root -> i), i))
      return root -> i;

   if (root -> left != nullptr && root -> left -> max >= i.low)
      return overlapSearch(root -> left, i);

   // Else interval can only overlap with right subtree
   return overlapSearch(root -> right, i);
}

void inorder(Node * root) {
   if (root == nullptr) return;
   inorder(root -> left);
   cout << "[" << root -> i -> low << ", " << root -> i -> high << "]" <<
      " max = " << root -> max << endl;
   inorder(root -> right);
}

int main() {
   Interval ints[] = {{15, 20}, {10, 30}, {17, 22},
      {5, 20}, {12, 25}, {20, 30}
    };
   int n = sizeof(ints) / sizeof(ints[0]);
   Node * root = nullptr;
   for (int i = 0; i < n; i++)
      root = insert(root, ints[i]);

   cout << "Inorder traversal of constructed Interval Tree is\n";
   inorder(root);

   Interval y = {4, 5};

   cout << "\nSearching for interval [" << y.low << "," << y.high << "]";
   Interval * res = overlapSearch(root, y);
   if (res == nullptr)
      cout << "\nNo Overlapping Interval";
   else
      cout << "\nOverlaps with [" << res -> low << ", " << res -> high << "]";
   return 0;
}

Following is the data of the interval tree:

Inorder traversal of constructed Interval Tree is
[5, 20] max = 20
[10, 30] max = 30
[12, 25] max = 25
[15, 20] max = 30
[17, 22] max = 30
[20, 30] max = 30

Searching for interval [4,5]
Overlaps with [5, 20]
Updated on: 2025-05-28T16:31:44+05:30

790 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements