HashTable InitializeTable( int TableSize ); voidDestroyTable( HashTable H ); Position Find( ElementType Key, HashTable H ); voidInsert( ElementType Key, HashTable H ); ElementType Retrieve( Position P, HashTable H ); HashTable Rehash( HashTable H ); /* Routines such as Delete are MakeEmpty are omitted */
/* Cell *TheCells will be an array of */ /* HashEntry cells, allocated later */ structHashTbl { int TableSize; Cell *TheCells; };
/* Return next prime; assume N >= 10 */
staticint 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) goto ContOuter; /* Sorry about this! */ return N; ContOuter:; } }
/* 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"); returnNULL; }
/* Allocate table */ H = new HashTbl; if (H == NULL) FatalError("Out of space!!!");
H->TableSize = NextPrime(TableSize);
H->TheCells = (Cell *)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; //初始化为1
return H; }
Position Find(ElementType Key, HashTable H) { Position CurrentPos; int CollisionNum;
structListNode { ElementType Element; Position Next; };
typedef Position List;
/* List *TheList will be an array of lists, allocated later */ /* The lists use headers (for simplicity), */ /* though this wastes space */ structHashTbl { int TableSize; List *TheLists; };
/* Return next prime; assume N >= 10 */ staticint 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) goto ContOuter; /* Sorry about this! */ return N; ContOuter:; } }
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"); returnNULL; }
/* Allocate table */ H=new HashTbl; if (H == NULL) FatalError("Out of space!!!");
H->TableSize = NextPrime(TableSize);
/* Allocate array of lists */ H->TheLists = (List*)malloc(sizeof(List) * H->TableSize); if (H->TheLists == NULL) FatalError("Out of space!!!");
/* Allocate list headers *//*实现表头*/ for (i = 0; i < H->TableSize; i++) { H->TheLists[i] = new ListNode; if (H->TheLists[i] == NULL) FatalError("Out of space!!!"); else H->TheLists[i]->Next = NULL; }
return H; }
Position Find(ElementType Key, HashTable H) { Position P; List L;
L = H->TheLists[Hash(Key, H->TableSize)]; P = L->Next; while (P != NULL && P->Element != Key) /* Probably need strcmp!! */ P = P->Next; return P; }
voidInsert(ElementType Key, HashTable H) { Position Pos, NewCell; List L;
Pos = Find(Key, H); if (Pos == NULL) /* Key is not found */ { NewCell = new ListNode; if (NewCell == NULL) FatalError("Out of space!!!"); else { L = H->TheLists[Hash(Key, H->TableSize)]; NewCell->Next = L->Next; NewCell->Element = Key; /* Probably need strcpy! */ L->Next = NewCell;S } } }
为了避免聚集,在探测时选择跳跃式的探测,即再使用一个散列函数,用来计算探测的位置。假设前面的散列函数为hash1(X),用于探测的散列函数为hash2(X),那么一种流行的选择是F(i) = i * hash2(X),即第一次冲突时探测hash1(X)+hash2(X)的位置,第二次探测hash1(X)+2hash2(X)的位置。模拟表明,双散列的探测几乎和随机冲突解决方法情景相同,这使得双散列在理论上很有吸引力。不过对于平方探测就没有必要使用第二个散列函数了。这个就不在具体说了。
可扩散列允许用两次磁盘访问执行一次查找,插入操作也只需很少的磁盘访问。它可以看作由B-树变化而来,增加 M ,使B-树的深度为1。根保存在内存中,用 D 代表根使用的位数, D 也称为目录,则目录中的项数为 2D 。树叶的元素个数最多为 M , d**L 为树叶 L 所有元素共有的最高位的位数, d**L≤D 。下图是可扩散列的一个例子。