散列用来以常数时间实现 Insert、Find 和 Delete 操作。
With [b]direct addressing[/b], an element with key k is stored in slot k.(相当于数组)
With [b]hashing[/b], this element is stored in slot h(k); that is, we use a hash function h to compute the slot from the key k.
h(k) 的范围远小于 k,所以必定会产生冲突(Collision)。
哈希函数表大小一般选择素数,可以使得均匀分布,缓解冲突。(为什么素数可以做到均匀分布?)
解决冲突方法一:链表数组实现,觉得代码很漂亮^_^
解决冲突方法二:[b]Open addressing[/b],数组实现
每个位置需要附加一个属性,表示这个位置 [b]已存、空的或已删的[/b]。
1. 线性探测法:往后面一个一个地找。
2. 平方探测法:往后面跳着找。
只能懒惰删除,不能真删。即标记已删。
再散列:表的大小不够时,建立另外一个大约两倍大小的新表,扫描原表,一个一个的插入到新表中。
来自《数据结构与算法分析》
With [b]direct addressing[/b], an element with key k is stored in slot k.(相当于数组)
With [b]hashing[/b], this element is stored in slot h(k); that is, we use a hash function h to compute the slot from the key k.
h(k) 的范围远小于 k,所以必定会产生冲突(Collision)。
哈希函数表大小一般选择素数,可以使得均匀分布,缓解冲突。(为什么素数可以做到均匀分布?)
解决冲突方法一:链表数组实现,觉得代码很漂亮^_^
typedef int ElementType;
typedef struct ListNode *Position;
struct ListNode
{
ElementType Element;
Position Next;
};
typedef Position List;
struct HashTbl
{
int TableSize;
List *TheLists; // an array of lists
};
typedef struct HashTbl *HashTable;
HashTable InitializeTable(int TableSize)
{
HashTable H;
int i;
H = (HashTbl *)malloc(sizeof(struct HashTbl));
if (H == NULL)
Error("Out of space!!!");
H->TableSize = NextPrime(TableSize);
H->TheLists = (List *)malloc(sizeof(List) * H->TableSize);
if (H->TheLists == NULL)
Error("Out of space!!!");
/* Allocate list headers */
for (i = 0; i < H->TableSize; i++)
{
H->TheLists[i] = (ListNode *)malloc(sizeof(struct ListNode));
if (H->TheLists[i] == NULL)
Error("Out of space!!!");
else
H->TheLists[i]->Next = NULL;
}
return H;
}
int Hash(ElementType Key, int TableSize)
{
return Key%TableSize;
}
Position Find(ElementType Key, HashTable H)
{
List L = H->TheLists[Hash(Key, H->TableSize)];
Position P = L->Next;
while (P != NULL && P->Element != Key)
P = P->Next;
return P;
}
void Insert(ElementType Key, HashTable H)
{
Position Pos, NewCell;
List L;
Pos = Find(Key, H);
if (Pos == NULL)
{
NewCell = (ListNode *)malloc(sizeof(struct ListNode));
if (NewCell == NULL) {
Error("Out of space!!!");
} else {
L = H->TheLists[Hash(Key, H->TableSize)];
NewCell->Next = L->Next;
NewCell->Element = Key;
L->Next = NewCell;
}
}
}
void DestroyTable(HashTable H)
{
int i;
for (i = 0; i < H->TableSize; i++)
{
Position P = H->TheLists[i];
Position Tmp;
while (P != NULL) {
Tmp = P->Next;
free(P);
P = Tmp;
}
}
free(H->TheLists);
free(H);
}
解决冲突方法二:[b]Open addressing[/b],数组实现
每个位置需要附加一个属性,表示这个位置 [b]已存、空的或已删的[/b]。
1. 线性探测法:往后面一个一个地找。
2. 平方探测法:往后面跳着找。
只能懒惰删除,不能真删。即标记已删。
再散列:表的大小不够时,建立另外一个大约两倍大小的新表,扫描原表,一个一个的插入到新表中。
来自《数据结构与算法分析》