分离链接散列表和平方探测散列表
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <cmath>
//判断一个数是否是素数
bool isPrime(int size)
{
//保证了size是奇数,因此因子也是奇数
for(int i=3;i<=sqrt(size);i+=2)
{
if(size%i==0)
return false;
}
return true;
}
//找到不小于这个数的下一个素数
int nextPrime(int size)
{
if(size<=2)
return 2; //最小素数
if(size%2==0) //除了2素数都是奇数,将偶数变成奇数
size++;
while(!isPrime(size)) //循环直到找到素数
{
size+=2;
}
return size;
}
//映射函数模板
template <typename Key>
class hash
{
public:
size_t operator()(const Key& k)const;
};
//默认映射函数
template <>
class hash<std::string>
{
public:
size_t operator()(const std::string& k)
{
size_t hashVal=0;
for(char ch:k)
{
hashVal=hashVal*37+ch;
}
return hashVal;
}
};
//映射对象
class Employee
{
private:
std::string name;
double salary;
int seniority;
public:
const std::string & getName()const
{
return name;
}
bool operator==(const Employee& rhs)const
{
return getName()==rhs.getName();
}
bool operator!=(const Employee& rhs)const
{
return !(*this==rhs);
}
};
template <>
class hash<Employee>
{
public:
size_t operator()(const Employee& item)
{
static hash<std::string> hf; //调用默认映射函数
return hf(item.getName());
}
};
//分离链接散列表
template <typename HashObj>
class HashTable
{
public:
explicit HashTable(int size = 101);
bool contains(const HashObj& x)const
{
auto & whichList=theLists[myhash(x)];
return find(whichList.begin(),whichList.end(),x)!=whichList.end();
}
void makeEmpty()
{
for(auto & thisList:theLists)
{
thisList.clear();
}
}
bool insert(const HashObj& x)
{
auto & whichList=theLists[myhash(x)];
if(find(whichList.begin(),whichList.end(),x)!=whichList.end())
{
return false;
}
whichList.push_back(x);
if(++currentSize>theLists.size()) //填充因子大于1再散列
{
rehash();
}
return true;
}
bool insert(HashObj&& x);
bool remove(const HashObj& x)
{
auto & whichList=theLists[myhash(x)];
auto itr=find(whichList.begin(),whichList.end(),x);
if(itr==whichList.end())
{
return false;
}
whichList.erase(itr);
--currentSize;
return true;
}
private:
std::vector<std::list<HashObj>> theLists;
int currentSize;
//再散列,重新计算位置
void rehash()
{
auto oldLists=theLists;
theLists.resize(nextPrime(2*oldLists.size()));
makeEmpty();
currentSize=0;
for(auto & thisList:oldLists)
{
for(auto & x:thisList)
{
insert(std::move(x));
}
}
}
//计算下标值
size_t myhash(const HashObj& x)const
{
static hash<HashObj> hf;
return hf(x) % theLists.size();
}
};
//平方探测散列
template <typename HashedObj>
class HashTable2
{
public:
explicit HashTable2(int size=101):array(nextPrime(size))
{
makeEmpty();
}
bool contains(const HashedObj& x)const
{
return isActive(findPos(x));
}
void makeEmpty()
{
currentSize=0;
for(auto &entry:array)
{
entry.info=EMPTY;
}
}
bool insert(const HashedObj& x)
{
int currentPos=findPos(x);
if(array[currentPos].info==ACTIVE)
return false;
array[currentPos].element=x;
array[currentPos].info=ACTIVE;
if(++currentSize>array.size()/2) //填充因子大于0.5再散列
rehash();
return true;
}
bool insert(HashedObj&& x);
bool remove(const HashedObj& x)
{
int currentPos=findPos(x);
if(array[currentPos].info!=ACTIVE)
return false;
array[currentPos].info=DELETED; //懒惰删除
return true;
}
enum EntryType{ACTIVE,EMPTY,DELETED}; //枚举类型,表明位置的状态
private:
struct HashEntry
{
HashedObj element;
EntryType info;
HashEntry(const HashedObj& e=HashedObj{},EntryType i=EMPTY):element(e),info(i){}
HashEntry(HashedObj&& e,EntryType i=EMPTY):element(std::move(e)),info(i){}
};
std::vector<HashEntry> array;
int currentSize;
bool isActive(int currentPos)const
{
return array[currentPos].info==ACTIVE;
}
//找到一个可以插入的位置
int findPos(const HashedObj& x)const
{
int offset=1;
int currentPos=myhash(x);
while(array[currentPos].info!=EMPTY
&&array[currentPos].element!=x)
{
currentPos+=offset;
offset+=2;
if(currentPos>=array.size())
{
currentPos-=array.size();
}
}
return currentPos;
}
void rehash()
{
std::vector<HashEntry> oldArray=array;
array.resize(nextPrime(oldArray.size()*2));
makeEmpty();
for(auto & entry:oldArray)
if(entry.info==ACTIVE)
{
insert(std::move(entry.element));
}
}
size_t myhash(const HashedObj& x)const;
};