hash map 自定义实现

本文探讨了在C++中自定义HashMap实现的原因,包括避免在遍历过程中修改数据容器时遇到的问题,以及为游戏对象设计通用数据结构的需求。自定义HashMap通过一个数组和链表实现,使用键的哈希值定位数据。在冲突处理上,虽然可以考虑使用红黑树提高查找效率,但在此设计中并未采用。删除操作不立即执行,而是将待删除项移到删除链表,并在更新周期内实际删除。添加操作则直接进行,容量扩充在特定更新方法中检查处理。

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

我们正常定义的 [键-->值] 类型数据容器 大多数都是用std::map, 或者std::std::unordered_map, 但是有些时候对其操作不太方便,特别是嵌套调用的时候进行添加删除操作,比如说:我有一个技能队列用的是std::std::unordered_map,当我们在帧循环中遍历技能队列数据,执行技能操作的时候,触发了一个新的技能或者删除了一个技能,这个时候在遍历的队列内部这个样就会出错:

// 错误示例:
std::unorder_map<int, skill_info>  m_mapSkill;

void OnSkillUpdate()
{
    for (auto iter = m_mapSkill.begin(); iter != m_mapSkill.end(); ++iter)
    {
        // 执行逻辑
        // todo
        // 触发了一个新的技能
        // 最后要执行:
        m_mapSkill.insert(std::make_pair(id, skill_info()));
        
        // 或者:
        m_mapSkill.erase()
        // 上面这行代码就出问题了,
    }
}

如果有这样的代码我们就要在执行遍历之前先把数据拷贝到另外一个零时队列,对零时队列进行遍历。或者对于添加或者删除操作添加到零时的容器中,在遍历完成以后再做添加或者删除操作。这种操作会破坏代码的整洁性,也添加了逻辑的复杂度。

第二是我写了一种新的通用数据结构,作为所有游戏对象的数据容器集合,有统一的查询、赋值和存储接口。需要定制特殊的容器,所以写了特殊的hashmap。可能下一次会讲下通用数据结构设计。

下面我讲下自定义hash map 实现逻辑:

hash map 的原理是定义一个数组,每个数组中是一个链表。 在插入操作时把键转换成int类型的hash值。然后这个hash值除以数组的大小,余数就落在了数组上面。数据根据余数存到数组对应的链表里。理想情况每个链表里就一个数据,不存在遍历操作。当然如果hash 值冲突,一个链表上的数据可能会不止一个。这个要看hash因子的设值,和hash值的计算。 现在很多库会把链表换成红黑树,加快查找速度。我觉得我的这个设计里面就没有必要了。

我自定义的hash map 在插入的时候会有 键,类型,和值三个参数, 键是唯一的,但是类型可能相同。我们可以根据唯一的键查找内容,也可以根据类型,遍历同一种类型的所有数据。而在删除的时候不是立即删除,而是把数据并行的添加到删除链表中。然后在帧循环中调用Hashmap 的update() 方法,进行实际的删除操作。添加的时候直接添加,不会在内部扩充容量,是在Hashmap的update()方法中检查是否需要扩充容量。



// 定制 hash 容器
/************************************************************************/
/* 


*/
/************************************************************************/


#ifndef CoreHashMap_h__
#define CoreHashMap_h__

#include <string>
#include <assert.h>
#include "CoreLink.h"
#include <new.h>
#include <functional>
#include "jemalloc.h"

#ifndef _WIN32
#include <stdlib.h>
#include <string.h>
#endif

// hash 值计算与比较
template <typename TYPE>
class HashComp
{
public:
	static size_t GetHashValue(const TYPE& t);
	static bool Equal(const TYPE& t1, const TYPE& t2);
};

template<>
class HashComp<int>
{
public:
	static size_t GetHashValue(const int& t)
	{
		return size_t(t);
	}
	
	static bool Equal(const int& t1, const int& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<long>
{
public:
	static size_t GetHashValue(const long& t)
	{
		return size_t(t);
	}

	static bool Equal(const long& t1, const long& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<long long>
{
public:
	static size_t GetHashValue(const long long& t)
	{
		return size_t(t);
	}

	static bool Equal(const long long& t1, const long long& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<unsigned int>
{
public:
	static size_t GetHashValue(const unsigned int& t)
	{
		return size_t(t);
	}

	static bool Equal(const unsigned int& t1, const unsigned int& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<unsigned long>
{
public:
	static size_t GetHashValue(const unsigned long& t)
	{
		return size_t(t);
	}

	static bool Equal(const unsigned long& t1, const unsigned long& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<unsigned long long>
{
public:
	static size_t GetHashValue(const unsigned long long& t)
	{
		return size_t(t);
	}

	static bool Equal(const unsigned long long& t1, const unsigned long long& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<unsigned short>
{
public:
	static size_t GetHashValue(const unsigned short& t)
	{
		return size_t(t);
	}

	static bool Equal(const unsigned short& t1, const unsigned short& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<short>
{
public:
	static size_t GetHashValue(const short& t)
	{
		return size_t(t);
	}

	static bool Equal(const short& t1, const short& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<std::string>
{
public:
	static size_t GetHashValue(const std::string& t)
	{
		assert(!t.empty());
		size_t hv = 0;
		for (int i = 0; t[i]; ++i)
		{
			hv = hv * 131 + t[i];
		}

		return hv;
	}

	static bool Equal(const std::string& t1, const std::string& t2)
	{
		return t1 == t2;
	}
};

template<>
class HashComp<std::wstring>
{
public:
	static size_t GetHashValue(const std::wstring& t)
	{
		assert(!t.empty());
		size_t hv = 0;
		for (int i = 0; t[i]; ++i)
		{
			hv = hv * 131 + t[i];
		}

		return hv;
	}

	static bool Equal(const std::wstring& t1, const std::wstring& t2)
	{
		return t1 == t2;
	}
};

// 初始化容器个数
#define INIT_NODE_SIZE 8

//
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值