(1)ohtbl.h
/*****************************************************************************
* *
* ------------------------------- ohtbl.h -------------------------------- *
* *
*****************************************************************************/
#ifndef OHTBL_H
#define OHTBL_H
#include <stdlib.h>
#include <string.h>
#include "ohtbl.h"
/*****************************************************************************
* *
* Define a structure for open-addressed hash tables. *
* *
*****************************************************************************/
typedef struct OHTbl_ {
int positions;
void *vacated;
int (*h1)(const void *key);
int (*h2)(const void *key);
int (*match)(const void *key1, const void *key2);
void (*destroy)(void *data);
int size;
void **table;
} OHTbl;
/*****************************************************************************
* *
* --------------------------- Public Interface --------------------------- *
* *
*****************************************************************************/
int ohtbl_init(OHTbl *htbl, int positions, int (*h1)(const void *key), int
(*h2)(const void *key), int (*match)(const void *key1, const void *key2),
void (*destroy)(void *data));
void ohtbl_destroy(OHTbl *htbl);
int ohtbl_insert(OHTbl *htbl, const void *data);
int ohtbl_remove(OHTbl *htbl, void **data);
int ohtbl_lookup(const OHTbl *htbl, void **data);
#define ohtbl_size(htbl) ((htbl)->size)
/*****************************************************************************
* *
* ------------------------------- ohtbl.c -------------------------------- *
* *
*****************************************************************************/
/*****************************************************************************
* *
* Reserve a sentinel memory address for vacated elements. *
* *
*****************************************************************************/
static char vacated;
/*****************************************************************************
* *
* ------------------------------ ohtbl_init ------------------------------ *
* *
*****************************************************************************/
int ohtbl_init(OHTbl *htbl, int positions, int (*h1)(const void *key), int
(*h2)(const void *key), int (*match)(const void *key1, const void *key2),
void (*destroy)(void *data)) {
int i;
/*****************************************************************************
* *
* Allocate space for the hash table. *
* *
*****************************************************************************/
if ((htbl->table = (void **)malloc(positions * sizeof(void *))) == NULL)
return -1;
/*****************************************************************************
* *
* Initialize each position. *
* *
*****************************************************************************/
htbl->positions = positions;
for (i = 0; i < htbl->positions; i++)
htbl->table[i] = NULL;
/*****************************************************************************
* *
* Set the vacated member to the sentinel memory address reserved for this. *
* *
*****************************************************************************/
htbl->vacated = &vacated;
/*****************************************************************************
* *
* Encapsulate the functions. *
* *
*****************************************************************************/
htbl->h1 = h1;
htbl->h2 = h2;
htbl->match = match;
htbl->destroy = destroy;
/*****************************************************************************
* *
* Initialize the number of elements in the table. *
* *
*****************************************************************************/
htbl->size = 0;
return 0;
}
/*****************************************************************************
* *
* ---------------------------- ohtbl_destroy ----------------------------- *
* *
*****************************************************************************/
void ohtbl_destroy(OHTbl *htbl) {
int i;
if (htbl->destroy != NULL) {
/**************************************************************************
* *
* Call a user-defined function to free dynamically allocated data. *
* *
**************************************************************************/
for (i = 0; i < htbl->positions; i++) {
if (htbl->table[i] != NULL && htbl->table[i] != htbl->vacated)
htbl->destroy(htbl->table[i]);
}
}
/*****************************************************************************
* *
* Free the storage allocated for the hash table. *
* *
*****************************************************************************/
free(htbl->table);
/*****************************************************************************
* *
* No operations are allowed now, but clear the structure as a precaution. *
* *
*****************************************************************************/
memset(htbl, 0, sizeof(OHTbl));
return;
}
/*****************************************************************************
* *
* ----------------------------- ohtbl_insert ----------------------------- *
* *
*****************************************************************************/
int ohtbl_insert(OHTbl *htbl, const void *data) {
void *temp;
int position,
i;
/*****************************************************************************
* *
* Do not exceed the number of positions in the table. *
* *
*****************************************************************************/
if (htbl->size == htbl->positions)
return -1;
/*****************************************************************************
* *
* Do nothing if the data is already in the table. *
* *
*****************************************************************************/
temp = (void *)data;
if (ohtbl_lookup(htbl, &temp) == 0)
return 1;
/*****************************************************************************
* *
* Use double hashing to hash the key. *
* *
*****************************************************************************/
for (i = 0; i < htbl->positions; i++) {
position = (htbl->h1(data) + (i * htbl->h2(data))) % htbl->positions;
if (htbl->table[position] == NULL || htbl->table[position] == htbl->
vacated) {
/***********************************************************************
* *
* Insert the data into the table. *
* *
***********************************************************************/
htbl->table[position] = (void *)data;
htbl->size++;
return 0;
}
}
/*****************************************************************************
* *
* Return that the hash functions were selected incorrectly. *
* *
*****************************************************************************/
return -1;
}
/*****************************************************************************
* *
* ----------------------------- ohtbl_remove ----------------------------- *
* *
*****************************************************************************/
int ohtbl_remove(OHTbl *htbl, void **data) {
int position,
i;
/*****************************************************************************
* *
* Use double hashing to hash the key. *
* *
*****************************************************************************/
for (i = 0; i < htbl->positions; i++) {
position = (htbl->h1(*data) + (i * htbl->h2(*data))) % htbl->positions;
if (htbl->table[position] == NULL) {
/***********************************************************************
* *
* Return that the data was not found. *
* *
***********************************************************************/
return -1;
}
else if (htbl->table[position] == htbl->vacated) {
/***********************************************************************
* *
* Search beyond vacated positions. *
* *
***********************************************************************/
continue;
}
else if (htbl->match(htbl->table[position], *data)) {
/***********************************************************************
* *
* Pass back the data from the table. *
* *
***********************************************************************/
*data = htbl->table[position];
htbl->table[position] = htbl->vacated;
htbl->size--;
return 0;
}
}
/*****************************************************************************
* *
* Return that the data was not found. *
* *
*****************************************************************************/
return -1;
}
/*****************************************************************************
* *
* ----------------------------- ohtbl_lookup ----------------------------- *
* *
*****************************************************************************/
int ohtbl_lookup(const OHTbl *htbl, void **data) {
int position,
i;
/*****************************************************************************
* *
* Use double hashing to hash the key. *
* *
*****************************************************************************/
for (i = 0; i < htbl->positions; i++) {
position = (htbl->h1(*data) + (i * htbl->h2(*data))) % htbl->positions;
if (htbl->table[position] == NULL) {
/***********************************************************************
* *
* Return that the data was not found. *
* *
***********************************************************************/
return -1;
}
else if (htbl->match(htbl->table[position], *data)) {
/***********************************************************************
* *
* Pass back the data from the table. *
* *
***********************************************************************/
*data = htbl->table[position];
return 0;
}
}
/*****************************************************************************
* *
* Return that the data was not found. *
* *
*****************************************************************************/
return -1;
}
#endif
(2)ex-1.c
/*****************************************************************************
* *
* ex-1.c *
* ====== *
* *
* Description: Illustrates using an open-addressed hash table (see Chapter *
* 8). *
* *
*****************************************************************************/
#include <stdio.h>
#include "ohtbl.h"
/*****************************************************************************
* *
* Define the size of the hash table. *
* *
*****************************************************************************/
#define TBLSIZ 11
/*****************************************************************************
* *
* ------------------------------ match_char ------------------------------ *
* *
*****************************************************************************/
static int match_char(const void *char1, const void *char2) {
/*****************************************************************************
* *
* Determine whether two characters match. *
* *
*****************************************************************************/
return (*(const char *)char1 == *(const char *)char2);
}
/*****************************************************************************
* *
* ------------------------------- h1_char -------------------------------- *
* *
*****************************************************************************/
static int h1_char(const void *key) {
/*****************************************************************************
* *
* Define a simplistic auxilary hash function. *
* *
*****************************************************************************/
return *(const char *)key % TBLSIZ;
}
/*****************************************************************************
* *
* ------------------------------- h2_char -------------------------------- *
* *
*****************************************************************************/
static int h2_char(const void *key) {
/*****************************************************************************
* *
* Define a simplistic auxilary hash function. *
* *
*****************************************************************************/
return 1 + (*(const char *)key % (TBLSIZ - 2));
}
/*****************************************************************************
* *
* ------------------------------ print_table ----------------------------- *
* *
*****************************************************************************/
static void print_table(const OHTbl *htbl) {
int i;
/*****************************************************************************
* *
* Display the open-addressed hash table. *
* *
*****************************************************************************/
fprintf(stdout, "Table size is %d\n", ohtbl_size(htbl));
for (i = 0; i < TBLSIZ; i++) {
if (htbl->table[i] != NULL && htbl->table[i] != htbl->vacated) {
fprintf(stdout, "Slot[%03d]=%c\n", i, *(char *)htbl->table[i]);
}
else {
fprintf(stdout, "Slot[%03d]= \n", i);
}
}
return;
}
/*****************************************************************************
* *
* --------------------------------- main --------------------------------- *
* *
*****************************************************************************/
int main(int argc, char **argv) {
OHTbl htbl;
char *data,
c;
int retval,
i,
j;
/*****************************************************************************
* *
* Initialize the open-addressed hash table. *
* *
*****************************************************************************/
if (ohtbl_init(&htbl, TBLSIZ, h1_char, h2_char, match_char, free) != 0)
return 1;
/*****************************************************************************
* *
* Perform some open-addressed hash table operations. *
* *
*****************************************************************************/
for (i = 0; i < 5; i++) {
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
/**************************************************************************
* *
* The following expression produces "random" data while avoiding dupli- *
* cates. *
* *
**************************************************************************/
*data = ((8 + (i * 9)) % 23) + 'A';
fprintf(stdout, "Hashing %c:", *data);
for (j = 0; j < TBLSIZ; j++)
fprintf(stdout," %02d", (h1_char(data) + (j * h2_char(data))) % TBLSIZ);
fprintf(stdout, "\n");
if (ohtbl_insert(&htbl, data) != 0)
return 1;
print_table(&htbl);
}
for (i = 0; i < 5; i++) {
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
/**************************************************************************
* *
* The following expression works similar to the one above but produces *
* collisions. *
* *
**************************************************************************/
*data = ((8 + (i * 9)) % 13) + 'j';
fprintf(stdout, "Hashing %c:", *data);
for (j = 0; j < TBLSIZ; j++)
fprintf(stdout," %02d", (h1_char(data) + (j * h2_char(data))) % TBLSIZ);
fprintf(stdout, "\n");
if (ohtbl_insert(&htbl, data) != 0)
return 1;
print_table(&htbl);
}
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'R';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Trying to insert R again...Value=%d (1=OK)\n", retval);
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'n';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Trying to insert n again...Value=%d (1=OK)\n", retval);
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'o';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Trying to insert o again...Value=%d (1=OK)\n", retval);
fprintf(stdout, "Removing R, n, and o\n");
c = 'R';
data = &c;
if (ohtbl_remove(&htbl, (void **)&data) == 0)
free(data);
c = 'n';
data = &c;
if (ohtbl_remove(&htbl, (void **)&data) == 0)
free(data);
c = 'o';
data = &c;
if (ohtbl_remove(&htbl, (void **)&data) == 0)
free(data);
print_table(&htbl);
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'R';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Hashing %c:", *data);
for (j = 0; j < TBLSIZ; j++)
fprintf(stdout, " %02d", (h1_char(data) + (j * h2_char(data))) % TBLSIZ);
fprintf(stdout, "\n");
fprintf(stdout, "Trying to insert R again...Value=%d (0=OK)\n", retval);
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'n';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Hashing %c:", *data);
for (j = 0; j < TBLSIZ; j++)
fprintf(stdout, " %02d", (h1_char(data) + (j * h2_char(data))) % TBLSIZ);
fprintf(stdout, "\n");
fprintf(stdout, "Trying to insert n again...Value=%d (0=OK)\n", retval);
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'o';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Hashing %c:", *data);
for (j = 0; j < TBLSIZ; j++)
fprintf(stdout, " %02d", (h1_char(data) + (j * h2_char(data))) % TBLSIZ);
fprintf(stdout, "\n");
fprintf(stdout, "Trying to insert o again...Value=%d (0=OK)\n", retval);
print_table(&htbl);
fprintf(stdout, "Inserting X\n");
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'X';
if (ohtbl_insert(&htbl, data) != 0)
return 1;
print_table(&htbl);
if ((data = (char *)malloc(sizeof(char))) == NULL)
return 1;
*data = 'Y';
if ((retval = ohtbl_insert(&htbl, data)) != 0)
free(data);
fprintf(stdout, "Trying to insert into a full table...Value=%d (-1=OK)\n",
retval);
c = 'o';
data = &c;
if (ohtbl_lookup(&htbl, (void **)&data) == 0)
fprintf(stdout, "Found an occurrence of o\n");
else
fprintf(stdout, "Did not find an occurrence of X\n");
c = 'Z';
data = &c;
if (ohtbl_lookup(&htbl, (void **)&data) == 0)
fprintf(stdout, "Found an occurrence of Z\n");
else
fprintf(stdout, "Did not find an occurrence of Z\n");
/*****************************************************************************
* *
* Destroy the open-addressed hash table. *
* *
*****************************************************************************/
fprintf(stdout, "Destroying the hash table\n");
ohtbl_destroy(&htbl);
return 0;
}