Open In App

Sort elements by frequency using Binary Search Tree

Last Updated : 11 Sep, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of integers, sort the array according to frequency of elements. For example, if the input array is {2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12}, then modify the array to {3, 3, 3, 3, 2, 2, 2, 12, 12, 4, 5}. 

In the previous post, we have discussed all methods for sorting according to frequency. In this post, method 2 is discussed in detail and C++ implementation for the same is provided.
Following is detailed algorithm. 

  • Create a BST and while creating BST maintain the count i,e frequency of each coming element in same BST. This step may take O(nLogn) time if a self balancing BST is used.
  • Do Inorder traversal of BST and store every element and count of each element in an auxiliary array. Let us call the auxiliary array as ‘count[]’. Note that every element of this array is element and frequency pair. This step takes O(n) time.
  • Sort ‘count[]’ according to frequency of the elements. This step takes O(nLohn) time if a O(nLogn) sorting algorithm is used.
  • Traverse through the sorted array ‘count[]’. For each element x, print it ‘freq’ times where ‘freq’ is frequency of x. This step takes O(n) time.

The overall time complexity of the algorithm can be minimum O(nLogn) if we use a O(nLogn) sorting algorithm and use a self-balancing BST with O(Logn) insert operation.
Following is the implementation of the above algorithm. 

C++




// Implementation of above algorithm in C++.
#include <iostream>
#include <stdlib.h>
using namespace std;
  
/* A BST node has data, freq, left and right pointers */
struct BSTNode
{
    struct BSTNode *left;
    int data;
    int freq;
    struct BSTNode *right;
};
  
// A structure to store data and its frequency
struct dataFreq
{
    int data;
    int freq;
};
  
/* Function for qsort() implementation. Compare frequencies to
sort the array according to decreasing order of frequency */
int compare(const void *a, const void *b)
{
    return ( (*(const dataFreq*)b).freq - (*(const dataFreq*)a).freq );
}
  
/* Helper function that allocates a new node with the given data,
frequency as 1 and NULL left and right pointers.*/
BSTNode* newNode(int data)
{
    struct BSTNode* node = new BSTNode;
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    node->freq = 1;
    return (node);
}
  
// A utility function to insert a given key to BST. If element
// is already present, then increases frequency
BSTNode *insert(BSTNode *root, int data)
{
    if (root == NULL)
        return newNode(data);
    if (data == root->data) // If already present
        root->freq += 1;
    else if (data < root->data)
        root->left = insert(root->left, data);
    else
        root->right = insert(root->right, data);
    return root;
}
  
// Function to copy elements and their frequencies to count[].
void store(BSTNode *root, dataFreq count[], int *index)
{
    // Base Case
    if (root == NULL) return;
  
    // Recur for left subtree
    store(root->left, count, index);
  
    // Store item from root and increment index
    count[(*index)].freq = root->freq;
    count[(*index)].data = root->data;
    (*index)++;
  
    // Recur for right subtree
    store(root->right, count, index);
}
  
// The main function that takes an input array as an argument
// and sorts the array items according to frequency
void sortByFrequency(int arr[], int n)
{
    // Create an empty BST and insert all array items in BST
    struct BSTNode *root = NULL;
    for (int i = 0; i < n; ++i)
        root = insert(root, arr[i]);
  
    // Create an auxiliary array 'count[]' to store data and
    // frequency pairs. The maximum size of this array would
    // be n when all elements are different
    dataFreq count[n];
    int index = 0;
    store(root, count, &index);
  
    // Sort the count[] array according to frequency (or count)
    qsort(count, index, sizeof(count[0]), compare);
  
    // Finally, traverse the sorted count[] array and copy the
    // i'th item 'freq' times to original array 'arr[]'
    int j = 0;
    for (int i = 0; i < index; i++)
    {
        for (int freq = count[i].freq; freq > 0; freq--)
            arr[j++] = count[i].data;
    }
}
  
// A utility function to print an array of size n
void printArray(int arr[], int n)
{
    for (int i = 0; i < n; i++)
        cout << arr[i] << " ";
    cout << endl;
}
  
/* Driver program to test above functions */
int main()
{
    int arr[] = {2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12};
    int n = sizeof(arr)/sizeof(arr[0]);
    sortByFrequency(arr, n);
    printArray(arr, n);
    return 0;
}


Java




import java.util.Arrays;
  
/* A BST node has data, freq, left and right pointers */
class BSTNode {
    BSTNode left, right;
    int data, freq;
    BSTNode(int data)
    {
        this.data = data;
        freq = 1;
        left = right = null;
    }
}
// A structure to store data and its frequency
class DataFreq implements Comparable<DataFreq> {
    int data, freq;
    DataFreq(int data, int freq)
    {
        this.data = data;
        this.freq = freq;
    }
  /* Function for qsort() implementation. Compare frequencies to
sort the array according to decreasing order of frequency */
    public int compareTo(DataFreq d)
    {
        return d.freq - freq;
    }
}
  
class Solution {
  // A utility function to insert a given key to BST. If element
// is already present, then increases frequency
    BSTNode insert(BSTNode root, int data)
    {
        if (root == null)
            return new BSTNode(data);
        if (data == root.data)// If already present
            root.freq++;
        else if (data < root.data)
            root.left = insert(root.left, data);
        else
            root.right = insert(root.right, data);
        return root;
    }
    
  // Function to copy elements and their frequencies to count[].
    void store(BSTNode root, DataFreq[] count, int[] index)
    {
        // Base Case
        if (root == null)
            return;
      // Recur for left subtree
        store(root.left, count, index);
      // Store item from root and increment index
        count[index[0]]
            = new DataFreq(root.data, root.freq);
        index[0]++;
       // Recur for right subtree
        store(root.right, count, index);
    }
    
  // The main function that takes an input array as an argument
// and sorts the array items according to frequency
    void sortByFrequency(int[] arr)
    {
      // Create an empty BST and insert all array items in BST
        BSTNode root = null;
        for (int i : arr)
            root = insert(root, i);
       // Create an auxiliary array 'count[]' to store data and
    // frequency pairs. The maximum size of this array would
    // be n when all elements are different
        DataFreq[] count = new DataFreq[arr.length];
        int[] index = new int[] { 0 };
        store(root, count, index);
      // Sort the count[] array according to frequency (or count)
        Arrays.sort(count, 0, index[0]);
        
        // Finally, traverse the sorted count[] array and copy the
    // i'th item 'freq' times to original array 'arr[]'
        int j = 0;
        for (DataFreq d : count) {
            if (d == null)
                break;
            for (int freq = d.freq; freq > 0; freq--)
                arr[j++] = d.data;
        }
    }
    public static void main(String[] args)
    {
        int[] arr = { 2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12 };
        Solution sol = new Solution();
        sol.sortByFrequency(arr);
        for (int i : arr)
            System.out.print(i + " ");
        System.out.println();
    }
}
  
// this code is contributed by snehalsalokhe


Python3




# Implementation of above algorithm in Python.
  
# A BST node has data, freq, left and right pointers.
class BSTNode:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
        self.freq = 1
  
# A structure to store data and its frequency.
class dataFreq:
    def __init__(self, data, freq):
        self.data = data
        self.freq = freq
  
# Helper function that allocates a new node with the given data,
# frequency as 1 and NULL left and right pointers.
def newNode(data):
    node = BSTNode(data)
    return node
  
# A utility function to insert a given key to BST. If element
# is already present, then increases frequency.
def insert(root, data):
    if root is None:
        return newNode(data)
    if data == root.data:  # If already present.
        root.freq += 1
    elif data < root.data:
        root.left = insert(root.left, data)
    else:
        root.right = insert(root.right, data)
    return root
  
# Function to copy elements and their frequencies to count[].
def store(root, count, index):
    # Base Case.
    if root is None:
        return
  
    # Recur for left subtree.
    store(root.left, count, index)
  
    # Store item from root and increment index.
    count[index[0]].freq = root.freq
    count[index[0]].data = root.data
    index[0] += 1
  
    # Recur for right subtree.
    store(root.right, count, index)
  
# The main function that takes an input array as an argument
# and sorts the array items according to frequency.
def sortByFrequency(arr, n):
    # Create an empty BST and insert all array items in BST.
    root = None
    for i in range(n):
        root = insert(root, arr[i])
  
    # Create an auxiliary array 'count[]' to store data and
    # frequency pairs. The maximum size of this array would
    # be n when all elements are different.
    count = [None]*n
    for i in range(n):
        count[i] = dataFreq(0,0)
    index = [0]
    store(root, count, index)
  
    # Sort the count[] array according to frequency (or count).
    count.sort(key=lambda x: x.freq, reverse=True)
  
    # Finally, traverse the sorted count[] array and copy the
    # i'th item 'freq' times to original array 'arr[]'.
    j = 0
    for i in range(index[0]):
        for freq in range(count[i].freq, 0, -1):
            arr[j] = count[i].data
            j += 1
  
# A utility function to print an array of size n.
def printArray(arr, n):
    for i in range(n):
        print(arr[i], end=" ")
    print()
  
# Driver program to test above functions.
if __name__ == "__main__":
    arr = [2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12]
    n = len(arr)
    sortByFrequency(arr, n)
    printArray(arr, n)


C#




// C# program for the above approach
  
using System;
using System.Collections.Generic;
  
/* A BST node has data, freq, left and right pointers */
class BSTNode
{
    public BSTNode left, right;
    public int data, freq;
    public BSTNode(int data)
    {
        this.data = data;
        freq = 1;
        left = right = null;
    }
}
  
// A structure to store data and its frequency
class DataFreq : IComparable<DataFreq>
{
    public int data, freq;
    public DataFreq(int data, int freq)
    {
        this.data = data;
        this.freq = freq;
    }
  
    /* Function for qsort() implementation. Compare frequencies to
    sort the array according to decreasing order of frequency */
    public int CompareTo(DataFreq d)
    {
        return d.freq - freq;
    }
}
  
class Solution
{
    // A utility function to insert a given key to BST. If element
    // is already present, then increases frequency
    BSTNode insert(BSTNode root, int data)
    {
        if (root == null)
            return new BSTNode(data);
        if (data == root.data)// If already present
            root.freq++;
        else if (data < root.data)
            root.left = insert(root.left, data);
        else
            root.right = insert(root.right, data);
        return root;
    }
  
    // Function to copy elements and their frequencies to count[].
    void store(BSTNode root, DataFreq[] count, int[] index)
    {
        // Base Case
        if (root == null)
            return;
        // Recur for left subtree
        store(root.left, count, index);
        // Store item from root and increment index
        count[index[0]]
            = new DataFreq(root.data, root.freq);
        index[0]++;
        // Recur for right subtree
        store(root.right, count, index);
    }
  
    // The main function that takes an input array as an argument
    // and sorts the array items according to frequency
    void sortByFrequency(int[] arr)
    {
        // Create an empty BST and insert all array items in BST
        BSTNode root = null;
        foreach (int i in arr)
            root = insert(root, i);
        // Create an auxiliary array 'count[]' to store data and
        // frequency pairs. The maximum size of this array would
        // be n when all elements are different
        DataFreq[] count = new DataFreq[arr.Length];
        int[] index = new int[] { 0 };
        store(root, count, index);
        // Sort the count[] array according to frequency (or count)
        Array.Sort(count, 0, index[0]);
  
        // Finally, traverse the sorted count[] array and copy the
        // i'th item 'freq' times to original array 'arr[]'
        int j = 0;
        foreach (DataFreq d in count)
        {
            if (d == null)
                break;
            for (int freq = d.freq; freq > 0; freq--)
                arr[j++] = d.data;
        }
    }
  
    public static void Main(string[] args)
    {
        int[] arr = { 2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12 };
        Solution sol = new Solution();
        sol.sortByFrequency(arr);
        foreach (int i in arr)
            Console.Write(i + " ");
        Console.WriteLine();
    }
}
  
  
// This codeis contributed by adityashatmfh


Javascript




// A BST node has data, freq, left and right pointers.
class BSTNode {
    constructor(data) {
        this.data = data;
        this.left = null;
        this.right = null;
        this.freq = 1;
    }
}
  
// A structure to store data and its frequency.
class dataFreq {
    constructor(data, freq) {
        this.data = data;
        this.freq = freq;
    }
}
  
// Helper function that allocates a new node with the given data,
// frequency as 1 and NULL left and right pointers.
function newNode(data) {
    const node = new BSTNode(data);
    return node;
}
  
// A utility function to insert a given key to BST. If element
// is already present, then increases frequency.
function insert(root, data) {
    if (root === null) {
        return newNode(data);
    }
    if (data === root.data) {
        root.freq += 1;
    } else if (data < root.data) {
        root.left = insert(root.left, data);
    } else {
        root.right = insert(root.right, data);
    }
    return root;
}
  
// Function to copy elements and their frequencies to count[].
function store(root, count, index) {
// Base Case.
    if (root === null) {
        return;
    }
      
    // Recur for left subtree.
    store(root.left, count, index);
      
    // Store item from root and increment index.
    count[index[0]].freq = root.freq;
    count[index[0]].data = root.data;
    index[0] += 1;
      
    // Recur for right subtree.
    store(root.right, count, index);
}
  
// The main function that takes an input array as an argument
// and sorts the array items according to frequency.
function sortByFrequency(arr, n) {
// Create an empty BST and insert all array items in BST.
    let root = null;
    for (let i = 0; i < n; i++) {
        root = insert(root, arr[i]);
    }
      
    // Create an auxiliary array 'count[]' to store data and
    // frequency pairs. The maximum size of this array would
    // be n when all elements are different.
    const count = new Array(n);
    for (let i = 0; i < n; i++) {
        count[i] = new dataFreq(0, 0);
    }
    const index = [0];
    store(root, count, index);
      
    // Sort the count[] array according to frequency (or count).
    count.sort((a, b) => b.freq - a.freq);
      
    // Finally, traverse the sorted count[] array and copy the
    // i'th item 'freq' times to original array 'arr[]'.
    let j = 0;
    for (let i = 0; i < index[0]; i++) {
        for (let freq = count[i].freq; freq > 0; freq--) {
            arr[j] = count[i].data;
            j += 1;
        }
    }   
}
  
// A utility function to print an array of size n.
function printArray(arr) {
    console.log(arr.join(" "));
}
  
// Driver program to test above functions.
const arr = [2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12];
const n = arr.length;
sortByFrequency(arr, n);
printArray(arr, n);
  
// This code is contributed by Prince


Output

3 3 3 3 2 2 2 12 12 4 5 

Time Complexity: O(n log n) as quick sort is being performed.

Auxiliary Space: (n) for BST implementation.

Exercise:  The above implementation doesn’t guarantee original order of elements with same frequency (for example, 4 comes before 5 in input, but 4 comes after 5 in output). Extend the implementation to maintain original order. For example, if two elements have same frequency then print the one which came 1st in input array.
This article is compiled by Chandra Prakash.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads