前一節用分離連結法解決了衝突問題,同時該演算法也具有自己的缺點。
- 需要指標,新單元分配地址需要時間,導致速度減慢。
- 需要實現另一種資料結構(單連結串列)。
所以就有了開放地址法,如其名 開放地址
就是把其他地址也開放出來 比如在 分離連結法裡面 hash 值為 0 的單元只對映 hash(x) = 0 的關鍵字,而在開放地址法裡面就會把這些地址開放給其他的關鍵字,開放地址法:當有衝突時,就嘗試選擇另外的單元,直到找出空單元為止
那麼他們又通過什麼規則來確定對映關係以及尋找另外的單元的呢?這就是下面要說的 線性探測
跟 平方探測
。
線性探測
顧名思義,就是一個接一個的尋找,比如 hash(x) = 0;在 0 單元上發生衝突,就往下探測 1、2、3 ...直到找到一個空單元為止。
平方探測
跟名字一樣,就是當衝突發生時用二次函式來作為尋找單元的計算方法,如 hash(x) = 0;在 0 單元上發生衝突,下一個位置為:F(i) = i^2 來探測,i 第幾次探測。
雜湊表的結構圖如下:hash_quad.h
標頭檔案定義
typedef unsigned int index;
typedef char* element_type;
typedef index position;
struct hash_table_node;
typedef struct hash_table_node *hash_table;
index hash(element_type key, int table_size);
hash_table initialize_table(int table_size);
void destroy_table(hash_table h);
position find(element_type key, hash_table h);
void insert(element_type key, hash_table h);
element_type retrieve(position p, hash_table h);
void delete(element_type key, hash_table h);
int next_prime(int table_size);
void random_hash_table(hash_table h, int len);
void print_hash_table(hash_table h);
void test();
enum kind_of_entry { legitimate, empty, deleted };
struct hash_entry
{
element_type element;
enum kind_of_entry info;
};
typedef struct hash_entry cell;
struct hash_table_node
{
int table_size;
int size;
cell *pcell_arr;
};
hash_quad 實現
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "hash_quad.h"
#define error(str) fatal_error(str)
#define fatal_error(str) fprintf(stderr, "%s\n", str), exit(1)
index hash(element_type key, int table_size)
{
unsigned int hash_value = 0;
while (*key != '\0') {
hash_value = (hash_value << 5) + *key++;
}
return hash_value % table_size;
}
int next_prime(int table_size)
{
int i, j = 2, k;
for (i = table_size; i > 0; i--) {
k = sqrt(i);
while (j <= k) {
if (i % j == 0)
break;
j++;
}
if (j > k)
break;
}
return i;
}
hash_table initialize_table(int table_size)
{
int min_table_size = 5;
hash_table h;
int i;
if ( table_size < min_table_size) {
error(" Table size is too small");
return NULL;
}
h = (hash_table)malloc(sizeof(struct hash_table_node));
if (NULL == h)
fatal_error("out of space");
h->table_size = next_prime(table_size);
h->size = 0;
h->pcell_arr = malloc(sizeof(struct hash_entry) * h->table_size);
if (NULL == h->pcell_arr)
fatal_error("out of space");
for (i = 0; i < h->table_size; i++) {
h->pcell_arr[i].info = empty;
}
return h;
}
position find(element_type key, hash_table h)
{
position current_pos;
int i;
i = 0;
current_pos = hash(key, h->table_size);
while (h->pcell_arr[current_pos].info != empty && h->pcell_arr[current_pos].element != key) {
// 線性探測
// current_pos += 1;
// 平方探測
current_pos += 2 * ++i - 1;
if (current_pos >= h->table_size)
current_pos -= h->table_size;
}
return current_pos;
}
void insert(element_type key, hash_table h)
{
position pos;
if (h->size > 0.8 * h->table_size) {
printf("超出 0.8 的裝填因子,需要擴容\n");
return;
}
pos = find(key, h);
if (h->pcell_arr[pos].info != legitimate) {
h->pcell_arr[pos].info = legitimate;
h->pcell_arr[pos].element = key;
h->size++;
}
}
void destroy(hash_table h)
{
if (NULL == h)
error("Hash Table is NULL");
int i;
free(h->pcell_arr);
free(h);
}
void delete(element_type key, hash_table h)
{
position pos;
pos = find(key, h);
if (h->pcell_arr[pos].info == legitimate) {
h->pcell_arr[pos].info = deleted;
free(h->pcell_arr[pos].element);
h->size--;
}
}
void random_hash_table(hash_table h, int len)
{
char dictionary[52] = "adcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int str_len, i, j;
srand((unsigned)time(NULL));
for (i = 0; i < len; i++) {
str_len = rand() % 8 + 1; // 1-8
char* str;
str = (char*)malloc(sizeof(char) * (str_len + 1));
for (j = 0; j < str_len; j++) {
str[j] = dictionary[rand() % 52];
}
str[j] = '\0';
insert(str, h);
str = NULL;
}
}
void print_hash_table(hash_table h)
{
index i;
for (i = 0; i < h->table_size; i++) {
printf("%d\t=>", i);
if (h->pcell_arr[i].info == legitimate)
printf("\t%s", h->pcell_arr[i].element);
printf("\n");
}
}
void test()
{
hash_table h;
h = initialize_table(22);
printf("\t\tinsert adc into hash table.\n");
char* str = (char*)malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
insert(str, h);
print_hash_table(h);
printf("\t\tdelete abc.\n");
delete(str, h);
print_hash_table(h);
random_hash_table(h, 13);
printf("\t\ta random hash table\n");
print_hash_table(h);
}
int main(int argc, char const *argv[])
{
test();
return 0;
}
- 開放地址法。
- 線性探測。
- 平方探測。
- 陣列結構實現的雜湊表。
- c 的 char 型別 跟 字串的理解。