C语言 实现 HashTable

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/**----------------------------------------哈希表节点-----------------------------------**/
typedef struct _Node {
    void * key;
    void * value;
    int  hash;
    struct _Node * next;
} Node;
/**----------------------------------------哈希表节点结束-------------------------------**/
/**-------------------------------------------------------------------------------------**/
/**-------------------------------------------------------------------------------------**/
/**-------------------------------------------------------------------------------------**/
/**----------------------------------------哈希表---------------------------------------**/
typedef  struct _HashTable {
    int cnt;
    int tableLength;
    Node ** tables;
    // simple Methord
    void (*put)(struct _HashTable *this, const void *key, void* value);
    void*(*get)(struct _HashTable *this, const void *key);
    void (*destroy)(struct _HashTable *this);
    void (*resize)(struct _HashTable *this);
    // help Methord 需要声明
    Node* (*Create_Node)(const void * key, void* value, int hash);
    void  (*Destory_Node)(Node * node);
    int   (*Compute_Hash)(const void * key);
    int   (*Keys_Equal)(const void * s, const void * t);
} HashTable;

void put(HashTable *this, const void *key, void * value) {
    int hash = this -> Compute_Hash(key);
    int pos  = hash & (this -> tableLength - 1);
    Node * head = this -> tables[pos];
    while(head != NULL) {
        if (this -> Keys_Equal(key, head -> key) == 0) {
            head -> value = value;
            return;
        }
        head = head -> next;
    }
    if (this -> cnt  >= (int)(this -> tableLength * 0.75)) {
        this -> resize(this);
        pos  = hash & (this -> tableLength - 1);
    }
    this -> cnt = this -> cnt + 1;
    Node * in = this -> Create_Node(key, value, hash);
    in -> next  = this -> tables[pos];
    this -> tables[pos] = in;
}

void* get(HashTable *this, const void *key) {
    int hash = this -> Compute_Hash(key);
    int pos  = hash & (this -> tableLength - 1);
    Node * head = this -> tables[pos];
    while(head != NULL) {
        if (this -> Keys_Equal(key, head -> key) == 0) {
            return head -> value;
        }
        head = head -> next;
    }
    return NULL;
}
void resize(HashTable *this) {
    int tableLength  =  this -> tableLength << 1;
    int i;
    Node * tmp;
    Node ** tables = (Node **)malloc(sizeof(Node *) * tableLength);
    memset(tables, 0, sizeof(Node *) * tableLength);

    // 拷贝 速度
    for(i = 0; i < this -> tableLength; ++i) {
        Node * head = this -> tables[i];
        while(head != NULL) {
            tmp = head;
            head = head -> next;
            int pos =  tmp -> hash & (tableLength - 1 );
            tmp -> next = tables[pos];
            tables[pos] = tmp;
        }
    }
    // 防止被别人申请到 但是不是0,其实不操作也没事
    memset(this -> tables, 0, sizeof(Node *) * this -> tableLength);
    free(this -> tables);
    this -> tables = tables;
    this -> tableLength = tableLength;
}
// 最后写 这是 C/C++ 语言最恶心的地方,切记
void destroy(HashTable *this) {
    int i = this -> tableLength;
    Node * next;
    for(i = 0; i < this -> tableLength; ++i) {
        Node * now  = this -> tables[i];
        while(now != NULL) {
            next = now -> next;
            this -> Destory_Node(now);
            now = next;
        }
    }
    free(this -> tables);
}

/**
 * @param Create_Node   创建hash节点的函数
 * @param Compute_Hash  计算hash节点key 的hashCode 的函数
 * @param Keys_Equal    判断hash节点key 相等的函数,判断  == 0 代表相等
 * @param Destory_Node  销毁hash节点的函数:
 * Description: 初始化 hash表
 *  之所以 需要填写 这么多的函数,主要是因为,HashNode 的key, value  在是指针的情况下,需要确定
 *      (1):初始化Node: 是拷贝模式,还是 直接使用模式
 *      (2):销毁  Node: 是否需要 去 free 掉
 *  所以 需要 手动的传递这么多函数
 *  一个 字符串作为 key
 */
HashTable * initTable(Node* (*Create_Node)(const void * key, void * value, int hash),
                    int (*Compute_Hash)(const void * key),
                    int (*Keys_Equal)(const void *s, const void *t),
                    void (*Destory_Node)(Node * node)) {
    HashTable * ans = (HashTable*)malloc(sizeof(HashTable));
    ans -> cnt = 0 ;
    ans -> tableLength = 8;
    ans -> put = put;
    ans -> get = get;
    ans -> destroy = destroy;
    ans -> resize  = resize;
    ans -> Create_Node  = Create_Node;
    ans -> Compute_Hash = Compute_Hash;
    ans -> Keys_Equal   = Keys_Equal;
    ans -> Destory_Node = Destory_Node;
    Node ** tables = (Node **)malloc(sizeof(Node *) * ans -> tableLength);
    memset(tables, 0, sizeof(Node *) * ans -> tableLength);
    ans -> tables = tables;
    return ans;
}


/**----------------------------------------哈希表结束---------------------------------------**/

/*
    下面三个函数,主要实现
        key(type = "字符串", mode = "拷贝模式")
        value(type = "int", mode = "拷贝模式")
*/
Node * initNode(const void * _key, void * _value, int hash){
    Node * in   = (Node *)malloc(sizeof(Node));

    char * key  = (char *)_key;
    int kLen    = strlen(key);
    char * copy = (char *)malloc(sizeof(char) * (kLen + 1));
    strcpy(copy, key);
    in -> key   = (void *) copy;

    int * value = (int *)malloc(sizeof(int));
    *value = *((int*)_value);
    in -> value = value;

    in -> hash  = hash;
    in -> next  = NULL;
    return in;
}
void destoryNode(Node * node) {
    free(node -> key);
    free(node -> value);
    node -> key = node -> next = node -> value = NULL;
    free(node);
}
int String_Hash_Code(const void * _ch) {
    const char * ch = (const char *)_ch;
    int i = 0, ans = 0;
    for(i = 0 ; ch[i] != '\0'; ++i) {
        ans = 31 * ans + ch[i];
    }
    return ans;
}

int stringEqual(const void * _s, const void * _t) {
    return strcmp(_s, _t);
}

int main() {
    HashTable* table = initTable(initNode, String_Hash_Code, stringEqual, destoryNode);
    char a[20];
    int  value, n;
    scanf("%d", &n);
    for(int w = 0; w < n; ++w) {
        scanf("%s %d", a, &value);
        table -> put(table, a, &value);
    }
    printf("table size %d, length %d\n", table -> cnt, table -> tableLength);
    printf("%s, %d\n", "1221",  *(int*)table -> get(table, "1221"));
    int* ans = (int*)table -> get(table, "12312");
    printf("%s, %d\n", "12312", ans == NULL ? -1 : *ans);
    table -> destroy(table);
    free(table);
    return 0;
}

 

posted @ 2020-01-15 19:43  默默无语敲代码  阅读(596)  评论(0编辑  收藏  举报