我正在尝试在C中实现哈希表,几乎拥有它。我正在通过链接使用每个数组槽中的链表来实现冲突解决,我希望能够在函数调用内部进行链接。
现在,问题在于为了使修改成为永久性的,我相信我需要一个额外的间接层。这是一个问题,当我尝试遍历列表时,前一个元素被下一个元素覆盖(请参阅我在insert()函数中的注释)。我试图传递这个数组与额外的间接级别指定几种不同的方式,但我得到编译器警告和seg错误。
这对你们中的一些人来说可能看起来很简单,但是现在我已经抓住了很长一段时间了,这个场景(传递修改指针的数组)在我的文本中没有处理,我似乎无法找到问这个确切的问题(虽然它可能是我不认识的形式)。我不一定在寻找代码的“快速修复”,但我想了解完成我想要做的事情的最佳实践。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//#include "list.c"
struct node{
int key;
struct node* next;
};
void createTable(struct node *table[], int numEls, int numSlots);
int hash(int key, int numSlots);
void insert(struct node *table[], int key, int slot, int numSlots);
void display(struct node *table[], int numEls);
int main(void){
srand(time(NULL));
int numEls, numSlots;
printf("Please enter the desired number of slots in the hash table: ");
scanf("%d", &numSlots);
struct node *table[numSlots];
printf("\nPlease enter the desired number of elements: ");
scanf("%d", &numEls);
printf("\nYour load factor will be %f", (float)numEls/numSlots);
createTable(table, numEls, numSlots);
}
void createTable(struct node *table[], int numEls, int numSlots){
for(int i = 0; i < numSlots; i++)
table[i] = NULL;
for(int j = 0; j < numEls; j++){
for(int k = 0; k < 99999999; k++){}//give the rand function time
int el = rand()%100;
insert(table, el, hash(rand()%100, numSlots), numSlots);
}
display(table, numSlots);
}
int hash(int key, int numSlots){
return((int)(pow(key, 2.819)) % numSlots);
}
void insert(struct node *table[], int key_, int slot, int numSlots){
printf("\nInserting %d into slot %d", key_, slot);
fflush(stdout);
struct node* new = malloc(sizeof(struct node));
(new)->key = key_;
(new)->next = NULL;
struct node** temp = &(table[slot]);
if((*temp) == NULL){
printf(" (*temp) == NULL");
(*temp) = new;
}
else{
printf(" %d", (*temp)->key);
while((*temp)->next != NULL){
printf(" %d", (*temp)->next->key);
(*temp) = (*temp)->next; //head is overwritten with head->next
}
(*temp)->next = new;
printf(" %d", (*temp)->next->key);
}
}
void display(struct node *table[], int numSlots){
for(int i = 0; i < numSlots; i++){
printf("\nSlot %d:", i);
struct node* temp = table[i];
while(temp != NULL){
printf(" %d", temp->key);
temp = temp->next;
}
}
}
答案 0 :(得分:2)
在注释的行中,您使用链接列表中的下一个元素将指针覆盖到头部(最外层数组内),这可能不是您的意图。
更正是沿着指针列表向下走,直到找到最后一个指针,而不是在步行期间修改主数据结构。
以下是insert()
的更正版本。
void insert(struct node *table[], int key_, int slot, int numSlots){
printf("\nInserting %d into slot %d", key_, slot);
fflush(stdout);
struct node* new = malloc(sizeof(struct node));
new->key = key_;
new->next = NULL;
// Here we make a copy of the pointer to the head node in the linked list.
// This way, we never overwrite the original copy which lives in the array itself.
struct node* head = table[slot];
if(head == NULL){
printf(" head == NULL");
table[slot] = new;
}
else{
while(head->next != NULL) {
head = head->next; //head is overwritten with head->next
}
head->next = new;
}
}
答案 1 :(得分:1)
这不是一个答案,但对于评论来说太大了......你能解释一下这段代码应该做什么吗?
while((*temp)->next != NULL)
{
printf(" %d", (*temp)->next->key);
(*temp) = (*temp)->next; //head is overwritten with head->next
}
(*temp)->next = new;
我希望您希望将新节点附加到此插槽中现有节点的链接列表的末尾。但是这段代码实际上更新了头部以指向列表中的最后一个节点,就像你的评论所说的那样(泄漏内存 - 列表中的早期节点现在无法访问)。然后它使最后一个节点(现在是列表中唯一的节点)指向new
。
所以你的&#34;列表&#34;只有长度为1或2,并且每次尝试输入第三个条目时它会泄漏内存。
在我看来,你传递table
(链接列表的头部列表)没有任何问题,但问题是维护这些列表的列表的代码是不对。