Added hashtable
This commit is contained in:
+157
-88
@@ -7,124 +7,193 @@
|
||||
#include "hashtable.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Hash function for hashtable
|
||||
*
|
||||
* This function takes a string key and calculates a hash value.
|
||||
* The hash value is used to determine the index in the hashtable
|
||||
* where the key-value pair should be stored.
|
||||
*
|
||||
* @param key The string key to hash
|
||||
* @return The calculated hash value
|
||||
*/
|
||||
|
||||
// entry in the hashtable
|
||||
struct entry
|
||||
{
|
||||
const char *key;
|
||||
void *value;
|
||||
struct entry *next;
|
||||
};
|
||||
|
||||
struct htobj
|
||||
{
|
||||
int size;
|
||||
struct entry **table;
|
||||
};
|
||||
|
||||
struct item {
|
||||
struct entry *prev, *found;
|
||||
int index;
|
||||
};
|
||||
|
||||
static unsigned int hash(const char *key)
|
||||
{
|
||||
unsigned int hash = 0; // Initialize hash value to 0
|
||||
unsigned int hash = 0;
|
||||
|
||||
// Iterate over each character in the key string
|
||||
while (*key)
|
||||
{
|
||||
// Calculate the hash value by multiplying the current hash value
|
||||
// with 32 (2^5) and subtracting the current hash value. Then add the
|
||||
// ASCII value of the current character.
|
||||
hash = (hash << 5) - hash + *key++;
|
||||
}
|
||||
|
||||
// Return the calculated hash value
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a new hashtable
|
||||
*
|
||||
* This function creates a new hashtable with the specified size.
|
||||
* It initializes the table with NULL entries.
|
||||
*
|
||||
* @param size The size of the hashtable
|
||||
* @return A pointer to the newly created hashtable
|
||||
*/
|
||||
hashtable *hashtable_new(int size)
|
||||
hashtable hashtable_new(int size)
|
||||
{
|
||||
// Allocate memory for the hashtable
|
||||
hashtable *h = malloc(sizeof(hashtable));
|
||||
hashtable h = malloc(sizeof(struct htobj));
|
||||
|
||||
// Set the size of the hashtable
|
||||
h->size = size;
|
||||
|
||||
// Allocate memory for the entry pointers
|
||||
h->table = malloc(sizeof(entry *) * size);
|
||||
|
||||
// Initialize all entries to NULL
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
h->table[i] = NULL;
|
||||
}
|
||||
h->table = calloc(size, sizeof(struct entry *));
|
||||
|
||||
// Return the newly created hashtable
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
// hashtable_insert
|
||||
void hashtable_insert(hashtable *h, const char *key, void *value) {
|
||||
struct item hashtable_lookup_item(hashtable h, const char *key)
|
||||
{
|
||||
struct item result = {
|
||||
.found = NULL,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
// Calculate the index using the hash function
|
||||
int index = hash(key) % h->size;
|
||||
struct entry *e = h->table[index];
|
||||
struct entry *prev = NULL;
|
||||
|
||||
// Create a new entry
|
||||
entry *e = malloc(sizeof(entry));
|
||||
e->key = key;
|
||||
e->value = value;
|
||||
e->next = NULL;
|
||||
|
||||
// Insert the entry at the beginning of the linked list
|
||||
e->next = h->table[index];
|
||||
h->table[index] = e;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// hashtable_lookup
|
||||
void *hashtable_lookup(hashtable *h, const char *key) {
|
||||
|
||||
// Calculate the index using the hash function
|
||||
int index = hash(key) % h->size;
|
||||
|
||||
// Traverse the linked list at the index
|
||||
entry *e = h->table[index];
|
||||
while (e != NULL) {
|
||||
if (strcmp(e->key, key) == 0) {
|
||||
return e->value;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
// Return NULL if the key is not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// hashtable_remove
|
||||
void hashtable_remove(hashtable *h, const char *key) {
|
||||
|
||||
// Calculate the index using the hash function
|
||||
int index = hash(key) % h->size;
|
||||
|
||||
// Traverse the linked list at the index
|
||||
entry *e = h->table[index];
|
||||
entry *prev = NULL;
|
||||
while (e != NULL) {
|
||||
if (strcmp(e->key, key) == 0) {
|
||||
if (prev == NULL) {
|
||||
h->table[index] = e->next;
|
||||
} else {
|
||||
prev->next = e->next;
|
||||
}
|
||||
free(e);
|
||||
return;
|
||||
result.index = index;
|
||||
result.found = e;
|
||||
result.prev = prev;
|
||||
return result;
|
||||
}
|
||||
prev = e;
|
||||
e = e->next;
|
||||
}
|
||||
return result; // empty in this case
|
||||
}
|
||||
|
||||
void *hashtable_set(hashtable h, const char *key, void *value)
|
||||
{
|
||||
|
||||
struct item item = hashtable_lookup_item(h, key);
|
||||
// not found - insert new
|
||||
if (item.found == NULL) {
|
||||
int index = hash(key) % h->size;
|
||||
|
||||
// Create a new entry
|
||||
struct entry *e = malloc(sizeof(struct entry));
|
||||
e->key = strdup(key); // key is the copy
|
||||
e->value = value;
|
||||
e->next = NULL;
|
||||
|
||||
// Insert the entry at the beginning of the linked list
|
||||
e->next = h->table[index];
|
||||
h->table[index] = e;
|
||||
return NULL;
|
||||
}
|
||||
// found replace the value
|
||||
void *old_value = item.found->value;
|
||||
item.found-> value = value;
|
||||
|
||||
return old_value;
|
||||
}
|
||||
|
||||
void *hashtable_lookup(hashtable h, const char *key)
|
||||
{
|
||||
struct item item = hashtable_lookup_item(h, key);
|
||||
if (item.found != NULL) {
|
||||
return item.found->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *hashtable_remove(hashtable h, const char *key)
|
||||
{
|
||||
struct item item = hashtable_lookup_item(h, key);
|
||||
if (item.found == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// found, so detete it
|
||||
if (item.prev != NULL) {
|
||||
item.prev->next = item.found->next;
|
||||
} else {
|
||||
h->table[item.index] = item.found->next;
|
||||
}
|
||||
// free unused memory
|
||||
void *value = item.found->value; // remember value
|
||||
free((void*) item.found->key); // free key
|
||||
free((void*) item.found); // free entry
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void hashtable_destroy_bucket(hashtable h, int i)
|
||||
{
|
||||
struct entry *e = h->table[i];
|
||||
while (e != NULL) {
|
||||
free((void*)e->key);
|
||||
e = e->next;
|
||||
free(e);
|
||||
}
|
||||
}
|
||||
|
||||
void hashtable_destroy(hashtable h)
|
||||
{
|
||||
if (h==NULL) return;
|
||||
for (int i = 0; i < h->size; i++) {
|
||||
hashtable_destroy_bucket(h, i);
|
||||
}
|
||||
free (h->table);
|
||||
free(h);
|
||||
}
|
||||
|
||||
ht_iterator hashtable_iter(hashtable h)
|
||||
{
|
||||
ht_iterator iter = {
|
||||
.h = h,
|
||||
.index = -1,
|
||||
.entry = NULL,
|
||||
};
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool ht_iter_next(ht_iterator *iter)
|
||||
{
|
||||
if (iter == NULL) {
|
||||
return false;
|
||||
}
|
||||
hashtable h = iter->h;
|
||||
|
||||
while(true) {
|
||||
if (iter->index >= h->size) {
|
||||
return false;
|
||||
}
|
||||
if (iter->entry == NULL) {
|
||||
iter->index++;
|
||||
iter->entry = h->table[iter->index];
|
||||
} else {
|
||||
iter->entry = iter->entry->next;
|
||||
}
|
||||
if (iter->entry != NULL) return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const char *ht_iter_key(ht_iterator *iter)
|
||||
{
|
||||
if (iter == NULL || iter->entry == NULL) return NULL;
|
||||
return iter->entry->key;
|
||||
}
|
||||
|
||||
void *ht_iter_value(ht_iterator *iter)
|
||||
{
|
||||
if (iter == NULL || iter->entry == NULL) return NULL;
|
||||
return iter->entry->value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user