Created
February 24, 2014 03:59
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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