#define HASH_SIZE 7
#define NULLKEY -32768
typedef int Status;
#define OK 1
#define ERROR 0
typedef struct {
int *elem; // 動態數組基址
int count; // 當前元素數(此處復用為表長)
} HashTable;
Status init_hash(HashTable *ht) {
ht->elem = (int *)malloc(HASH_SIZE * sizeof(int));
if (!ht->elem) return ERROR;
ht->count = HASH_SIZE;
for (int i = 0; i < HASH_SIZE; i++) ht->elem[i] = NULLKEY;
return OK;
}
int hash_func(int key) {
return key % HASH_SIZE;
}
void hash_insert(HashTable *ht, int key) {
int addr = hash_func(key);
// 線性探測尋找空槽
while (ht->elem[addr] != NULLKEY) {
addr = (addr + 1) % HASH_SIZE;
}
ht->elem[addr] = key;
}
// 返回索引,-1 表示未找到
int hash_search(HashTable *ht, int key) {
int addr = hash_func(key);
int start = addr;
do {
if (ht->elem[addr] == key) return addr;
if (ht->elem[addr] == NULLKEY) return -1; // 遇到空槽,必不存在
addr = (addr + 1) % HASH_SIZE;
} while (addr != start); // 繞回起點,表滿未找到
return -1;
}
void hash_display(HashTable *ht) {
printf("==============================\n");
for (int i = 0; i < ht->count; i++) {
if (ht->elem[i] == NULLKEY) printf("[%d]: NULL ", i);
else printf("[%d]: %d ", i, ht->elem[i]);
}
printf("\n==============================\n");
}
int main() {
HashTable ht;
int data[] = {13, 29, 27, 28, 26, 30, 38}; // 7 個數,恰好填滿
int n = sizeof(data) / sizeof(data[0]);
init_hash(&ht);
for (int i = 0; i < n; i++) hash_insert(&ht, data[i]);
hash_display(&ht);
// 查找測試
int targets[] = {27, 38, 99};
for (int i = 0; i < 3; i++) {
int idx = hash_search(&ht, targets[i]);
if (idx >= 0) printf("找到 %d @ 索引 %d\n", targets[i], idx);
else printf("%d 不存在\n", targets[i]);
}
free(ht.elem);
return 0;
}
| 插入鍵值 | 初始地址 | 探測序列 | 最終位置 |
|---|---|---|---|
| 13 | 13%7=6 | 6 | 6 |
| 29 | 29%7=1 | 1 | 1 |
| 27 | 27%7=6 | 6(佔)→0 | 0 |
| 28 | 28%7=0 | 0(佔)→1(佔)→2 | 2 |
| 26 | 26%7=5 | 5 | 5 |
| 30 | 30%7=2 | 2(佔)→3 | 3 |
| 38 | 38%7=3 | 3(佔)→4 | 4 |
索引: 0 1 2 3 4 5 6 值 : 27 29 28 30 38 26 13
本文實現了教科書級的開放定址法散列表,涵蓋初始化、哈希函數、線性探測插入/查找、遍歷顯示。理解「哈希函數決定初始位置,探測序列解決衝突」這一核心模式,是掌握所有散列表變體(雙重哈希、Cuckoo、Robin Hood、Hopscotch)的基石。