哈希函数:若是输入的关键字是整数,则通常合理的方法是直接返回“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; }