diff --git a/ch17/exercise08.c b/ch17/exercise08.c new file mode 100644 index 0000000..79822a2 --- /dev/null +++ b/ch17/exercise08.c @@ -0,0 +1,164 @@ +// C Primer Plus +// Chapter 17 Exercise 8: + +// Modify the Pet Club program so that all pets with the same name are stored +// in a list in the same node. When the user chooses to find a pet, the +// program should request the pet name and then list all pets (along with their +// kinds) having that name. + +// compile with pettree.c + +#include +#include +#include +#include +#include "pettree.h" + +char menu(void); +void addpet(Tree * pt); +void printpet(Pet pet); +void droppet(Tree * pt); +void showpets(const Tree * pt); +void findpet(const Tree * pt); +void uppercase(char * str); +char * get(char * st, int n); + +int main(void) { + Tree pets; + char choice; + InitializeTree(&pets); + + while ((choice = menu()) != 'q') { + puts(""); + if (choice == 'a') { + addpet(&pets); + } else if (choice == 'l') { + showpets(&pets); + } else if (choice == 'f') { + findpet(&pets); + } else if (choice == 'n') { + printf("%d pets in club\n", TreeItemCount(pets)); + } else if (choice == 'd') { + droppet(&pets); + } else { + printf("Not a valid option.\n"); + } + puts(""); + } + DeleteAll(&pets); + puts("Bye."); + + return 0; +} + +char menu(void) { + int ch; + + puts("Nerfville Pet Club Membership Program"); + puts("Enter the letter corresponding to your choice:"); + puts("a) add a pet l) show list of pets"); + puts("n) number of pets f) find pets"); + puts("d) delete a pet q) quit"); + while ((ch = getchar()) != EOF) { + while (getchar() != '\n') + continue; + ch = tolower(ch); + if (strchr("alfndq", ch) == NULL) + puts("Please enter an a, l, f, n, d or q:"); + else + break; + } + if (ch == EOF) + ch = 'q'; + + return ch; +} + +void addpet(Tree * pt) { + Pet * ppet = (Pet *) malloc(sizeof(Pet)); + if (ppet == NULL) { + fprintf(stderr, "Could not allocate memory.\n"); + return; + } + + if (TreeIsFull(pt)) { + puts("No room in the club!"); + } + else { + puts("Please enter name of pet:"); + get(ppet->name, STRLEN); + puts("Please enter pet kind:"); + get(ppet->type, STRLEN); + uppercase(ppet->name); + uppercase(ppet->type); + ppet->next = NULL; + AddPet(ppet, pt); + } +} + +void droppet(Tree * pt) { + Pet temp; + + if (TreeIsEmpty(pt)) { + printf("No entries!\n"); + return; + } + + puts("Please enter name of pet you wish to delete:"); + get(temp.name, STRLEN); + puts("Please enter type of pet:"); + get(temp.type, STRLEN); + uppercase(temp.name); + uppercase(temp.type); + printf("%s the %s ", temp.name, temp.type); + if (DeletePet(&temp, pt)) + printf("is dropped from the club.\n"); + else + printf("is not a member.\n"); +} + +void showpets(const Tree * pt) { + if (TreeIsEmpty(pt)) + puts("No entries!"); + else + TraverseTree(pt, printpet); +} + +void printpet(Pet pet) { + printf("Pet: %-19s Kind: %-19s\n", pet.name, pet.type); +} + +void findpet(const Tree * pt) { + Pet temp; + + if (TreeIsEmpty(pt)) { + puts("No entries."); + return; + } + + puts("Please enter name of pet you wish to find:"); + get(temp.name, STRLEN); + uppercase(temp.name); + printf("Here are all pets named %s:\n", temp.name); + ApplyToNode(&temp, pt, printpet); +} + +void uppercase(char * str) { + for (; *str != '\0'; str++) + *str = toupper(*str); +} + +char * get(char * string, int n) { + // wrapper for fgets - read from stdin and replace + // first newline with null character + + char * retval = fgets(string, n, stdin); + + for (; *string != '\0'; string++) { + if (*string == '\n') { + *string = '\0'; + break; + } + } + return retval; +} diff --git a/ch17/pettree.c b/ch17/pettree.c new file mode 100644 index 0000000..65a0011 --- /dev/null +++ b/ch17/pettree.c @@ -0,0 +1,243 @@ +// pettree.c -- implementation for binary search tree linked list data type + +#include +#include +#include +#include +#include "pettree.h" + +static bool AddItemToList(Pet * ppet, List * plist); +static int ListCount(List * plist); +static bool InList(Pet * ppet, List * plist); +static void TraverseList(List * plist, void (*fn)(Pet)); +static void DeleteList(List * plist); +static bool DeleteListItem(Pet * ppet, List * plist); + +Tree * InitializeTree(Tree * ptree) { + *ptree = NULL; + return ptree; +} + +bool TreeIsEmpty(const Tree * ptree) { + return (*ptree == NULL); +} + +bool TreeIsFull(const Tree * ptree) { + Node * pnode = (Node *) malloc(sizeof(Node)); + Pet * ppet = (Pet *) malloc(sizeof(Pet)); + if (pnode == NULL || ppet == NULL) { + return true; + } + else { + free(pnode); + free(ppet); + return false; + } +} + +bool AddPet(Pet * ppet, Tree * ptree) { + if (TreeIsFull(ptree)) { + return false; + } + + int cmp; + while (*ptree != NULL) { + int cmp = strcmp(ppet->name, (*ptree)->name); + if (cmp == 0) { + // add new pet item to list in Node + return AddItemToList(ppet, &((*ptree)->head)); + } + else if (cmp < 0) { + ptree = &((*ptree)->left); + } + else { + ptree = &((*ptree)->right); + } + } + + // create a new node if one doesn't already exist + Node * pnode = (Node *) malloc(sizeof(Node)); + if (pnode == NULL) { + fprintf(stderr, "Could not allocate memory.\n"); + return false; + } + + strncpy(pnode->name, ppet->name, STRLEN); + pnode->head = ppet; + pnode->left = NULL; + pnode->right = NULL; + + *ptree = pnode; + return true; +} + +bool DeletePet(Pet * ppet, Tree * ptree) { + while (*ptree != NULL) { + int cmp = strcmp(ppet->name, (*ptree)->name); + if (cmp == 0) { + List * plist = &((*ptree)->head); + bool deleted = DeleteListItem(ppet, plist); + // the list at this node is empty, delete the entire node + if ((*ptree)->head == NULL) { + Node * tmp = (*ptree); + if ((*ptree)->left == NULL) { + *ptree = (*ptree)->right; + } + else { + Node * right = (*ptree)->right; + *ptree = (*ptree)->left; + // reattach right subtree + if (right != NULL) { + while ((*ptree)->right != NULL) { + *ptree = (*ptree)->right; + } + (*ptree)->right = right; + } + } + free(tmp); + } + return deleted; + } + else if (cmp < 0) { + ptree = &((*ptree)->left); + } + else { + ptree = &((*ptree)->right); + } + } + return false; +} + +bool InTree(Pet * ppet, const Tree * ptree) { + Node * pnode = *ptree; + while (pnode != NULL) { + int cmp = strcmp(ppet->name, pnode->name); + if (cmp == 0) { + return InList(ppet, &(pnode->head)); + } + else if (cmp < 0) { + pnode = pnode->left; + } + else { + pnode = pnode->right; + } + } + return false; +} + +int TreeItemCount(Tree tree) { + int count = 0; + if (tree == NULL) { + return count; + } + count += ListCount(&(tree->head)); + count += TreeItemCount(tree->left); + count += TreeItemCount(tree->right); + return count; +} + +void ApplyToNode(Pet * ppet, const Tree * ptree, void (*fn)(Pet)) { + Node * pnode = *ptree; + while (pnode != NULL) { + int cmp = strcmp(ppet->name, pnode->name); + if (cmp == 0) { + TraverseList(&(pnode->head), fn); + return; + } + else if (cmp < 0) { + pnode = pnode->left; + } + else { + pnode = pnode->right; + } + } + return; +} + +void TraverseTree(const Tree * ptree, void (*fn)(Pet)) { + Node * pnode = *ptree; + if (pnode == NULL) { + return; + } + TraverseTree(&(pnode->left), fn); + TraverseList(&(pnode->head), fn); + TraverseTree(&(pnode->right), fn); +} + +void DeleteAll(Tree * ptree) { + if (*ptree == NULL) { + return; + } + Node * pnode = *ptree; + DeleteAll(&(pnode->left)); + DeleteAll(&(pnode->right)); + DeleteList(&(pnode->head)); + free(pnode); +} + +static bool AddItemToList(Pet * ppet, List * plist) { + if (*plist == NULL) { + *plist = ppet; + } + else { + Pet * current = *plist; + while(current->next != NULL) { + current = current->next; + } + current->next = ppet; + } + ppet->next = NULL; + return true; +} + +static int ListCount(List * plist) { + int count = 0; + Pet * ppet = *plist; + while (ppet != NULL) { + count++; + ppet = ppet->next; + } + return count; +} + +static bool InList(Pet * ppet, List * plist) { + while (*plist != NULL) { + if (strcmp(ppet->name, (*plist)->name) == 0) + if (strcmp(ppet->type, (*plist)->type) == 0) + return true; + } + return false; +} + +static void TraverseList(List * plist, void (*fn)(Pet)) { + Pet * ppet = *plist; + while (ppet != NULL) { + fn(*ppet); + ppet = ppet->next; + } +} + +static void DeleteList(List * plist) { + Pet * save, * ppet = *plist; + while (ppet != NULL) { + save = ppet; + ppet = ppet->next; + free(save); + } + *plist = NULL; +} + +static bool DeleteListItem(Pet * ppet, List * plist) { + Pet * save; + while (*plist != NULL) { + if (strcmp((*plist)->type, ppet->type) == 0 && + strcmp((*plist)->name, ppet->name) == 0 ) { + save = *plist; + *plist = (*plist)->next; + free(save); + return true; + } + plist = &((*plist)->next); + } + return false; +} \ No newline at end of file diff --git a/ch17/pettree.h b/ch17/pettree.h new file mode 100644 index 0000000..05218d9 --- /dev/null +++ b/ch17/pettree.h @@ -0,0 +1,76 @@ +// pettree.h -- interface for a binary search tree linked list data type + +#ifndef PETTREE_H_ +#define PETTREE_H_ 1 + +#include + +#define STRLEN 30 + +// Type definitions + +typedef struct pet +{ + char type[STRLEN]; + char name[STRLEN]; + struct pet * next; +} Pet; + +typedef Pet * List; + +typedef struct node { + char name[STRLEN]; + List head; + struct node * left; + struct node * right; +} Node; + +typedef Node * Tree; + +// Operations + +// Operation: Initialize a Tree +// Preconditions: ptree points to an unitialized Tree +// Postconditions: ptree points to an initialized Tree +Tree * InitializeTree(Tree * ptree); + + +// Return true if Tree pointed to by ptree is empty, otherwise +// return false +bool TreeIsEmpty(const Tree * ptree); + +// Return true if Tree pointed to by ptree is full, otherwise +// return false +bool TreeIsFull(const Tree * ptree); + +// Add Pet item with given name and type to Tree pointed +// to by ptree +// Return: true if operation succeeds, otherwise false +bool AddPet(Pet * ppet, Tree * ptree); + +// Find and remove the Node corresponding the to string word +// in the Tree pointed to by ptree if it exists. +// Return: true if the Node corresponding to word is found +// and deleted, otherwise false +bool DeletePet(Pet * ppet, Tree * ptree); + +// Search for Node corresponding to string name in Tree +// pointed to by ptree. +// Return: true if word is found in Tree, otherwise false +bool InTree(Pet * ppet, const Tree * ptree); + +int TreeItemCount(Tree tree); + +// Visit each Node in Tree pointed to by ptree, calling +// function pointed to by fn on each Pet member of each Node +void TraverseTree(const Tree * ptree, void (*fn)(Pet)); + +// Search for Node matching string name and if found, call +// function pointed to by fn on each Pet member of Node +void ApplyToNode(Pet * ppet, const Tree * ptree, void (*fn)(Pet)); + +// Delete all Nodes in Tree pointed to by ptree and free all +// allocated memory +void DeleteAll(Tree * ptree); + +#endif \ No newline at end of file