**Problem : **
Augmenting our current implementation of the hash table, write a delete
function to remove a string from the hash table.

int delete_string(hash_table_t *hashtable, char *str)
{
int i;
list_t *list, *prev;
unsigned int hashval = hash(str);
/* find the string in the table keeping track of the list item
* that points to it
*/
for(prev=NULL, list=hashtable->table[hashval];
list != NULL && strcmp(str, list->str);
prev = list,
list = list->next);
/* if it wasn't found, return 1 as an error */
if (list==NULL) return 1; /* string does not exist in table */
/* otherwise, it exists. remove it from the table */
if (prev==NULL) hashtable[hashval] = list->next;
else prev->next = list->next;
/* free the memory associate with it */
free(list->str);
free(list);
return 0;
}

**Problem : **
To augment our current implementation, write a function that counts the
number of strings stored in the hash table.

int count_strings(hash_table_t *hashtable)
{
int i, count = 0;
list_t *list;
/* error check to make sure hashtable exists */
if (hashtable==NULL) return -1;
/* go through every index and count all list elements in each index */
for(i=0; i<hashtable->size; i) {
for(list=hashtable[i]; list != NULL; list = list->next) count;
}
return count;
}

**Problem : **
How would we augment our hash table such that it stores information on
students? We'd still like to look up a student's name to find them, but
we'd then immediately have access to information about them, such as a
letter grade, their graduation year, etc.

All we'd have to do is modify the linked list structure to include all that information:

typedef struct _list_t_ {
char *name; /* and of course we'd have to change our code to use name */
int grad_year;
char letter_grade;
struct _list_t_ *next;
} list_t;

**Problem : **
If something happened to your code and you accidentally lost your hash
function after having stored a lot of data in the hash table, how could
you still search for a specific string? What would the search efficiency
now be?

Just like in the count function above, you could do a linear search of the
hash table until you found what you were looking for. But this is
incredibly inefficient when compared to the normal hash lookup efficiency of

*O*(1). Since we're essentially doing a linear search through n strings,
the efficiency of this strategy is

*O*(*n*).

**Problem : **
Linear probing is another method for collision avoidance. With linear
probing, if a collision occurs, you sequentially look from the current
place in the hashtable for the next open spot, and store the string there.
What disadvantage does this method have for an insertion in terms of
efficiency?

Linear probing insertion could be

*O*(*n*), while separate chaining is

*O*(1)
as you always insert at the beginning of the list.