基本思想
散列表的数据结构可以看作是包含有关关键字的具有固定大小的数组。假设这个数组(hash表)的大小是tableSize,那么我们可以把数据按照从0-tableSize-1的键值来存放,数据通过hash来映射不同的键值。这个映射就叫做散列函数(hash function),理想情况下它应该运算简单并且应该保证任何两个不同的关键字映射到不同的单元。不过,数据很多的情况下,这基本上是不可能的,不过可以通过一些方法来解决出现冲突的情况,比如使用分离链接法。
分离链接法
基本思想是通过链表的形式,把hash到相同键值的数据连接起来。
可参考下面的代码
#include <stdio.h>
#include <stdlib.h>
#define MinTableSize 10
int Hash(const int key, int tableSize)
{
return key % tableSize;
}
struct List
{
int val;
struct List*next;
};
typedef struct List ListNode;
struct hashtable
{
int tableSize;
ListNode **theLists;
};
typedef struct hashtable HashTable;
//获得合适的模的大小
int getModuleSize(int tableSize)
{
int i;
if(tableSize%2 == 0)
tableSize++;
i = 3;
while(i*i <= tableSize)
{
if(tableSize%i == 0)
{
tableSize = tableSize + 2;
i = 3;
}
else{
i+=2;
}
}
return tableSize;
}
//初始化hash表
HashTable *InitalizeTable(int TableSize)
{
HashTable *hashTable;
int i = 0;
if(TableSize < MinTableSize)
{
perror("Table size too small");
return NULL;
}
//allocate tableSize
hashTable = malloc(sizeof(HashTable));
if(NULL== hashTable)
perror("Out of space");
hashTable->tableSize = getModuleSize(TableSize);
hashTable->theLists = malloc(sizeof(ListNode)*hashTable->tableSize);
if(hashTable->theLists == NULL)
perror("Out of space");
/* allocate list headers */
printf("hashTable size : %d\n", hashTable->tableSize);
for(i = 0; i < hashTable->tableSize; ++i)
{
hashTable->theLists[i] = malloc(sizeof(ListNode));
if(hashTable->theLists[i] == NULL)
perror("out of space");
else
hashTable->theLists[i]->next = NULL;
}
return hashTable;
}
//从hash表中找到key
ListNode* Find(int key, HashTable*H)
{
ListNode* p;
p = H->theLists[Hash(key, H->tableSize)];
while(p != NULL)
{
if(p->val == key)
{
return p;
}
p = p->next;
}
return NULL;
}
//插入key
void Insert(int key, HashTable* H)
{
ListNode* Pos, *NewCell;
ListNode *L;
Pos = Find(key, H);
if(Pos == NULL)
{
NewCell = malloc(sizeof(ListNode));
if(NULL == NewCell)
printf("out of space\n");
else
{
L = H->theLists[Hash(key, H->tableSize)];
NewCell->next = L->next;
NewCell->val = key;
L->next = NewCell;
}
}
}
//打印hash表
void printHashTable(HashTable *hashTable)
{
int key = 0;
ListNode *pNode;
for(key = 0; key < hashTable->tableSize; ++key)
{
pNode = hashTable->theLists[Hash(key, hashTable->tableSize)];
pNode = pNode->next;
printf("+------------+\n");
printf("hashTable[%d]",key);
while(pNode != NULL)
{
printf("->%d",pNode->val);
pNode = pNode->next;
}
printf("\n+------------+\n");
}
}
//单元测试
void testHash()
{
int tableSize = 12;
ListNode *nodeBeToFound;
HashTable* H = InitalizeTable(tableSize);
if(H == NULL)
{
printf("Func InitalizeTable return NULL\n");
return;
}
int i = 0;
int size = 5;
int goal = 5;
for(i = 1; i <= size; ++i)
{
Insert(i*i, H);
//printf("%d:%d\n",i*i, Hash(i*i,10));
}
printHashTable(H);
nodeBeToFound = Find(25,H);
if(nodeBeToFound != NULL)
printf("node found is %d\n",nodeBeToFound->val);
}
void main()
{
testHash();
}