实现一个简单的哈希表
#include <stdio.h>
#include <stdlib.h>
#define SIZE 9
// 将数组元素封装成 key
typedef struct Element{
int key;
}* Element;
// 利用数组实现哈希表
typedef struct HashTable{
Element* table;
}* HashTable;
/**
* 哈希函数,计算对应的哈希值
*/
int hash(int key) {
return key % SIZE;
}
// 初始化哈希表
void init(HashTable hashTable) {
hashTable->table = malloc(sizeof (struct Element) * SIZE);
for(int i = 0; i < SIZE; i++) {
hashTable->table[i] = NULL;
}
}
// 往哈希表中插入元素(此处暂未考虑装满的情况)
void put(HashTable hashTable, Element element) {
// 计算哈希值
int hashCode = hash(element->key);
// 对号入座
hashTable->table[hashCode] = element;
}
// 查找
int get(HashTable hashTable, int key) {
int hashCode = hash(key);
if(hashTable->table[hashCode]->key == key) {
return 1;
}
return 0;
}
// 创建一个新元素
struct Element* createElement(int key) {
struct Element* element = malloc(sizeof(struct Element));
element->key = key;
return element;
}
冲突处理
线性探测法
当前有冲突就往后查找空闲位置
#include <stdio.h>
#include <stdlib.h>
#define SIZE 9
// 将数组元素封装成 key
typedef struct Element{
int key;
}* Element;
// 利用数组实现哈希表
typedef struct HashTable{
// 此处是指针的指针,数组中存放的是地址
Element* table;
}* HashTable;
/**
* 哈希函数,计算对应的哈希值
*/
int hash(int key) {
return key % SIZE;
}
// 初始化哈希表
void init(HashTable hashTable) {
hashTable->table = malloc(sizeof (struct Element) * SIZE);
for(int i = 0; i < SIZE; i++) {
hashTable->table[i] = NULL;
}
}
// 往哈希表中插入元素(此处暂未考虑装满的情况)
void put(HashTable hashTable, Element element) {
// 计算哈希值
int hashCode = hash(element->key);
int count = 0;
// 若当前哈希值对应位置已有元素则向后寻找
while(hashTable->table[hashCode]) {
// 重新计算哈希值,不能单纯 hashCode++,这样很可能会数组下标越界
hashCode = hash(element->key + ++count);
}
// 对号入座
hashTable->table[hashCode] = element;
}
// 查找
int get(HashTable hashTable, int key) {
int hashCode = hash(key);
int count = 0;
// 记录最初的位置,目的是方便后面判断 hashcode 是否已经走了一圈回来
int startIndex = hashCode;
do{
int cur = hashTable->table[hashCode]->key;
if(cur == key) {
return 1;
}
// 没找到则重新计算哈希值
hashCode = hash(key + ++count);
} while (startIndex != hashCode && hashTable->table[hashCode]);
return 0;
}
// 创建一个新元素
struct Element* createElement(int key) {
struct Element* element = malloc(sizeof(struct Element));
element->key = key;
return element;
}
int main() {
struct HashTable hashTable;
init(&hashTable);
for (int i = 0; i < 9; ++i) {
put(&hashTable, createElement(i * 9));
}
for (int i = 0; i < 9; ++i) {
printf("%d ", hashTable.table[i]->key);
}
}
链地址法
当前有冲突则将其变成链表连接起来
#include <stdio.h>
#include <stdlib.h>
#define SIZE 9
// 链表结构
typedef struct LinkNode {
int key;
struct LinkNode* next;
}* LinkNode;
// 数组模拟哈希表
typedef struct HashTable {
// 此处数组存放的是struct LinkNode类型节点
struct LinkNode* node;
}* HashTable;
int hash(int key) {
return key % SIZE;
}
void init(HashTable hashTable) {
hashTable->node = malloc(sizeof(struct LinkNode) * SIZE);
// 将哈希表中的所有头节点初始化
for (int i = 0; i < SIZE; ++i) {
// hashtable->node[i] 指的是数组中第 i 个的 struct LinkNode 节点,而不是指针(地址),故后面是用 . 来引出其结构体变量
hashTable->node[i].key = -1;
hashTable->node[i].next = NULL;
}
}
LinkNode createNode(int key) {
LinkNode node = malloc(sizeof(struct LinkNode));
node->key = key;
node->next = NULL;
return node;
}
void put(HashTable hashTable, int key) {
int hashCode = hash(key);
LinkNode head = &hashTable->node[hashCode];
// 若已有元素占领该位置,则继续直至链表尾,然后插入
while(head->next) {
head = head->next;
}
head->next = createNode(key);
}
int get(HashTable hashTable, int key) {
int hashCode = hash(key);
LinkNode head = &hashTable->node[hashCode];
// 此处设计的哈希表中的链表头节点默认全为 -1(类似于虚拟头节点),故真正的节点在head->next上
while(head->next) {
if(head->next->key == key) {
return 1;
}
head = head->next;
}
return 0;
}
int main() {
struct HashTable table;
init(&table);
put(&table, 10);
put(&table, 19);
put(&table, 20);
printf("%d\n", get(&table, 20));
printf("%d\n", get(&table, 17));
printf("%d\n", get(&table, 19));
}