美文网首页C++
Build your own hash table in C[3

Build your own hash table in C[3

作者: greatseniorsde | 来源:发表于2023-12-30 03:43 被阅读0次

    Step 3 Hash Table APIs

    In this implementations, hash table provides public APIs like get and set; Internally, hash table supports resize, iterate etc.

    // hash_table.c
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "hash_table.h"
    
    
    #define INITIAL_CAPACITY 10
    #define FNV_offset_basis 14695981039346656037UL
    #define FNV_prime 1099511628211UL
    
    item* create_item(const char* key, void* value) {
        item* i = malloc(sizeof(item));
        i->key = strdup(key);
        i->value = value;
        return i;
    }
    
    void free_item(item* i) {
        free((void*)i->key);
        free(i->value);
        free(i);
    }
    
    hash_table* create_ht() {
        hash_table* ht = malloc(sizeof(hash_table));
        ht->size = INITIAL_CAPACITY;
        ht->count = 0;
        ht->items = calloc(ht->size, sizeof(item*));
        return ht;
    }
    
    void free_ht(hash_table* ht) {
        for (int i=0; i<ht->size; ++i) {
            item* item = ht->items[i];
            if (item != NULL){
                free_item(item);
            }
        }
        free(ht->items);
        free(ht);
    }
    
    // https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function
    // algorithm fnv-1a is
    //     hash := FNV_offset_basis
    //     for each byte_of_data to be hashed do
    //         hash := hash XOR byte_of_data
    //         hash := hash × FNV_prime
    //     return hash
    
    
    uint64_t hash(const char* key) {
        uint64_t hash = FNV_offset_basis;
        int len = strlen(key);
        for (int i=0; i<len; ++i) {
            hash ^= key[i];
            hash *= FNV_prime;
        }
        return hash;
    }
    
    void* get(hash_table* ht, const char* key){
        uint64_t index = hash(key) % ht->size;
        while (ht->items[index] != NULL){
            if (strcmp(ht->items[index]->key, key) == 0) {
                return ht->items[index]->value;
            }
            index += 1;
            if (index >= ht->size) {
                index = 0;
            }
        }
        return NULL;
    }
    
    void set(hash_table* ht, const char* key, void* value) {
    
        // If more than half of the capacity is filled, expand the table
        if (ht->count > ht->size / 2) {
            resize(ht);
        }
    
        uint64_t index = hash(key) % ht->size;
    
        // Look up if the key already exists, update the value if so
        while (ht->items[index] != NULL){
            if (strcmp(ht->items[index]->key, key) == 0) {
                ht->items[index]->value = value;
                return;
            }
            index += 1;
            if (index >= ht->size) {
                index = 0;
            }
        }
    
        // Key doesn't exist yet, add the item
        ht->items[index] = create_item(key, value);
        ht->count++;
    }
    
    size_t size(hash_table* ht){
        return ht->count;
    }
    
    void resize(hash_table* ht){
        item** new_items = calloc(ht->size * 2, sizeof(item*));
            for (int i=0; i<ht->size; ++i) {
                item* item = ht->items[i];
                if (item != NULL) {
                    uint64_t new_index = hash(item->key) % (ht->size * 2);
                    while (new_items[new_index] != NULL) {
                        new_index += 1;
                        if (new_index >= ht->size * 2) {
                            new_index = 0;
                        }
                    }
                    new_items[new_index] = item;
                }
            }
            free(ht->items);
            ht->items = new_items;
            ht->size *= 2;
    }
    
    hash_iterator create_iterator(hash_table* ht){
        hash_iterator it;
        it.ht = ht;
        it.index = 0;
        return it;
    }
    
    bool next(hash_iterator* it){
        hash_table* ht = it->ht;
        while (it->index < ht->size) {
            size_t i = it->index;
            it->index += 1;
    
            if (ht->items[i] != NULL) {
                item* item = ht->items[i];
                it->key = item->key;
                it->value = item->value;
                return true;
            }
        }
        return false;
    }
    
    void dump(hash_table* ht){
        if (ht == NULL) {
            return;
        }
        if (ht->count == 0) {
            printf("empty\n");
        }
    
        for (int i=0; i<ht->size; ++i) {
            item* item = ht->items[i];
            if (item != NULL) {
                printf("index: %d; key: %s; value: %s\n", i, item->key, (char*)item->value);
            }
        }
    }
    
    
    int main(int argc, char** argv) {
      hash_table* ht = create_ht();
      set(ht, "key1", "val1");
      set(ht, "key2", "val2");
      set(ht, "key3", "val3");
      set(ht, "key4", "val4");
      set(ht, "key5", "val5");
      set(ht, "key6", "val6");
      set(ht, "key7", "val7");
      set(ht, "key8", "val8");
      set(ht, "key8", "newVal8");
      dump(ht);
    }
    
    
    //hash_table.h
    #include <stdbool.h>
    
    // Hashtable Structure
    typedef struct {
        const char* key;
        void* value;
    } item;
    
    typedef struct {
        item** items;
        int size;
        int count;
    } hash_table;
    
    typedef struct {
        hash_table* ht;
        size_t index;
        const char* key;
        void* value;
    } hash_iterator;
    
    // Public APIs:
    hash_table* create_ht();
    
    void free_ht(hash_table* ht);
    
    void* get(hash_table* ht, const char* key);
    
    void set(hash_table* ht, const char* key, void* value);
    
    //void* remove(hash_table* ht, const char* key);
    
    size_t size(hash_table* ht);
    
    bool next(hash_iterator* it);
    
    
    // Internal APIs:
    uint64_t hash(const char* key);
    void resize(hash_table* ht);
    item* create_item(const char* key, void* value);
    void free_item(item* i);
    
    

    demo run:

    ./hash_table                                   
    index: 1; key: key7; value: val7
    index: 3; key: key1; value: val1
    index: 4; key: key8; value: newVal8
    index: 5; key: key3; value: val3
    index: 8; key: key4; value: val4
    index: 10; key: key6; value: val6
    index: 14; key: key2; value: val2
    index: 19; key: key5; value: val5
    

    相关文章

      网友评论

        本文标题:Build your own hash table in C[3

        本文链接:https://www.haomeiwen.com/subject/ecojndtx.html