C++实现Hash表的插入,删除,重建开放寻址法
#include<iostream>
using namespace std;
typedef int KeyType; //设关键字域为整形,需要修改类型时,只需修改这里就可以
const int NULLKEY=0; //NULLKEY表示该位置无值
int c=0; //用来统计冲突次数
struct Elemtype //数据元素类型
{
KeyType key;
int ord;
};
int hashsize[]={11,19,29,37,47}; //hash表容量递增表
int Hash_length=0;//hash表表长
class HashTable
{
private:
Elemtype *elem; //数据元素数组,动态申请
int count;// 当前数据元素个数
int size; //决定hash表的容量为第几个,hashsize[size]为当前hash容量
public:
int Init_HashTable() //构造一个空hash表
{
int i;
count=0;
size=0; //初始化容量为hashsize[0]=11
Hash_length=hashsize[0]; //初始的hash表的容量是11
elem=new Elemtype[Hash_length];
if(!elem)
{
cout<<"内存申请失败"<<endl;
exit(0);
}
for(i=0;i<Hash_length;i++) //初始化hash表,每个元素都是NULLKEY
elem[i].key=NULLKEY;
return 1;
}
~HashTable() //析构函数
{
delete[]elem;
elem=NULL;
count=0;
size=0;
}
unsigned Hash(KeyType k) //选取hash函数的一种(取模法,模为hash表的长度)
{
return k%Hash_length;
}
void Collision(int &p,int d) //解决冲突
{
p=(p+d)%Hash_length; //采用开放地址法里的线性探测法来解决冲突
}
bool Search_Hash(KeyType k,int &p) //查找
{
//在开放地址hash表中查找关键字等于k的元素
//若找到用p表示待查数据的地址标号
c=0;
p=Hash(k); //求hash地址
while(elem[p].key!=NULLKEY && elem[p].key!=k&&c<Hash_length) //遇到空巢或者超过表容量或者已经找到循环终止
{
c++;
Collision(p,c);
}
if(elem[p].key==k) //如果查找成功返回1
return 1;
else
return 0;
}
int Insert_Hash(Elemtype e) //插入
{
//在查找不成功的情况下将k插入到hash表中
int p; int c=0;
int Hash_length=hashsize[0];
if(Search_Hash(e.key,p))
return -1; //表示该元素已在hash表中
else
{
while(c<Hash_length)
{
int j= (Hash(e.key)+c)%Hash_length;
if(elem[j].key==NULLKEY)
{
elem[p]=e;
count++;
return 1;
}
c++;
}
return 0;
//原来的hash表溢出时,需要扩大hash表的容量再插入
if(c=Hash_length)
ReCreate_HashTable(); // 重建hash表,把输入插入到表中
}
}
void ReCreate_HashTable() //重建hash表
{
int i,count2=count;
Elemtype *p,*elem2=new Elemtype[count];
p=elem2;
cout<<"____重建hash表_____"<<endl;
for(i=0;i<Hash_length;i++) //将原有元素暂存到elem2中
if(elem[i].key!=NULLKEY)
*p++=*(elem+i);
count=0;
delete []elem; //清空elem中的元素
size++; //hash容量增大
Hash_length=hashsize[size];
Elemtype *q=new Elemtype[Hash_length];
if(!q)
{
cout<<"空间申请失败"<<endl;
exit(0);
}
elem=q; //原来的elem表变大了,用了新的表长度
for(i=0;i<Hash_length;i++)
elem[i].key=NULLKEY;
for(p=elem2;p<elem2+count2;p++) //将原有元素依次插入到elem表中
Insert_Hash(*p);
}
void Traverse_HashTable()
{
cout<<"哈希地址0->"<<Hash_length-1<<endl;
for(int i=0;i<Hash_length;i++)
if(elem[i].key!=NULLKEY)
cout<<"元素的关键字值和它的标志分别是:"<<elem[i].key<<" "<<elem[i].ord<<endl;
}
void Get_Data(int p)
{
cout<<"元素的关键字值和它的标志分别是:"<<elem[p].key<<" "<<elem[p].ord<<endl;
}
};
int main()
{
Elemtype r[12]={{17,1},{60,2},{29,3},{38,4},{1,5},{2,6},{3,7},{4,8},{5,9},{6,10},{7,11},{6,12}};
HashTable H;
int i,p,j;
KeyType k;
H.Init_HashTable(); //初始化hash表,能装11个元素
for(i=0;i<11;i++) //插入前11个记录
{
j=H.Insert_Hash(r[i]);
if(j==-1)
cout<<"表中已有关键字为"<<r[i].key<<" "<<r[i].ord<<"的记录"<<endl;
}
cout<<"按哈希地址顺序遍历哈希表"<<endl;
H.Traverse_HashTable();
cout<<endl;
cout<<"输入要查找的记录的关键字:";
cin>>k;
j=H.Search_Hash(k,p);
if(j==1)
H.Get_Data(p);
else
cout<<"无此记录"<<endl;
j=H.Insert_Hash(r[11]); //插入一个元素
if(j==0)
{
cout<<"插入失败"<<endl;
cout<<"需要重建哈希表才可以插入"<<endl;
cout<<"____重建哈希表____"<<endl;
H.Insert_Hash(r[i]); //重建后重新插入
}
if(j==-1)
{
cout<<"hash表中已经有这个值"<<endl;
}
cout<<"遍历重建后的哈希表"<<endl;
H.Traverse_HashTable();
cout<<endl;
cout<<"输入要查找的记录的关键字:";
cin>>k;
j=H.Search_Hash(k,p);
if(j==1)
H.Get_Data(p);
else
cout<<"该记录不存在"<<endl;
return 0;
}