开放定址法解决散列冲突时主要有线性探测法,平方探测法和双散列法,以下代码通过插入大量随机数,来统计几种探测法产生冲突的次数。
#include<iostream> using namespace std; #define MinTablesize 10 #define Num 3000 typedef unsigned int Index; typedef Index Position; struct Hashtal; typedef struct Hashtal *Hashtable; int num_quadratic_probing = 0; int num_liner_probing = 0; int num_double_probing = 0; int array_rand[Num]; //大小为1000的随机数组 enum KindOfEntry //枚举类型,只能是其中的一个值 { Legitimate,Empty,Delete }; struct HashEntry { int Element; enum KindOfEntry Info; }; typedef struct HashEntry Cell; struct Hashtal { int TableSize; int Insert_num; //记录插入的个数 Cell *Thecells; }; Hashtable Rehash (Hashtable H,int ty); Hashtable Insert(int Key,Hashtable H,int ty); int Hash (int x,Hashtable H) //散列函数 { return x % H->TableSize; } int NextPrime (int Key) // 寻找Key后的第一个素数 { if(Key == 1 || Key == 2) return Key; bool flag = 0; int pre_Key; while(!flag) { pre_Key = Key; for(int i = 2; i != Key; ++i) { if(Key % i == 0) //Key不是素数 { Key++; break; } } if(pre_Key == Key) //说明Key没有改变 flag = 1; else flag = 0; } return Key; } Hashtable InitTable(int Tablesize) //创建一个散列表 { Hashtable H; if(Tablesize < MinTablesize) { cout << "Table is too small" << endl; return NULL; } //创建散列表 H = (Hashtable)malloc(sizeof(struct Hashtal)); if(H == NULL) cout << "out of space " << endl; H->TableSize = NextPrime(Tablesize); //大小为H->TableSize后的第一个素数 H->Thecells = (Cell*)malloc(sizeof(Cell) * H->TableSize ); if(H->Thecells == NULL) cout << "out of space " << endl; H->Insert_num = 0; for (int i = 0; i != H->TableSize; ++i) H->Thecells[i].Info = Empty; //每个元素都标记为空 return H; } Position Find_linear_probing (int Key , Hashtable H) //使用线性探测散列 { Position CurrPos; int CollNum; CollNum = 0; CurrPos = Hash(Key,H); while(H->Thecells[CurrPos].Info != Empty && H->Thecells[CurrPos].Element != Key) //找不到时返回一个空单元 { CurrPos = (CurrPos + (++CollNum)) % H->TableSize; //使用线性探测散列法 ++num_liner_probing; //冲突次数加1 if((int)CurrPos >= H->TableSize ) CurrPos -= H->TableSize; } return CurrPos; } Position Find_quadratic_probing (int Key , Hashtable H) //使用平方探测散列 { Position CurrPos; int CollNum; CollNum = 0; CurrPos = Hash(Key,H); while(H->Thecells[CurrPos].Info != Empty && H->Thecells[CurrPos].Element != Key) //找不到时返回一个空单元 { ++CollNum; CurrPos = (CurrPos + CollNum * CollNum) % H->TableSize; //使用平方探测散列法 ++num_quadratic_probing; //冲突次数加1 if((int)CurrPos >= H->TableSize ) CurrPos -= H->TableSize; } return CurrPos; } Position Find_double (int Key , Hashtable H) //使用双散列 { Position CurrPos; int CollNum; CollNum = 0; CurrPos = Hash(Key,H); while(H->Thecells[CurrPos].Info != Empty && H->Thecells[CurrPos].Element != Key) //找不到时返回一个空单元 { CurrPos = (CurrPos + (++CollNum) * (7 - (Key % 7 ))) % H->TableSize; //使用双散列探测 ++num_double_probing; //冲突次数加1 if((int)CurrPos >= H->TableSize ) CurrPos -= H->TableSize; } return CurrPos; } Hashtable Insert(int Key,Hashtable H,int ty) { if(((double)H->Insert_num /H->TableSize) > 0.5) //如果装填因子大于0.5,就再散列, H = Rehash(H,ty); Position Pos; switch (ty) { case 1: Pos = Find_quadratic_probing(Key,H); break; case 2: Pos = Find_linear_probing(Key,H); break; case 3: Pos = Find_double(Key,H); break; default: cout << "Insert type error" << endl; } if(H->Thecells[Pos].Info != Legitimate) // { H->Thecells[Pos].Element = Key; H->Thecells[Pos].Info = Legitimate; H->Insert_num++; //插入的元素个数加1 } return H; } Hashtable Rehash (Hashtable H,int ty) //再散列,把表的大小放大到原来的2倍,再把原来的元素插入到新散列表中 { int Oldsize; Cell *Oldcells; Oldcells = H->Thecells; Oldsize = H->TableSize; H = InitTable(2 * Oldsize); for (int i = 0; i != Oldsize; ++i) { if(Oldcells[i].Info == Legitimate) Insert(Oldcells[i].Element, H,ty); } free(Oldcells); return H; } void destroyTable(Hashtable H) { free(H->Thecells ); free(H); } int main () { for (int i = 0; i != Num; ++i) { array_rand[i] = rand(); //产生随机数 } Hashtable H1 = InitTable(200); //200大小的散列表 for(int i = 0; i != Num; ++i) { H1 = Insert(array_rand[i],H1,1); } cout << num_quadratic_probing << endl; destroyTable(H1); Hashtable H2 = InitTable(200); //200大小的散列表 for(int i = 0; i != Num; ++i) { H2 = Insert(array_rand[i],H2,2); } cout << num_liner_probing << endl; destroyTable(H2); Hashtable H3 = InitTable(200); //200大小的散列表 for(int i = 0; i != Num; ++i) { H3 = Insert(array_rand[i],H3,3); } cout << num_double_probing << endl; destroyTable(H3); return 0; }
通过改变随机数组的大小,可以多次观察结果,发现每次都是双散列产生的冲突次数最少,但是也少不了多少。
夜深了,,,
好像是陷入死循环,希望后面的代码有个break。