#include
#include
#include
#include
typedef struct WORD
{
char *Word;
size_t Count;
struct WORD *Left;
struct WORD *Right;
} WORD;
#define SUCCESS 0
#define CANNOT_MALLOC_WORDARRAY 1
#define NO_WORDS_ON_INPUT 2
#define NO_MEMORY_FOR_WORDNODE 3
#define NO_MEMORY_FOR_WORD 4
#define NONALPHA "1234567890
\v\f\n\t\r+=-*/\\,.;:'#~?<>|{}[]`!\"¡ê$%^&()"
int ReadInputToTree(WORD **DestTree, size_t *Treecount, FILE
*Input);
int AddToTree(WORD **DestTree, size_t *Treecount, char
*Word);
int WalkTree(WORD **DestArray, WORD *Word);
int CompareCounts(const void *vWord1, const void
*vWord2);
int OutputWords(FILE *Dest, size_t Count, WORD
**WordArray);
void FreeTree(WORD *W);
char *my_dupstr(char *s);
int main(void)
{
int Status =
SUCCESS;
WORD *Words =
NULL;
size_t Treecount =
0;
WORD **WordArray =
NULL;
//Read the words on
stdin into a tree
if (SUCCESS ==
Status)
{
Status = ReadInputToTree(&Words,
&Treecount, stdin);
}
//Sanity check for no
sensible input
if (SUCCESS ==
Status)
{
if (0 == Treecount)
{
Status =
NO_WORDS_ON_INPUT;
}
}
//allocate a
sufficiently large array
if (SUCCESS ==
Status)
{
WordArray = malloc(Treecount
*sizeof(*WordArray));
if (NULL == WordArray)
{
Status =
CANNOT_MALLOC_WORDARRAY;
}
}
//walk the tree into the
array
if (SUCCESS ==
Status)
{
Status = WalkTree(WordArray, Words);
}
//sort the array
if (SUCCESS ==
Status)
{
qsort(WordArray, Treecount, sizeof(*WordArray),
CompareCounts);
}
//walk down the
WordArray outputting the values
if (SUCCESS ==
Status)
{
Status = OutputWords(stdout, Treecount,
WordArray);
}
//free the word
array
if (NULL !=
WordArray)
{
free(WordArray);
WordArray = NULL;
}
//free the tree
memory
if (NULL != Words)
{
FreeTree(Words);
Words = NULL;
}
//error report and
finish
if (SUCCESS !=
Status)
{
fprintf(stderr, "Program failed with code %d\n",
Status);
}
system("pause");
return (SUCCESS ==
Status ? EXIT_SUCCESS:EXIT_FAILURE);
}
void FreeTree(WORD *W)
{
if (NULL != W)
{
if (NULL != W->Word)
{
free(W->Word);
W->Word = NULL;
}
if (NULL != W->Left)
{
FreeTree(W->Left);
W->Left = NULL;
}
if (NULL != W->Right)
{
FreeTree(W->Right);
W->Right = NULL;
}
}
}
int AddToTree(WORD **DestTree, size_t *Treecount, char
*Word)
{
int Status =
SUCCESS;
int CompResult =
0;
//safety check
assert(NULL !=
DestTree);
assert(NULL !=
Treecount);
assert(NULL !=
Word);
if (NULL ==
*DestTree)
{
*DestTree = malloc(sizeof **DestTree);
if (NULL == *DestTree)
{
Status =
NO_MEMORY_FOR_WORDNODE;
}
else
{
(*DestTree)->Left = NULL;
(*DestTree)->Right = NULL;
(*DestTree)->Count = 1;
(*DestTree)->Word = my_dupstr(Word);
if (NULL
== (*DestTree)->Word)
{
Status =
NO_MEMORY_FOR_WORD;
free(*DestTree);
*DestTree = NULL;
}
else
{
++*Treecount;
}
}
}
else
{
CompResult = strcmp(Word,
(*DestTree)->Word);
if (0 < CompResult)
{
Status =
AddToTree(&(*DestTree)->Left,
Treecount, Word);
}
else if (0 > CompResult)
{
Status =
AddToTree(&(*DestTree)->Left,
Treecount, Word);
}
else
{
++(*DestTree)->Count;
}
}
return Status;
}
int ReadInputToTree(WORD **DestTree, size_t *Treecount, FILE
*Input)
{
int Status =
SUCCESS;
char Buf[8192] =
{0};
char *Word = NULL;
//safety check
assert(NULL !=
DestTree);
assert(NULL !=
Treecount);
assert(NULL !=
Input);
printf("Please input
strings(# to quit):\n");
while (NULL !=
fgets(Buf, sizeof(Buf), Input))
{
if (strcmp(Buf, "#\n") == 0)
break;
Word = strtok(Buf, NONALPHA);
while (SUCCESS == Status
&& NULL != Word)
{
Status =
AddToTree(DestTree, Treecount, Word);
if
(SUCCESS == Status)
{
Word = strtok(NULL,
NONALPHA);
}
}
}
return Status;
}
int WalkTree(WORD **DestArray, WORD *Word)
{
int Status =
SUCCESS;
static WORD **Write =
NULL;
//safety check
assert(NULL !=
Word);
//store the starting
poing if this is the first call
if (NULL !=
DestArray)
{
Write = DestArray;
}
//now add this node and
its kids
if (NULL != Word)
{
*Write = Word;
++Write;
if (NULL != Word->Left)
{
Status =
WalkTree(NULL, Word->Left);
}
if (NULL != Word->Right)
{
Status =
WalkTree(NULL, Word->Right);
}
}
return Status;
}
int CompareCounts(const void *vWord1, const void
*vWord2)
{
int Result = 0;
WORD * const *Word1 =
vWord1;
WORD * const *Word2 =
vWord2;
assert(NULL !=
vWord1);
assert(NULL !=
vWord2);
if
((*Word1)->Count <
(*Word2)->Count)
{
Result = 1;
}
else if
((*Word1)->Count >
(*Word2)->Count)
{
Result = -1;
}
else
{
Result = 0;
}
return Result;
}
int OutputWords(FILE *Dest, size_t Count, WORD
**WordArray)
{
int Status =
SUCCESS;
size_t Pos = 0;
//safety check
assert(NULL !=
Dest);
assert(NULL !=
WordArray);
//print a header
fprintf(Dest, "Total
Words: %lu\n", (unsigned long)Count);
//print the words in
descending order
while (SUCCESS == Status
&& Pos <
Count)
{
fprintf(Dest, "%lu %s\n", (unsigned
long)WordArray[Pos]->Count,
WordArray[Pos]->Word);
++Pos;
}
return Status;
}
char *my_dupstr(char *s)
{
char *Result =
NULL;
size_t slen = 0;
//sanity check
assert(NULL != s);
//get string
length
slen = strlen(s);
//allocate enough
storage
Result = malloc(slen +
1);
//populate string
if (NULL !=
Result)
{
memcpy(Result, s, slen);
*(Result + slen) = '\0';
}
return Result;
}