11. 开放定址散列表
fatal.h
#include <stdio.h>
#include <stdlib.h>
#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)
hashquad.h
/* Interface for quadratic probing hash table */
typedef int ElementType;
#ifndef _HashQuad_H
#define _HashQuad_H
typedef unsigned int Index;
typedef Index Position;
struct HashTbl;
typedef struct HashTbl *HashTable;
HashTable InitializeTable(int TableSize);
void DestroyTable(HashTable H);
Position Find(ElementType Key, HashTable H);
void Insert(ElementType Key, HashTable H);
ElementType Retrieve(Position P, HashTable H);
HashTable Rehash(HashTable H);
void PrintTable(HashTable H);
/* Routines such as Delete are MakeEmpty are omitted */
#endif /* _HashQuad_H */
hashquad.c
#include "fatal.h"
#include "hashquad.h"
#include <stdlib.h>
#define MinTableSize (10)
enum KindOfEntry { Legitimate, Empty, Deleted };
struct HashEntry
{
ElementType Element;
enum KindOfEntry Info;
};
typedef struct HashEntry Cell;
/* Cell *TheCells will be an array of */
/* HashEntry cells, allocated later */
struct HashTbl
{
int TableSize;
Cell *TheCells;
};
/* Return next prime; assume N >= 10 */
static int NextPrime(int N)
{
int i;
if (N % 2 == 0)
N++;
for (; ; N += 2)
{
for (i = 3; i * i <= N; i += 2)
if (N % i == 0)
break;
if (i*i > N)
return N;
}
}
/* Hash function for ints */
Index Hash(ElementType Key, int TableSize)
{
return Key % TableSize;
}
HashTable InitializeTable(int TableSize)
{
HashTable H;
int i;
if (TableSize < MinTableSize)
{
Error("Table size too small");
return NULL;
}
/* Allocate table */
H = malloc(sizeof(struct HashTbl));
if (H == NULL)
FatalError("Out of space!!!");
H->TableSize = NextPrime(TableSize);
/* Allocate array of Cells */
H->TheCells = malloc(sizeof(Cell) * H->TableSize);
if (H->TheCells == NULL)
FatalError("Out of space!!!");
for (i = 0; i < H->TableSize; i++)
H->TheCells[i].Info = Empty;
return H;
}
Position Find(ElementType Key, HashTable H)
{
Position CurrentPos;
int CollisionNum;
CollisionNum = 0;
CurrentPos = Hash(Key, H->TableSize);
while (H->TheCells[CurrentPos].Info != Empty &&
H->TheCells[CurrentPos].Element != Key)
/* Probably need strcmp!! */
{
CurrentPos += 2 * ++CollisionNum - 1;
if (CurrentPos >= H->TableSize)
CurrentPos -= H->TableSize;
}
return CurrentPos;
}
void Insert(ElementType Key, HashTable H)
{
Position Pos;
Pos = Find(Key, H);
if (H->TheCells[Pos].Info != Legitimate)
{
/* OK to insert here */
H->TheCells[Pos].Info = Legitimate;
H->TheCells[Pos].Element = Key;
/* Probably need strcpy! */
}
}
HashTable Rehash(HashTable H)
{
int i, OldSize;
Cell *OldCells;
OldCells = H->TheCells;
OldSize = H->TableSize;
/* Get a new, empty table */
H = InitializeTable(2 * OldSize);
/* Scan through old table, reinserting into new */
for (i = 0; i < OldSize; i++)
if (OldCells[i].Info == Legitimate)
Insert(OldCells[i].Element, H);
free(OldCells);
return H;
}
ElementType Retrieve(Position P, HashTable H)
{
return H->TheCells[P].Element;
}
void DestroyTable(HashTable H)
{
free(H->TheCells);
free(H);
}
void PrintTable(HashTable H)
{
int i;
for (i = 0; i < H->TableSize; i++)
{
if (H->TheCells[i].Info == Legitimate)
printf("%d\t", Retrieve(i, H));
else if (H->TheCells[i].Info == Empty)
printf("-\t");
}
printf("\n\n");
}
testhash.c
#include "hashquad.h"
#include <stdio.h>
#define NumItems 110
int main()
{
HashTable H;
Position P;
int i;
int j = 0;
int CurrentSize;
int RehashCount = 0;
H = InitializeTable(CurrentSize = 11);
for (i = 0; i < NumItems; i++, j += 71)
{
if (i > CurrentSize / 2)
{
printf("Rehash before:\n");
PrintTable(H);
H = Rehash(H);
printf("%d: Rehashing...\n\n", ++RehashCount);
CurrentSize *= 2;
printf("Rehash after:\n");
PrintTable(H);
printf("\n");
}
Insert(j, H);
}
for (i = 0, j = 0; i < NumItems; i++, j += 71)
if (Retrieve((P = Find(j, H)), H) != j)
printf("Error at %d\n", j);
printf("hash table:\n");
PrintTable(H);
printf("End of program.\n");
return 0;
}