解决HashTable的冲突的第二种方法叫做开放定址法。开放定址法不需要使用指针,不需要特意的动态分配空间。当发生冲突时此算法会选择其他的空的单元。因此核心问题来了,怎么有效的选择空的单元呢?
- 算法一:线性探测法 F(i)=i(i为寻址次数)
原理:对HashTable进行插入时,出现Index相同时,我们在原始Index的基础上加F(i)。但是问题又来了,因为F(i)为线性函数,它会连续的Insert元素,因此会出现很多元素的聚集现象,我们也叫做一次聚集。怎么解决呢?往下看哦~
- 算法二:平方探测法F(i)=F(i-1)+2*i-1 (F(i)=i*i)(i为寻址次数)
原理:对HashTable进行插入时,出现Index相同时,我们在原始Index的基础上加F(i)。但是问题又来了,因为F(i)为平方函数,虽然不会连续的Insert元素,但是会出现二次聚集现象。怎么解决呢?可使用双散列进行,本篇不详细讨论了。
HashTable完整源码如下:
#include<iostream>
#include<memory>
typedef size_t Index;
typedef std::string ElemType;
const size_t MaxSize = 11;
enum class KindOfEntry{ NoEmpty,Empty,Deleted };
struct HashUnit {
ElemType element;
KindOfEntry info; //Lazy Delete
};
struct HashTab {
size_t tablesize;
HashUnit* arrays;
};
class HashTable {
public:
HashTable() :hashtable(std::make_unique<HashTab>()) {
hashtable->tablesize = MaxSize;
hashtable->arrays = new HashUnit[MaxSize];
for (int i = 0; i < hashtable->tablesize; ++i)
hashtable->arrays[i].info = KindOfEntry::Empty;
};
~HashTable() {
if (hashtable->arrays)
delete[] hashtable->arrays;
}
public:
Index Find(const ElemType key)const;
void Insert(const ElemType key);
void Delete(const ElemType key);
void Display()const;
private:
Index Hash_one(const ElemType key)const;
Index Hash_two(const ElemType key)const;
Index Hash_three(const ElemType key)const;
private:
std::unique_ptr<HashTab>hashtable;
};
Index HashTable::Hash_one(const ElemType key)const {
size_t hashval = 0;
int i = 0;
while (key[i] != '\0') {
hashval += key[i];
++i;
}
return hashval % hashtable->tablesize;
}
Index HashTable::Hash_two(const ElemType key)const {
auto hashval = key[0] + key[1] * 27 + key[2] * 27 * 27;
return hashval % hashtable->tablesize;
}
Index HashTable::Hash_three(const ElemType key)const {
size_t hashval = 0;
int i = 0;
while (key[i] != '\0') {
hashval = (hashval << 5)/* hashval*32 */ + key[i];
++i;
}
return hashval % hashtable->tablesize;
}
Index HashTable::Find(const ElemType key)const {
auto index = Hash_three(key);
size_t count = 0;
while (hashtable->arrays[index].info != KindOfEntry::Empty && hashtable->arrays[index].element != key) {
index += 2 * ++count - 1;
if (index >= hashtable->tablesize)
index -= hashtable->tablesize;
}
return index;
}
void HashTable::Insert(const ElemType key) {
auto index = Find(key);
if (hashtable->arrays[index].info != KindOfEntry::NoEmpty) {
hashtable->arrays[index].info = KindOfEntry::NoEmpty;
hashtable->arrays[index].element = key;
}
}
void HashTable::Delete(const ElemType key) {
auto index = Hash_three(key);
if (hashtable->arrays[index].info != KindOfEntry::Deleted)
hashtable->arrays[index].info = KindOfEntry::Deleted;
}
void HashTable::Display()const {
for (int i = 0; i < hashtable->tablesize; ++i){
std::cout << "i:" << i << " " << hashtable->arrays[i].element.c_str() << " Info:";
if (hashtable->arrays[i].info == KindOfEntry::Deleted)
std::cout << "Deleted" << std::endl;
if (hashtable->arrays[i].info == KindOfEntry::Empty)
std::cout << "Empty" << std::endl;
if (hashtable->arrays[i].info == KindOfEntry::NoEmpty)
std::cout << "NoEmpty" << std::endl;
}
}
int main(void)
{
HashTable hash;
const std::string name = "Jay";
hash.Insert(name);
hash.Display();
std::cout << "Delete a key: Jay" << std::endl;
hash.Delete(name);
hash.Display();
}