C语言——基于拉链法实现的固定长度哈希表


前言`

请手动实现一个固定长度,基于拉链法的哈希表。包含创建、销毁、插入、删除、查找等基本操作。


一、头文件

#ifndef HASH_MAP_H
#define HASH_MAP_H
#define _CRT_SECURE_NO_WARNINGS
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define HASHMAP_CAPACITY 10
typedef char* KeyType;
typedef char* ValueType;

//键值对结点
typedef struct node_s {
	KeyType key;
	ValueType val;
	struct node_s* next;
}KeyValueNode;
//表结构体
typedef struct {
	//哈希桶
	KeyValueNode* bucket[HASHMAP_CAPACITY];
	//哈希函数需要的种子值
	uint32_t hash_seed;
}HashMap;
//创建
HashMap* hashmap_create();
//插入
ValueType hashmap_put(HashMap *map,KeyType key,ValueType val);
//查询一个键值对
ValueType hashmap_get(HashMap* map, KeyType key);
//删除一个键值对
bool hashmap_remove(HashMap* map, KeyType key);
//销毁
void hashmap_destroy(HashMap* map);
#endif // !HASH_MAP_H


二、基本操作

#include "hash_map.h"
/* murmur_hash2 */
static uint32_t hash(const void* key, int len, uint32_t seed) {
	const uint32_t m = 0x5bd1e995;
	const int r = 24;
	uint32_t h = seed ^ len;
	const unsigned char* data = (const unsigned char*)key;

	while (len >= 4) {
		uint32_t k = *(uint32_t*)data;
		k *= m;
		k ^= k >> r;
		k *= m;
		h *= m;
		h ^= k;
		data += 4;
		len -= 4;
	}

	switch (len) {
	case 3: h ^= data[2] << 16;
	case 2: h ^= data[1] << 8;
	case 1: h ^= data[0];
		h *= m;
	};

	h ^= h >> 13;
	h *= m;
	h ^= h >> 15;

	return h;
}
//创建
HashMap* hashmap_create() {
	HashMap *map=calloc(1, sizeof(HashMap));
	if (map == NULL) {
		printf("error:calloc failed in hashmap_create.\n");
		exit(1);
	}
	map->hash_seed = time(NULL);
	return map;
}
//插入一个键值对
ValueType hashmap_put(HashMap* map, KeyType key, ValueType val) {
	//通过哈希函数确定在哪个桶中
	int idx = hash(key, strlen(key), map->hash_seed) % HASHMAP_CAPACITY;
	//遍历找到的哈希桶,查找key是否重复
	KeyValueNode* curr = map->bucket[idx];
	while (curr) {
		if (strcmp(key, curr->key)==0) {
			//key已存在,更新val,返回旧val
			ValueType old_val = curr->val;
			curr->val = val;
			return old_val;
		}
		curr = curr->next;
	}
	//key不重复就重新插入
	KeyValueNode* new_node = malloc(sizeof(KeyValueNode));
	if (new_node == NULL) {
		printf("Error: malloc failed in hashmap_put.\n");
		exit(1);
	}
	new_node->val = val;
	new_node->key = key;
	new_node->next = map->bucket[idx];
	map->bucket[idx] = new_node;
	return NULL;
}
//查询一个键值对
ValueType hashmap_get(HashMap* map, KeyType key) {
	int idx = hash(key, strlen(key), map->hash_seed) % HASHMAP_CAPACITY;
	KeyValueNode* curr = map->bucket[idx];
	while (curr) {
		if (strcmp(curr->key,key)==0) {
			return curr->val;
		}
		curr = curr->next;
	}
	return NULL;
}
//删除一个键值对
bool hashmap_remove(HashMap* map, KeyType key) {
	int idx = hash(key, strlen(key), map->hash_seed) % HASHMAP_CAPACITY;
	KeyValueNode* curr = map->bucket[idx];
	KeyValueNode* p = NULL;
	if (strcmp(curr->key, key) == 0) {
		map->bucket[idx] = curr->next;
		free(curr);
		return true;
	}
	p = curr;
	curr = curr->next;
	while (curr) {
		if (strcmp(curr->key, key) == 0) {
			p->next = curr->next;
			free(curr);
			return true;
		}
		p = curr;
		curr = curr->next;
	}
	return false;
}
//销毁
void hashmap_destroy(HashMap* map) {
	for (size_t i = 0; i < HASHMAP_CAPACITY; i++) {
		KeyValueNode* curr = map->bucket[i];
		while (curr) {
			KeyValueNode* tmp = curr->next;
			free(curr);
			curr = tmp;
		}

	}
	free(map);
}

三、测试源

#include "hash_map.h"
int main(void) {
    HashMap* map = hashmap_create();
    if (map == NULL) {
        printf("hashmap_create failed in main.\n");
        return 1;
    }
    //插入键值对
    hashmap_put(map,"二氧","化钙");
    hashmap_put(map, "氯化", "钠");
    hashmap_put(map, "高锰", "酸钾");
    //更新键值对
    char *old_value=hashmap_put(map, "二氧", "化钛");
    printf("更新键值对后返回的旧值为:%s\n",old_value);
    printf("根据key值为‘氢氧’查询已有键值对val值为:%s\n", hashmap_get(map, "氢氧"));
    printf("根据key值为‘氯化’查询已有键值对val值为:%s\n", hashmap_get(map, "氯化"));
    hashmap_remove(map, "氯化");
    printf("删除key值为‘氯化’的键值对后再查询为:%s\n", hashmap_get(map, "氯化"));
    hashmap_destroy(map);
    return 0;
}

四、输出样例

在这里插入图片描述


总结

哈希表是一种“数组+链表”的结构。键值对:键、值、next指针。哈希表结构体:哈希桶和种子值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值