字典與哈希表 | 自己實現Redis源代碼(3)

通過對《Redis設計與實現》一書的學習,我打算動手自己實現一份“Redis源代碼”作爲自己的學習記錄。

對Redis感興趣的同學可以查看我的另一篇文章 造個輪子 | 自己動手寫一個Redis

本章介紹的是Redis源代碼中的字典及其內部哈希表的實現。



字典dict的實現


dict的API

(1)創建一個新的字典

dict dictCreate(dictType type,int hashSize);

(2)根據key尋找其在hashTable中對應的結點

dictEntry lookup(dict d,void *key);

(3)將給定的鍵值對添加到字典裏面

(如果鍵已經存在於字典,那麼用新值取代原有的值)
bool dictInsert(dict d, void key, void *val);

(4)返回給定的鍵的值

void dictFetchValue(dict d, void *key);

(5)從字典中刪除給定鍵所對應的鍵值對

void dictDelete(dict d, void key);

(6)釋放給定字典,以及字典中包含的所有鍵值對

void dictRelease(dict *d);



頭文件

#ifndef __DICT_H
#define __DICT_H

//哈希表的結點使用dictEntry結構來表示
//每個dictEntry結構都保存着一個key-value
typedef struct dictEntry{
    //鍵
    void *key;
    //值
    void *value;
    //指向下個哈希表結點,形成鏈表——避免鍵衝突
    struct dictEntry *next;
}dictEntry;

//保存一組用於操作特定類型鍵值對的函數
typedef struct dictType {
    //計算哈希值的函數
    unsigned int (*hashFunction)(void *key,int size);
    //複製鍵的函數
    void *(*keyDup)(void *key);
    //複製值的函數
    void *(*valDup)(void *obj);
    //對比鍵的函數
    int (*keyCompare)(void *key1, void *key2);
    //銷燬鍵的函數
    void (*keyDestructor)(void *key);
    //銷燬值的函數
    void (*valDestructor)(void *obj);
} dictType;

//哈希表
typedef struct dictht {
    //哈希表數組
    dictEntry **table;
    //哈希表大小
    int size;
    //該哈希表已有結點的數量
    int used;
} dictht;

//字典
//其實字典就是對普通的哈希表再做一層封裝
//增加了一些屬性
typedef struct dict {
    //類型特定函數
    dictType *type;
    //哈希表
    dictht *ht;
} dict;

//創建一個新的字典
//需要傳入哈希表的大小
dict *dictCreate(dictType *type,int hashSize);
//根據key尋找其在hashTable中對應的結點
dictEntry* lookup(dict *d,void *key);
//將給定的鍵值對添加到字典裏面
//將給定的鍵值對添加到字典裏面,如果鍵已經存在於字典,
//那麼用新值取代原有的值
bool dictInsert(dict *d, void *key, void *val);
//返回給定的鍵的值
void *dictFetchValue(dict *d, void *key);
//從字典中刪除給定鍵所對應的鍵值對
void dictDelete(dict *d, void *key);
//釋放給定字典,以及字典中包含的所有鍵值對
void dictRelease(dict *d);

#endif



dict API的實現

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dict.h"

//哈希表的大小
#define HASHSIZE 10

//定義對哈希表進行相關操作的函數集
//計算哈希值的函數
unsigned int myHashFunction(void *key,int size){
    char* charkey=(char*)key;
    unsigned int hash=0;
    for(;*charkey;++charkey){
        hash=hash*33+*charkey;
    }
    return hash%size;
}
//複製鍵的函數
void *myKeyDup(void *key){
    return key;
}
//複製值的函數
void *myValDup(void *obj){
    return obj;
}
//對比鍵的函數
int myKeyCompare(void *key1, void *key2){
    char*charkey1=(char*)key1;
    char*charkey2=(char*)key2;
    return strcmp(charkey1,charkey2);
}
//銷燬鍵的函數
void myKeyDestructor(void *key){
    //free(key);
}
//銷燬值的函數
void myValDestructor(void *obj){
    //free(obj);
}

//創建一個新的字典
dict *dictCreate(dictType *type,int hashSize){
    dict* d=(dict*)malloc(sizeof(dict));
    //對hashTable進行相關操作的特定函數集
    if(type==NULL){
        printf("PIG Redis WARNING : Type is NULL.\n");
    }
    d->type=type;
    //哈希表初始化
    d->ht=(dictht*)malloc(sizeof(dictht));
    d->ht->size=hashSize;
    d->ht->used=0;
    d->ht->table=(dictEntry**)malloc(sizeof(dictEntry*)*hashSize);
    //全部結點都設爲NULL
    for(int i=0;i<hashSize;i++){
        d->ht->table[i]=NULL;
    }
    return d;
}

//根據key尋找其在hashTable中對應的結點
dictEntry* lookup(dict *d,void *key){
    dictEntry* node;
    //該key在hashTable中對應的下標
    unsigned int index;
    index=d->type->hashFunction(key,d->ht->size);
    for(node=d->ht->table[index];node;node=node->next){
        if(!(d->type->keyCompare(key,node->key))){
            return node;
        }
    }
    return NULL;
}

//將給定的鍵值對添加到字典裏面
bool dictInsert(dict *d, void *key, void *val){
    unsigned int index;
    dictEntry* node;
    if(!(node=lookup(d,key))){
        index=d->type->hashFunction(key,d->ht->size);
        node=(dictEntry*)malloc(sizeof(dictEntry));
        if(!node)return false;
        node->key=d->type->keyDup(key);
        node->next=d->ht->table[index];
        d->ht->table[index]=node;
    }
    //若存在,直接修改其對應的value值
    node->value=d->type->valDup(val);
    return true;
}

//返回給定的鍵的值
void *dictFetchValue(dict *d, void *key){
    unsigned int index;
    dictEntry* node;
    //找不到這個結點
    if(!(node=lookup(d,key))){
        return NULL;
    }
    return node->value;
}

//從字典中刪除給定鍵所對應的鍵值對
void dictDelete(dict *d, void *key){
    dictEntry* node;
    dictEntry* temp;
    //該key在hashTable中對應的下標
    unsigned int index;
    index=d->type->hashFunction(key,d->ht->size);
    node=d->ht->table[index];
    //key相同
    if(!(d->type->keyCompare(key,node->key))){
        d->ht->table[index]=node->next;
        d->type->keyDestructor(node->key);
        d->type->valDestructor(node->value);
        free(node);
        return;
    }
    temp=node;
    node=node->next;
    while(node){
        if(!(d->type->keyCompare(key,node->key))){
            temp->next=node->next;
            d->type->keyDestructor(node->key);
            d->type->valDestructor(node->value);            
            free(node);
            return;
        }
        temp=node;
        node=node->next;
    }
    return;
}
//釋放給定字典,以及字典中包含的所有鍵值對
void dictRelease(dict *d){
    dictEntry* node;
    dictEntry* temp;
    for(int i=0;i<d->ht->size;i++){
        node=d->ht->table[i];
        //printf("%d\n",i);
        while(node){
            char* t=(char*)node->value;
            //printf("%s\n",t);
            temp=node;
            node=node->next;
            d->type->keyDestructor(temp->key);
            d->type->valDestructor(temp->value);
            free(temp);
        }
    }
    free(d->ht);
    free(d->type);
    free(d);
}

/*int main(){
    dictType*type=(dictType*)malloc(sizeof(dictType));
    type->hashFunction=myHashFunction;
    type->keyDup=myKeyDup;
    type->valDup=myValDup;
    type->keyCompare=myKeyCompare;
    type->keyDestructor=myKeyDestructor;
    type->valDestructor=myValDestructor;
    dict* d=dictCreate(type,HASHSIZE);
    
    char*key1="sss";
    char*value1="111";
    bool result=dictInsert(d,key1,value1);
    if(result){
        printf("insert1 success\n");
    }else{
        printf("insert1 fail\n");
    }

    char*key2="3sd";
    char*value2="ddd";
    result=dictInsert(d,key2,value2);
    if(result){
        printf("insert2 success\n");
    }else{
        printf("insert2 fail\n");
    }

    char*key3="ddds";
    char*value3="1ss";
    result=dictInsert(d,key3,value3);
    if(result){
        printf("insert3 success\n");
    }else{
        printf("insert3 fail\n");
    }
    
    char *value4=(char*)dictFetchValue(d,key3);
    printf("---%s\n",value4);

    dictDelete(d,key3);
    value4=(char*)dictFetchValue(d,key3);
    printf("---%s\n",value4);

    dictRelease(d);
    system("pause");
    return 0;
}*/



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章