Open In App

Cartesian Tree Sorting

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Cartesian Sort is an Adaptive Sorting as it sorts the data faster if data is partially sorted. In fact, there are very few sorting algorithms that make use of this fact. For example consider the array {5, 10, 40, 30, 28}. The input data is partially sorted too as only one swap between “40” and “28” results in a completely sorted order. 

See how Cartesian Tree Sort will take advantage of this fact below. Below are steps used for sorting. 

Step 1 : Build a (min-heap) Cartesian Tree from the given input sequence. 

Applications for Cartesian Tree Sorting:

  • It is possible to quantify how much faster algorithm will run than O(nlogn) using a measurement called oscillation. Practically, the complexity is close to O(nlog(Osc)) (where Osc is oscillation).
  • Oscillation is small if the sequence is partially sorted, hence the algorithm performs faster with partially sorted sequences.

ctree1 Step 2 : Starting from the root of the built Cartesian Tree, we push the nodes in a priority queue. Then we pop the node at the top of the priority queue and push the children of the popped node in the priority queue in a pre-order manner.

  1. Pop the node at the top of the priority queue and add it to a list.
  2. Push left child of the popped node first (if present).
  3. Push right child of the popped node next (if present).

ctree1 ctree2

How to build (min-heap) Cartesian Tree? 

Building min-heap is similar to building a (max-heap) Cartesian Tree (discussed in previous post), except the fact that now we scan upward from the node’s parent up to the root of the tree until a node is found whose value is smaller (and not larger as in the case of a max-heap Cartesian Tree) than the current one and then accordingly reconfigure links to build the min-heap Cartesian tree.

Why not to use only priority queue?

 One might wonder that using priority queue would anyway result in a sorted data if we simply insert the numbers of the input array one by one in the priority queue (i.e- without constructing the Cartesian tree). But the time taken differs a lot. Suppose we take the input array – {5, 10, 40, 30, 28} If we simply insert the input array numbers one by one (without using a Cartesian tree), then we may have to waste a lot of operations in adjusting the queue order everytime we insert the numbers (just like a typical heap performs those operations when a new number is inserted, as priority queue is nothing but a heap). Whereas, here we can see that using a Cartesian tree took only 5 operations (see the above two figures in which we are continuously pushing and popping the nodes of Cartesian tree), which is linear as there are 5 numbers in the input array also. So we see that the best case of Cartesian Tree sort is O(n), a thing where heap-sort will take much more number of operations, because it doesn’t make advantage of the fact that the input data is partially sorted. 

Why pre-order traversal? 

The answer to this is that since Cartesian Tree is basically a heap- data structure and hence follows all the properties of a heap. Thus the root node is always smaller than both of its children. Hence, we use a pre-order fashion popping-and-pushing as in this, the root node is always pushed earlier than its children inside the priority queue and since the root node is always less than both its child, so we don’t have to do extra operations inside the priority queue. Refer to the below figure for better understanding- ctree3
Approach:

  • Construct a Cartesian tree for given sequence.
  • Create a priority queue, at first having only the root of Cartesian tree.
  • Pop the minimum value x from the priority queue
  • Add x to the output sequence
  • Push the left child of x from Cartesian tree into priority queue.
  • Push the right child of x from Cartesian tree into priority queue.
  • If priority queue is not empty, again goto step 3.

Below is the implementation for the above approach:

CPP




// A C++ program to implement Cartesian Tree sort
// Note that in this program we will build a min-heap
// Cartesian Tree and not max-heap.
 
#include<bits/stdc++.h>
using namespace std;
 
/* A binary tree node has data, pointer to left child
   and a pointer to right child */
struct Node
{
    int data;
    Node *left, *right;
};
 
// Creating a shortcut for int, Node* pair type
typedef pair<int, Node*> iNPair;
 
// This function sorts by pushing and popping the
// Cartesian Tree nodes in a pre-order like fashion
void pQBasedTraversal(Node* root)
{
    // We will use a priority queue to sort the
    // partially-sorted data efficiently.
    // Unlike Heap, Cartesian tree makes use of
    // the fact that the data is partially sorted
    priority_queue <iNPair, vector<iNPair>, greater<iNPair>> pQueue;
     pQueue.push (make_pair (root->data, root));
 
    // Resembles a pre-order traverse as first data
    // is printed then the left and then right child.
    while (! pQueue.empty())
    {
        iNPair popped_pair = pQueue.top();
         printf("%d ", popped_pair.first);
 
        pQueue.pop();
 
        if (popped_pair.second->left != NULL)
            pQueue.push (make_pair(popped_pair.second->left->data,
                                   popped_pair.second->left));
 
        if (popped_pair.second->right != NULL)
                pQueue.push (make_pair(popped_pair.second->right->data,
                                    popped_pair.second->right));
    }
 
    return;
}
 
 
Node *buildCartesianTreeUtil(int root, int arr[],
           int parent[], int leftchild[], int rightchild[])
{
    if (root == -1)
        return NULL;
 
    Node *temp = new Node;
 
    temp->data = arr[root];
    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 smaller 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 smallest 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));
}
 
// Sorts an input array
int printSortedArr(int arr[], int n)
{
    // Build a cartesian tree
    Node *root = buildCartesianTree(arr, n);
 
    printf("The sorted array is-\n");
 
    // Do pr-order traversal and insert
    // in priority queue
    pQBasedTraversal(root);
}
 
/* Driver program to test above functions */
int main()
{
    /*  Given input array- {5,10,40,30,28},
        it's corresponding unique Cartesian Tree
        is-
 
        5
          \
          10
            \
             28
            /
          30
         /
        40
    */
 
    int arr[] = {5, 10, 40, 30, 28};
    int n = sizeof(arr)/sizeof(arr[0]);
 
    printSortedArr(arr, n);
 
    return(0);
}


Java




// A Java program to implement Cartesian Tree sort
// Note that in this program we will build a min-heap
// Cartesian Tree and not max-heap.
import java.util.*;
 
public class Main {
    /* A binary tree node has data, pointer to left child
   and a pointer to right child */
    static class Node {
        int data;
        Node left, right;
 
        Node(int d)
        {
            data = d;
            left = null;
            right = null;
        }
    }
 
    static class iNPair implements Comparable<iNPair> {
        int first;
        Node second;
 
        iNPair(int f, Node s)
        {
            first = f;
            second = s;
        }
 
        @Override public int compareTo(iNPair other)
        {
            return Integer.compare(first, other.first);
        }
    }
 
    // This function sorts by pushing and popping the
    // Cartesian Tree nodes in a pre-order like fashion
    static void pQBasedTraversal(Node root)
    {
        // We will use a priority queue to sort the
        // partially-sorted data efficiently.
        // Unlike Heap, Cartesian tree makes use of
        // the fact that the data is partially sorted
        PriorityQueue<iNPair> pQueue
            = new PriorityQueue<>();
        pQueue.add(new iNPair(root.data, root));
 
        // Resembles a pre-order traverse as first data
        // is printed then the left and then right child.
        while (!pQueue.isEmpty()) {
            iNPair popped_pair = pQueue.poll();
            System.out.print(popped_pair.first + " ");
 
            if (popped_pair.second.left != null)
                pQueue.add(
                    new iNPair(popped_pair.second.left.data,
                               popped_pair.second.left));
 
            if (popped_pair.second.right != null)
                pQueue.add(new iNPair(
                    popped_pair.second.right.data,
                    popped_pair.second.right));
        }
    }
 
    static Node buildCartesianTreeUtil(int root, int arr[],
                                       int parent[],
                                       int leftchild[],
                                       int rightchild[])
    {
        if (root == -1)
            return null;
 
        Node temp = new Node(arr[root]);
        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
        Arrays.fill(parent, -1);
        Arrays.fill(leftchild, -1);
        Arrays.fill(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 smaller 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 smallest element yet; make it
            // new root
            if (arr[last] >= arr[i]) {
                parent[root] = i;
                leftchild[i] = root;
                root = i;
            }
            else if (rightchild[last] == -1) {
                rightchild[last] = i;
                parent[i] = last;
                leftchild[i] = -1;
            }
            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 printSortedArr(int arr[], int n)
    {
        Node root = buildCartesianTree(arr, n);
        System.out.println("The sorted array is-");
        pQBasedTraversal(root);
    }
 
    public static void main(String[] args)
    {
        /*  Given input array- {5,10,40,30,28},
            it's corresponding unique Cartesian Tree
            is-
 
            5
              \
              10
                \
                 28
                /
              30
             /
            40
        */
        int[] arr = { 5, 10, 40, 30, 28 };
        int n = arr.length;
        printSortedArr(arr, n);
    }
}


Python3




#  A C++ program to implement Cartesian Tree sort
#  Note that in this program we will build a min-heap
#  Cartesian Tree and not max-heap.
import queue
 
''' A binary tree node has data, pointer to left child
   and a pointer to right child '''
class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
 
# This function sorts by pushing and popping the
# Cartesian Tree nodes in a pre-order like fashion
def pQBasedTraversal(root):
    # We will use a priority queue to sort the
    # partially-sorted data efficiently.
    # Unlike Heap, Cartesian tree makes use of
    # the fact that the data is partially sorted
    pQueue = queue.PriorityQueue()
    pQueue.put((root.data, root))
     
    # Resembles a pre-order traverse as first data
    # is printed then the left and then right child.
    while not pQueue.empty():
        popped_pair = pQueue.get()
        print(popped_pair[0], end=' ')
 
        if popped_pair[1].left is not None:
            pQueue.put((popped_pair[1].left.data, popped_pair[1].left))
 
        if popped_pair[1].right is not None:
            pQueue.put((popped_pair[1].right.data, popped_pair[1].right))
 
def buildCartesianTreeUtil(root, arr, parent, leftchild, rightchild):
    if root == -1:
        return None
 
    temp = Node(arr[root])
    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
def buildCartesianTree(arr, n):
    # Arrays to hold the index of parent, left-child,
    # right-child of each number in the input array
    # Initialize all array values as -1
    parent = [-1] * n
    leftchild = [-1] * n
    rightchild = [-1] * n
 
     
    ''' '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 '''
    root, last = 0, 0
     
     
    # Starting from the second element of the input array
    # to the last on scan across the elements, adding them
    # one at a time.
    for i in range(1, n):
        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 smaller than the current one
        # This is the same as Step 2 mentioned in the
        # algorithm
        while arr[last] >= arr[i] and last != root:
            last = parent[last]
 
        # arr[i] is the smallest element yet; make it
        # new root
        if arr[last] >= arr[i]:
            parent[root] = i
            leftchild[i] = root
            root = i
         
         
        # Just insert it
        elif 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)
 
 
# Sorts an input array
def printSortedArr(arr, n):
    # Build a cartesian tree
    root = buildCartesianTree(arr, n)
    print("The sorted array is-")
     
    # Do pr-order traversal and insert
    # in priority queue
    pQBasedTraversal(root)
 
# Driver code
 
    '''  Given input array- {5,10,40,30,28},
        it's corresponding unique Cartesian Tree
        is-
 
        5
          \
          10
            \
             28
            /
          30
         /
        40
    '''
arr = [5, 10, 40, 30, 28]
n = len(arr)
 
printSortedArr(arr, n)
 
# This code is contributed by Prince Kumar


C#




using System;
using System.Collections.Generic;
 
/* A binary tree node has data, pointer to left child
   and a pointer to right child */
public class Node
{
    public int data;
    public Node left, right;
}
 
// Creating a shortcut for int, Node* pair type
public class iNPair : IComparable<iNPair>
{
    public int first;
    public Node second;
 
    public iNPair(int f, Node s)
    {
        first = f;
        second = s;
    }
 
    public int CompareTo(iNPair other)
    {
        return first.CompareTo(other.first);
    }
}
 
class CartesianTreeSort
{
    // This function sorts by pushing and popping the
    // Cartesian Tree nodes in a pre-order like fashion
    static void pQBasedTraversal(Node root)
    {
        // We will use a priority queue to sort the
        // partially-sorted data efficiently.
        // Unlike Heap, Cartesian tree makes use of
        // the fact that the data is partially sorted
        PriorityQueue<iNPair> pQueue = new PriorityQueue<iNPair>();
 
        pQueue.Enqueue(new iNPair(root.data, root));
 
        // Resembles a pre-order traverse as first data
        // is printed then the left and then right child.
        while (!pQueue.IsEmpty())
        {
            iNPair poppedPair = pQueue.Dequeue();
            Console.Write(poppedPair.first + " ");
 
            if (poppedPair.second.left != null)
                pQueue.Enqueue(new iNPair(poppedPair.second.left.data, poppedPair.second.left));
 
            if (poppedPair.second.right != null)
                pQueue.Enqueue(new iNPair(poppedPair.second.right.data, poppedPair.second.right));
        }
 
        Console.WriteLine();
    }
 
    static Node buildCartesianTreeUtil(int root, int[] arr,
                                       int[] parent, int[] leftChild, int[] rightChild)
    {
        if (root == -1)
            return null;
 
        Node temp = new Node();
 
        temp.data = arr[root];
        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
        Array.Fill(parent, -1);
        Array.Fill(leftChild, -1);
        Array.Fill(rightChild, -1);
 
        // 'root' and 'last' stores the index of the root and the
        // last processed of the Cartesian Tree.
        // Initially, we take the 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 smaller 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 smallest element yet; make it
            // the new root
            if (arr[last] >= arr[i])
            {
                parent[root] = i;
                leftChild[i] = root;
                root = i;
            }
 
            else if (rightChild[last] == -1)
            {
                rightChild[last] = i;
                parent[i] = last;
                leftChild[i] = -1;
            }
 
            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);
    }
 
    // Sorts an input array
    static void printSortedArr(int[] arr, int n)
    {
        // Build a Cartesian tree
        Node root = buildCartesianTree(arr, n);
 
        Console.WriteLine("The sorted array is-");
 
        // Do pre-order traversal and insert
        // in priority queue
        pQBasedTraversal(root);
    }
 
    /* Driver program to test above functions */
    static void Main()
    {
        /*  Given input array- {5,10,40,30,28},
            its corresponding unique Cartesian Tree
            is-
 
            5
              \
              10
                \
                 28
                /
              30
             /
            40
        */
 
        int[] arr = { 5, 10, 40, 30, 28 };
        int n = arr.Length;
 
        printSortedArr(arr, n);
    }
}
 
// Priority Queue implementation for C#
public class PriorityQueue<T> where T : IComparable<T>
{
    private List<T> data;
 
    public PriorityQueue()
    {
        this.data = new List<T>();
    }
 
    public bool IsEmpty()
    {
        return this.data.Count == 0;
    }
 
    public void Enqueue(T item)
    {
        this.data.Add(item);
        int ci = this.data.Count - 1; // child index; start at end
        while (ci > 0)
        {
            int pi = (ci - 1) / 2; // parent index
            if (this.data[ci].CompareTo(this.data[pi]) >= 0)
                break; // child item is larger than (or equal) parent so we're done
            T tmp = this.data[ci];
            this.data[ci] = this.data[pi];
            this.data[pi] = tmp;
            ci = pi;
        }
    }
 
    public T Dequeue()
    {
        // assumes pq is not empty; up to calling code
        int li = this.data.Count - 1; // last index (before removal)
        T frontItem = this.data[0];   // fetch the front
        this.data[0] = this.data[li];
        this.data.RemoveAt(li);
 
        --li; // last index (after removal)
        int pi = 0; // parent index. start at front of pq
        while (true)
        {
            int ci = pi * 2 + 1; // left child index of parent
            if (ci > li)
                break// no children so done
            int rc = ci + 1;     // right child
            if (rc <= li && this.data[rc].CompareTo(this.data[ci]) < 0)
                ci = rc; // if there is a rc (ci + 1), and it is smaller than left child,
                         // use the rc instead
            if (this.data[pi].CompareTo(this.data[ci]) <= 0)
                break; // parent is smaller than (or equal to) smallest child so done
            T tmp = this.data[pi];
            this.data[pi] = this.data[ci];
            this.data[ci] = tmp; // swap parent and child
            pi = ci;
        }
        return frontItem;
    }
}


Javascript




// A Javascript program to implement Cartesian Tree sort
// Note that in this program we will build a min-heap
// Cartesian Tree and not max-heap.
// Define the Node class
 
/* A binary tree node has data, pointer to left child
and a pointer to right child */
class Node {
constructor(d) {
this.data = d;
this.left = null;
this.right = null;
}
}
 
// Define the iNPair class
class iNPair {
constructor(f, s) {
this.first = f;
this.second = s;
}
 
// Implement the compareTo method to allow the iNPair objects to be sorted in a priority queue
compareTo(other) {
return this.first - other.first;
}
}
 
// Define the pQBasedTraversal function
// This function sorts by pushing and popping the
// Cartesian Tree nodes in a pre-order like fashion
function pQBasedTraversal(root) {
     
     
// We will use a priority queue to sort the
// partially-sorted data efficiently.
// Unlike Heap, Cartesian tree makes use of
// the fact that the data is partially sorted
let pQueue = [];
 
pQueue.push(new iNPair(root.data, root));
 
// Resembles a pre-order traverse as first data
// is printed then the left and then right child.
while (pQueue.length > 0) {
let poppedPair = pQueue.shift();
console.log(poppedPair.first + " ");
 
if (poppedPair.second.left !== null) {
  pQueue.push(
    new iNPair(poppedPair.second.left.data, poppedPair.second.left)
  );
}
 
if (poppedPair.second.right !== null) {
  pQueue.push(
    new iNPair(poppedPair.second.right.data, poppedPair.second.right)
  );
}
}
}
 
// Define the buildCartesianTreeUtil function
function buildCartesianTreeUtil(root, arr, parent, leftchild, rightchild) {
if (root == -1) {
return null;
}
 
let temp = new Node(arr[root]);
temp.left = buildCartesianTreeUtil(
leftchild[root],
arr,
parent,
leftchild,
rightchild
);
temp.right = buildCartesianTreeUtil(
rightchild[root],
arr,
parent,
leftchild,
rightchild
);
return temp;
}
 
// Define the buildCartesianTree function
// 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
// Initialize all array values as -1
let parent = new Array(n).fill(-1);
let leftchild = new Array(n).fill(-1);
let rightchild = new Array(n).fill(-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 smaller 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 smallest element yet; make it
// new root
if (arr[last] >= arr[i]) {
  parent[root] = i;
  leftchild[i] = root;
  root = i;
} else if (rightchild[last] == -1) {
  rightchild[last] = i;
  parent[i] = last;
  leftchild[i] = -1;
} 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);
}
 
// Define the printSortedArr function
function printSortedArr(arr, n) {
let root = buildCartesianTree(arr, n);
console.log("The sorted array is-");
pQBasedTraversal(root);
}
 
// Main function
function main() {
     
     
        /* Given input array- {5,10,40,30,28},
            it's corresponding unique Cartesian Tree
            is-
 
            5
            \
            10
                \
                28
                /
            30
            /
            40
        */
let arr = [5, 10, 40, 30, 28];
let n = arr.length;
printSortedArr(arr, n);
}
 
// Call the main function
main();
 
//This code is contributed by shivhack999


Output

The sorted array is-
5 10 28 30 40 

Time Complexity: 

  • O(n) best-case behaviour (when the input data is partially sorted), 
  • O(n log n) worst-case behavior (when the input data is not partially sorted) 

Auxiliary Space: We use a priority queue and a Cartesian tree data structure. Now, at any moment of time the size of the priority queue doesn’t exceeds the size of the input array, as we are constantly pushing and popping the nodes. 
Hence we are using O(n) auxiliary space. 

 

If you like GeeksforGeeks and would like to contribute, you can also write an article and mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above



Last Updated : 09 Jan, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads