##functions.h
#include<stdio.h>
#include<assert.h>
#include<windows.h>
typedef int KeyType;//关键字类型
typedef int ValueType;//个数类型
typedef struct HashNode //哈希链式节点
{
KeyType _key;//关键字值
ValueType _value;//个数
struct HashNode* _next;//指向下个节点的指针
}HashNode;
typedef struct HashTable//哈希表
{
HashNode** _tables; // hashnode *表示数组内每个元素类型 ,*table表示数组
size_t _size;//数组内已用个数
size_t _capacity;//数组最大容量
}HashTable;
HashNode* BuyHashNode(KeyType key, ValueType value)
{
HashNode *newnode = (HashNode*)malloc(sizeof(HashNode));
assert(newnode);
newnode->_key = key;
newnode->_next = NULL;
newnode->_value = value;
return newnode;
}
void HashPrint(HashTable *ht)
{
assert(ht);
for (size_t i = 0;i < ht->_capacity;i++)
{
HashNode *cur = ht->_tables[i];
printf("%d:", i);
while (cur)
{
printf("[%d %d]->", cur->_key, cur->_value);
cur = cur->_next;
}
printf("NULL\n");
}
}
size_t HashFunc(KeyType key, size_t capacity)
{
return key % capacity;
}
size_t GetNextPrimeNum(size_t cur)
{
int i = 0;
const int _PrimeSize = 28;
static const unsigned long _PrimeList[28] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for (int i = 0;i < 28;i++)
{
if (_PrimeList[i] >(unsigned long)cur)
{
return _PrimeList[i];
}
}
return _PrimeList[i];
}
void HashTableInit(HashTable* ht, size_t capacity)
{
assert(ht);
ht->_tables = (HashNode**)malloc(sizeof(HashNode*)*capacity);
assert(ht->_tables);
ht->_size = 0;
ht->_capacity = capacity;
//注意每个数组元素要设置为NULL
for (size_t i = 0;i < ht->_capacity;i++)
{
ht->_tables[i] = NULL;
}
}
void HashTableDestory(HashTable* ht)
{
assert(ht);
for (size_t i = 0;i < ht->_capacity;i++)
{
HashNode *cur = ht->_tables[i];
while (cur)
{
HashNode *next = cur->_next;
free(cur);
cur = next;
}
}
free(ht->_tables);
ht->_size = ht->_capacity = 0;
}
void check_capacity(HashTable *ht)
{
assert(ht);
if (ht->_size == ht->_capacity)//扩容条件
{
HashTable newtable;
HashTableInit(&newtable, GetNextPrimeNum(ht->_capacity));
for (size_t i = 0;i < ht->_capacity;i++)//依次将旧表的数据指向新表的映射点
{
HashNode *cur = ht->_tables[i];
while (cur)
{
HashNode *next = cur->_next;
size_t index = HashFunc(cur->_key, newtable._capacity);
cur->_next = newtable._tables[index];
newtable._tables[index] = cur;
cur = next;
}
}
//完成扩容+转移后,仍然使用旧表ht;
HashTableDestory(ht);
ht->_tables = newtable._tables;
ht->_size = newtable._size;
ht->_capacity = newtable._capacity;
}
}
void HashTableInsert(HashTable* ht, KeyType key, ValueType value)
{
assert(ht);
//检查是否需要扩容
check_capacity(ht);
//求映射点
size_t index = HashFunc(key, ht->_capacity);
//判断该key值已经在哈希表中
HashNode *cur = ht->_tables[index];
while (cur)
{
if (cur->_key == key)
{
cur->_value++;
return;
}
cur = cur->_next;
}
HashNode *newnode = BuyHashNode(key, value);
newnode->_next = ht->_tables[index];
ht->_tables[index] = newnode;
ht->_size++;
}
HashNode* HashTableFind(HashTable* ht, KeyType key)
{
assert(ht);
size_t index = HashFunc(key, ht->_capacity);
HashNode *cur = ht->_tables[index];
while (cur)
{
if (cur->_key == key)
{
return cur;
}
cur = cur->_next;
}
printf("can not find the key!\n");
return NULL;
}
//成功删除返回1 ,删除失败返回0;
int HashTableRemove(HashTable* ht, KeyType key)
{
//找映射点,变成从单链表中删除一个节点,删除时检查该key值得
//value值,如果>1的话减1,如果等于1直接删除。
assert(ht);
size_t index = HashFunc(key, ht->_capacity);
HashNode *cur = ht->_tables[index];
while (cur)
{
if (cur->_key == key)
{
if (cur->_value > 1)
{
cur->_value--;
return 1;
}
if (cur->_next)
{
//要删除的节点value值为1且不是尾节点,可以使用替换法
HashNode *next = cur->_next;
cur->_key = next->_key;
cur->_value = next->_value;
cur->_next = next->_next;
free(next);
next = NULL;
return 1;
}
else
{
//说明要删除的节点是尾节点且value值为1
HashNode *pcur = ht->_tables[index];
if (pcur = cur)
{
//说明该哈希地址出只有1个节点且是要删除的那个
free(pcur);
ht->_tables[index] = NULL;
return 1;
}
while (pcur->_next != cur)
{
pcur = pcur->_next;
}
pcur->_next = NULL;
free(cur);
cur = NULL;
return 1;
}
}
cur = cur->_next;
}
return 0;//没有找到
}
##test.c
#include"functions.h"
void test()
{
HashTable ht;
HashTableInit(&ht, 13);
HashTableInsert(&ht, 14, 2);
HashTableInsert(&ht, 27, 1);
HashTableInsert(&ht, 1, 1);
HashTableInsert(&ht, 3, 1);
HashPrint(&ht);
printf("\n\n");
HashTableRemove(&ht,14);
HashPrint(&ht);
}
int main()
{
test();
system("pause");
return 0;
}