大雪Hash表の実現とテスト


StringHash.H
#ifndef __STRING_HASH_H__
#define __STRING_HASH_H__

// Definition of MPQHashTable
struct MPQHashTable
{
	long nHashA;
	long nHashB;
	bool bExists;
};

#define   CRYPT_TABLE_LENGTH  (256 * 5)
#define   MAX_TABLE_LENGTH    1024

class StringHash
{
private:
	unsigned long m_pCryptTable[CRYPT_TABLE_LENGTH];
	unsigned long m_nTableLength;
	MPQHashTable* m_pHashTable;
private:
	void InitCryptTable();
	unsigned long HashString(const char* lpszString, unsigned long hashType);
public:
	StringHash(unsigned long tableLength = MAX_TABLE_LENGTH);
	~StringHash();
	bool Hash(const char* lpszString);
	unsigned long Hashed(const char* lpszString);
	unsigned long getHashTableLength();
};

#endif

StringHash.CPP
#include "StringHash.h"
#include <ctype.h>
#include <stdlib.h>

// Initialize the crypt array
void StringHash::InitCryptTable()
{
	unsigned long seed = 0x00100001;

	for (int i = 0; i < 256; ++i)
	{
		for (int j = i, k = 0; k < 5; ++k, j += 256)
		{
			seed = (seed * 125 + 3) % 0x2AAAAB;
			unsigned long tmp = (seed & 0xFFFF) << 0x10;
			seed = (seed * 125 + 3) % 0x2AAAAB;
			m_pCryptTable[j] = tmp | (seed & 0xFFFF);
		}
	}
}

StringHash::StringHash(unsigned long tableLength)
{
	m_nTableLength = tableLength;
	m_pHashTable = new MPQHashTable[m_nTableLength];
	InitCryptTable();

	for (unsigned long i = 0; i < m_nTableLength; ++i)
	{
		m_pHashTable[i].nHashA = -1;
		m_pHashTable[i].nHashB = -1;
		m_pHashTable[i].bExists = false;
	}
}

StringHash::~StringHash()
{
	if (NULL != m_pHashTable)
	{
		delete[] m_pHashTable;
		m_pHashTable = NULL;
		m_nTableLength = 0;
	}
}

// The one-way hash function
unsigned long StringHash::HashString(const char*lpszString, unsigned long hashType)
{
	unsigned char* key = (unsigned char*)lpszString;
	unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
	int ch;

	while (*key != 0)
	{
		ch = toupper(*key++);
		seed1 = m_pCryptTable[hashType << 8] ^ (seed1 + seed2);
		seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
	}

	return seed1;
}

// Hash a string to the hash table
bool StringHash::Hash(const char* lpszString)
{
	const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
	unsigned long nHash = HashString(lpszString, HASH_OFFSET);
	unsigned long nHashA = HashString(lpszString, HASH_A);
	unsigned long nHashB = HashString(lpszString, HASH_B);
	unsigned long nHashStart = nHash % m_nTableLength;
	unsigned long nHashPos = nHashStart;

	while (m_pHashTable[nHashPos].bExists)
	{
		nHashPos = (nHashPos + 1) % m_nTableLength;
		if (nHashPos == nHashStart)
		{
			return false;
		}
	}

	m_pHashTable[nHashPos].bExists = true;
	m_pHashTable[nHashPos].nHashA = nHashA;
	m_pHashTable[nHashPos].nHashB = nHashB;

	return true;
}

// Find a string in the hash table, if it exists then return
// the index of the string, else return -1
unsigned long StringHash::Hashed(const char* lpszString)
{
	const unsigned long HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
	unsigned long nHash = HashString(lpszString, HASH_OFFSET);
	unsigned long nHashA = HashString(lpszString, HASH_A);
	unsigned long nHashB = HashString(lpszString, HASH_B);
	unsigned long nHashStart = nHash % m_nTableLength;
	unsigned long nHashPos = nHashStart;

	while (m_pHashTable[nHashPos].bExists)
	{
		if (m_pHashTable[nHashPos].nHashA == nHashA && m_pHashTable[nHashPos].nHashB == nHashB)
		{
			return nHashPos;
		}
		else
		{
			nHashPos = (nHashPos + 1) % m_nTableLength;
		}

		if (nHashPos == nHashStart)
		{
			break;
		}
	}

	return -1;
}

unsigned long StringHash::getHashTableLength()
{
	return m_nTableLength;
}

テスト関数:
#include "StringHash.h"
#include <iostream>

using namespace std;

int main()
{
	char* str1 = "StringHash.h";
	char* str2 = "StringHash.cpp";

	StringHash hasher(20);
	cout << "Length of Hash Table: " << hasher.getHashTableLength() << endl;
	cout << "Hash \"" << str1 << "\": " << boolalpha << hasher.Hash(str1) << endl;
	cout << "Hash \"" << str2 << "\": " << boolalpha << hasher.Hash(str2) << endl;

	cout << "Checking ..." << endl;
	cout << "Position of \"" << str1 << "\": " << hasher.Hashed(str1) << endl;
	cout << "Position of \"" << str1 << "\": " << hasher.Hashed(str2) << endl;

	return 0;
}

参照先:http://sfsrealm.hopto.org/inside_mopaq/chapter2.htm