哈希表(1)

哈希表也称散列表,是根据关键码值而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。哈希表的查找速度非常快,几乎是O(1)的时间复杂度。

下面我们实现的哈希表期望存储的数据是键值对的结构。

头文件:

hash.h:
#pragma once

#include
#include

#define HashMaxSize 1000

typedef int KeyType;
typedef int ValType;

typedef enum{
        Empty,
            Valid,
                Deleted,

}Stat;

typedef struct HashElem{
        KeyType key;
            ValType value;
                Stat stat;

}HashElem;

typedef size_t (*HashFunc)(KeyType key); 

typedef  struct HashTable{
        HashElem data[HashMaxSize];
            size_t size;
                HashFunc func;

}HashTable;

size_t HashFuncDefault(KeyType key);
void HashPrint(HashTable* ht,const char* msg);
void HashInit(HashTable* ht,HashFunc hash_func);
void HashDestroy(HashTable* ht);
void HashInsert(HashTable* ht,KeyType key,ValType value);
int HashFind(HashTable* ht,KeyType key,ValType* value);
void HashRemove(HashTable* ht,KeyType key);
  • 初始化
void HashInit(HashTable* ht,HashFunc hash_func){
    if(ht == NULL)
        return;
    ht->size = 0;
    ht->func = hash_func;
    size_t i = 0;
    for(;i < HashMaxSize;++i){
        ht->data[i].stat = Empty;
    }
    return;
}
  • 销毁
void HashDestroy(HashTable* ht){
    if(ht == NULL)
        return;
    ht->size = 0;
    ht->func = NULL;
    return;
}
  • 插入
void HashInsert(HashTable* ht,KeyType key,ValType value){
    if(ht == NULL)//非法输入
        return;
    if(ht->size >= 0.8*HashMaxSize)//判定hash表能否继续插入(根据负载因子判定),这里我们假定负载因子为0.8
        return;
    size_t offset = ht->func(key);//根据key计算offset
    //从offset位置开始线性的往后查找,找到第一个状态为Empty的元素来进行插入
    while(1){
        if(ht->data[offset].stat != Valid){
            //此时找到了一个合适的位置来放置要插入的元素
            ht->data[offset].stat = Valid;
            ht->data[offset].key = key;
            ht->data[offset].value = value;
            //++size
            ++ht->size;
            return;
        }
        else if(ht->data[offset].stat == Valid && ht->data[offset].key == key){
            //hash表中存在了一个key相同的元素,此时我们单纯的认为插入失败
            return;
        }
        else{
            ++offset;
            if(offset >= HashMaxSize)
                offset = 0;
        }
    }
    //如果发现了key相同的元素,此时认为插入失败
    return;
}
  • 查找
int HashFind(HashTable* ht,KeyType key,ValType* value){
    if(ht == NULL || value == NULL)
        return 0;
    if(ht->size == 0)
        return 0;
    size_t offset = ht->func(key);//根据key计算出offset
    while(1){//从offset开始往后进行查找,每次取得一个元素,使用key进行比较
        //如果找到了key相同的元素,此时直接把value返回,并且认为查找成功
        if(ht->data[offset].key == key && ht->data[offset].stat == Valid){
            //找到了
            *value = ht->data[offset].value;
            return 1;
        }
        else if(ht->data[offset].stat == Empty)
            //如果发现当前元素是一个空元素,此时认为查找失败
            return 0;
        else{
            //如果发现当前的key不相同,就继续往后查找
            ++offset;
            offset = offset>=HashMaxSize?0:offset;
        }
    }
    return 0;
}
  • 删除
void HashRemove(HashTable* ht,KeyType key){
    if(ht == NULL)
        return;
    if(ht->size == 0)
        return;
    size_t offset = ht->func(key);//根据key计算offset
    //从offset开始,依次判定当前元素的key和要删除元素的key是否相同
    while(1){
        //若当前的key就是要删除的key,删除当前元素即可,将要删除元素的状态标记为Deleted
        if(ht->data[offset].key == key && ht->data[offset].stat == Valid){
            ht->data[offset].stat = Deleted;
            --ht->size;
            return;
        }
        //若当前元素为空元素,则key在hash表中没有找到,删除失败,直接返回即可
        else if(ht->data[offset].stat == Empty)
            return;
        else{
            ++offset;
            offset = offset>=HashMaxSize?0:offset;
        }
    }
    return;
}
  • 哈希表打印
void HashPrint(HashTable* ht,const char* msg){
    printf("[%s]\n",msg);
    size_t i = 0;
    for(;i < HashMaxSize;++i){
        if(ht->data[i].stat == Empty){
            continue;
        }
        printf("[%lu   %d:%d]  ",i,ht->data[i].key,ht->data[i].value);
    }
    printf("\n");
}
  • 默认函数
size_t HashFuncDefault(KeyType key){
    return key % HashMaxSize;
}

测试函数:

#include"hash.h"

#define PRINT_HEAD printf("\n============%s============\n",__FUNCTION__);

void TestInit(){
    PRINT_HEAD;
    HashTable ht;
    HashInit(&ht,HashFuncDefault);
    printf("size expect 0,actual %lu\n",ht.size);
    printf("func expect %p,actual %p\n",HashFuncDefault,ht.func);
    return;
}

void TestDestroy(){
    PRINT_HEAD;
    HashTable ht;
    HashInit(&ht,HashFuncDefault);
    HashDestroy(&ht);
    printf("size expect 0,actual %lu\n",ht.size);
    printf("func expect NULL,actual %p\n",ht.func);
    return;
}

void TestInsert(){
    PRINT_HEAD;
    HashTable ht;
    HashInit(&ht,HashFuncDefault);
    HashInsert(&ht,1,1);
    HashInsert(&ht,1,10); 
    HashInsert(&ht,2,2); 
    HashInsert(&ht,1001,11); 
    HashInsert(&ht,1002,12);
    HashPrint(&ht,"插入若干元素");
    return;
}

void TestFind(){
    PRINT_HEAD;
    HashTable ht;
    HashInit(&ht,HashFuncDefault);
    HashInsert(&ht,1,1);
    HashInsert(&ht,1,10); 
    HashInsert(&ht,2,2); 
    HashInsert(&ht,1001,11); 
    HashInsert(&ht,1002,12);
    ValType value;
    int ret = HashFind(&ht,1002,&value);
    printf("ret expect 1,actual %d\n",ret);
    printf("value expect 12,actual %d\n",value);
    ret = HashFind(&ht,3,&value);
    printf("ret expect 0,actual %d\n",ret);
}

void TestRemove(){
    PRINT_HEAD;
    HashTable ht;
    HashInit(&ht,HashFuncDefault);
    HashInsert(&ht,1,1);
    HashInsert(&ht,1,10); 
    HashInsert(&ht,2,2); 
    HashInsert(&ht,1001,11); 
    HashInsert(&ht,1002,12);
    HashRemove(&ht,2);
    ValType value;
    int ret = HashFind(&ht,1002,&value);
    printf("ret expect 1,actual %d\n",ret);
    printf("value expect 12,actual %d\n",value);
    ret = HashFind(&ht,2,&value);
    printf("ret expect 0,actual %d\n",ret);
}

int main(){
    TestInit();
    TestDestroy();
    TestInsert();
    TestFind();
    TestRemove();
    return 0;
}


结果演示:

哈希表(1)_第1张图片






你可能感兴趣的:(数据结构)