Skip to content

Instantly share code, notes, and snippets.

@mohamed-ennahdi
Created February 24, 2014 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mohamed-ennahdi/9181739 to your computer and use it in GitHub Desktop.
Save mohamed-ennahdi/9181739 to your computer and use it in GitHub Desktop.
A contest Huffman Encoding Problem. This solution is expensive from an algorithm analysis perspective (unsuitable data structure preliminary choice). However, the algorithm is worth it.
#include <stdio.h>
#define N 26
/*
* This structure gathers the elements (letters) and their frequency.
*/
typedef struct {
char sourceAlphabet[N];
unsigned frequency;
} Symbol;
/*
* This structure represents an array of Symbol elements. It includes
* the size of the array.
*/
typedef struct {
Symbol symbols[N];
unsigned size;
} ListSymbols;
/*
* This array of strings contains the resulting codes.
*/
char targetAlphabet[N][N];
/*
* The array below is a buffer which is storing frequencies when inserted.
*/
char frequencies[N];
/*
* This function uses insertion sort to sort elements according to their frequency,
* then according to the alphabetical order of the uppercase letter.
*/
void insertionSort( ListSymbols* );
/*
* This function uses insertion sort to sort characters of a given string
* in the alphabetical order.
*/
void stringInsertionSort( char* );
/*
* This function shifts the list to the left, meaning that the last element
* erases the element before, and so forth.
*/
void leftShift( ListSymbols * , unsigned );
/*
* This function inverse a given string.
* SOURCE: http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
*/
void strrev( char * );
/*
* This algorithm relies on insertion sort to keep the 2 least frequency elements
* next to each other so that they can be concatenated (upper case letters) and
* their frequencies summed.
* The list starts with a number of symbols, each symbols is a single character
* and a frequency.
* After each pass, 2 characters are concatenated (and their frequencies summed),
* and the symbols next to the 2nd symbols erase the latter (left shift).
* The number of symbols is reduced, and an insertion sort is invoked again to
* reorganize the symbols again.
* While the above is occurring, the target alphabet is updated, and since R = 2
* we use '0' and '1' to represent values.
*/
int main() {
ListSymbols listSymbols;
unsigned n , m , i , j , cases = 1;
float averageLength;
scanf("%d", &n);
while ( n != 0 ) {
m = listSymbols.size = n;
for ( i = 0; i < n ; i ++) {
scanf("%d", &listSymbols.symbols[i].frequency);
listSymbols.symbols[i].sourceAlphabet[0] = 'A' + i;
listSymbols.symbols[i].sourceAlphabet[1] = 0;
strcpy(targetAlphabet[i], "");
frequencies[i] = listSymbols.symbols[i].frequency;
}
for ( i = 0 ; i < n ; i ++) {
insertionSort(&listSymbols);
if (n > 1) {
if ( listSymbols.symbols[ i ].frequency > listSymbols.symbols[ i + 1 ].frequency ) {
m = strlen(listSymbols.symbols[ i ].sourceAlphabet);
for ( j = 0 ; j < m ; j ++ ) {
strcat(targetAlphabet[listSymbols.symbols[ i ].sourceAlphabet[j] - 'A'], "1");
}
m = strlen(listSymbols.symbols[ i + 1 ].sourceAlphabet);
for ( j = 0 ; j < m ; j ++ ) {
strcat(targetAlphabet[listSymbols.symbols[ i ].sourceAlphabet[j] - 'A'], "0");
}
} else {
m = strlen(listSymbols.symbols[ i ].sourceAlphabet);
for ( j = 0 ; j < m ; j ++ ) {
strcat(targetAlphabet[listSymbols.symbols[ i ].sourceAlphabet[j] - 'A'], "0");
}
m = strlen(listSymbols.symbols[ i + 1 ].sourceAlphabet);
for ( j = 0 ; j < m ; j ++ ) {
strcat(targetAlphabet[listSymbols.symbols[ i + 1 ].sourceAlphabet[j] - 'A'], "1");
}
}
strcat(listSymbols.symbols[ i ].sourceAlphabet, listSymbols.symbols[ i + 1 ].sourceAlphabet);
listSymbols.symbols[ i ].frequency += listSymbols.symbols[ i + 1 ].frequency;
}
leftShift( &listSymbols , i + 1 );
n = listSymbols.size;
i --;
}
stringInsertionSort(listSymbols.symbols[ i ].sourceAlphabet);
printf("Set %d; average length ", cases);
n = strlen(listSymbols.symbols[ 0 ].sourceAlphabet);
averageLength = 0;
for ( i = 0 ; i < n ; i++ ) {
averageLength += strlen(targetAlphabet[i]) * frequencies[i];
}
printf("%.2f", averageLength / listSymbols.symbols[ 0 ].frequency);
for ( i = 0 ; i < n ; i++ ) {
strrev(targetAlphabet[i]);
printf("\n%c: %s", listSymbols.symbols[ 0 ].sourceAlphabet[i], targetAlphabet[i]);
}
puts("\n");
scanf("%d", &n);
cases++;
}
return 0;
}
/*
* This function shifts the list to the left, meaning that the last element
* erases the element before, and so forth.
*/
void leftShift(ListSymbols *listSymbols, unsigned limit ) {
unsigned i;
for ( i = limit ; i < listSymbols->size - 1 ; i++ ) {
listSymbols->symbols[ i ] = listSymbols->symbols[ i + 1 ];
}
listSymbols->size --;
}
/*
* This function uses insertion sort to sort elements according to their frequency,
* then according to the alphabetical order of the uppercase letter.
*/
void insertionSort( ListSymbols *listSymbols ) {
int i, j;
Symbol temp;
for (i = 1; i < listSymbols->size; i++) {
temp = listSymbols->symbols[i];
j = i;
while ( ( j > 0 ) && ( listSymbols->symbols[j - 1].frequency > temp.frequency || (strcmp(listSymbols->symbols[j - 1].sourceAlphabet, temp.sourceAlphabet ) >= 0 && listSymbols->symbols[j - 1].frequency >= temp.frequency ) ) ) {
listSymbols->symbols[j] = listSymbols->symbols[j - 1];
j = j - 1;
}
listSymbols->symbols[j] = temp;
}
}
/*
* This function uses insertion sort to sort characters of a given string
* in the alphabetical order.
*/
void stringInsertionSort( char* str ) {
unsigned i, j, n;
char temp;
n = strlen(str);
for (i = 1; i < n; i++) {
temp = str[i];
j = i;
while ((j > 0) && (str[j - 1] > temp)) {
str[j] = str[j - 1];
j = j - 1;
}
str[j] = temp;
}
}
/*
* This function inverse a given string.
* SOURCE: http://stackoverflow.com/questions/198199/how-do-you-reverse-a-string-in-place-in-c-or-c
*/
void strrev(char *p) {
char *q = p;
while(q && *q) ++q;
for(--q; p < q; ++p, --q)
*p = *p ^ *q,
*q = *p ^ *q,
*p = *p ^ *q;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment