Sort elements by frequency | Set 1

Asked By Binod

Question:
Print the elements of an array in the decreasing frequency if 2 numbers have same frequency then print the one which came 1st
E.g. 2 5 2 8 5 6 8 8 output: 8 8 8 2 2 5 5 6.



METHOD 1 (Use Sorting)

  1) Use a sorting algorithm to sort the elements O(nlogn)    
  2) Scan the sorted array and construct a 2D array of element and count O(n).
  3) Sort the 2D array according to count O(nlogn).

Example:

  Input 2 5 2 8 5 6 8 8

  After sorting we get
  2 2 5 5 6 8 8 8

  Now construct the 2D array as
  2, 2
  5, 2
  6, 1
  8, 3

  Sort by count
  8, 3
  2, 2
  5, 2
  6, 1

There is one issue with above approach (thanks to ankit for pointing this out). If we modify the input to 5 2 2 8 5 6 8 8, then we should get 8 8 8 5 5 2 2 6 and not 8 8 8 2 2 5 5 6 as will be the case.
To handle this, we should use indexes in step 3, if two counts are same then we should first process(or print) the element with lower index. In step 1, we should store the indexes instead of elements.

  Input 5  2  2  8  5  6  8  8

  After sorting we get
  Element 2 2 5 5 6 8 8 8
  Index   1 2 0 4 5 3 6 7

  Now construct the 2D array as
  Index, Count
  1,      2
  0,      2
  5,      1
  3,      3

  Sort by count (consider indexes in case of tie)
  3, 3
  0, 2
  1, 2
  5, 1
  
  Print the elements using indexes in the above 2D array.



METHOD 2(Use BST and Sorting)
1. Insert elements in BST one by one and if an element is already present then increment the count of the node. Node of the Binary Search Tree (used in this approach) will be as follows.

struct tree
{
  int element;
  int first_index /*To handle ties in counts*/
  int count;
}BST;

2.Store the first indexes and corresponding counts of BST in a 2D array.
3 Sort the 2D array according to counts (and use indexes in case of tie).

Time Complexity: O(nlogn) if a Self Balancing Binary Search Tree is used.



METHOD 3(Use Hashing and Sorting)
Using a hashing mechanism, we can store the elements (also first index) and their counts in a hash. Finally, sort the hash elements according to their counts.



These are just our thoughts about solving the problem and may not be the optimal way of solving. We are open for better solutions.



Related Links
http://www.trunix.org/programlama/c/kandr2/krx604.html
http://drhanson.s3.amazonaws.com/storage/documents/common.pdf
http://www.cc.gatech.edu/classes/semantics/misc/pp2.pdf





  • zzer

    #include

    #include

    #include

    #include

    #include

    #include

    using namespace std;

    class Elem

    {

    public:

    Elem(){}

    Elem(int v,int c,int i):value(v),count(c),index(i){}

    int value;

    int count;

    int index;// lowest index

    bool operator other.count) || (count==other.count && index < other.index);

    }

    };

    void sort_by_frequency(int arr[],int n)

    {

    if(n <= 0)

    return;

    map maps;

    for(int i = 0; i 0 )

    {

    maps[arr[i]].count++;

    }

    else

    maps.insert(make_pair(arr[i],Elem(arr[i],1,i)));

    }

    vector vec;

    for(map::iterator it = maps.begin(); it != maps.end(); it++)

    vec.push_back(it->second);

    sort(vec.begin(),vec.end());

    for(vector::iterator it = vec.begin(); it != vec.end(); it++)

    {

    while(it->count– > 0)

    cout <value << " ";

    }

    cout << endl;

    }

    int main()

    {

    int arr[] = {2,5,2,8,5,6,8,8};

    for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)

    cout << arr[i] << " ";

    cout << endl << "——————————" << endl;

    sort_by_frequency(arr,sizeof(arr)/sizeof(arr[0]));

    return 0;

    }

  • Mari

    In third Solution, Step 2, Since the frequency of any number lies between 1 to n, we can use Counting Sort. Thus over all running time of this solution will be O(n)(Hash table operations + counting sort).

  • Meenal

    I tried to modify merge sort for storing original indexes after modification it is not sorting properly.. I am not able to find where I have gone wrong Please help me find the issue..

    Please find my code below.

    http://ideone.com/ORQLql

    • Coder011

      You havent mentioned what does the ordered pair {x,y} , in your array ‘a’ signify? I assumed the value y as array value and, x as index. But even going by that logic where have you stored the frequency?
      Link to Ideone: http://ideone.com/Y6GeeA

      • Meenal

        Hi, your assumption of {x,y} is correct.
        This part of code is written just for sorting the array and storing previous indexes corresponding to elements in a[i][1] only. As it is not sorting correctly itself. I could not proceed.

        I am not able to get why making it a 2D array affected it, as with 1D array having only values this merge sort program works perfectly fine.

        • Coder011

          In the stdout of the program (taken from Ideone):
          553456789102
          Array after sorting:

          Index after sorting:
          9 1 2 3 4 5 6 7 8 0
          Array after sorting:
          2 3 4 5 6 7 8 9 10 55

          I suppose, the array has been sorted. Have you tried it on any other test cases as well? Otherwise the code looks fine to me.

          • Meenal

            Thanks for checking it..
            I was facing problem with same test case, there was one issue in my code in if loop instead of (L[i][1]
            < R[j][1]) i used (L[i] < R[j]) by mistake… Gues you have fixed it in your code…
            Thanks

  • Guest
  • jedi

    #include

    //given an array, first sort in nlogn time using merge sort

    mergesort(int A[][2],int left,int right)

    {

    if(left>=right)

    return A[left][1];

    int mid=(left+right)/2;

    mergesort(A,left,mid);

    mergesort(A,mid+1,right);

    merge(A,left,mid,right);

    }

    merge(int A[][2],int left,int mid,int right)

    {

    int n=mid-left+1;

    int m=right-mid;

    int i;

    int B[n][2],C[m][2];

    for(i=0;i<n;i++)

    {

    B[i][1]=A[left+i][1];

    B[i][0]=A[left+i][0];

    }

    for(i=0;i<m;i++)

    {

    C[i][1]=A[mid+1+i][1];

    C[i][0]=A[mid+1+i][0];

    }

    i=left;

    int j,k;

    j=0;

    k=0;

    while((j<mid-left+1)&&(k<right-mid))

    {

    if(B[j][1]<C[k][1])

    {

    A[i][1]=B[j][1];

    A[i][0]=B[j][0];

    j++;

    i++;

    }

    else if(B[j][1]==C[k][1])

    {

    if(B[j][0]=mid-left+1)

    {

    while(k<right-mid)

    {A[i][1]=C[k][1];

    A[i][0]=C[k][0];

    k++;

    i++;}

    }

    else

    {

    while(j<mid-left+1)

    {A[i][1]=B[j][1];

    A[i][0]=B[j][0];

    j++;

    i++;}

    }

    }

    //calc frequency of each using variables count,store as follows….copy the initial index values of A in 1st column of B i.e. B[i][0]

    //remember to import a copy of the original unsorted array to pass to print function

    checkingFreq(int A[][2],int C[][2],int n)

    {

    //printing the sorted array

    printA(A,n);

    printf("n");

    int i,j,count,store;

    j=0;

    count=1;

    int B[10][2];

    store=0;

    for(i=1;i<=n;i++)

    {

    //checking the repetitions

    if(A[i][1]==A[i-1][1])

    count++;

    //increment in case of repetition

    else

    {

    //store the first occuring index of a set of repeating numbers into B to break ties in sorting

    B[j][0]=A[store][0];

    //counting the number of repetitions of a particular number

    B[j][1]=count;

    //reset count

    count=1;

    //move to index of next number

    store=i;

    j++;

    }

    }

    //for your reference

    printA(B,j);

    printf("n");

    //sorting by frequency, size of array=j

    mergesort(B,0,j-1);

    //F Y R

    printA(B,j);

    printf("n");

    //final answer

    print(C,B,j);

    }

    print(int A[][2],int B[][2],int n)

    {

    int i;

    for(i=0;i<n;i++)

    {

    printf("%d %dn",A[(B[i][0])][1],B[i][1]);

    }

    }

    printA(int A[][2],int n)

    {

    int i;

    for(i=0;i<n;i++)

    {

    printf("%d %dn",A[i][0],A[i][1]);

    }

    }

    main()

    {

    int n=6,i,j;

    int A[n][2],B[n][2];

    for(i=0;i<n;i++)

    {A[i][0]=i;}

    A[0][1]=3;

    A[1][1]=3;

    A[2][1]=5;

    A[3][1]=2;

    A[4][1]=3;

    A[5][1]=1;

    //copying A into B

    for(j=0;j<n;j++)

    {

    B[j][0]=A[j][0];

    B[j][1]=A[j][1];

    }

    printf("n");

    mergesort(A,0,5);

    checkingFreq(A,B,6);

    }

    • jedi

      sorry about that..

  • Suryabhan Singh

    How i m going to use hashing if range is unknown ????

    • alien

      You need not use the same element to store in hashing array. You can use some hash function on each element and put them into a specific range and then put into hash table

    • alien

      it would be in o(n) time but the question is you need to change the key for hash table

  • hbandi

    see this

     
    
    import java.util.*;
    
    
    public class NumberCount {
    
    	public static void main(String[] args) {
    		NumberCount nc = new NumberCount();
    		int[] array = { 2, 5, 2, 8, 5, 6, 8, 8 };
    		System.out.println("Map is :: " + nc.getMapForCounts(array));
    	}
    
    	private Map sortedMap(Map map) {
    		List<Integer> list = new ArrayList(map.entrySet());
    		Collections.sort(list, new Comparator() {
    			public int compare(Object one, Object two) {
    				return ((Comparable) ((Map.Entry) (two)).getValue())
    						.compareTo(((Map.Entry) (one)).getValue());
    			}
    		});
    		Map<Integer, Integer> sortedMap = new LinkedHashMap<Integer, Integer>();
    		for (Iterator it = list.iterator(); it.hasNext();) {
    			Map.Entry entry = (Map.Entry) it.next();
    
    			sortedMap.put((Integer) entry.getKey(), (Integer) entry.getValue());
    		}
    		return sortedMap;
    	}
    
    	public Map<Integer, Integer> getMapForCounts(int[] array) {
    
    		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
    
    		for (int i = 0; i < array.length; i++) {
    			if (map.containsKey(array[i])) {
    				map.put(array[i], map.get(array[i]).intValue() + 1);
    			} else {
    				map.put(array[i], 1);
    			}
    		}
    		return sortedMap(map);
    	}
    
    }
    
     
  • akshat gupta

    GeeksforGeeks?-in Method 2:
    BST can have height Ranging from lg10 – 10,
    so T(n)=O(10.n) or O(n),
    not O(n lgn)

    • Guest

      @GeeksforGeeks, We can using the idea similar to counting sort and solve this problem in O(n) time and O(n) space. Although we have random input, but the frequency of any element inside the input data set will be between 1 to n, and we can exploit this property.

  • Ankit Malhotra

    O(n^2) code follows. First build a linked list with frequency and lowest index. Then use the linked list to build a BST. The case of equal frequencies is handled easily here as the liked list anyway returns lower indices first.

     
    #include <iostream>
    #define MAXCOUNT 1000
    using namespace::std;
    typedef int element;
    typedef int counter;
    
    struct datanode
    {
      element data;
      counter frequency;
      counter index;
      datanode * next;
      datanode (element data, counter index)
      {
        this->data = data;
        this->frequency = 1;
        this->index = index;
        this->next = NULL;
      }
    };
    
    typedef datanode * lptr;
    
    lptr frequency (element * term, counter count)
    {
      if (!count) return NULL;
      lptr start = new datanode(term[0], 0), p;
      for (counter i = 1; i < count; i++)
      {
        for(p = start; p && p->next && p->data != term[i]; p = p->next);
        if (p && p->data == term[i]) p->frequency++;
        else p->next = new datanode(term[i], i);
      }
      return start;
    }
    
    void destroy (lptr p)
    {
      lptr k;
      while(p)
      {
        k = p;
        p = p->next;
        delete k;
      }
    }
    
    struct frequencynode
    {
      counter frequency;
      counter index;
      frequencynode * left;
      frequencynode * right;
      frequencynode (counter frequency, counter index)
      {
        this->frequency = frequency;
        this->index = index;
        this->left = this-> right = NULL;
      }
    };
    
    typedef frequencynode * ptr;
    
    ptr sortfrequencyindex (lptr datalist)
    {
      if (!datalist) return NULL;
      ptr start = new frequencynode (datalist->frequency, datalist->index), p, k, last;
      for (datalist = datalist->next; datalist; datalist = datalist->next)
      {
        for(p = start, last = NULL; p != last;)
        {
          last = p;
          if (datalist->frequency <= p->frequency) p = p->left ? p->left : p;
          else p = p->right ? p->right : p;
        }
        k = new frequencynode (datalist->frequency, datalist->index);
        if (datalist->frequency <= p->frequency) p->left = k;
        else p-> right = k;
      }
      return start;
    }
    
    // Count must be passed set to 0
    void frequencyorder (ptr p, element * term, element * reordered, counter &count)
    {
      if (!p) return;
      frequencyorder (p -> right, term, reordered, count);
      for(int i = 0; i < p->frequency; reordered[count + i++] = term[p->index]);
      count += p->frequency;
      frequencyorder (p -> left, term, reordered, count);
    }
    
    int main()
    {
      element term[] = {-10, 0, -30, 0, -30, 0, -36, -10, -25}, reordered[MAXCOUNT];
      counter count = sizeof(term)/sizeof(element), index[MAXCOUNT] = {-1};
      cout << "Original Array ..." << endl;
      for (counter i = 0; i < count; i++) cout << term[i] << ' ';
      cout << endl;
      lptr list = frequency (term, count);
      ptr k = sortfrequencyindex (list);
      destroy (list);
      frequencyorder (k, term, reordered, count = 0); // Pass count reference set to 0
      cout << "Frequency Sorted on Index ..." << endl;
      for (counter i = 0; i < count; i++) cout << reordered[i] << ' ';
      cout << endl;
      return 0;
    }
     
    • Ankit Malhotra

      Added code to destory binary tree.

       
      void destroy (ptr p)
      {
        if (!p) return;
        ptr k = p;
        destroy (p->left);
        destroy (p->right);
        delete k;
      }
      
      int main()
      {
        element term[] = {-10, 0, -30, 0, -30, 0, -36, -10, -25}, reordered[MAXCOUNT];
        counter count = sizeof(term)/sizeof(element), index[MAXCOUNT] = {-1};
        cout << "Original Array ..." << endl;
        for (counter i = 0; i < count; i++) cout << term[i] << ' ';
        cout << endl;
        lptr list = frequency (term, count);
        ptr k = sortfrequencyindex (list);
        destroy (list);
        frequencyorder (k, term, reordered, count = 0); // Pass count reference set to 0
        destroy (k);
        cout << "Frequency Sorted on Index ..." << endl;
        for (counter i = 0; i < count; i++) cout << reordered[i] << ' ';
        cout << endl;
        return 0;
      }
       
  • ankit

    In my opinion maxHeap will be the best ds, heapify based on the count, and store count, number and index in the node. If there is a tie in the frequency, we have to just check the children of the root.

    • alien

      it would be iin o(nlogn). If linear time algorithm is there, we should use that only

    • alien

      it would be iin o(nlogn). If linear time algorithm is there, we should use that only

  • algobard

    Can you guys post the codes for this question? Please!

  • saurabh
     
    It can be done by performing Counting Sort twice. 
    For the first time the frequency of each number is counted in another array.
    For the second time, we perform counting on the frequencies with same value.
    Space complexity = O(4n). Time Complexity = O(5n). So basically both space and time complexities are of the order n.
    
    
    #include <stdio.h>
    # define ARY_SIZE 50
    //a[] is input array, d[] is output array
    int sortByFreq(int a[], int d[], int len) {  
        int b[len], c[len], i, newLen = 0;
        for(i = 0; i < len; i++) {
            b[i] = 0;
            c[i] = 0;
        }
    // Frequency of each element is stored in b[]
        for(i = 0; i < len; i++) 
            b[a[i]]++;                       
    // Counting for freq with same value in c[]
        for(i = 0; i < len; i++) 
            c[b[i]]++;                       
    // indexing for the output in array d[]
        for(i = len - 2; i > 0; i--)
            c[i] += c[i+1];                  
    // d[] is finally created now
        for(i = len - 1; i >= 0; i--) {    
            if(b[a[i]]) {
                d]] - 1] = a[i];
                c[b[a[i]]]--;
                b[a[i]] = 0;
                newLen++;
            }
        }
        return newLen;
    }
    
    
    int main() {
        int len = 0, n;
        int a[ARY_SIZE];
        printf("Enter the numbers of the array:\n");
        while(scanf("%d", &n) == 1)
            a[len++] = n;
        int d[len];
        len = sortByFreq(a, d, len);
        printf("The sorted array in decreasing frequency is:\n");
        for(n = 0; n < len; n++)
            printf("%d  ", d[n]);
        printf("\n");
    }
     
    • Ankit Malhotra

      This code gives segmentation fault on the simplest of inputs. Also has a huge design constraint in total inability to use negative numbers at all as terms are used as direct array indices.

  • http://www.crazylearner.com student

    can’t we use array of structures instead of using bst ?

  • rajcools
     
    //Code for method 1
    //anybody who wants to test using different values please change //values in main
    //MergeSort(initial2D,0,7); here 7 is sizeof array -1
    //CreateArray(initial2D,8); 8 is sizeof array
    //MergeSort1(initial2D,0,3); 3 is number of different values in //array -1
    
    
    void swap(int &a,int &b)
    {
    	int temp;
    	temp = b;
    	b=a;
    	a=temp;
    }
    void Merge(int arr[][3], int p, int q, int r)
    {
    	int n1 = q-p+1;
    	int n2 = r-q;
    	int l[n1][2];
    	int m[n2][2];
    	for(int i=0;i<n1;i++)
    	{
    		l[i][0]=arr[p+i][0];        
    		l[i][1]=arr[p+i][1];
    	}
    	for(int j=0;j<n2;j++)
    	{
    		m[j][0]=arr[q+j+1][0];            
    		m[j][1]=arr[q+j+1][1];
    	}
    	l[n1][0]=10000;
    	m[n2][0]=10000;
    	int i=0;
    	int j=0;
    	for(int k=p;k<=r;k++)
    	{
    		if(l[i][0]<=m[j][0])
    		{
    			arr[k][0]=l[i][0];
    			arr[k][1]=l[i][1];
    			i=i+1;
    		} 
    		else
    		{
    			arr[k][0]=m[j][0];
    			arr[k][1]=m[j][1];
    			j=j+1;
    		}
    	}
    }
    
    void MergeSort(int arr[][3],  int p, int r)
    {
    	int q;
    	if(p<r)
    	{
    		q = (p+r)/2;
    		MergeSort(arr,p,q);
    		MergeSort(arr,q+1,r);
    		Merge(arr,p,q,r);
    	}
    }
    void Merge1(int arr[][3], int p, int q, int r)
    {
    	int n1 = q-p+1;
    	int n2 = r-q;
    	int l[n1][3];
    	int m[n2][3];
    	for(int i=0;i<n1;i++)
    	{
    		l[i][2]=arr[p+i][2];        
    		l[i][1]=arr[p+i][1];
    		l[i][0]=arr[p+i][0];
    	}
    	for(int j=0;j<n2;j++)
    	{
    		m[j][2]=arr[q+j+1][2];            
    		m[j][1]=arr[q+j+1][1];
    		m[j][0]=arr[q+j+1][0];
    	}
    	l[n1][2]=0;
    	l[n1][1]=10000;
    	m[n2][2]=0;
    	l[n2][1]=10000;
    	int i=0;
    	int j=0;
    	for(int k=p;km[j][2])
    		{
    			arr[k][0]=l[i][0];
    			arr[k][1]=l[i][1];
    			arr[k][2]=l[i][2];
    			i=i+1;
    		} 
    		else if(l[i][2]==m[j][2])
    		{
    			if(l[i][1]<m[j][1])
    			{
    				arr[k][0]=l[i][0];
    				arr[k][1]=l[i][1];
    				arr[k][2]=l[i][2];
    				i=i+1;
    				
    			}
    			else
    			{
    				arr[k][0]=m[j][0];
    				arr[k][1]=m[j][1];
    				arr[k][2]=m[j][2];
    				
    				j=j+1;
    
    			}
    		}
    		else
    		{
    			arr[k][0]=m[j][0];
    			arr[k][1]=m[j][1];
    			arr[k][2]=m[j][2];
    			
    			j=j+1;
    		}
    	}
    }
    
    void MergeSort1(int arr[][3],  int p, int r)
    {
    	int q;
    	if(p<r)
    	{
    		q = (p+r)/2;
    		MergeSort1(arr,p,q);
    		MergeSort1(arr,q+1,r);
    		Merge1(arr,p,q,r);
    	}
    }
    
    void CreateArray(int arr2D[][3],int size)    
    {   
    	int k=0;
    	int count=1;
    	//create index
    	int i;
    	for( i =0;i<size;i++)
    	{
    		if((i!=0)&&(arr2D[i][0]==arr2D[i-1][0]))
    		{
    			count++;
    			continue;
    		}
    		else
    		{
    			if(i!=0)
    			{
    				//count is at 2nd column
    				arr2D[i-count][2] = count;
    				
    				count =1;
    			}
    		}             
    	}
    	arr2D[i-count][2] = count;
    	for(int i=0;i<8;i++)
    	{
    		printf("%d\t",arr2D[i][0]);
    		printf("%d\t",arr2D[i][1]);
    		printf("%d\t",arr2D[i][2]);
    		printf("\n");
    	}
    
    	k=0;
    	for(int i=0;i<size;i++)
    	{
    		if(arr2D[k][2] ==0)
    		{
    			while((arr2D[i][2] ==0)&&(i<size))
    			i++;
    			if(i==size)
    			break;
    			arr2D[k][0]=arr2D[i][0];     
    			arr2D[k][1]=arr2D[i][1];
    			arr2D[k][2]=arr2D[i][2];
    			arr2D[i][0] = arr2D[i][1] = arr2D[i][2] =0;
    			
    		}
    		k++;
    	}
    }
    
    int main()
    {
    	int arr[8] = {5,2,2,8,5,6,8,8};
    	//CHECKED WITH SECOND INPUT 23,12,45,23,9,23,45,12
    	printf("Original array is \n");
    	for(int i=0;i<8;i++)
    	printf("%d  ",arr[i]);
    	printf("\n");
    	int initial2D[8][3];
    	for(int i=0;i<8;i++)
    	{
    		initial2D[i][0] = arr[i];
    		initial2D[i][1] = i;
    		initial2D[i][2] = 0;
    	}
    	MergeSort(initial2D,0,7);
    	CreateArray(initial2D,8);
    	MergeSort1(initial2D,0,3);
    	printf("Value\tindex\tcount\n");
    	for(int i=0;i<8;i++)
    	{
    		printf("%d\t",initial2D[i][0]);
    		printf("%d\t",initial2D[i][1]);
    		printf("%d\t",initial2D[i][2]);
    		printf("\n");
    	}
    	int i=0;
    	while(initial2D[i][2]!=0)
    	{
    		for(int j =0;j<initial2D[i][2];j++)
    		printf("%d ",initial2D[i][0]);
    
    		i++;
    	}
    
    	getchar();
    }
     
  • rajcools

    I have written the code for method 1.
    I have created a 2-D array that stores – value, index and count
    step1
    1) sort this 2-D array on the basis of number
    2) count the number of times value exist
    3) sort on the basis of count taking index into consideration when there is a tie.
    4)output the value

    My implementation
    1)merge sort used for this function name MergeSort O(n)
    2)in 2d array calculate count for every value and store in 1st entry corresponding to that value. In subsequent entries corresponding to this value count value is zero.And then delete repetitive entries of value , only entries in which count value is non zero remain. 2d array is condensed. If there are four different values only 1st 4 entries of 2D array will be useful
    This is in function create array. O(n)
    3)this is accomplished again via mergesort(different from mergesort of 1st step). iin function mergesort1
    4)this is done in main

  • abc

    A small correction:
    In the first example the treap I drew at the end is wrong. It should be:

     
                 8 (c=3, fi =4)
                / 
               2 (c=2, fi =0)
                \
                 5 (c=2, fi=1)       
                   
  • abc

    Just thinking aloud, I somewhere feel we can use a treap here? This looks like a classic example where a treap can be used.
    Say the input is:
    2,5,2,5,8,8,8
    o/p should be: 8,8,8,2,2,5,5

    So here count will serve as priority for a treap.
    So lets enter numbers.
    (i am using ‘c’ for count and ‘fi’ as the first index in the brackets for a node)

     
    1) 2
                  2 (c=1, fi=0)
    2) 5 
                  2 (c=1, fi=0)
                 / \
                5
          (c=1, fi=1)
    3) enter 2. So here as its already present we increment the count
                  2 (c=2, fi=0)
                 / \
                5
          (c=1, fi=1)
       Whenever we increment the count (aka priority) in a treap, we do a set of rotations if the priority of the node gets bigger than it's parent.
       Here that's not the case so we go ahead
    4) 5:
                  2 (c=2, fi=0)
                 / \
                5
          (c=2, fi=1)
          
          Now the additional step here when the priority of the node is same as priority of the parent. we do rotation if the first index of node is smaller than parent. here that's not the case. so we go ahead
    
    5) add 3 8's: 
    
                  2 (c=2, fi=0)
                 / \
    (c=2, fi=1) 5   8 (c=3, fi =4)
      
                  
          when count of 8 became 2, it became same as parent's but then we didn't need rotation as the fi of 8 was greater than 2.
          now when the count became 3, the count is greater than parent's so we do rotation
          
                 8 (c=3, fi =4)
                / 
               5 (c=2, fi =1)
              /
             2 (c=2, fi=0)       
             
             Now just do extract max (treap is a heap on the count variable)
             
    Another example:
    5,2,8,2,5,8,8
    
    1) 5:
             5 (c=1, fi =0) 
    2) 2:
                   5 (c=1, fi =0) 
                  /
    (c=1, fi = 1)2  
    3) 8:
    
                   5 (c=1, fi =0) 
                  / \
    (c=1, fi = 1)2   8 (c=1, fi = 2)
    
    4) 2:
    
                   5 (c=1, fi =0) 
                  / \
    (c=2, fi = 1)2   8 (c=1, fi = 2)
    
    rotate:
    
                   2 (c=2, fi =1) 
                    \
                     5 (c=1, fi =0) 
                      \
                       8 (c=1, fi = 2)
                       
    5) 5:
    
                   2 (c=2, fi =1) 
                    \
                     5 (c=2, fi =0) 
                      \
                       8 (c=1, fi = 2)
    priority same as parent's and fi less than parent's - rotate
    
                   5 (c=2, fi =0) 
                  / \
    (c=2, fi = 1)2   8 (c=1, fi = 2)
    
    6) 8: 
                   5 (c=2, fi =0) 
                  / \
    (c=2, fi = 1)2   8 (c=2, fi = 2)
    
    7) 8:
    
                   5 (c=2, fi =0) 
                  / \
    (c=2, fi = 1)2   8 (c=3, fi = 2)
    
    Priority got more than parent's - rotate
    
                   8 (c=3, fi = 2)
                  /
                 5 (c=2, fi =0) 
                /
               2 (c=2, fi = 1)
    
    now: 8885522           
     
  • Vamshi Krishna

    In Method 1 using [index, count] approach – there is no need to sort the array to obtain the [index, count] array. Just traverse thru the input array, add new index in the if the element is new, else increment the count for the existing entry.

    This can be done in O(n) time complexity, where as sorting would take O(nlogn) time.

  • http://www.wgpshashank.co.cc WgpShashank

    HI Sandeep, GeeksforGeeks

    i am just about to finish the exact working solution my program time complexity is O(nlogn) & space complexity is O(n) can we do it in O(1) may b i am missing sum-thing..given suggestion….posting the solution of this problem exits me..so reply fast…what i am trying to saying is that once we get the freq.of each word,char int ..then we have to store it in some array or hashset or simple set ..so space is o(nj) ..so can we do better

    Reply ASAP
    Shashank

  • Shashank Mani Narayan

    http://codepad.org/JzSNCEkL

    will help just little modification needed

  • Rini

    In the hashing technique, if we modify it to maintain (instead of the count)a linked list of pointers to the position of the element in the array, or say the index in the array, then sorting would no longer be required. The linked list would ensure it’s stable too.

  • Sam

    My solution is as following and appreciate your code optimization

     
    public class FreqIndexPair
            {
                public int Freq { get; set; }
                public int FirstIndex { get; set; }
            }
    
            public static int[] SortByFrequencyAndFirstOccurence(int[] array)
            {
                Dictionary hash = new Dictionary();
                for (int i = 0; i < array.Length; i++)
                {
                    if (!hash.ContainsKey(array[i]))
                    {
                        hash.Add(array[i], new FreqIndexPair() { FirstIndex = i, Freq = 0 });
                    }
                    hash[array[i]].Freq++;
                }
    
                FreqIndexPair[] FIArray = hash.Values.ToArray();
                Array.Sort(FIArray, new MyCompare());
    
                int[] newArray = new int[array.Length];
                int counter = 0;
                for (int j = 0; j < FIArray.Length; j++)
                {
                    for (int k = 0; k < FIArray[j].Freq; k++)
                    {
                        newArray[counter] = array[FIArray[j].FirstIndex];
                        counter++;
                    }
                }
    
                for (int i = 0; i < newArray.Length; i++)
                {
                    array[i] = newArray[i];
                }
    
                return array;
            }
    
            public class MyCompare : IComparer
            {
    
                #region IComparer Members
    
                public int Compare(FreqIndexPair x, FreqIndexPair y)
                {
                    if (x.Freq > y.Freq)
                    {
                        return -1;
                    }
                    else if (x.Freq  y.FirstIndex)
                        {
                            return 1;
                        }
                        else if (x.FirstIndex < y.FirstIndex)
                        {
                            return -1;
                        }
                        else
                        {
                            return 0;
                        }
                    }
                }
     
  • geeksforgeeks

    @ankit: Thanks for reporting this case. We have modified the above methods to handle same.

  • ankit

    If we modify the input as: 5 2 2 8 5 6 8 8, the code should print 8 8 8 5 5 2 2 6 and not 8 8 8 2 2 5 5 6 as will be the case.

  • umesh

    Working solution…:)

    public class RepeatedNumber {

    public static void sort(int[] a)
    {
    HashMap map=new HashMap();

    for(int i=0;i<a.length;i++)
    {
    if(map.containsKey(a[i]))
    {
    int count=map.get(a[i]);
    map.put(a[i],++count);
    }
    else
    {
    map.put(a[i],1);
    }
    }

    Set keys=map.keySet();

    LinkedList q=new LinkedList();
    Iterator it=keys.iterator();
    while(it.hasNext())
    {
    int key=(Integer) it.next();
    int value=map.get(key);

    Number num=new Number();
    num.count=value;
    num.num=key;
    q.add(num);
    }
    System.out.println(q.size());
    Collections.sort(q);

    Iterator listIterator = q.iterator();
    while(listIterator.hasNext())
    {
    Number i=(Number) listIterator.next();
    for(int k=0;knewNum.count)
    return -1;
    else
    return 1;
    }

    }