数据结构--开放定址法解决散列冲突时几种探测法的比较

Posted waitforyoull

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构--开放定址法解决散列冲突时几种探测法的比较相关的知识,希望对你有一定的参考价值。

     开放定址法解决散列冲突时主要有线性探测法,平方探测法和双散列法,以下代码通过插入大量随机数,来统计几种探测法产生冲突的次数。

 

    

#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。

 

     

以上是关于数据结构--开放定址法解决散列冲突时几种探测法的比较的主要内容,如果未能解决你的问题,请参考以下文章

哈希表处理冲突的几种方式

线性探测法

散列表解决冲突的方式

数据结构—— 散列查找:冲突处理方法

散列表的开放定址法以及再散列法(C语言)

散列——排解冲突 开放定址法(上)