Cuckoo Hash 基本思想和代码实现

Cuckoo Hash 是一种hash冲突解决方法, 其目的是即时使用简易的hash function 也能够实现hash key的均匀分布。

基本思想是使用2个hash函数来处理碰撞,从而每个key都对应到2个位置。

插入操作如下:

1. 对key值hash,生成两个hash key值,hashk1和 hashk2, 如果对应的两个位置上有一个为空,那么直接把key插入即可。

2. 否则,任选一个位置,把key值插入,把已经在那个位置的key值踢出来。

3. 被踢出来的key值,需要重新插入,直到没有key被踢出为止。

查找思路比较简单。


代码实现如下:

// Cuckoo_hash.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>
#include <cmath>
#include <iostream>
using namespace std;

template<class KeyT>
class CuckooHash;

template<>
class CuckooHash<int>
{

private:
	int lnBucket;	//size of bucket
	int *mpKeyBucket1;	//the first bucket for first hash
	int *mpKeyBucket2;	//the second bucket for second hash
	enum {MaxLoop = 1000};	//used to control rehash loop

	int lnCantInsertNum;

private:
	//first hash function
	int hHashOne(int& irKey)
	{
		int lHashKey = 0;

		lHashKey = irKey % lnBucket;

		return lHashKey;
	}

	//second hash function
	int hHashTwo(int& irKey)
	{
		int lHashKey = 0;

		lHashKey = irKey / lnBucket;
		lHashKey = lHashKey % lnBucket;

		return lHashKey;
	}

	//todo: juge one num is Prime NUM or not
	bool hIsPrime(int inN)
	{
		if(inN <= 0) return false;

		int last = sqrt((double)inN);

		for(int i = 2; i<= last; i++)
		{
			if(inN % i == 0)
				return false;
		}

		return true;
	}
	int hGetMinPrime(int inNum)
	{
		while( !hIsPrime(inNum) ) inNum ++;

		return inNum; 
	}

	//try to rehash all the other key
	bool hReHash(int iKey, int deeps)
	{
		if(deeps <= 0) return false;

		int lHashKey1 = hHashOne(iKey);
		int lHashKey2 = hHashTwo(iKey);

		if(iKey == mpKeyBucket1[lHashKey1])
		{
			if(mpKeyBucket2[lHashKey2] == 0)
			{
				mpKeyBucket2[lHashKey2] = iKey;
				return true;
			}
			else
			{
				if( hReHash(mpKeyBucket2[lHashKey2], deeps - 1) )
				{	mpKeyBucket2[lHashKey2] = iKey;
					return true;
				}
					
			}
		}
		else if(iKey == mpKeyBucket2[lHashKey2])
		{
			if(mpKeyBucket1[lHashKey1] == 0)
			{
				mpKeyBucket1[lHashKey1] = iKey;
				return true;
			}
			else
			{
				if( hReHash(mpKeyBucket1[lHashKey1], deeps - 1))
				{
					mpKeyBucket1[lHashKey1] = iKey;
					return true;
				}
			}
		}

		return false;

	}

public:
	CuckooHash(int inNum)
	{
		lnBucket = inNum;

		mpKeyBucket1 = NULL;

		mpKeyBucket2 = NULL;

		lnCantInsertNum = 0;
	}

	void InitHashTable()
	{
		lnBucket = hGetMinPrime(lnBucket);
		
		mpKeyBucket1 = new int[lnBucket];
		memset(mpKeyBucket1, 0, sizeof(int) * lnBucket);
		
		mpKeyBucket2 = new int[lnBucket];
		memset(mpKeyBucket2, 0, sizeof(int) * lnBucket);
	}

	~CuckooHash()
	{
		if(mpKeyBucket1)
			delete[] mpKeyBucket1;

		if(mpKeyBucket2)
			delete[] mpKeyBucket2;
	}

	void Insert(int& irKey)
	{
		if(find(irKey)) return;

		int lHashKey1 = hHashOne(irKey);
		int lHashKey2 = hHashTwo(irKey);

		if(mpKeyBucket1[lHashKey1]  == 0)
			mpKeyBucket1[lHashKey1] = irKey;
		else if(mpKeyBucket2[lHashKey2] == 0)
			mpKeyBucket2[lHashKey2] = irKey;
		else
		{
			if(hReHash(mpKeyBucket1[lHashKey1], MaxLoop))
				mpKeyBucket1[lHashKey1] = irKey;
			else if(hReHash(mpKeyBucket2[lHashKey2], MaxLoop))
				mpKeyBucket2[lHashKey2] = irKey;
			else
				lnCantInsertNum ++;

		}

		cout << "After insert : " << irKey << endl;
		cout << lHashKey1 << " " << lHashKey2 << endl;
		PrintBucket4Test();
	
	}

	bool find(int& irKey)
	{
		int lHashKey1 = hHashOne(irKey);
		if(mpKeyBucket1 && mpKeyBucket1[lHashKey1] == irKey)
			return true;

		int lHashKey2 = hHashTwo(irKey);
		if(mpKeyBucket2 && mpKeyBucket2[lHashKey2] == irKey)
			return true;

		return false;
	}

	void PrintBucket4Test()
	{	
		for(int i = 0; i<lnBucket; i++ )
			cout << mpKeyBucket1[i] << ' ';
		cout << endl;

		for(int i = 0; i<lnBucket; i++ )
			cout << mpKeyBucket2[i] << ' ';
		cout << endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{

	CuckooHash<int> CKHash(12);
	CKHash.InitHashTable();


	int a[] = {20, 50, 53, 75, 100, 67, 105, 3, 36, 39, 6};
	for(int i = 0; i< sizeof(a)/sizeof(int); i++)
	{
		CKHash.Insert(a[i]);
	}

	int b;
	cin >> b;
	return 0;
}



参考链接如下:

http://www.it-c.dk/people/pagh/papers/cuckoo-undergrad.pdf

http://www.it-c.dk/people/pagh/papers/cuckoo-jour.pdf

http://en.wikipedia.org/wiki/Cuckoo_hashing

http://hi.baidu.com/algorithms/blog/item/eb89b582add48f95f703a61e.html

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
以下是一个简单的C++实现Cuckoo Hash的示例代码: ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; const int TABLE_SIZE = 11; const int MAX_RETRIES = 500; class CuckooHash { private: vector<int> table1; vector<int> table2; public: CuckooHash() { table1.resize(TABLE_SIZE); table2.resize(TABLE_SIZE); } int hash1(int key) { return key % TABLE_SIZE; } int hash2(int key) { return (key / TABLE_SIZE) % TABLE_SIZE; } void insert(int key) { int count = 0; while (count < MAX_RETRIES) { int index1 = hash1(key); int index2 = hash2(key); if (table1[index1] == key || table2[index2] == key) { cout << key << " already exists." << endl; return; } if (table1[index1] == 0) { table1[index1] = key; return; } else if (table2[index2] == 0) { table2[index2] = key; return; } else { int evictedKey = table1[index1]; table1[index1] = key; key = table2[index2]; table2[index2] = evictedKey; count++; } } cout << "Insertion failed." << endl; } void remove(int key) { int index1 = hash1(key); int index2 = hash2(key); if (table1[index1] == key) { table1[index1] = 0; } else if (table2[index2] == key) { table2[index2] = 0; } else { cout << key << " does not exist." << endl; } } bool search(int key) { int index1 = hash1(key); int index2 = hash2(key); return table1[index1] == key || table2[index2] == key; } }; int main() { CuckooHash hash; hash.insert(10); hash.insert(22); hash.insert(37); hash.insert(40); hash.insert(50); hash.insert(60); hash.remove(22); hash.remove(40); hash.insert(70); hash.insert(80); cout << "Search for 10: " << (hash.search(10) ? "Found" : "Not Found") << endl; cout << "Search for 37: " << (hash.search(37) ? "Found" : "Not Found") << endl; cout << "Search for 50: " << (hash.search(50) ? "Found" : "Not Found") << endl; cout << "Search for 80: " << (hash.search(80) ? "Found" : "Not Found") << endl; cout << "Search for 90: " << (hash.search(90) ? "Found" : "Not Found") << endl; return 0; } ``` 代码中使用了两个哈希表作为Cuckoo Hash的基础数据结构,其中使用了两个不同的哈希函数来计算每个键的两个哈希值。在插入键时,如果一个键已经存在于两个哈希表中的任何一个中,则插入操作失败。如果两个哈希表中有一个空闲位置,则将键插入其中一个哈希表中。如果两个哈希表中都没有空闲位置,则使用Cuckoo Hash算法将其中一个哈希表中的键替换为新插入的键,同时将被替换的键移动到另一个哈希表中。在删除键时,如果一个键存在于哈希表中,则将其从哈希表中删除。在搜索键时,如果一个键存在于两个哈希表中的任何一个中,则返回true,否则返回false。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值