手动简单实现HashMap

本文详细介绍了如何手动实现Java中的HashMap数据结构,包括数组加链表的结构设计,以及put和get方法的具体实现,展示了hash碰撞时的数据处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先必须明确HashMap的数据结构,网上有很多解释;手动实现HashMap最主要就是表现出来数组加链表的结构,以及可用的put和get方法,体现出hash碰撞时候的数据处理即可。

//定义接口
public interface MyMap<K, V> {

	//长度(这里指的是数组的长度)
	int size();
	//是否为空
	boolean isEmpty();
	//get方法
	Object get(Object key);
	//put方法
	Object put(Object key, Object value);
	//内部接口 模仿Map.Entry
	interface Entry {
		Object getKey();

		Object getValue();
	}

}

//实现类
public class MyMapImpl<K, V> implements MyMap {

	// 默认容量
	private final int DEFAULT_CAPACITY = 16;

	// 数组存放Node容器
	Node[] table = new Node[DEFAULT_CAPACITY];

	// 长度
	private int size = 0;

	// 静态内部类
	static class Node implements Entry {
		// 属性
		int hash;
		Object key;
		Object value;
		Node next;

		// 构造器
		public Node(int hash, Object key, Object value, Node next) {
			super();
			this.hash = hash;
			this.key = key;
			this.value = value;
			this.next = next;
		}

		@Override
		public Object getKey() {
			return key;
		}

		@Override
		public Object getValue() {
			return value;
		}

	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	@Override
	public Object get(Object key) {
		int hash = hashcode(key);
		int indexOf = indexOf(hash, table.length);
		Node node = table[indexOf];
		while (node != null) {
			if (node.key.equals(key) && node.hash == hash) {
				return node.value;
			}
			node = node.next;
		}
		return null;
	}

	public int hashcode(Object key) {
		return key.hashCode();
	}

	//这里给出的索引计算是为了测试碰撞比如 key="1"和key="a"会出现hash碰撞
	public int indexOf(int hash, int length) {
		return hash % length;
	}

	@Override
	public Object put(Object key, Object value) {
		// 先判断数组中有没有这个值
		int hashcode = hashcode(key);
		int indexOf = indexOf(hashcode, table.length);
		Node node = table[indexOf];
		if (node == null) {
			// 则说明不存在,即往数组里面添加数据
			table[indexOf] = new Node(hashcode, key, value, null);
			++size;
		} else {
			// 在链表里面添加 已经发生碰撞了
			//第一个判断是看是否在数组中有相同的key和hash
			if (node.hash == hashcode && node.key == key || node.key.equals(key)) {
				// 此时应该新值替换旧值
				Object oldValue = node.value;
				node.value = value;
				return oldValue;
			} else {
				// 否则循环链表
				while (true) {
					if (node.next == null) {
						node.next = new Node(hashcode, key, value, null);
						break;
					}
					if (node.next.hash == hashcode && node.next.key == key || node.next.key.equals(key)) {
						break;
					}
					node = node.next;
				}
			}

		}
		//扩容
		if (size == table.length) {
			Node[] tableNew = new Node[table.length * 2];
			System.arraycopy(table, 0, tableNew, 0, table.length);
			table = tableNew;
		}
		return null;
	}
}

//测试类
public class MyMapTest {

	public static void main(String[] args) {
		MyMap<String,Object> map = new MyMapImpl<>();
		//map.put("name", "薛东");
		//map.put("age", 28);
		map.put("1", 111);
		map.put("a", 222);
		//System.out.println(map.get("name"));
		//System.out.println(map.get("age"));
		System.out.println(map.size());
		System.out.println(map.get("1"));
		System.out.println(map.get("a"));
	}
	
}

<think>好的,用户想了解如何在C语言中实现一个HashMap。我需要先回忆HashMap的基本概念和结构。HashMap通常由数组和链表(或红黑树)组成,处理冲突的方法有开放寻址和链地址法。C语言没有内置的哈希表,所以需要手动实现。 首先,确定哈希表的结构。每个节点应该包含键、值和指向下一个节点的指针,处理冲突用链地址法。然后定义哈希表的结构,包括容量、大小和存储桶数组。 接下来,哈希函数的选择。可能用简单的取模运算,或者更复杂的如djb2算法。这里可能需要考虑哈希函数的分布均匀性。 然后,需要实现基本的操作:插入、查找、删除。插入时要处理冲突,可能需要动态扩容,但用户可能暂时不需要太复杂的扩容机制,先实现基础版本。 还要考虑内存管理,特别是节点的创建和释放。需要确保没有内存泄漏,比如在删除节点时正确释放内存。 可能用户会关心如何处理不同的数据类型,但C语言中通常用void指针来支持泛型,但会增加复杂性。可能需要先实现固定类型的键值,比如字符串键和整型值,简化示例。 最后,测试代码,验证各个功能是否正常。比如插入几个键值对,然后查找和删除,确保正确性。 需要提醒用户注意哈希表容量选择为质数,减少哈希冲突。另外,动态扩容的阈值和策略,比如负载因子超过0.75时扩容,但可能在基础实现中暂不处理,保持简单。 可能用户是初学者,所以代码示例要清晰,结构明确,避免复杂的优化,重点放在核心逻辑上。同时解释每一步的作用,确保用户能够理解每个函数的功能和实现方法。</think>在C语言中实现HashMap需要手动处理内存和数据结构,以下是分步实现说明: --- ### 一、HashMap核心结构 ```c #define DEFAULT_CAPACITY 16 // 初始容量(建议使用质数) #define LOAD_FACTOR 0.75 // 扩容阈值 // 哈希节点结构 typedef struct HashNode { char* key; // 键(字符串示例) int value; // 值 struct HashNode* next; // 链表解决冲突 } HashNode; // HashMap主体结构 typedef struct { HashNode** buckets; // 存储桶数组 int capacity; // 总容量 int size; // 当前元素数 } HashMap; ``` --- ### 二、关键函数实现 #### 1. 哈希函数 ```c // 使用djb2算法(高效字符串哈希) unsigned long hash_func(const char* key, int capacity) { unsigned long hash = 5381; int c; while ((c = *key++)) { hash = ((hash << 5) + hash) + c; // hash * 33 + c } return hash % capacity; } ``` #### 2. 创建HashMap ```c HashMap* hashmap_create() { HashMap* map = (HashMap*)malloc(sizeof(HashMap)); map->capacity = DEFAULT_CAPACITY; map->size = 0; map->buckets = (HashNode**)calloc(DEFAULT_CAPACITY, sizeof(HashNode*)); return map; } ``` #### 3. 插入键值对 ```c void hashmap_put(HashMap* map, const char* key, int value) { // 计算桶索引 unsigned long index = hash_func(key, map->capacity); // 检查键是否存在 HashNode* current = map->buckets[index]; while (current) { if (strcmp(current->key, key) == 0) { current->value = value; // 更新值 return; } current = current->next; } // 创建新节点 HashNode* newNode = (HashNode*)malloc(sizeof(HashNode)); newNode->key = strdup(key); // 深拷贝键 newNode->value = value; newNode->next = map->buckets[index]; // 头插法 map->buckets[index] = newNode; map->size++; } ``` #### 4. 查找键值 ```c int hashmap_get(HashMap* map, const char* key, int* found) { unsigned long index = hash_func(key, map->capacity); HashNode* current = map->buckets[index]; while (current) { if (strcmp(current->key, key) == 0) { *found = 1; return current->value; } current = current->next; } *found = 0; return -1; // 未找到的返回值 } ``` #### 5. 删除键值 ```c void hashmap_remove(HashMap* map, const char* key) { unsigned long index = hash_func(key, map->capacity); HashNode* current = map->buckets[index]; HashNode* prev = NULL; while (current) { if (strcmp(current->key, key) == 0) { if (prev) { prev->next = current->next; } else { map->buckets[index] = current->next; } free(current->key); free(current); map->size--; return; } prev = current; current = current->next; } } ``` --- ### 三、使用示例 ```c int main() { HashMap* map = hashmap_create(); // 插入数据 hashmap_put(map, "apple", 42); hashmap_put(map, "banana", 17); // 查找数据 int found; int val = hashmap_get(map, "apple", &found); if (found) printf("apple的值: %d\n", val); // 删除数据 hashmap_remove(map, "banana"); // 释放内存(需实现hashmap_destroy) return 0; } ``` --- ### 四、优化方向 1. **动态扩容**:当`size/capacity > LOAD_FACTOR`时,新建更大的桶数组并重新哈希 2. **红黑树优化**:当链表长度超过阈值(如8)时,转换为红黑树(类似Java HashMap) 3. **泛型支持**:使用`void*`实现任意类型键值 4. **线程安全**:添加互斥锁实现并发访问 --- ### 五、注意事项 - 内存管理需严格对应:每个`malloc`必须有对应的`free` - 字符串键建议使用`strdup`深拷贝,避免外部修改 - 哈希函数的选择直接影响性能,需根据数据类型优化 完整实现代码约200行,需要处理更多边界条件。建议参考开源项目(如Redis字典实现)获取生产级方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dong__xue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值