【数据结构 09】哈希

哈希算法:哈希也叫散列、映射,将任意长度的输入通过散列运算转化为固定长度的输出,该输出就是哈希值(散列值)。

哈希映射是一种压缩映射,通常情况下,散列值的空间远小于输入值的空间。

哈希运算的结果称为哈希值,哈希运算是不可逆过程,即不能通过哈希值推算出原值。

哈希运算常用于加密、位图、布隆过滤,位图的作用是海量数据的标记,布隆过滤器的作用是提高海量数据查询的效率(客户端向服务端查询数据)。

一、哈希函数

HashFunc.h

#pragma once
#include 

// 仿函数
template
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

// 特化
template<>
struct HashFunc
{
	size_t operator()(const std::string& str)
	{
		size_t res = 0;
		for (const auto& ch : str)
		{
			res *= 131;	// 随机数取值,避免哈希冲突
			res += ch;
		}
		return res;
	}
};

哈希表:将数据根据哈希运算得到哈希值(关键值),再根据哈希值将数据映射在表中,哈希表通常情况是一个vector容器。哈希表分为闭散列和开散列(哈希桶)。

哈希表的数据增删与红黑树差别不大,各有优劣,但是哈希表的数据查询效率远高于红黑树。

二、闭散列

【数据结构 09】哈希_第1张图片

#define _CRT_SECURE_NO_WARNINGS 1

#pragma
#include 
#include 
#include "HashFunc.h"

enum status
{
	EMPTY,
	EXIST,
	DELETE
};

template
struct CloseHashNode
{
	std::pair _kv;
	status _status = EMPTY;
};

template>
class CloseHash
{
	typedef CloseHashNode Data;
public:
	CloseHash()
		: _n(0)
	{
		_table.resize(10);
	}

	bool Insert(const std::pair& kv)
	{
		if (Find(kv.first))
			return false;

		// 负载因子为0.7
		if (_n * 10 / _table.size() >= 7)
		{
			std::vector newTable;
			newTable.resize(2 * _table.size());
			for (int i = 0; i < _table.size(); ++i)
			{
				if (_table[i]._status == EXIST)
				{
					size_t pos = Hash()(_table[i]._kv.first) % newTable.size();
					while (newTable[pos]._status != EMPTY)
					{
						pos = (++pos) % newTable.size();
					}
					newTable[pos] = _table[i];
				}
			}
			_table.swap(newTable);
		}

		size_t pos = Hash()(kv.first) % _table.size();
		while (_table[pos]._status != EMPTY)
		{
			pos = (++pos) % _table.size();
		}
		_table[pos]._kv = kv;
		_table[pos]._status = EXIST;
		++_n;
		return true;
	}

	Data* Find(const K& key)
	{
		size_t pos = Hash()(key) % _table.size();
		int cnt = 0;
		while (_table[pos]._status != EMPTY && cnt != _table.size())
		{
			if (key == _table[pos]._kv.first && _table[pos]._status == EXIST)
				return &_table[pos];
			pos = (++pos) % _table.size();
			++cnt;
		}
		return nullptr;
	}

	bool Erase(const K& key)
	{
		Data* ret = Find(key);
		if (ret)
		{
			ret->_status = DELETE;
			--_n;
			return true;
		}
		else
		{
			return false;
		}
	}

private:
	std::vector _table;
	size_t _n;
};

三、开散列

开散列也称哈希桶,哈希桶的vector节点存储的是数据节点,相同哈希值的节点以链表的形式存储在同一个vector位置上,当节点数与vector容量的比值为平衡因子值(1)时,哈希桶扩容,扩容时重新遍历原表,将原表的元素重新取哈希进行映射,为了提高效率,不拷贝节点,而是改变节点的指向。

【数据结构 09】哈希_第2张图片

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once
#include 
#include 
#include "HashFunc.h"

template
struct OpenHashNode
{
	std::pair kv;
	OpenHashNode* next;
	
	OpenHashNode(const std::pair& x)
		: kv(x), next(nullptr)
	{}
};

template>
class OpenHash
{
	typedef OpenHashNode Node;
public:
	OpenHash()
		: _n(0)
	{
		_table.resize(10, nullptr);
	}

	bool Insert(const std::pair& kv)
	{
		if (Find(kv.first))
			return false;

		// 检查扩容,平衡因子为 1
		if (_n == _table.size())
		{
			std::vector newTable;
			newTable.resize(2 * _table.size(), nullptr);

			for (int i = 0; i < _table.size(); ++i)
			{
				Node* cur = _table[i];
				while (cur)
				{
					Node* next = cur->next;

					size_t pos = Hash()(cur->kv.first) % newTable.size();
					cur->next = newTable[pos];
					newTable[pos] = cur;

					cur = next;
				}
			}

			_table.swap(newTable);
		}

		// 插入新节点
		Node* newNode = new Node(kv);
		size_t pos = Hash()(newNode->kv.first) % _table.size();
		newNode->next = _table[pos];
		_table[pos] = newNode;
		++_n;
		return true;

	}

	Node* Find(const K& key)
	{
		size_t pos = Hash()(key) % _table.size();
		Node* cur = _table[pos];
		while (cur)
		{
			if (cur->kv.first == key)
				return cur;
			cur = cur->next;
		}
		return nullptr;
	}

	bool Erase(const K& key)
	{
		Node* ret = Find(key);
		if (ret)
		{
			size_t pos = Hash()(key) % _table.size();
			Node* cur = _table[pos];
			if (cur == ret)
			{
				cur = ret->next;
				delete ret;
				ret = nullptr;
			}
			else
			{
				while (cur->next != ret)
				{
					cur = cur->next;
				}
				cur->next = ret->next;
				delete ret;
				ret = nullptr;
			}
			--_n;
			return true;
		}
		else
		{
			return false;
		}
	}

private:
	std::vector _table;
	int _n;
};

四、测试

#define _CRT_SECURE_NO_WARNINGS 1

#include "CloseHash.h"
#include "OpenHash.h"
using namespace std;

void TestCloseHash()
{
	cout << "CloseHash: " << endl << endl;
	CloseHash hash;

	int arr[] = { 34, 36, 12, 54, 5, 22, 65, 32, 13, 4, 1, 52 };
	for (auto& e : arr)
	{
		hash.Insert(make_pair(e, e));
	}

	cout << hash.Find(12) << endl;
	cout << hash.Find(22) << endl;
	cout << hash.Find(32) << endl;
	cout << hash.Find(42) << endl;
	cout << hash.Find(52) << endl;

	cout << endl;
	hash.Erase(32);
	cout << hash.Find(12) << endl;
	cout << hash.Find(22) << endl;
	cout << hash.Find(32) << endl;
	cout << hash.Find(42) << endl;
	cout << hash.Find(52) << endl;
}

void TestOpenHash()
{
	cout << endl << endl << "OpenHash: " << endl << endl;
	OpenHash hash;

	int arr[] = { 34, 36, 12, 54, 5, 22, 65, 32, 13, 4, 1, 52 };
	for (auto& e : arr)
	{
		hash.Insert(make_pair(e, e));
	}

	cout << hash.Find(12) << endl;
	cout << hash.Find(22) << endl;
	cout << hash.Find(32) << endl;
	cout << hash.Find(42) << endl;
	cout << hash.Find(52) << endl;

	cout << endl;
	hash.Erase(32);
	cout << hash.Find(12) << endl;
	cout << hash.Find(22) << endl;
	cout << hash.Find(32) << endl;
	cout << hash.Find(42) << endl;
	cout << hash.Find(52) << endl;
}

int main()
{
	TestCloseHash();
	TestOpenHash();

	return 0;
}

你可能感兴趣的:(数据结构,哈希算法,数据结构,算法)