Search code examples
carrayssortingasciicounting-sort

Sort a character array in ascending order using Counting sort


Input char a[10] = {'c','b','c','d','E','C','a','A','b','C'};

Output : A a b b C C c c d e

I have been given a character array and I have to sort it in ascending order and I must use Counting sort to do that

I have tried so far:

#include <stdio.h>
#include <stdlib.h>
#define RANGE 255


void countingSort(char a[], char b[], int n) // a = array, b = empty array, n = size
{
    int i;

    int c[RANGE +1];
    memset(c, 0, sizeof(c));


    for( i = 0; i< n; i++)
    {
        c[a[i]] = c[a[i]] + 1;
    }
    for(i = 1; i<RANGE; i++)
    {
        c[i] = c[i] + c[i-1];
    }
    for(i = n-1; i>=0; i--)
    {
        b[c[a[i]] - 1] = a[i];
        c[a[i]] = c[a[i]] - 1;
    }

}

int main()
{
    char a[10] = {'c','b','c','d','E','C','a','A','b','C'};
    int n = 10;
    char b[10];
    int i;
    for( i = 0; i<n;i++)
    {
        printf("%c",a[i]);
    }
    printf("\n");
    countingSort(a,b,n);
    for( i = 0; i<n;i++)
    {
        printf("%c",b[i]);
    }
    printf("\n");

    return 0;
}

I have used ASCII table to sort the array and my output is

ACCEabbccd

I managed to sort the array in ascending order but I DO NOT know how to put a right after A and so on.


Solution

  • One approach simply doubles the c[] size and forms an index where all even indexes are uppercase and odd ones are lowercase.

    #if 1
    #define RANGE (255*2 + 1)
    #include <ctype.h>
    #define CH_TO_INDEX(ch) \
        (2*toupper((unsigned char)ch) + !!islower((unsigned char) ch))
    
    #else
    // Original
    #define RANGE 255
    #define CH_TO_INDEX(ch)    (ch)
    
    #endif
    
    void countingSort(char a[], char b[], int n) {
      int i;
      int c[RANGE + 1];
      memset(c, 0, sizeof(c));
    
      for (i = 0; i < n; i++) {
        //c[a[i]] = c[a[i]] + 1;
        c[CH_TO_INDEX(a[i])]++;
      }
      for (i = 1; i < RANGE; i++) {
        c[i] = c[i] + c[i - 1];
      }
      for (i = n - 1; i >= 0; i--) {
        // b[c[a[i]] - 1] = a[i];
        b[c[CH_TO_INDEX(a[i])] - 1] = a[i];
        // c[a[i]] = c[a[i]] - 1;
        c[CH_TO_INDEX(a[i])]--;
      }
    }
    

    Output

    cbcdECaAbC
    AabbCCccdE
    

    A more complex char --> index could be had that does not double the size of c[]. Such mappings tend to make assumptions that there are only letters A-Z. Such a mapping may use an auxiliary mapping array:

    unsigned char map[256] - {
        0, 1, 2, ...., 31, ' ', ... 'A', 'a', 'B', 'b', ... 'Z', 'z', 
        ASCII characters after 'Z' and before 'a'
        ASCII characters after 'z', .... 255 };
    

    OP requested

    Output : A a b b C C c c d e
    

    But based on {'c', 'b', 'c', 'd', 'E', 'C', 'a', 'A', 'b', 'C'}, I think OP wants

    Output : A a b b C C c c d E
    

    Note that original code fails when a[i] < 0. Code needs re-work for negative char. Re-code using unsigned char.