A Cartesian tree is a tree data structure created from a set of data that obeys the following structural invariants:
- The tree obeys in the min (or max) heap property - each node is less (or greater) than its children.
- An inorder traversal of the nodes yields the values in the same order in which they appear in the initial sequence.
Suppose we have an input array- {5,10,40,30,28}. Then the max-heap Cartesian Tree would be.

A min-heap Cartesian Tree of the above input array will be-

Note:
- Cartesian Tree is not a height-balanced tree.
- Cartesian tree of a sequence of distinct numbers is always unique.
Cartesian tree of a sequence of distinct numbers is always unique.
We will prove this using induction. As a base case, empty tree is always unique. For the inductive case, assume that for all trees containing n' < n elements, there is a unique Cartesian tree for each sequence of n' nodes. Now take any sequence of n elements. Because a Cartesian tree is a min-heap, the smallest element of the sequence must be the root of the Cartesian tree. Because an inorder traversal of the elements must yield the input sequence, we know that all nodes to the left of the min element must be in its left subtree and similarly for the nodes to the right. Since the left and right subtree are both Cartesian trees with at most n-1 elements in them (since the min element is at the root), by the induction hypothesis there is a unique Cartesian tree that could be the left or right subtree. Since all our decisions were forced, we end up with a unique tree, completing the induction.
How to construct Cartesian Tree?
A O(n2) solution for construction of Cartesian Tree is discussed here (Note that the above program here constructs the “special binary tree” (which is nothing but a Cartesian tree)
A O(nlogn) Algorithm :
It's possible to build a Cartesian tree from a sequence of data in O(NlogN) time on average. Beginning with the empty tree,
Scan the given sequence from left to right adding new nodes as follows:
- Position the node as the right child of the rightmost node.
- Scan upward from the node's parent up to the root of the tree until a node is found whose value is greater than the current value.
- If such a node is found, set its right child to be the new node, and set the new node's left child to be the previous right child.
- If no such node is found, set the new child to be the root, and set the new node's left child to be the previous tree.
CPP
// A O(n) C++ program to construct cartesian tree
// from a given array
#include<bits/stdc++.h>
/* A binary tree node has data, pointer to left
child and a pointer to right child */
struct Node
{
int data;
Node *left, *right;
};
/* This function is here just to test buildTree() */
void printInorder (Node* node)
{
if (node == NULL)
return;
printInorder (node->left);
cout << node->data << " ";
printInorder (node->right);
}
// Recursively construct subtree under given root using
// leftChild[] and rightchild
Node * buildCartesianTreeUtil (int root, int arr[],
int parent[], int leftchild[], int rightchild[])
{
if (root == -1)
return NULL;
// Create a new node with root's data
Node *temp = new Node;
temp->data = arr[root] ;
// Recursively construct left and right subtrees
temp->left = buildCartesianTreeUtil( leftchild[root],
arr, parent, leftchild, rightchild );
temp->right = buildCartesianTreeUtil( rightchild[root],
arr, parent, leftchild, rightchild );
return temp ;
}
// A function to create the Cartesian Tree in O(N) time
Node * buildCartesianTree (int arr[], int n)
{
// Arrays to hold the index of parent, left-child,
// right-child of each number in the input array
int parent[n],leftchild[n],rightchild[n];
// Initialize all array values as -1
memset(parent, -1, sizeof(parent));
memset(leftchild, -1, sizeof(leftchild));
memset(rightchild, -1, sizeof(rightchild));
// 'root' and 'last' stores the index of the root and the
// last processed of the Cartesian Tree.
// Initially we take root of the Cartesian Tree as the
// first element of the input array. This can change
// according to the algorithm
int root = 0, last;
// Starting from the second element of the input array
// to the last on scan across the elements, adding them
// one at a time.
for (int i=1; i<=n-1; i++)
{
last = i-1;
rightchild[i] = -1;
// Scan upward from the node's parent up to
// the root of the tree until a node is found
// whose value is greater than the current one
// This is the same as Step 2 mentioned in the
// algorithm
while (arr[last] <= arr[i] && last != root)
last = parent[last];
// arr[i] is the largest element yet; make it
// new root
if (arr[last] <= arr[i])
{
parent[root] = i;
leftchild[i] = root;
root = i;
}
// Just insert it
else if (rightchild[last] == -1)
{
rightchild[last] = i;
parent[i] = last;
leftchild[i] = -1;
}
// Reconfigure links
else
{
parent[rightchild[last]] = i;
leftchild[i] = rightchild[last];
rightchild[last] = i;
parent[i] = last;
}
}
// Since the root of the Cartesian Tree has no
// parent, so we assign it -1
parent[root] = -1;
return (buildCartesianTreeUtil (root, arr, parent,
leftchild, rightchild));
}
/* Driver program to test above functions */
int main()
{
/* Assume that inorder traversal of following tree
is given
40
/ \
10 30
/ \
5 28 */
int arr[] = {5, 10, 40, 30, 28};
int n = sizeof(arr)/sizeof(arr[0]);
Node *root = buildCartesianTree(arr, n);
/* Let us test the built tree by printing Inorder
traversal */
printf("Inorder traversal of the constructed tree : \n");
printInorder(root);
return(0);
}
Java
// A O(n) Java program to construct cartesian tree
// from a given array
/* A binary tree node has data, pointer to left
child and a pointer to right child */
class GFG
{
static class Node
{
int data;
Node left, right;
};
/* This function is here just to test buildTree() */
static void printInorder (Node node)
{
if (node == null)
return;
printInorder (node.left);
System.out.print(node.data + " ");
printInorder (node.right);
}
// Recursively construct subtree under given root using
// leftChild[] and rightchild
static Node buildCartesianTreeUtil (int root, int arr[],
int parent[], int leftchild[], int rightchild[])
{
if (root == -1)
return null;
// Create a new node with root's data
Node temp = new Node();
temp.data = arr[root] ;
// Recursively construct left and right subtrees
temp.left = buildCartesianTreeUtil( leftchild[root],
arr, parent, leftchild, rightchild );
temp.right = buildCartesianTreeUtil( rightchild[root],
arr, parent, leftchild, rightchild );
return temp ;
}
// A function to create the Cartesian Tree in O(N) time
static Node buildCartesianTree (int arr[], int n)
{
// Arrays to hold the index of parent, left-child,
// right-child of each number in the input array
int []parent = new int[n];
int []leftchild = new int[n];
int []rightchild = new int[n];
// Initialize all array values as -1
memset(parent, -1);
memset(leftchild, -1);
memset(rightchild, -1);
// 'root' and 'last' stores the index of the root and the
// last processed of the Cartesian Tree.
// Initially we take root of the Cartesian Tree as the
// first element of the input array. This can change
// according to the algorithm
int root = 0, last;
// Starting from the second element of the input array
// to the last on scan across the elements, adding them
// one at a time.
for (int i = 1; i <= n - 1; i++)
{
last = i - 1;
rightchild[i] = -1;
// Scan upward from the node's parent up to
// the root of the tree until a node is found
// whose value is greater than the current one
// This is the same as Step 2 mentioned in the
// algorithm
while (arr[last] <= arr[i] && last != root)
last = parent[last];
// arr[i] is the largest element yet; make it
// new root
if (arr[last] <= arr[i])
{
parent[root] = i;
leftchild[i] = root;
root = i;
}
// Just insert it
else if (rightchild[last] == -1)
{
rightchild[last] = i;
parent[i] = last;
leftchild[i] = -1;
}
// Reconfigure links
else
{
parent[rightchild[last]] = i;
leftchild[i] = rightchild[last];
rightchild[last] = i;
parent[i] = last;
}
}
// Since the root of the Cartesian Tree has no
// parent, so we assign it -1
parent[root] = -1;
return (buildCartesianTreeUtil (root, arr, parent,
leftchild, rightchild));
}
static void memset(int[] arr, int value)
{
for (int i = 0; i < arr.length; i++)
{
arr[i] = value;
}
}
/* Driver code */
public static void main(String[] args)
{
/* Assume that inorder traversal of following tree
is given
40
/ \
10 30
/ \
5 28 */
int arr[] = {5, 10, 40, 30, 28};
int n = arr.length;
Node root = buildCartesianTree(arr, n);
/* Let us test the built tree by printing Inorder
traversal */
System.out.printf("Inorder traversal of the" +
" constructed tree : \n");
printInorder(root);
}
}
// This code is contributed by PrinciRaj1992
Python3
# A O(n) python program to construct cartesian tree
# from a given array
# Define a Node class for the binary tree
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# Function to print the inorder traversal of the tree
def printInorder(node):
if node is None:
return
printInorder(node.left)
print(node.data, end=" ")
printInorder(node.right)
# Recursive function to construct the Cartesian tree
def buildCartesianTreeUtil(root, arr, parent, leftchild, rightchild):
# If the root index is -1, return None
if root == -1:
return None
# Create a new node with the root's data
temp = Node(arr[root])
# Recursively construct the left and right subtrees
temp.left = buildCartesianTreeUtil(leftchild[root], arr, parent, leftchild, rightchild)
temp.right = buildCartesianTreeUtil(rightchild[root], arr, parent, leftchild, rightchild)
# Return the constructed node
return temp
# Function to construct the Cartesian tree
def buildCartesianTree(arr):
n = len(arr)
# Initialize arrays for parent, left child, and right child
parent = [-1]*n
leftchild = [-1]*n
rightchild = [-1]*n
# Set the root of the tree to be the first element of the input array
root = 0
last = None
# Iterate through the input array, adding each element to the tree
for i in range(1, n):
last = i-1
rightchild[i] = -1
# Scan upward from the element's parent until a node is found whose value is greater than the current one
while last != root and arr[last] <= arr[i]:
last = parent[last]
# If the element is the largest so far, make it the new root
if arr[last] <= arr[i]:
parent[root] = i
leftchild[i] = root
root = i
# If there is no right child for the last node, insert the element as the right child
elif rightchild[last] == -1:
rightchild[last] = i
parent[i] = last
leftchild[i] = -1
# Else, reconfigure the links to insert the element as the right child
else:
parent[rightchild[last]] = i
leftchild[i] = rightchild[last]
rightchild[last] = i
parent[i] = last
# Set the root of the tree to have no parent
parent[root] = -1
# Return the constructed tree
return buildCartesianTreeUtil(root, arr, parent, leftchild, rightchild)
# Driver program to test above functions
if __name__ == '__main__':
arr = [5, 10, 40, 30, 28]
root = buildCartesianTree(arr)
print('Inorder traversal of the constructed tree :')
printInorder(root)
C#
// A O(n) C# program to construct cartesian tree
// from a given array
/* A binary tree node has data, pointer to left
child and a pointer to right child */
using System;
class GFG
{
class Node
{
public int data;
public Node left, right;
};
/* This function is here just to test buildTree() */
static void printInorder (Node node)
{
if (node == null)
return;
printInorder (node.left);
Console.Write(node.data + " ");
printInorder (node.right);
}
// Recursively construct subtree under given root using
// leftChild[] and rightchild
static Node buildCartesianTreeUtil (int root, int []arr,
int []parent, int []leftchild, int []rightchild)
{
if (root == -1)
return null;
// Create a new node with root's data
Node temp = new Node();
temp.data = arr[root] ;
// Recursively construct left and right subtrees
temp.left = buildCartesianTreeUtil( leftchild[root],
arr, parent, leftchild, rightchild );
temp.right = buildCartesianTreeUtil( rightchild[root],
arr, parent, leftchild, rightchild );
return temp ;
}
// A function to create the Cartesian Tree in O(N) time
static Node buildCartesianTree (int []arr, int n)
{
// Arrays to hold the index of parent, left-child,
// right-child of each number in the input array
int []parent = new int[n];
int []leftchild = new int[n];
int []rightchild = new int[n];
// Initialize all array values as -1
memset(parent, -1);
memset(leftchild, -1);
memset(rightchild, -1);
// 'root' and 'last' stores the index of the root and the
// last processed of the Cartesian Tree.
// Initially we take root of the Cartesian Tree as the
// first element of the input array. This can change
// according to the algorithm
int root = 0, last;
// Starting from the second element of the input array
// to the last on scan across the elements, adding them
// one at a time.
for (int i = 1; i <= n - 1; i++)
{
last = i - 1;
rightchild[i] = -1;
// Scan upward from the node's parent up to
// the root of the tree until a node is found
// whose value is greater than the current one
// This is the same as Step 2 mentioned in the
// algorithm
while (arr[last] <= arr[i] && last != root)
last = parent[last];
// arr[i] is the largest element yet; make it
// new root
if (arr[last] <= arr[i])
{
parent[root] = i;
leftchild[i] = root;
root = i;
}
// Just insert it
else if (rightchild[last] == -1)
{
rightchild[last] = i;
parent[i] = last;
leftchild[i] = -1;
}
// Reconfigure links
else
{
parent[rightchild[last]] = i;
leftchild[i] = rightchild[last];
rightchild[last] = i;
parent[i] = last;
}
}
// Since the root of the Cartesian Tree has no
// parent, so we assign it -1
parent[root] = -1;
return (buildCartesianTreeUtil (root, arr, parent,
leftchild, rightchild));
}
static void memset(int[] arr, int value)
{
for (int i = 0; i < arr.Length; i++)
{
arr[i] = value;
}
}
/* Driver code */
public static void Main(String[] args)
{
/* Assume that inorder traversal of following tree
is given
40
/ \
10 30
/ \
5 28 */
int []arr = {5, 10, 40, 30, 28};
int n = arr.Length;
Node root = buildCartesianTree(arr, n);
/* Let us test the built tree by printing Inorder
traversal */
Console.Write("Inorder traversal of the" +
" constructed tree : \n");
printInorder(root);
}
}
// This code is contributed by 29AjayKumar
JavaScript
<script>
// A O(n) Javascript program to construct cartesian tree
// from a given array
/* A binary tree node has data, pointer to left
child and a pointer to right child */
class Node
{
constructor(data)
{
this.data=data;
this.left=this.right=null;
}
}
/* This function is here just to test buildTree() */
function printInorder (node)
{
if (node == null)
return;
printInorder (node.left);
document.write(node.data + " ");
printInorder (node.right);
}
// Recursively construct subtree under given root using
// leftChild[] and rightchild
function buildCartesianTreeUtil(root,arr,parent,leftchild,rightchild)
{
if (root == -1)
return null;
// Create a new node with root's data
let temp = new Node();
temp.data = arr[root] ;
// Recursively construct left and right subtrees
temp.left = buildCartesianTreeUtil( leftchild[root],
arr, parent, leftchild, rightchild );
temp.right = buildCartesianTreeUtil( rightchild[root],
arr, parent, leftchild, rightchild );
return temp ;
}
// A function to create the Cartesian Tree in O(N) time
function buildCartesianTree (arr,n)
{
// Arrays to hold the index of parent, left-child,
// right-child of each number in the input array
let parent = new Array(n);
let leftchild = new Array(n);
let rightchild = new Array(n);
// Initialize all array values as -1
memset(parent, -1);
memset(leftchild, -1);
memset(rightchild, -1);
// 'root' and 'last' stores the index of the root and the
// last processed of the Cartesian Tree.
// Initially we take root of the Cartesian Tree as the
// first element of the input array. This can change
// according to the algorithm
let root = 0, last;
// Starting from the second element of the input array
// to the last on scan across the elements, adding them
// one at a time.
for (let i = 1; i <= n - 1; i++)
{
last = i - 1;
rightchild[i] = -1;
// Scan upward from the node's parent up to
// the root of the tree until a node is found
// whose value is greater than the current one
// This is the same as Step 2 mentioned in the
// algorithm
while (arr[last] <= arr[i] && last != root)
last = parent[last];
// arr[i] is the largest element yet; make it
// new root
if (arr[last] <= arr[i])
{
parent[root] = i;
leftchild[i] = root;
root = i;
}
// Just insert it
else if (rightchild[last] == -1)
{
rightchild[last] = i;
parent[i] = last;
leftchild[i] = -1;
}
// Reconfigure links
else
{
parent[rightchild[last]] = i;
leftchild[i] = rightchild[last];
rightchild[last] = i;
parent[i] = last;
}
}
// Since the root of the Cartesian Tree has no
// parent, so we assign it -1
parent[root] = -1;
return (buildCartesianTreeUtil (root, arr, parent,
leftchild, rightchild));
}
function memset(arr,value)
{
for (let i = 0; i < arr.length; i++)
{
arr[i] = value;
}
}
/* Driver code */
/* Assume that inorder traversal of following tree
is given
40
/ \
10 30
/ \
5 28 */
let arr = [5, 10, 40, 30, 28];
let n = arr.length;
let root = buildCartesianTree(arr, n);
/* Let us test the built tree by printing Inorder
traversal */
document.write("Inorder traversal of the" +
" constructed tree : <br>");
printInorder(root);
// This code is contributed by rag2127
</script>
Output:
Inorder traversal of the constructed tree :
5 10 40 30 28
Time Complexity :
At first look, the code seems to be taking O(n2) time as there are two loop in buildCartesianTree(). But actually, it takes O(NlogN) time in average and O(n^2) for sorted preorder traversal.
Auxiliary Space:
We declare a structure for every node as well as three extra arrays- leftchild[], rightchild[], parent[] to hold the indices of left-child, right-child, parent of each value in the input array. Hence the overall O(4*n) = O(n) extra space.
Application of Cartesian Tree
- Cartesian Tree Sorting
- A range minimum query on a sequence is equivalent to a lowest common ancestor query on the sequence's Cartesian tree. Hence, RMQ may be reduced to LCA using the sequence's Cartesian tree.
- Treap, a balanced binary search tree structure, is a Cartesian tree of (key,priority) pairs; it is heap-ordered according to the priority values, and an inorder traversal gives the keys in sorted order.
- Suffix tree of a string may be constructed from the suffix array and the longest common prefix array. The first step is to compute the Cartesian tree of the longest common prefix array.
References:
http://wcipeg.com/wiki/Cartesian_tree
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem