哈希技术

1. 哈希的定义

在数据元素的存储位置和它的关键字之间建立一个映射关系f,通过f可以直接得到关键字所代表的数据元素

2. 哈希表

哈希技术中用于存储数据元素的数据结构

3. 哈希函数

哈希技术中的映射关系f

4. 哈希技术的关键点

① 哈希表:哈希技术需要具体的数据结构为基础,如数组、链表、二叉树......

②哈希函数:哈希技术需要映射关键字和数据元素的存储位置,依赖于数学运算,如四则运算、逻辑运算、比较......

5. 哈希的操作

① 创建哈希: Hash* Hash_Create();
② 销毁哈希: void Hash_Destroy(Hash* hash);
③ 清空哈希: void Hash_Clear(Hash* hash);
④ 加入键值对: int Hash_Add(Hash* hash, HashKey* key, HashValue* value);
⑤ 删除键值对: HashValue* Hash_Remove (Hash* hash, HashKey* key);
⑥ 根据建获取值: HashValue* Hash_Get(Hash* hash, HashKey* key);
⑦ 获取键值对数目: int Hash_Count(Hash* hash);

6. 哈希的实现

哈希表 = 数组 + 链表

① DList.h

#ifndef DLIST_H
#define DLIST_H

typedef enum _Ret
{
    RET_OK,
    RET_OOM,
    RET_STOP,
    RET_PARAMS,
    RET_FAIL
} Ret;

struct _DList;
typedef struct _DList DList;

typedef void (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

#endif

② DList.c

#include <stdlib.h>
#include "DList.h"

typedef struct _DListNode
{
    struct _DListNode* prev;
    struct _DListNode* next;

    void* data;
}DListNode;

struct _DList
{
    DListNode* first;
    DListDataDestroyFunc data_destroy;
    void* data_destroy_ctx;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
    if(thiz->data_destroy != NULL)
    {
        thiz->data_destroy(thiz->data_destroy_ctx, data);
    }

    return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
    DListNode* node = malloc(sizeof(DListNode));

    if(node != NULL)
    {
        node->prev = NULL;
        node->next = NULL;
        node->data = data;
    }

    return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
    if(node != NULL)
    {
        node->next = NULL;
        node->prev = NULL;
        dlist_destroy_data(thiz, node->data);
        free(node);
    }

    return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx)
{
    DList* thiz = malloc(sizeof(DList));

    if(thiz != NULL)
    {
        thiz->first = NULL;
        thiz->data_destroy = data_destroy;
        thiz->data_destroy_ctx = data_destroy_ctx;
    }

    return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
    DListNode* iter = thiz->first;

    while(iter != NULL && iter->next != NULL && index > 0)
    {
        iter = iter->next;
        index--;
    }

    if(!fail_return_last)
    {
        iter = index > 0 ? NULL : iter;
    }

    return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
    DListNode* node = NULL;
    DListNode* cursor = NULL;

    if((node = dlist_create_node(thiz, data)) == NULL)
    {
        return RET_OOM; 
    }

    if(thiz->first == NULL)
    {
        thiz->first = node;

        return RET_OK;
    }

    cursor = dlist_get_node(thiz, index, 1);
    
    if(index < dlist_length(thiz))
    {
        if(thiz->first == cursor)
        {
            thiz->first = node;
        }
        else
        {
            cursor->prev->next = node;
            node->prev = cursor->prev;
        }
        node->next = cursor;
        cursor->prev = node;
    }
    else
    {
        cursor->next = node;
        node->prev = cursor;
    }

    return RET_OK;
}

Ret dlist_prepend(DList* thiz, void* data)
{
    return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
    return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
    DListNode* cursor = dlist_get_node(thiz, index, 0);

    if(cursor != NULL)
    {
        if(cursor == thiz->first)
        {
            thiz->first = cursor->next;
        }

        if(cursor->next != NULL)
        {
            cursor->next->prev = cursor->prev;
        }

        if(cursor->prev != NULL)
        {
            cursor->prev->next = cursor->next;
        }

        dlist_destroy_node(thiz, cursor);
    }

    return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
    DListNode* cursor = dlist_get_node(thiz, index, 0);

    if(cursor != NULL)
    {
        *data = cursor->data;
    }

    return cursor != NULL ? RET_OK : RET_FAIL;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
    DListNode* cursor = dlist_get_node(thiz, index, 0);

    if(cursor != NULL)
    {
        cursor->data = data;
    }

    return cursor != NULL ? RET_OK : RET_FAIL;
}

size_t   dlist_length(DList* thiz)
{
    size_t length = 0;
    DListNode* iter = thiz->first;

    while(iter != NULL)
    {
        length++;
        iter = iter->next;
    }

    return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
    Ret ret = RET_OK;
    DListNode* iter = thiz->first;

    while(iter != NULL && ret != RET_STOP)
    {
        ret = visit(ctx, iter->data);

        iter = iter->next;
    }

    return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
    int i = 0;
    DListNode* iter = thiz->first;

    while(iter != NULL)
    {
        if(cmp(ctx, iter->data) == 0)
        {
            break;
        }
        i++;
        iter = iter->next;
    }

    return i;
}

void dlist_destroy(DList* thiz)
{
    DListNode* iter = thiz->first;
    DListNode* next = NULL;

    while(iter != NULL)
    {
        next = iter->next;
        dlist_destroy_node(thiz, iter);
        iter = next;
    }

    thiz->first = NULL;
    free(thiz);

    return;
}

③ HashTable.h

#ifndef HASHTABLE_H_
#define HASHTABLE_H_

#include "DList.h"

typedef int(*DataHashFunc)(void* data);

typedef DListDataDestroyFunc DataDestroyFunc;

typedef DListDataCompareFunc DataCompareFunc;

typedef DListDataVisitFunc DataVisitFunc;

typedef struct HashTable_
{
    DataHashFunc hashFunc;
    DList** slots;
    int slotNr;
    DataDestroyFunc dataDestroy;
    void* dataDestroyCtx;
} HashTable;

HashTable* HashTableCreate(DataDestroyFunc dataDestroy, void* ctx, DataHashFunc hashFunc, int slotNr);

Ret HashTableInsert(HashTable* hashTable, void* data);

Ret HashTableDelete(HashTable* hashTable, DataCompareFunc cmp, void* data);

Ret HashTableFind(HashTable* hashTable, DataCompareFunc cmp, void* data, void** retData);

int HashTableLength(HashTable* hashTable);

Ret HashTableForeach(HashTable* hashTable, DataVisitFunc visit, void* ctx);

void HashTableDestroy(HashTable* hashTable);


#endif

④ HashTable.c

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

HashTable* HashTableCreate(DataDestroyFunc dataDestroy, void* ctx, DataHashFunc hashFunc, int slotNr)
{
    HashTable* pNewHashTable = (HashTable*)malloc(sizeof(HashTable));
    
    if(pNewHashTable != NULL)
    {
        pNewHashTable->hashFunc = hashFunc;
        pNewHashTable->slotNr = slotNr;
        pNewHashTable->dataDestroy = dataDestroy;
        pNewHashTable->dataDestroyCtx = ctx;
        
        pNewHashTable->slots = (DList**)malloc(slotNr * sizeof(DList*));
        if(pNewHashTable->slots != NULL)
        {
            memset(pNewHashTable->slots, 0, (slotNr * sizeof(DList*)));
        }
        else
        {
            free(pNewHashTable);
            pNewHashTable = NULL;
        }
    }
    
    return pNewHashTable;
}

Ret HashTableInsert(HashTable* hashTable, void* data)
{
    Ret ret = RET_FAIL;
    int index = 0;
    
    if(hashTable != NULL)
    {
        index = hashTable->hashFunc(data) % hashTable->slotNr;
        
        if(hashTable->slots[index] == NULL)
        {
            hashTable->slots[index] = dlist_create(hashTable->dataDestroy, hashTable->dataDestroyCtx);
        }
        
        dlist_append(hashTable->slots[index], data);
        
        ret = RET_OK;
    }
    
    return ret;
}

Ret HashTableDelete(HashTable* hashTable, DataCompareFunc cmp, void* data)
{
    Ret ret = RET_FAIL;
    int index = 0;
    DList* dList = NULL;
    
    if(hashTable != NULL)
    {
        index = hashTable->hashFunc(data) % hashTable->slotNr;
        
        dList = hashTable->slots[index];
        
        if(dList != NULL)
        {
            index = dlist_find(dList, cmp, data);
            
            dlist_delete(dList, index);
            
            ret = RET_OK;
        }
    }
    
    return ret;
}

Ret HashTableFind(HashTable* hashTable, DataCompareFunc cmp, void* data, void** retData)
{
    Ret ret = RET_FAIL;
    int index = 0;
    DList* dList = NULL;
    
    if(hashTable != NULL && cmp != NULL && data != NULL && retData != NULL)
    {
        index = hashTable->hashFunc(data) % hashTable->slotNr;
        
        dList = hashTable->slots[index];
        
        if(dList != NULL)
        {
            index = dlist_find(dList, cmp, data);
            
            dlist_get_by_index(dList, index, retData);
            
            ret = RET_OK;
        }
    }
    
    return ret;
    
}

int HashTableLength(HashTable* hashTable)
{
    int sum = 0;
    int index = 0;
    
    if(hashTable != NULL)
    {
        for(index = 0; index < hashTable->slotNr; index++)
        {
            if(hashTable->slots[index] != NULL)
            {
                sum = sum + dlist_length(hashTable->slots[index]);
            }
        }
    }
    
    return sum;
}

Ret HashTableForeach(HashTable* hashTable, DataVisitFunc visit, void* ctx)
{
    int index = 0;
    
    if(hashTable != NULL)
    {
        for(index = 0; index < hashTable->slotNr; index++)
        {
            if(hashTable->slots[index] != NULL)
            {
                dlist_foreach(hashTable->slots[index], visit, ctx);
            }
        }
    }
    
    return RET_OK;
}

void HashTableDestroy(HashTable* hashTable)
{
    int index = 0;
    if(hashTable != NULL)
    {
        if(hashTable->slots != NULL)
        {
            for(index = 0; index < hashTable->slotNr; index++)
            {
                if(hashTable->slots[index] != NULL)
                {
                    dlist_destroy(hashTable->slots[index]);
                    hashTable->slots[index] = NULL;
                }
            }
            
            free(hashTable->slots);
            hashTable->slots = NULL;    
        }
        
        free(hashTable);
        hashTable = NULL;
    }    
}

注:数组是最简单的哈希实现

原文地址:https://www.cnblogs.com/wulei0630/p/9351056.html