Data.Structures.For.Game.Programmers.PART2.Basics.8.HashTables

1.Sparse Data // 稀疏数据
e.g:
  Imagine each player in the game is accessed by an id number.This number is often called a key in programming.Each key will be unique.They are instead generated by a complex algorithm that produces seemingly random numbers from 0 to 1000,000.These numbers are sparse, they are far away from each other.

2.The Basic Hash Table
  It allows to do:
`Quickly store sparse key-based data in a reasonable amount of space
`Quickly determine if a certain key is within the table
TIP:
  It's more efficient to make your hash table sizes prime numbers.However, I use 10 cells throghtout this chapter because it makes the hashing functions easier to explain.
  The easiest and most common way of placing a key into a hash table is to modulo the key by the size of the table:
player = table[key % 10];
  Because of the way you look up keys, the algorithm to determine whether an item is in the table is essentially instantaneous(瞬间发生的).An ideal hash table can search for items in O(c) time, which is a tremendous benefit for fast programs.

3.Collisions: More than one items are placed into the same cell.
TIP: When you modulo a key by a prime number you get fewer collisions.
  One method of solving collisions is to use a hashing function.
NOTE: The modulo function used in the basic hash table is a hash funciton for integers.

Digit Addition: A simple alternative hashing function used on a kye from 0 to 1000000 would be to add all of the digits together.
Double Hashing: one func to hash a key, and then the other func to hash the result of the first func.

4.Hashing Strings
  Besides integers, the other popular datatype that is frequently hashed is strings.The following does a really good job at hashing strings into an integer with very few collisions:
unsigned long int StringHash(const chra* p_string)
{
	unsigned long int hash = 0;
	int length = strlen(p_string);
	for (i = 0; i < length; i++)
	{
		hash += ((i+1) * p_string[i]);
	}
	return hash;
}

  This method is similar to the digit addition method, but it multiplies each digit by an integer and then adds them.

5.Enhancing the Hash Table Structure
  There is no perfect hash function.You will probably always end up with collisions.
[Linear Overflow]
  With this method, you hash a number and then try to insert the number into the index that the hash function created.If there is an item already in the hash table at that index, you increment the index and try to insert it again.If that index is full, then you increment the index again and repeat the method until you find an empty index.
  But this turns the fast O(c) hash table search time into a slow O(n) time.I wouldn't bother with this kind of collision resolution unless I was forced to.
[Quadratic二次 Overflow] increment by 1^2、2^2、3^2 and so on until find an open index.
[Linked Overflow]
  This leads me to the method that works best in my opinion, linked overflow.This method gives each cell in the hash table a linked list.
  When there are collisions, the items will be inserted into a list of the cell.Whenever 2 hashes collide, the data is just appended to the back of the list.

  In order to search for data within this kind of table, you first hash the key to find the desired index.Once you have found the correct index, you need to search the linked list within that cell and nowhere else.If you don't find the data, you've searched through only one or two items.
  This beats the heck out of (胜过) the other collistion resolution methods I've shown you because you don't waste your time searching for data that isn't in the table.

6.Implementing a Hash Table
  As I have stated before, there are two pieces of data associated with a hash table entry: a key and the actual data that will be entered into the table.
  The key for the data must be unique for the data that it is associated with.
  When you put data into a hash table, you put in both data and the key assocaited with the data.The hash table will remember the key and the data.Whenever you want to search for data in the hash table, you tell the table which key you are looking for, and the table will return the data if it exists.


[HashEntry Class] // entry 条目
Because the hash table needs to store two pieces of information for every item you insert, it is easiest to create a class that holds both pieces of data.
template<class KeyType, class DataType>
class HashEntry
{
public:
	KeyType m_key;
	DataType m_data;
};

[HashTable Class]
  Functions: Constructor, Insert, Find, Remove, Count
[The Data]
  The HashTable class needs to keep track of the size of the table, the number of entries within the table, the array of linked lists that makes up the actual table, and a function pointer to the hash function.
template<class KeyType, class DataType>
class HashTable
{
public:
	typedef HashEntry<KeyType, DataType> Entry;

	int m_size;
	int m_count;
	Array<DLinkedList<Entry>> m_table;
	unsigned long int (*m_hash)(KeyType);
};
[Cons]
HashTable(int p_size, unsigned long int (*p_hash)(KeyType)) : m_table(p_size)
{
	m_size = p_size;
	m_hash = p_hash;
	m_count = 0;
}
[Insert]
void Insert(KeyType p_key, DataType p_data)
{
	Entry entry;
	entry.m_data = p_data;
	entry.m_key = p_key;
	int index = m_hash(p_key) % m_size;
	m_table[index].Append(entry);
	m_count++;
}
[Find]
Entry* Find(KeyType p_key)
{
	int index = m_hash(p_key) % m_size;
	DListIterator<Entry> itr = m_table[index].GetIterator();
	while (itr.Valid())
	{
		if (itr.Item().m_key == p_key)
			return &(itr.Item());
		itr.Forth();
	}
	return 0;
}
[Remove]
bool Remove(KeyType p_key)
{
	int index = m_hash(p_key) % m_size;
	DListIterator<Entry> itr = m_table[index].GetIterator();
	while (itr.Valid())
	{
		if (itr.Item().m_key == p_key)
		{
			m_table[index].Remove(itr);
			m_count--;
			return true;
		}
		itr.Forth();
	}
	return false;
}

7.Using the Hash Table
[Hash Func]
unsigned long int Hash(int k)
{
	return k;
}
[Create the Hash Table]
HashTable<int, int> table(size, Hash);
HashEntry<int, int>* entry;			// used for searching the table later on
[Insert]
table.Insert(key, data);
[Find]
entry = table.Find(key);
[Remove]
table.Remove(key);

[String Class]
class String
{
public:
	char m_string[64];
	String() { strcpy(m_string, "");}
	String(char* p_string) { strcpy(m_string, p_string);}
	bool operator == (String& p_right)
	{
		return !strcmp(m_string, p_right.m_string);
	}
};
[e.g.]
g_resource = SDL_LoadBMP("sky.bmp");
g_table.Insert("sky", g_resource);
[StringHash]
unsigned long int StringHash( String p_string )
{
    unsigned long int hash = 0;
    int i;
    int length = strlen( p_string.m_string );
    for( i = 0; i < length; i++ )
    {
        hash += ( (i + 1) * p_string.m_string[i] );
    }
    return hash;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值