哈希桶的增删查改简单实现

个人简单笔记。

目录

闭散列

开散列

插入

删除

查找

改变


什么是哈希桶呢?这是一个解决哈希数据结构的一种解决方法,在STL中的unorder_map与unorder_set的底层结构就是使用它来实现的。

闭散列

首先我们知道,哈希映射表是依据数组下标数据的。

 这时候然后如果来了映射值数据为0的数据,检测发现0位置已经被30占用,需要线性探测后面的空位置,就存入数据,这就叫做哈希冲突。

这样看似非常方便,但是有一个非常不好的地方那就是将其他位置给占用了,这样如果存储了其他数据连带一片的冲突产生:让我们看下图。

 我们1将下标1的位置占用了,那么11、21、31使用了依次占用后面空间位置。进入进数据

映射1的数据他们的连带将2,3,4下标位置映射给占用了,导致22、3、14第一次映射位置就发生哈希冲突,并且这3个数据也占用了下标5、6、7位置,造成一大片哈希冲突,极其影响数据增删查改。所以我们的必须改变哈希结构,使用开散列的方法。

文章来源地址https://uudwc.com/A/v05wG

开散列

开散列又名哈希桶、开链法。

我们的数据存放的不再是单纯存放数据到数组中,还记得我们的链表吗?我们的哈希表中存放的就是一个一个的链表的头节点数据。

 这时候我们再将数据存放入表中。

这时候映射到1的数据,自己冲突自己的,不影响其他下标位置,这就是我们的哈希桶模型。

插入

先映射寻找链表首端,再就是普通的链表插入。需要注意尾插的第一个插入或者头删的

bool insert(const pair<K, V>& kv)
{
	//哈希桶的负载因子为1
	if (_size + 1 > _tables.size())
	{
		//扩容逻辑
		Hash hash;
		size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
		vector<Node*>newTables;//我们的开散列不能去像闭散列一样创建新对象插入,
		//我们需要的是重新创建的是数组表,将一个个node
		//重新链接到新数组表中,避免需要一直重新创建结点。
		newTables.resize(newsize);
		//old表node移动到new表
		//为了不浪费
		for (size_t i = 0; i < _tables.size(); ++i)
		{
			Node* cur = _tables[i];//原表的每个元素都给cur
			while (cur)
			{
				Node* oldnext = cur->_next;//记录原表当前结点的下一个
				size_t index = hash(cur->_kv.first) % newTables.size();
				cur->_next = newTables[index];//这里采用的是头插。
				newTables[index] = cur;
				cur = oldnext;//迭代
			}
			_tables[i] = nullptr;//置空原表,没必要但是好习惯
		}
		newTables.swap(_tables);//交换old与new表,完成扩容
	}

	Hash hash;//仿函数
	size_t index = hash(kv.first) % (_tables.size());
	//头插
	if (Find(kv.first))
	{
		return false;
	}
	Node* newnode = new Node(kv);
	newnode->_next = _tables[index];
	_tables[index] = newnode;
	//尾插
	/*Node* newnode = new Node(kv);
	if (_tables[index] == nullptr)
	{
		_tables[index] = newnode;
	}
	else
	{
		Node* cur = _tables[index];
		Node*prev = _tables[index];
		while (cur)
		{
			if (cur->_kv == kv)
			{
				delete newnode;//如果发现已经存在我们需要delete新结点,防止内存泄漏
				return false;
			}
			prev = cur;
			cur = cur->_next;
		}
		prev->_next = newnode;
	}*/
	_size++;//数据加一
	return true;
}

删除

bool Erese(const K& key)
{
	if (_tables.size() == 0)//防止除0
	{
		return false;
	}
	Hash hash;
	size_t index = hash(key) % (_tables.size());
	Node* cur = _tables[index];//简单的链表删除
	Node* prev = cur;
	while (cur)
	{
		if (cur->_kv.first == key)
		{
			if (cur == _tables[index])//如果就是删除链表头结点
			{
				_tables[index] = cur->_next;
			}
			else//非头节点删除
			{
				prev->_next = cur->_next;
			}
			delete cur;
			_size--;
			return true;
		}
		prev = cur;//迭代
		cur = cur->_next;
	}
	return false;
}

查找

Node* Find(const K& key)
{
	if (_tables.size() == 0)//防止除0
	{
		return nullptr;
	}
	Hash hash;
	size_t index = hash(key) % (_tables.size());//找头节点位置
	Node* cur = _tables[index];//普通的单链表查找
	while (cur)
	{
		if (cur->_kv.first == key)//找到了
		{
			return cur;
		}
		cur = cur->_next;
	}
	return nullptr;//没找到
}

改变

bool change(const K& key, const V& val)
{
	Node* ret = Find(key);//查找位置
	if (!ret)//没找到返回
	{
		return false;
	}
	else//找到改变返回
	{
		ret->_kv.second = val;
		return true;
	}
}

原文地址:https://blog.csdn.net/2201_75352618/article/details/131517070

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年07月04日 10:25
一款支持AI思维导图的AI助手——ChatMindAI
下一篇 2023年07月04日 10:25