200 likes | 333 Views
Homework. Continuing K&R Chapter 6. now. is. the. men. for. of. time. all. good. their. to. party. aid. come. Self Referential structs, K&R 6.5. Count the occurrences of all the words in some input
E N D
Homework • Continuing K&R Chapter 6
now is the men for of time all good their to party aid come Self Referential structs, K&R 6.5 • Count the occurrences of all the words in some input • Look at this binary tree structure (Pg. 139) for the sentence “now is the time for all good men to come to the aid of their party” • At any node, the left subtree only has words that are lexicographically less than the word at the node. The right subtree has words that are greater.
Self Referential structs struct tnode { /* the tree node struct */ char *word; /* points to the word at this node */ int count; /* has a count of occurances */ struct tnode *left; /* a word < one at this node */ struct tnode *right; /* a word > one at this node */ }; • OK to have a pointer to a struct of same type in its own definition • NOT OK to have a struct itself in its own definition (OK to have a different struct as a member)!
Tree of struct tnodes tnode *root char *word int count tnode *left tnode *right keyword \0 … char *word int count tnode *left tnode *right … … … char *word int count tnode *left tnode *right … …
Self Referential structs • Each node is a struct tnode with a string value and a count of occurrences • Each node also contains a pointer to a left child and a right child • Each child is another struct tnode
Declarations / Prototypes #include <stdio.h> #include <ctype.h> (see functions in App. B2, pp. 248-249, K&R) #include <string.h> (see functions in App. B3, pp. 249-250, K&R) #define MAXWORD 100 int getword(char *word, int lim); struct tnode *addtree(struct tnode *, char *); void treeprint(struct tnode *);
Main program int main( ) { struct tnode *root; /* ptr to root for binary tree */ char word[MAXWORD]; /* word to get from stdin */ root = NULL; /* initially, no tnodes in tree */ /* OK that root pointer points to NULL initially */ while (getword(word, MAXWORD) != EOF) /* getword from stdin */ if (isalpha(word[0])) /* from ctype.h library */ root = addtree(root, word); /* expect not NULL anymore */ treeprint(root); /* print it out in order */ return 0; }
getword ( ) /* getword: get next word or character from input */ /* a word is either a string of letters and digits beginning with a letter, or a single non-white space character */ int getword(char *word, int lim) { int c, getch(void); void ungetch(int); char *w = word; while (isspace(c = getch())) /* skip spaces; c first non-space */ ; if (c != EOF) *w++=c; /* c might be EOF here (empty word) */ if(!isalpha(c)) { /* c (identifier) starts with alpha */ *w = '\0'; return c; /* if not, form word with 1 non-white space char*/ } for( ; --lim > 0; w++) if (!isalnum(*w = getch())) { /* identify alpha or digits */ ungetch(*w); break; /* need to go back 1 character if the end is reached*/ } *w = '\0'; return word[0]; }
addtree ( ) struct tnode *talloc(void); /* allocate. return ptr to tnode */ char *strdup(char *); /* allocate space, copy word there */ /* addtree: add a node with w, at or below p */ struct tnode *addtree(struct tnode *p, char *w) { int cond; /*for empty tree, root is NULL */ if (p == NULL) { /* nothing at this node yet */ p = talloc(); /* allocate a new node */ p->word = strdup(w); /* allocate space, copy word there */ p->count = 1; /* count is 1 */ p->left = p->right = NULL; /* this works; see precedence */ } else if ((cond = strcmp(w, p->word)) == 0) /* string.h */ p->count++; /* repeated word, increment count */ else if (cond < 0) /* note cond remembers strcmp above */ p->left = addtree(p->left, w); /* less: go left subtree */ else /* more, go to right subtree */ p->right = addtree(p->right, w); return p; }
addtree( ) • Note, that addtree is recursive. If it adds a node, it might need to add root or any left or right child anywhere down the tree • We pass struct tnode *p as first argument, and also pass back the same type - always a pointer to the node at the current recursive nesting level • Any time a new node is created: root, p->left or p->right in node above will be set for the FIRST time based on return value from addtree
addtree ( ) • When main calls addtree, the return sets root value each time even if the root already pointed to tnode • Allows for possible addition of a pointer to a node • Why do we need to return a struct tnode *p when we have struct tnode *p as an argument? • Can't we just set it via argument, return void from addtree, and write (in main)? addtree(root, word); instead of root = addtree(root, word);
addtree ( ) • No, root is already a pointer, struct tnode *p, but it is the pointer p itself that must be modified • To modify root, we would need to declare addtree with a pointer to p as 1st arg: void addtree(struct tnode **p, char *w); • Call it from main recursively by invocation: addtree(&root, word); • Then, addtree could set the value for root directly instead of by return value. Same is true of lower levels when adding a left or right child
talloc ( ) • How to write talloc to allocate a tnode and return a pointer. struct tnode *talloc(void) { return (struct tnode *) malloc (sizeof(struct tnode)); }
strdup ( ) • strdup ( ) creates space for a character string, copies a word into it (up to null terminator) and returns the char pointer char *strdup(char *s) { char * p; p = (char *) malloc (strlen(s)+1); /* +1 for '\0' */ if (p != NULL) /* if malloc didn’t fail */ strcpy(p, s); /* library function in string.h */ return p; }
treeprint ( ) • To print out tree contents in order: void treeprint (struct tnode *p) { if (p != NULL) { treeprint (p->left); printf (%4d %s\n”, p->count, p->word); treeprint (p->right); } }
treeprint Recursion Program Flow now 41 1 23 22 the is 2 40 21 24 18 men 31 17 30 time for of 3 20 32 39 29 16 19 13 25 26 12 35 36 party their to all good 4 11 27 28 8 14 15 33 34 37 38 7 aid come 5 6 9 10
Table Lookup, K&R 6.6 • struct for a linked list of names/definitions struct nlist { /* table entry */ struct nlist *next; /* link to next */ char *name; /* word name */ char *defn; /* word definition */ };
Table Lookup / Linked Lists • Array of pointers to null terminated linked lists of structs defining table entries 0 array nlist [0] [1] 0 nlist=0 means end of the list [2] 0 0 [3] [4] 0
Table Lookup / Linked List • Hash search- incoming name is converted into a non-negative integer which is used to index into an array of pointers • Hash function to select starting array element unsigned int hash (char *s) { for (hashval = 0; *s != ‘\0’; s++) hashval = *s + 31 * hashval; return hashval % HASHSIZE; } • In lookup ( ), std code for following a linked list: for (ptr = head; ptr != NULL; ptr = ptr->next)
Lookup Function /* look for s in hashtab */ struct nlist *lookup(char *s) { struct nlist *np; for (np = hashtab[hash(s)]; np !=null; np=np->next) if (strcmp(s, np->name) ==0) return np; return NULL; }