哈希表(Hash Table)是一种常见的数据结构,能够快速地进行查找和插入操作。它的核心思想是利用哈希函数将关键字映射到数组的某个位置上,使得查找和插入的时间复杂度接近O(1)。
下面是C语言实现哈希表的基本步骤:
- 定义哈希表结构体
首先定义一个哈希表结构体,其中包含两个成员:一是数组buckets用来存储哈希表中的元素,二是size表示buckets中元素的数量。
#define TABLE_SIZE 10000 // 哈希表大小
typedef struct
{
int* buckets;
int size;
} HashTable;
2.初始化哈希表
初始化哈希表时需要为buckets分配内存,并将其所有元素初始化为-1。这里用-1表示哈希表当前位置没有元素
HashTable* create_table()
{ //根据自己需求创建哈希表的大小
HashTable* table = (HashTable*)malloc(sizeof(HashTable));
table->buckets = (int*)malloc(sizeof(int) * TABLE_SIZE);
table->size = TABLE_SIZE;
for (int i = 0; i < TABLE_SIZE; i++)
{
table->buckets[i] = -1;
}
return table;
}
3.定义哈希函数
哈希函数的作用是将关键字映射到数组的某个位置上。一个好的哈希函数应该尽可能地避免冲突,即不同的关键字映射到相同的位置上。这里采用简单的取余法作为哈希函数
int hash(int key)
{
return key % TABLE_SIZE;
}
4.插入元素
插入元素时需要先对关键字进行哈希,得到它在数组中的位置。如果该位置还没有被占用,则直接插入;否则需要处理冲突,例如使用开放地址法、链地址法等方法。
void insert(HashTable* table, int key, int value) {
int index = hash(key);
while (table->buckets[index] != -1)
{
index++;
index %= TABLE_SIZE;
}
table->buckets[index] = value;
}
5.查找元素
查找元素时同样需要先进行哈希,得到它在数组中的位置。然后依次向后查找,直到找到对应的元素或者遇到空位置停止查找。
int search(HashTable* table, int key)
{
int index = hash(key);
while (table->buckets[index] != -1)
{
if (table->buckets[index] == key)
{
return index;
}
index++;
index %= TABLE_SIZE;
}
return -1;
}
难度中等
136
给定正整数 k ,你需要找出可以被 k 整除的、仅包含数字 1 的最 小 正整数 n 的长度。
返回 n 的长度。如果不存在这样的 n ,就返回-1。
注意: n 不符合 64 位带符号整数。
示例 1:
输入:k = 1输出:1解释:最小的答案是 n = 1,其长度为 1。
示例 2:
输入:k = 2输出:-1解释:不存在可被 2 整除的正整数 n 。
示例 3:
输入:k = 3输出:3解释:最小的答案是 n = 111,其长度为 3
该题只需对特殊值进行判断后在进行遍历就可以了
int smallestRepunitDivByK(int k)
{
if(k%5==0 || k%2==0)
return -1;
int min=1,ans=1;
while(min % k)
{
min = min%k;
min = min*10 +1;
ans ++;
}
return ans;
}
看到一个比较新奇的,用字符串进行记录,但不太明白它的原理是什么。
看了ChatGPT的解释,才晓得具体实现中,代码通过动态数组kc来记录每个余数是否出现过,如果某个余数已经出现过,则说明已经进入了一个循环。函数的返回值为最小循环长度,如果无法被K整除,则返回-1,表示不存在符合条件的数字序列。
int smallestRepunitDivByK(int K)
{
int *kc = (int *)calloc(K, sizeof(int));
int count = 0, i = 0;
while (!kc[i])
{
kc[i] = 1;
i = (i * 10 + 1) % K;
count++;
}
return (i == 0) ? count : -1;
}
官解的哈希表,感觉和字符串判断有相似,都是判断是否掉入死循环,然后得出能否整除。
// 定义一个哈希表的元素结构体,含有键值 key 和指向哈希表的指针
typedef struct {
int key;
UT_hash_handle hh;
} HashItem;
// 在哈希表中查找键值为 key 的元素,返回找到的元素指针
HashItem *hashFindItem(HashItem **obj, int key) {
HashItem *pEntry = NULL;
// 使用 UT_hash_handle 库中的 HASH_FIND_INT 宏实现
HASH_FIND_INT(*obj, &key, pEntry);
return pEntry;
}
// 在哈希表中添加键值为 key 的元素,如果已存在则返回 false,否则返回 true
bool hashAddItem(HashItem **obj, int key) {
if (hashFindItem(obj, key)) {
return false;
}
// 创建一个新的元素结构体,并设置键值
HashItem *pEntry = (HashItem *)malloc(sizeof(HashItem));
pEntry->key = key;
// 使用 UT_hash_handle 库中的 HASH_ADD_INT 宏将元素添加到哈希表中
HASH_ADD_INT(*obj, key, pEntry);
return true;
}
// 释放哈希表 obj 中所有元素的内存
void hashFree(HashItem **obj) {
HashItem *curr = NULL, *tmp = NULL;
// 使用 UT_hash_handle 库中的 HASH_ITER 宏遍历哈希表
HASH_ITER(hh, *obj, curr, tmp) {
// 使用 UT_hash_handle 库中的 HASH_DEL 宏从哈希表中删除元素
HASH_DEL(*obj, curr);
// 释放元素的内存
free(curr);
}
}
// 解决问题的函数
int smallestRepunitDivByK(int k) {
// 初始化余数为 1,长度为 1,并创建一个空的哈希表
int resid = 1 % k, len = 1;
HashItem *st = NULL;
// 在哈希表中添加余数
hashAddItem(&st, resid);
// 当余数不为 0 时,重复以下操作
while (resid != 0) {
// 计算下一个余数
resid = (resid * 10 + 1) % k;
// 长度加 1
len++;
// 如果哈希表中已经存在该余数,则说明已经出现循环,直接返回 -1
if (hashFindItem(&st, resid) != NULL) {
hashFree(&st);
return -1;
}
// 在哈希表中添加余数
hashAddItem(&st, resid);
}
// 释放哈希表的内存,返回长度
hashFree(&st);
return len;
}