本文主要是介绍【C++】多态:实现一个可以自定义哈希函数的哈希表类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目
请实现一个可以自定义哈希函数的哈希表类
哈希函数
哈希函数包括:函数、函数对象、Lambda表达式
分析
一片内存空间存储数据,一个可以自行配置的哈希方法,冲突处理方法。
根据题意哈希函数的类型,所以要传入一个可调用对象来配置哈希函数,可以存储可调用类型的是 function
。
基础版本
#include <iostream>
#include <vector>
using namespace std;class Node { //拉链法的节点
public :Node() = default;Node(string, Node *);string data();Node *next();void insert(Node *);void erase_next();
private :string __data;Node *__next;
};class HashTable {
public ://function可以存储函数对象typedef function<int(string)> HASH_FUNC_T;HashTable(HASH_FUNC_T hash_func, int);bool insert(string);bool erase(string);bool find(string);private :int size;HASH_FUNC_T hash_func;vector<Node> data;
};Node::Node(string data, Node *next = nullptr) : __data(data), __next(next) {}
string Node::data() { return this->__data; }
Node *Node::next() { return this->__next; }
void Node::insert(Node *p) {p->__next = this->__next;this->__next = p;
}void Node::erase_next() {if (this->__next == nullptr) return ;Node *q = this->__next;this->__next = this->__next->__next;delete q;return ;
}HashTable::HashTable(HASH_FUNC_T hash_func, int size = 10000) : size(size), data(size), hash_func(hash_func) {}
bool HashTable::insert(string s) {if (find(s)) return false;int h = hash_func(s) % size;//传入的字符串插入到哈希表相应的位置//data[h]为虚拟头节点data[h].insert(new Node(s));return true;
}bool HashTable::erase(string s) {int h = hash_func(s) % size;for (Node *p = &data[h]; p->next(); p = p->next()) {if (p->next()->data() != s) continue;p->erase_next();return true;}return false;
}bool HashTable::find(string s) {int h = hash_func(s) % size;for (Node *p = data[h].next(); p; p = p->next()) {if (p->data() == s) return true;}return false;
}int BKDRHash(string s) {int seed = 31;int h = 0;for (int i = 0; s[i]; i++) {h = h * seed + s[i];}//将负的哈希值变成正的哈希值return h & 0x7fffffff;
}class APHash_class {
public ://重载()使其成为函数对象int operator()(string s) {int h = 0;for (int i = 0; s[i]; i++) {if (i % 2) {h = (h << 3) ^ s[i] ^ (h >> 5);} else {h = ~((h << 7) ^ s[i] ^ (h >> 11));}}return h & 0x7fffffff;}
};int main() {//用函数配置哈希函数HashTable h1(BKDRHash);APHash_class APHash;//用函数对象配置哈希函数HashTable h2(APHash);int op;string s;while (cin >> op >> s) {switch (op) {case 0: {cout << "insert " << s << " to hash table 1 = ";cout << h1.insert(s) << endl;cout << "insert " << s << " to hash table 2 = ";cout << h2.insert(s) << endl;} break; //insertcase 1: {cout << "erase " << s << " from hash table 1 = ";cout << h1.erase(s) << endl;cout << "erase " << s << " from hash table 2 = ";cout << h2.erase(s) << endl;} break; //erasecase 2: {cout << "find " << s << " at hash table 1 = ";cout << h1.find(s) << endl;cout << "find " << s << " at hash table 2 = ";cout << h1.find(s) << endl;} break; //find}}return 0;
}
运行结果:
优化版本一:实现 []
运算符
当前实现的哈希表表现得像个 unordered_map
,想让它表现得像个数组一样,于是实现 []
运算符。
#include <iostream>
#include <vector>
using namespace std;class Node { //拉链法的节点
public :Node() = default;Node(string, int, Node *);string key();int value;Node *next();void insert(Node *);void erase_next();
private :string __key;Node *__next;
};class HashTable {
public ://function可以存储函数对象typedef function<int(string)> HASH_FUNC_T;HashTable(HASH_FUNC_T hash_func, int);bool insert(string, int);bool erase(string);bool find(string);int &operator[](string);private :Node *__insert(string, int);Node *__find(string);int size;HASH_FUNC_T hash_func;vector<Node> data;
};Node::Node(string key, int value = 0, Node *next = nullptr) : __key(key), value(value), __next(next) {}
string Node::key() { return this->__key; }
Node *Node::next() { return this->__next; }
void Node::insert(Node *p) {p->__next = this->__next;this->__next = p;
}void Node::erase_next() {if (this->__next == nullptr) return ;Node *q = this->__next;this->__next = this->__next->__next;delete q;return ;
}HashTable::HashTable(HASH_FUNC_T hash_func, int size = 10000) : size(size), data(size), hash_func(hash_func) {}bool HashTable::insert(string key, int value = 0) {if (find(key)) return false;return __insert(key, value); //返回地址是否为空
}Node *HashTable::__insert(string key, int value = 0) {int h = hash_func(key) % size;//传入的字符串插入到哈希表相应的位置//data[h]为虚拟头节点data[h].insert(new Node(key, value));return data[h].next();
}bool HashTable::erase(string s) {int h = hash_func(s) % size;for (Node *p = &data[h]; p->next(); p = p->next()) {if (p->next()->key() != s) continue;p->erase_next();return true;}return false;
}bool HashTable::find(string s) {return __find(s);
}
Node *HashTable::__find(string key) {int h = hash_func(key) % size;for (Node *p = data[h].next(); p; p = p->next()) {if (p->key() == key) return p;}return nullptr;
}int &HashTable::operator[](string key) {Node *p;if (!(p = __find(key))) return (__insert(key)->value);return p->value;
}int BKDRHash(string s) {int seed = 31;int h = 0;for (int i = 0; s[i]; i++) {h = h * seed + s[i];}//将负的哈希值变成正的哈希值return h & 0x7fffffff;
}class APHash_class {
public ://重载()使其成为函数对象int operator()(string s) {int h = 0;for (int i = 0; s[i]; i++) {if (i % 2) {h = (h << 3) ^ s[i] ^ (h >> 5);} else {h = ~((h << 7) ^ s[i] ^ (h >> 11));}}return h & 0x7fffffff;}
};int main() {//用函数配置哈希函数HashTable h1(BKDRHash);APHash_class APHash;//用函数对象配置哈希函数HashTable h2(APHash);int op;string s;h1["hello"] = 123;h1["world"] = 456;cout << h1["hello"] << " " << h1["world"] << " " << h1["hahaha"] << endl; //输出123 456 0while (cin >> op >> s) {switch (op) {case 0: {cout << "insert " << s << " to hash table 1 = ";cout << h1.insert(s) << endl;cout << "insert " << s << " to hash table 2 = ";cout << h2.insert(s) << endl;} break; //insertcase 1: {cout << "erase " << s << " from hash table 1 = ";cout << h1.erase(s) << endl;cout << "erase " << s << " from hash table 2 = ";cout << h2.erase(s) << endl;} break; //erasecase 2: {cout << "find " << s << " at hash table 1 = ";cout << h1.find(s) << endl;cout << "find " << s << " at hash table 2 = ";cout << h1.find(s) << endl;} break; //find}}return 0;
}
优化版本二:扩容哈希表
- 新建哈希表
- 将原哈希表中的数据插入到新建的哈希表中
- 交换新建的哈希表和原哈希表中的内容
#include <iostream>
#include <vector>
using namespace std;class Node { //拉链法的节点
public :Node() = default;Node(string, int, Node *);string key();int value;Node *next();void insert(Node *);void erase_next();
private :string __key;Node *__next;
};class HashTable {
public ://function可以存储函数对象typedef function<int(string)> HASH_FUNC_T;HashTable(HASH_FUNC_T hash_func, int);bool insert(string, int);bool erase(string);bool find(string);int capacity();int &operator[](string);private :Node *__insert(string, int);Node *__find(string);void __expand();int __size, data_cnt;HASH_FUNC_T hash_func;vector<Node> data;
};Node::Node(string key, int value = 0, Node *next = nullptr) : __key(key), value(value), __next(next) {}
string Node::key() { return this->__key; }
Node *Node::next() { return this->__next; }
void Node::insert(Node *p) {p->__next = this->__next;this->__next = p;
}void Node::erase_next() {if (this->__next == nullptr) return ;Node *q = this->__next;this->__next = this->__next->__next;delete q;return ;
}HashTable::HashTable(HASH_FUNC_T hash_func, int size = 2) : __size(size), data(__size), hash_func(hash_func), data_cnt(0) {}int HashTable::capacity() {return this->__size;
}bool HashTable::insert(string key, int value = 0) {if (find(key)) return false;return __insert(key, value); //返回地址是否为空
}Node *HashTable::__insert(string key, int value = 0) {if (data_cnt >= __size) __expand();cout << "__insert " << key << " " << value << endl;int h = hash_func(key) % __size;//传入的字符串插入到哈希表相应的位置//data[h]为虚拟头节点data[h].insert(new Node(key, value));data_cnt += 1;//拉链法的每条链上有2个节点return data[h].next();
}void HashTable::__expand() {cout << "Expand hash table" << endl;int new_size = __size * 2;HashTable temp_h(hash_func, new_size);//遍历当前哈希表中的数据依次插入到新的哈希表中for (int i = 0; i < __size; i++) {for (Node *p = data[i].next(); p; p = p->next()) {temp_h[p->key()] = p->value;}}//交换当前哈希表和临时哈希表swap(*this, temp_h);return ;
}bool HashTable::erase(string s) {int h = hash_func(s) % __size;for (Node *p = &data[h]; p->next(); p = p->next()) {if (p->next()->key() != s) continue;p->erase_next();data_cnt -= 1;return true;}return false;
}bool HashTable::find(string s) {return __find(s);
}
Node *HashTable::__find(string key) {int h = hash_func(key) % __size;for (Node *p = data[h].next(); p; p = p->next()) {if (p->key() == key) return p;}return nullptr;
}int &HashTable::operator[](string key) {Node *p;if (!(p = __find(key))) return (__insert(key)->value);return p->value;
}int BKDRHash(string s) {int seed = 31;int h = 0;for (int i = 0; s[i]; i++) {h = h * seed + s[i];}//将负的哈希值变成正的哈希值return h & 0x7fffffff;
}class APHash_class {
public ://重载()使其成为函数对象int operator()(string s) {int h = 0;for (int i = 0; s[i]; i++) {if (i % 2) {h = (h << 3) ^ s[i] ^ (h >> 5);} else {h = ~((h << 7) ^ s[i] ^ (h >> 11));}}return h & 0x7fffffff;}
};int main() {//用函数配置哈希函数HashTable h1(BKDRHash);APHash_class APHash;//用函数对象配置哈希函数HashTable h2(APHash);int op;string s;cout << h1.capacity() << endl;cout << h2.capacity() << endl;h1["hello"] = 123;h1["world"] = 456;h1["maureen"] = 789;cout << h1.capacity() << endl;cout << h1["hello"] << " " << h1["world"] << " " << h1["hahaha"] << endl;while (cin >> op >> s) {switch (op) {case 0: {cout << "insert " << s << " to hash table 1 = ";cout << h1.insert(s) << endl;cout << "insert " << s << " to hash table 2 = ";cout << h2.insert(s) << endl;} break; //insertcase 1: {cout << "erase " << s << " from hash table 1 = ";cout << h1.erase(s) << endl;cout << "erase " << s << " from hash table 2 = ";cout << h2.erase(s) << endl;} break; //erasecase 2: {cout << "find " << s << " at hash table 1 = ";cout << h1.find(s) << endl;cout << "find " << s << " at hash table 2 = ";cout << h1.find(s) << endl;} break; //find}}return 0;
}
运行结果:
这篇关于【C++】多态:实现一个可以自定义哈希函数的哈希表类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!