最近复习数据结构相关的知识,自己实现一个简单的散列表:
散列表的总结
- 散列表是键与值得对应,最主要的优点就是查找的速度很快。
- 通过一个hash函数f(k),将key计算得到一个唯一的hash值,然后通过这hash值作为数组的下标来访问元素。
- 如果数据量很多或者hash函数选择不当,那么很可能多个多个key计算出来对应了一个数组的下标,这个称为冲突,解决冲突的方法从两个方面入手
- 哈希函数:哈希函数的公式比较多,最简单的应该就是取模运算了
- 冲突解决:如果真的发生了,那么可以使用额外的步骤来存储这些元素,我这里使用了链表来存储这些元素
- 一个简单的示意图,左边代表了一个数组,数组元素指向一个链表,这个链表保存了hash值相同的元素。
- 下面是我自己的简单的一个实现,一些优化
- Hash函数
- 可以实时的调整hash表的大小的,比如当前存储的元素与最大的元素比例到达80%,那么此时可以扩大从而减小冲突
- 如果模板的参数是一个引用类型,编译不过
// hashtable.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <Windows.h> #include <iostream> using namespace std; typedef struct _hash_table { } hash_table_t; template <typename K, typename V> class hashtable { private: typedef struct _hash_entry { K key; V value; struct _hash_entry *next; } hash_entry_t; typedef struct _iterator_data { hash_entry_t *cur_entry; hash_entry_t *next_entry; UINT cur_index; bool it_started; } iterator_data_t; hash_entry_t **table; UINT max_number; UINT persist_number; UINT cur_entry; iterator_data_t it_data; UINT get_hashkey(K &key); public: hashtable(UINT max_number = 10, UINT(*hash_key)(K &key) = NULL); ~hashtable(); bool insert(K key, V value); bool lookup(K key, V &value); bool remove(K key, V &value); void remove_all(); bool start_iterator(); bool has_next(); bool next_entry(K &key, V &value); bool end_iterator(); UINT(*hash_key)(K &key); }; template<typename K, typename V> hashtable<K, V>::hashtable(UINT max_number, UINT(*hash_key)(K &key)) { this->hash_key = hash_key; this->max_number = max_number; persist_number = 0; cur_entry = 0; table = new hash_entry_t*[this->max_number]; memset(table, 0x00, sizeof(hash_entry_t*) * this->max_number); memset(&it_data, 0x00, sizeof(it_data)); } template<typename K, typename V> hashtable<K, V>::~hashtable() { remove_all(); delete table; table = NULL; } template<typename K, typename V> UINT hashtable<K, V>::get_hashkey(K &key) { if (hash_key) { return hash_key(key); } else { UINT val = (UINT)key; return val % max_number; } } template<typename K, typename V> bool hashtable<K, V>::insert(K key, V value) { UINT index = get_hashkey(key); hash_entry_t *entry = table[index]; hash_entry_t *prev_entry = NULL; do { if (entry) { if (entry->key == key) { return false; } else { prev_entry = entry; entry = entry->next; } } else { entry = new hash_entry_t; entry->key = key; entry->value = value; entry->next = NULL; if (prev_entry) { prev_entry->next = entry; } else { table[index] = entry; } break; } } while (TRUE); return true; } template<typename K, typename V> bool hashtable<K, V>::lookup(K key, V & value) { UINT index = get_hashkey(key); if (table[index]) { hash_entry_t *entry = table[index]; while (entry) { if (entry->key == key) { value = entry->value; return true; } entry = entry->next; } } return false; } template<typename K, typename V> bool hashtable<K, V>::remove(K key, V & value) { UINT index = get_hashkey(key); if (table[index]) { hash_entry_t *entry = table[index]; hash_entry_t *prev_entry = NULL; while (entry) { if (entry->key == key) { value = entry->value; if (prev_entry) { prev_entry->next = entry->next; delete entry; entry = NULL; } else { table[index] = NULL; delete entry; entry = NULL; } return true; } prev_entry = entry; entry = entry->next; } } return false; } template<typename K, typename V> void hashtable<K, V>::remove_all() { for (UINT index = 0; index < max_number; index++) { if (table[index]) { hash_entry_t *entry = table[index]; while (entry) { hash_entry_t *entry_temp = entry; entry = entry->next; delete entry_temp; entry_temp = NULL; } table[index] = NULL; } } } template<typename K, typename V> bool hashtable<K, V>::start_iterator() { if (it_data.it_started) { return false; } it_data.cur_entry = NULL; it_data.cur_index = -1; it_data.it_started = true; return true; } template<typename K, typename V> bool hashtable<K, V>::has_next() { if (it_data.cur_entry) { it_data.cur_entry = it_data.cur_entry->next; if (it_data.cur_entry) { return true; } } for (it_data.cur_index++; it_data.cur_index < max_number; it_data.cur_index++) { it_data.cur_entry = table[it_data.cur_index]; if (it_data.cur_entry) { return true; } } return false; } template<typename K, typename V> bool hashtable<K, V>::next_entry(K &key, V &value) { if (it_data.cur_entry) { key = it_data.cur_entry->key; value = it_data.cur_entry->value; return true; } return false; } template<typename K, typename V> bool hashtable<K, V>::end_iterator() { if (!it_data.it_started) { return false; } it_data.cur_entry = NULL; it_data.cur_index = -1; it_data.it_started = false; return true; } int main() { hashtable<int, int> table; for (int i = 0; i < 200; i++) { table.insert(i, i * 20); } for (int i = 200; i >= 0; i--) { int value; if (table.lookup(i, value)) { cout << "Lookup:" << i << " = " << value << endl; } else { cout << "Lookup " << i << " failed" << endl; } } int value; table.remove(10, value); table.remove(50, value); for (int i = 200; i >= 0; i--) { int value; if (table.lookup(i, value)) { cout << "Lookup:" << i << " = " << value << endl; } else { cout << "Lookup " << i << " failed" << endl; } } table.start_iterator(); while (table.has_next()) { int key, value; table.next_entry(key, value); cout << key << " : " << value << endl; } table.end_iterator(); return 0; }