❤️️💚💙💛🧡💜🖤🤍🧡
大家好!我是曾续缘🥰
欢迎关注💕
❤️点赞 👍 收藏 ⭐再看,养成习惯
🔥人有两条路要走,一条是必须走的,一条是想走的,你必须把必须走的路走漂亮,才可以走想走的路。📚
散列表(也叫哈希表),是根据关键字值而直接进行访问的数据结构。
通过把关键字值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
散列函数的构造方法:
(1)直接定址法
(2)除留余数法
(3)平方取中法
(4)折叠法
(5)数值分析法
通常采用除留余法,通过对KEY进行求余,使得KEY分布在HashTable的数组中,同时为了减少键冲突,除数通常选择为素数。
本文介绍拉链法:将大小为 M 的数组中的每个元素指向一条链表,链表中的每个结点都存储了散列值为该元素的索引的键值对。
将关键码通过散列函数映射至特定的单链表中,当多个关键码映射至相同地址时,称这些关键码互为同义词,通过一个单链表存储同义词。
这个方法的基本思想就是选择足够大的 M ,使得所有链表都尽可能短以保证高效的查找。
1 拉链法解决冲突的方法
拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。
2 拉链法的优点
(1)拉链法处理冲突简单,且无堆积现象,即非同义词决不会发生冲突,因此平均查找长度较短;
(2)由于拉链法中各链表上的结点空间是动态申请的,故它更适合于造表前无法确定表长的情况;
(3)当结点较大时,拉链法中增加的指针域可忽略不计,因此节省空间;
(4)在用拉链法构造的散列表中,删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。
结构体设计
template<class E, class K>
struct node {// 链表结点
K key; // 键值
E data; // 数据
node<E, K>* next; // 下一个结点
node() { next = nullptr; }
};
template<class E, class K>
class HashTable {
public:
HashTable(int d);
bool search(K key);// 查找
bool insert(K key, E e); // 插入
bool remove(K key); // 删除
node<E, K>get(K key); // 获取值
void print();
private:
int divisor; // 散列方式为除留余数法
int size, maxsize;
node<E, K>** hash; // 指针数组
};
代码实现
template<class E, class K>
HashTable<E, K>::HashTable(int d) { // 初始化
divisor = d;
maxsize = d;
size = 0;
hash = new node<E, K>*[maxsize];
if (hash == nullptr)exit(1);
for (int i = 0;i < maxsize;i++)hash[i] = nullptr;
}
// 查找分两步:首先根据散列值找到对应的链表,然后沿着链表顺序查找对应的键。
template<class E, class K>
bool HashTable<E, K>::search(K key) {
int i = key % divisor;
node<E, K>* p = hash[i];
while (p != nullptr && p->key != key)p = p->next;
if (p == nullptr)return false;
return true;
}
// 采用尾插法,从头到尾判断键值对是否已经存在,判断不存在后插入
template<class E, class K>
bool HashTable<E, K>::insert(K key, E e) {
node<E, K>* p = nullptr, * s;
int i = key % divisor;
p = hash[i];
s = new node<E, K>;
s->key = key;
s->data = e;
if (p == nullptr) {
hash[i] = s;
size++;
return true;
}
while (p != nullptr && p->key != key)p = p->next; //从头到尾判断键值对是否已经存在
if (p != nullptr)return false;
s->next = hash[i];
hash[i] = s;
size++;
return true;
}
template<class E, class K>
bool HashTable<E, K>::remove(K key) {
int i = key % divisor;
node<E, K>* p = hash[i];
if (p == nullptr)return false;
if (p->key == key) {
hash[i] = p->next;
size--;
delete p;
p = nullptr;
return true;
}
node<E, K>* cur = p->next;
while (cur != nullptr && cur->key != key) {
cur = cur->next;
p = p->next;
}
if (cur == nullptr)return false;
p->next = cur->next;
size--;
delete cur;
return true;
}
template<class E, class K>
node<E, K> HashTable<E, K>::get(K key) {
if (search(key)) {
int i = key % divisor;
node<E, K>* p = hash[i];
while (p != nullptr && p->key != key)p = p->next;
return *p;
}
return node<E, K>();
}
template<class E, class K>
void HashTable<E, K>::print() {
for (int i = 0;i < maxsize;i++) {
node<E, K>* p = hash[i];
cout << i << ": ";
while (p != nullptr) {
cout << "(" << p->key << "," << p->data << ") ";
p = p->next;
}
cout << endl;
}
}
参考书籍推荐:参考书籍
有用的话点个赞吧~关注@曾续缘,持续获取更多资料。