【发布时间】:2021-03-11 22:29:28
【问题描述】:
所以我到处寻找灵感,但我并没有真正找到使用单独链接方法重新散列哈希表的任何东西。所以我自己尝试了一下,我想我知道我做错了什么,但我不知道如何实现它,请帮助。
一切正常,除了新添加的函数 rehash()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
struct list_node
{
struct list_node *next;
char *key;
char *value;
};
struct hash_table
{
int table_size;
struct list_node **list_arr;
};
unsigned int hash(const char *key, unsigned int table_size);
struct hash_table *initialize(unsigned int table_size);
struct list_node *find(struct hash_table *H, const char *key);
void insert(struct hash_table *H, const char *key, const char *value);
void dump(struct hash_table *H);
void del(struct hash_table *H, const char *key);
struct hash_table *rehash(struct hash_table *H);
unsigned int
hash(const char *key, unsigned int table_size)
{
unsigned long int hashx = 0;
for(int i=0;key[i];i++)
{
hashx = (hashx<<5) + key[i];
}
return (hashx%table_size);
}
struct hash_table
*initialize(unsigned int table_size)
{
struct hash_table *H = malloc(sizeof(*H));
H->list_arr = malloc(sizeof(*H->list_arr)*table_size);
H->table_size = table_size;
for(unsigned int i = 0; i<table_size; i++)
{
H->list_arr[i] = malloc(sizeof(*H->list_arr[i]));
H->list_arr[i]->next = NULL;
}
return H;
}
void
insert(struct hash_table *H, const char *key, const char *value)
{
unsigned int index = hash(key, H->table_size);
struct list_node *head = H->list_arr[index];
struct list_node *current = head->next;
while(current!=NULL)
{
if(strcmp(current->key,key)==0)
{
free(current->value);
current->value = malloc(strlen(value)+1);
strcpy(current->value,value);
return;
}
current=current->next;
}
struct list_node *newNode = malloc(sizeof(*H->list_arr[index]));
newNode->next = head->next;
head->next = newNode;
newNode->key = malloc(strlen(key)+1);
newNode->value = malloc(strlen(value)+1);
strcpy(newNode->key,key);
strcpy(newNode->value,value);
}
void
dump(struct hash_table *H)
{
for( int i = 0; i<H->table_size; i++)
{
struct list_node *entry = H->list_arr[i]->next;
if(entry==NULL){continue;}
printf("Index[%d]: ", i);
while(entry!=NULL)
{
printf("\t%s|%s\t--> ", entry->key, entry->value);
entry = entry->next;
}
printf("\tNULL");
printf("\n");
}
}
void delete(struct hash_table *H, const char *key)
{
unsigned int index = hash(key,H->table_size);
struct list_node *prev = H->list_arr[index];
while(strcmp(prev->next->key,key)!=0)
{
if(prev->next==NULL){printf("Key not found!");return;}
prev=prev->next;
}
struct list_node *temp = prev->next;
prev->next = temp->next;
free(temp);
}
struct hash_table *rehash(struct hash_table *H)
{
unsigned int old_size = H->table_size;
struct list_node *old_entries = H->list_arr;
H = initialize(2*old_size);
for(unsigned int i = 0; i<old_size; i++)
{
while(old_entries[i]!=NULL)
{
insert(H,old_entries[i].key,old_entries[i].value);
old_entries[i] = old_entries[i]->next;
}
}
free(old_entries);
return H;
}
int main()
{
struct hash_table *H = initialize(20);
insert(H,"name1","David");
insert(H,"name2","Radka");
dump(H);
H = rehash(H);
dump(H);
return 1;
}
我认为做 old_entries[i] 是错误的,但没有想到别的,请帮我解决这个问题。
【问题讨论】:
-
这在多个层面上都是错误的。是的,你的
old_entries逻辑被破坏了,如果没有其他原因,只是因为类型显然不匹配。但真正的问题是列表项管理。您永远不需要在重新散列中触发插入。所有的桶扩展都是关于保存旧表链,开始一个新表,从旧项目(仍然是有效节点)计算新哈希值,然后将这些节点移动到它们的新表中的新链。唯一的分配应该是链指针的新表床。 -
@WhozCraig 感谢您的回复。我应该如何将旧参数复制到新的“新表”而不插入?由于我是第三学期的 CS 本科生,请更“简单”地解释一下。
-
使用
insert()进行重新散列本身并没有错,但是您将创建新节点,这是一种浪费。但是,您忘记释放旧节点,因此您确实应该有一个单独的函数来插入节点而不是值。 -
@ThomasMailund 好的,所以如果我将
free((*H)->list_arr[i]);添加到 while 循环中应该没问题,对吧? -
@DaveHlave 您不能只释放 bin 中的第一个元素。那里可能不止一个。您必须遍历 bin 中的所有节点并释放它们。
标签: c function pointers data-structures hashtable