/* Robert S Laramee
* CS391S/T
* 8 April 1997
* Assignment #1
*
* see end of program for required documentation
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct dict_template {
char word[50];
char signature[50];
} dict_struct;
dict_struct dictionary[73000];
/* a function to swap two characters in a word, a helper function for the
* version of quicksort used to sort the words into their corresponding
* signatures
*/
static void swap_them(char *char_1, char *char_2)
{
register char temp_char;
temp_char = *char_1;
*char_1 = *char_2;
*char_2 = temp_char;
}
/* This is the version of quicksort used to sort the individual words
* into signatures.
*/
void quicksort(char array[], unsigned word_length) {
unsigned i, j, left, right;
while (word_length > 1) {
swap_them(&array[0], &array[word_length/2]);
for (i = 0, j = word_length; ; ) {
do --j;
while (array[j] > array[0]);
do ++i;
while (i < j && array[i] < array[0]);
if (i >= j) {
break;
}
swap_them(&array[i], &array[j]);
}
swap_them(&array[j], &array[0]);
left = j;
right = word_length - ++j;
if (left < right) {
quicksort(array, left);
array += j;
word_length = right;
} else {
quicksort(array + j, right);
word_length = left;
}
}
}
/* This is the quicksort algorithm used to sort the entire bunch
* of signatures.
*/
void QuickSort(dict_struct Dictionary[], int left, int right) {
int i = left;
int j = right;
char mid[50] = Dictionary[(left+right)/2].signature;
if (left >= right) return;
do {
while (strcmp(Dictionary[i].signature,mid) < 0)
i++;
while (strcmp(mid, Dictionary[j].signature) < 0)
j--;
if (i <= j) {
dict_struct temp[1];
temp[0] = Dictionary[i];
Dictionary[i++] = Dictionary[j];
Dictionary[j--] = temp[0];
}
} while (i <= j);
QuickSort(Dictionary, left, j);
QuickSort(Dictionary, i, right);
}
void main(void) {
FILE *dict_file_ptr, *output_file_ptr;
char input_array[50];
char current_signature[50];
int i = 0;
int j = 0;
int number_of_words = 0;
/* Open the dictionary file.
*/
if ((dict_file_ptr = fopen("dict", "r")) == NULL) {
printf("Error cannot open file 'dict' for reading. \n");
}
/* Read in the words from the dictionary and then sort the
* letters to get a signature
*/
while (fgets(input_array, 50, dict_file_ptr) != NULL) {
dictionary[number_of_words].word = input_array;
quicksort(input_array, strlen(input_array) - 1);
dictionary[number_of_words].signature = input_array;
number_of_words++;
}
/* Now sort the entire bunch of signatures using quicksort.
*/
QuickSort(dictionary, 0, number_of_words);
/* Open the output file (text).
*/
if ((output_file_ptr = fopen("anagram.out", "w")) == NULL) {
printf("Error cannot open file 'anagram.out' for writing. \n");
}
/* Start outputting to file.
*/
int a, b;
for (int a = 0; a <= number_of_words; a++) {
while (strcmp(dictionary[a].signature,dictionary[a + 1].signature) !=0)
{ a++;}
current_signature = dictionary[a].signature;
b = 0;
while (strcmp(current_signature, dictionary[a].signature) == 0) {
b = 1;
for (int tmp = 0; tmp <= (strlen(current_signature)); tmp++) {
if (current_signature[tmp] != '\n'
&& current_signature[tmp] != NULL)
putc(dictionary[a].word[tmp], output_file_ptr);
}
a++;
putc(' ',output_file_ptr);
}
if (b == 1) {
a--;
}
putc('\n',output_file_ptr);
}
/* Close both files
*/
if (fclose(output_file_ptr)) {
printf("Problem closing anagram.out file...\n");
}
if (fclose(dict_file_ptr)) {
printf("Problem closing dict file...\n");
}
}
/* The quicksort algorithm was used in both sorts. This is because
* it take nlog(n) time. It was chosen over Insertion sort because
* that takes n squared time. It was also chosen over Counting sort
* because counting sort requires a lot of extra memeory. And we
* would need a lot of extra memory in this program.
*
* Running Time:
* el1> time anagram
* 6.742u 0.786s 0:07.76 96.9% 0+52k 1+9io 0pf+0w
*
* Machine
* el1> machine
* alpha
*
* Number of words:
* el1> wc anagram.out
* 3496 7774 60032 anagram.out
*
* Anagram classes that contain more than 5 words in them:
* el1> cat anagram.out | awk 'NF > 5'.
* bread beard debar ardeb barde debra
* caret cater trace react crate recta
* plate pleat palet leapt petal lepta
* steal teals stale stela least setal slate
* vela vale elva veal leva lave
* lair lira rial aril liar rail
* risen serin resin siren reins rinse
* lustre ulster sutler rustle result luster
*/