散列函數以及化解衝突的兩種方法

哈希函數:若是輸入的關鍵字是整數,則通常合理的方法是直接返回「key mod TableSize」的結果,除非key碰巧具備某些特殊的性質。在這種狀況下,散列函數的選擇須要仔細考慮。例如,若表的大小爲10而關鍵字都以0爲個位,則此時上述標準的散列函數就是一個很差的選擇。爲了不這種狀況,好的辦法一般是保證表的大小爲素數。前端

剩下的主要編程細節是解決衝突的消除問題。若果當一個元素被插入時,另外一個元素已經存在(散列值相同),那麼就會產生一個衝突,解決這種衝突的方法有多種,其中最簡單的就是:分離連接法和開放地址法。ios

(一)分離連接法:將散列到同一個值得全部元素都保留着一個表中。爲方便起見這些表都有表頭。爲執行查找操做(Find),使用散列函數肯定使用哪一個表,一般的方式遍歷該表,找到全部查找的元素在該表中的位置。執行插入操做是(Insert),遍歷一個相應的表以檢查該元素是否已經處在適當的位置(若是插入一個重複元,一般留出一個額外的域,這個域當重複元出現時增長1)。若是這個元素是一個新的元素,那麼它或者插入表的前端,或者插入表的尾部(有時候新元素插入到表的前端,不只是由於方便,而還由於新進插入的元素最有可能最早訪問)。算法

散列函數處理衝突的方法(一):分離連接散列表編程


#include<iostream>
#define MINTABLESIZE 8
using namespace std;數據結構

typedef int ElemType;函數

typedef struct LNode            //聲明表的節點(鏈表)
{
 ElemType data;
 struct LNode *next;
}LinstNode, *LinkList;this

typedef struct HashNode    //哈希表的聲明
{
 int TableSize;
 LinkList *TheLists;
}HashNode, *HashTable;spa

int Hash(const ElemType key, int TableSize)        //哈希函數的構造
{
 return key % TableSize;
}指針

int NextPrime(int data)            //哈希表長的選擇(素數)
{
 int prime = data;
 while(prime >= data)
 {
  int i;
  for(i = 2; i <= prime / 2; i++)
  {
   if(prime % i == 0)
    break;
  }
  if(i > prime / 2)
   return prime;
  prime ++;
 }
}code

//散列表的初始化
HashTable InitializeHashTable(int TableSize)
{
 HashTable H;
 if(TableSize < MINTABLESIZE)
 {
  cout << "Table size is too small!" << endl;
  return NULL;
 }
 H = new HashNode();
 H->TableSize = NextPrime(TableSize);    //所須要的哈希表長
 
 H->TheLists = new LinkList();  //指向鏈表指針的指針

 for(int i = 0; i < H->TableSize; i++)
 {
  H->TheLists[i] = new LNode();  //爲每個哈希表元素分配一個鏈表
  H->TheLists[i]->next = NULL;  //爲每個鏈表構建一個頭結點
 }
 return H;
}

//插入元素
void Insert(ElemType key, HashTable H)
{
 LNode *position, *Newcell;
 LinkList L;
 L = NULL;
 //設哈希表中沒有該元素
 Newcell = new LNode();
 Newcell->data = key;
 L = H->TheLists[Hash(key, H->TableSize)];
 Newcell->next = L->next;
 L->next = Newcell;
}

void Find(ElemType key, HashTable H)        //在哈希表中查找某一元素
{
 LNode *position;
 LinkList L;
 L = H->TheLists[Hash(key, H->TableSize)];
 position = L->next;
 while(position != NULL && position->data != key)
 {
  position = position->next;
 }
 if(position == NULL)
  cout << "Not find this value!" << endl;
 else
  cout << position ->data << endl;
}

int main()
{
 HashTable H;
 H = InitializeHashTable(9);
 for(int i = 0; i < 10; i++)
  Insert(i, H);
 Find(3, H);

 system("pause");
 return 0;
}

(二)開放地址散列表

分離連接散列算法的缺點是須要指針,因爲給新單元分配地址須要時間,所以這就致使算法的速度多少有些減慢,同時,算法實際上還要求對另外一種數據結構的實現。開放地址散列法是另外一種不用鏈表解決衝突的方法。在開放地址散列算法系統中,若是有衝突發生那麼就要嘗試使用另外一種單元直到找到空的單元爲止。

1)線性探測解決衝突:

#include<iostream>
#define NULLKEY -32768
using namespace std;
#define TableSize 10

typedef int ElemType;
typedef struct HashNode
{
 ElemType *data;
 int HashSize;
} HashTable;

int InitializedHashTable(HashTable *H)
{
 H->HashSize = TableSize;
 H->data = new int [TableSize];
 
 for(int i = 0; i < TableSize; i++)
 {
  H->data[i] = NULLKEY;
 }
 return 0;
}

int HashKey(ElemType key)
{
 return key % TableSize;
}

void InsertHashValue(HashTable *H, ElemType key)
{
 int position;
 
 position = HashKey(key);


 while(H->data[position] != NULLKEY)
 {
  position = (position + 1) % TableSize;
  //position = position + 2 * ++collisionNum -1;

 }
 //if(position >= H->HashSize)
 // position -= H->HashSize;
 H->data[position] = key;
}

int Find(HashTable *H, ElemType key)
{
 int position;
 //int collisionNum = 0;
 position = HashKey(key);
 while(H->data[position] != key)
 {
  position = (position + 1) % TableSize;
  //position = position + 2 * ++collisionNum -1;
  if(H->data[position] == NULLKEY || position == HashKey(key))
   return -1;
 }
 
 cout << H->data[position] << " " << key << endl;
 return 0;
}

int main()
{

 int position;
 HashTable H;

 InitializedHashTable(&H);
 
 for(int i = 2; i < 8; i++)
  InsertHashValue(&H, i);
 position = Find(&H, 7);

 

 system("pause");
 return 0;
}

2)平方探測進行查找

int Find(HashTable H, ElemType key)
{
 int CurrentPosition;
 int CollisionNum = 0;
 CurrentPosition = Hash(key, H->TableSize);
 cout << Hash(key, H->TableSize) << endl;
 while(H->TheCells[CurrentPosition].Info != Empty
  && H->TheCells[CurrentPosition].data != key)
 {
  CollisionNum++;
  CurrentPosition = CurrentPosition + 2 * ++CollisionNum - 1;
 }
 if(CurrentPosition >= H->TableSize)
  CurrentPosition -= H->TableSize;
 cout << H->TheCells[CurrentPosition].data << endl;
 return CurrentPosition;
}
相關文章
相關標籤/搜索