我正在尝试使用链表实现哈希表,并且有一件事情无法正常工作。 首先,我制作了链接列表代码,并确保它按照预期的方式工作,所以我发现它必须是哈希表实现或它们之间的交互。
我可以添加多个对象并再次找到它们,没有任何问题。但是如果使用相同的键对两个或多个对象进行哈希处理,则应该创建一个链表但由于某种原因,我只能在链表中找到最新添加的对象。
之前添加的对象就在那里,因为我可以使用“lookup_string”函数成功删除无法找到的对象,因此我知道该对象存储在该位置。
因此函数“lookup_string”应该在哈希表中传递我搜索的对象,而“搜索”功能是我在实现链表时使用的功能。值得一提的是,“搜索”功能用于删除过程但不在我只想找到对象的过程中,我不确定这是否重要,因为我相信“lookup_string”应该能够找到没有“搜索”功能的对象。
为了简单起见,我存储了两个对象:
对象1:
name(key) = bcd
telephone number = 123
对象2:
name(key) = ace
telephone number = 910
现在对象1和对象2都将获得相同的哈希键值,因此它们将存储在哈希表的相同插槽中。他们应该创建一个链表,但是当我搜索对象(菜单中的选项编号3)时,我只能找到最新添加的对象,即对象2。 但我仍然可以删除对象1,它会告诉我对象1已成功删除。
代码:
struct post
{
char name[30];
int tel;
struct post *next;
};
typedef struct post Post;
Post *head = NULL;
Post *current;
struct hash_table
{
Post **table;
int size;
};
typedef struct hash_table Post_table;
unsigned int Hash(Post_table *hash_table, char tempname[30])
{
int i;
int sum;
int key;
for(i = 0; i < strlen(tempname); i++)
{
sum += (int)tempname[i];
}
key = sum % hash_table->size;
return key;
}
Post_table *create_hash_table(int size)
{
int i;
Post_table *new_table;
if (size < 1)
{
return NULL;
}
//attempt to allocate memory for the table structure
if ((new_table = malloc(sizeof(Post_table))) == NULL)
{
return NULL;
}
//attempt to allocate memory for the table itself
if ((new_table->table = malloc(sizeof(Post *) * size)) == NULL)
{
return NULL;
}
//Initialize the elements of the table
for(i = 0; i < size; i++)
{
new_table->table[i] = NULL;
new_table->size = size;
}
return new_table;
}
Post *lookup_string(Post_table *hash_table, char tempname[30])
{
Post *list;
unsigned int hashkey = Hash(hash_table, tempname);
for(list = hash_table->table[hashkey]; list != NULL; list = list->next)
{
if (strcmp(tempname, list->name) == 0)
{
return list;
}
}
return NULL;
}
int add_string(Post_table *hash_table, char tempname[30], int temptel)
{
Post *new_list;
Post *current_list;
unsigned int hashkey = Hash(hash_table, tempname);
/* Attempt to allocate memory for list */
if ((new_list = malloc(sizeof(Post))) == NULL)
{
return 1;
}
/* Does item already exist? */
current_list = lookup_string(hash_table, tempname);
/* item already exists, don't insert it again. */
if (current_list != NULL)
{
return 2;
}
/* Insert into list */
printf("\nHash-key: %d\n", hashkey);
hash_table->table[hashkey] = AddList(tempname, temptel);
return 0;
}
Post* CreateList(char tempname[30], int temptel)
{
Post *ptr = (Post*)malloc(sizeof(Post));
strcpy(ptr->name, tempname);
ptr->tel = temptel;
ptr->next = NULL;
printf("\n creating list with headnode as [%s]\n",tempname);
head = current = ptr;
return ptr;
}
Post* AddList(char tempname[30], int temptel)
{
if (NULL == head)
{
return (CreateList(tempname, temptel));
}
printf("\n Adding node to end of list with value [%s]\n",tempname);
Post *ptr = (Post*)malloc(sizeof(Post));
strcpy(ptr->name, tempname);
ptr->tel = temptel;
ptr->next = NULL;
current->next = ptr;
current = ptr;
return ptr;
}
void skrivMeny(void)
{
printf("\n1: Register name and telephone number\n");
printf("2: Remove name and telephone number\n");
printf("3: Search for name\n");
printf("5: Exit\n");
}
Post* Search(char tempname[30], Post **prev)
{
Post *ptr = head;
Post *tmp = NULL;
int found = 0;
char structname[sizeof(tempname)];
printf("\n Searching the list for value [%s] \n",tempname);
while(ptr != NULL)
{
if (strcmp(ptr->name, tempname) == 0)
{
found = 1;
break;
}
else
{
tmp = ptr;
ptr = ptr->next;
}
}
if(found == 1)
{
if(prev)
{
*prev = tmp;
}
return ptr;
}
else
{
return NULL;
}
}
void free_entry(Post_table *hash_table, char tempname[30])
{
Post *del_list;
Post *temp;
int ret = 0;
unsigned int hashkey = Hash(hash_table, tempname);
del_list = lookup_string(hash_table, tempname);
ret = Delete(tempname);
if(ret != 0)
{
printf("\n delete [name = %s] failed, no such element found\n",tempname);
}
else
{
printf("\n delete [name = %s] passed \n",tempname);
}
}
int Delete(char tempname[30])
{
Post *prev = NULL;
Post *del = NULL;
printf("\n Deleting value [%s] from list\n",tempname);
del = Search(tempname,&prev);
if(del == NULL)
{
return -1;
}
else
{
if(prev != NULL)
{
prev->next = del->next;
}
if(del == current && del != head)
{
current = prev;
}
else if(del == head)
{
head = del->next;
}
}
free(del);
del = NULL;
return 0;
}
int main()
{
printf("\nHej och välkommen till hashlistan\n\n");
int menyval = 1;
char tempname[30];
int temptel;
int key;
Post * ptr;
Post_table *hash_table;
int table_size = 10;
hash_table = create_hash_table(table_size);
while (menyval > 0 && menyval <= 5)
{
skrivMeny();
scanf("%d", &menyval);
if (menyval == 1)
{
printf("[Name] [Number] = ");
scanf("%s %d", &tempname[0], &temptel);//inmatning
add_string(hash_table, tempname, temptel);
}
if (menyval == 2)
{
printf("[Name] = ");
scanf("%s", &tempname[0]);
free_entry(hash_table, tempname);
}
if (menyval == 3)
{
printf("[Name] = ");
scanf("%s", &tempname[0]);
ptr = lookup_string(hash_table, tempname);
if(ptr == NULL)
{
printf("\n Search [name = %s] failed, no such element found\n",tempname);
}
else
{
printf("\n Search passed [name = %s tel = %d]\n",ptr->name, ptr->tel);
}
}
if (menyval == 5)
{
break;
}
}
return 0;
}
我感谢所有帮助或提示解决我的问题!
编辑: 这就是我的代码现在的样子,我将文件分成两个文件; hash.c和lista.h,其中我将头文件包含在c文件中。
lista.h:
struct post
{
char name[30];
int tel;
struct post *next;
};
typedef struct post Post;
struct list
{
Post *head = NULL;
Post *current;
};
typedef struct list List;
Post* CreateList(char tempname[30], int temptel)
{
Post *ptr = (Post*)malloc(sizeof(Post));
strcpy(ptr->name, tempname);
ptr->tel = temptel;
ptr->next = NULL;
printf("\n creating list with headnode as [%s]\n",tempname);
return ptr;
}
Post* AddList(char tempname[30], int temptel, int emptyElement)
{
if (emptyElement == 1)
{
return (CreateList(tempname, temptel));
}
printf("\n Adding node to end of list with value [%s]\n",tempname);
Post *ptr = (Post*)malloc(sizeof(Post));
strcpy(ptr->name, tempname);
ptr->tel = temptel;
ptr->next = NULL;
return ptr;
}
int Delete(Post_table *hash_table, char tempname[30])
{
Post *prev = NULL;
Post *del = NULL;
printf("\n Deleting value [%s] from list\n",tempname);
del = Search(tempname,&prev);
if(del == NULL)
{
return -1;
}
else
{
if(prev != NULL)
{
prev->next = del->next;
}
if(del == hash_table->table[hashkey].current && del != hash_table->table[hashkey].head)
{
hash_table->table[hashkey].current = prev;
}
else if(del == hash_table->table[hashkey].head)
{
hash_table->table[hashkey].head = del->next;
}
}
free(del);
del = NULL;
return 0;
}
hash.c:
struct hash_table
{
List *table;
int size;
};
typedef struct hash_table Post_table;
unsigned int Hash(Post_table *hash_table, char tempname[30])
{
int i;
int sum;
int key;
for(i = 0; i < strlen(tempname); i++)
{
sum += (int)tempname[i];
}
key = sum % hash_table->size;
return key;
}
Post_table *create_hash_table(int size)
{
int i;
Post_table *new_table;
if (size < 1)
{
return NULL;
}
//attempt to allocate memory for the table structure
if ((new_table = malloc(sizeof(Post_table))) == NULL)
{
return NULL;
}
//attempt to allocate memory for the table itself
if ((new_table->table = malloc(sizeof(Post *) * size)) == NULL)
{
return NULL;
}
//Initialize the elements of the table
for(i = 0; i < size; i++)
{
new_table->table[i] = NULL;
new_table->size = size;
}
return new_table;
}
Post *lookup_string(Post_table *hash_table, char tempname[30])
{
Post *list;
unsigned int hashkey = Hash(hash_table, tempname);
for(list = hash_table->table[hashkey]; list != NULL; list = list->next)
{
if (strcmp(tempname, list->name) == 0)
{
return list;
}
}
return NULL;
}
int add_string(Post_table *hash_table, char tempname[30], int temptel)
{
int emptyElement = 0;
Post *new_list;
Post *current_list;
unsigned int hashkey = Hash(hash_table, tempname);
/* Attempt to allocate memory for list */
if ((new_list = malloc(sizeof(Post))) == NULL)
{
return 1;
}
/* Does item already exist? */
current_list = lookup_string(hash_table, tempname);
/* item already exists, don't insert it again. */
if (current_list != NULL)
{
return 2;
}
/* Insert into list */
if (hash_table->table[hashkey] == NULL)
{
emptyElement = 1;
}
printf("\nHash-key: %d\n", hashkey);
hash_table->table[hashkey] = AddList(tempname, temptel);
if (emptyElement == 1)
{
hash_table->table[hashkey].head = hash_table->table[hashkey];
hash_table->table[hashkey].current = hash_table->table[hashkey];
}
if (emptyElement == 0)
{
hash_table->table[hashkey].current = hash_table->table[hashkey];
}
return 0;
}
void free_entry(Post_table *hash_table, char tempname[30])
{
Post *del_list;
Post *temp;
int ret = 0;
unsigned int hashkey = Hash(hash_table, tempname);
del_list = lookup_string(hash_table, tempname);
ret = Delete(tempname);
if(ret != 0)
{
printf("\n delete [name = %s] failed, no such element found\n",tempname);
}
else
{
printf("\n delete [name = %s] passed \n",tempname);
}
}
void skrivMeny(void)
{
printf("\n1: Register name and telephone number\n");
printf("2: Remove name and telephone number\n");
printf("3: Search for name\n");
printf("5: Exit\n");
}
Post* Search(char tempname[30], Post **prev)
{
Post *ptr = head;
Post *tmp = NULL;
int found = 0;
char structname[sizeof(tempname)];
printf("\n Searching the list for value [%s] \n",tempname);
while(ptr != NULL)
{
if (strcmp(ptr->name, tempname) == 0)
{
found = 1;
break;
}
else
{
tmp = ptr;
ptr = ptr->next;
}
}
if(found == 1)
{
if(prev)
{
*prev = tmp;
}
return ptr;
}
else
{
return NULL;
}
}
int main()
{
printf("\nHej och välkommen till hashlistan\n\n");
int menyval = 1;
char tempname[30];
int temptel;
int key;
Post * ptr;
Post_table *hash_table;
int table_size = 10;
hash_table = create_hash_table(table_size);
while (menyval > 0 && menyval <= 5)
{
skrivMeny();
scanf("%d", &menyval);
if (menyval == 1)
{
printf("[Name] [Number] = ");
scanf("%s %d", &tempname[0], &temptel);//inmatning
add_string(hash_table, tempname, temptel);
}
if (menyval == 2)
{
printf("[Name] = ");
scanf("%s", &tempname[0]);
free_entry(hash_table, tempname);
}
if (menyval == 3)
{
printf("[Name] = ");
scanf("%s", &tempname[0]);
ptr = lookup_string(hash_table, tempname);
if(ptr == NULL)
{
printf("\n Search [name = %s] failed, no such element found\n",tempname);
}
else
{
printf("\n Search passed [name = %s tel = %d]\n",ptr->name, ptr->tel);
}
}
if (menyval == 5)
{
break;
}
}
return 0;
}
但正如我所说,这部分似乎有问题:
struct list
{
Post *head = NULL;
Post *current;
};
由于这是不正确的,它会导致其他几个错误,所以我试图先看看这个部分有什么问题。
答案 0 :(得分:0)
对不起,如果我弄错了,但据我所知,你的lookup_string()函数遍历到哈希表的最后一个元素(最近添加的那个)。 尝试以相反的方式遍历它或使用双向链表。
P.S:你不用自己的搜索功能吗?这是查找和搜索的冗余吗?
快乐的编码!
答案 1 :(得分:0)
我认为问题导致混合一个链表和哈希表。列表未排序,因此哈希表不能指向列表位置,其中可以找到具有给定键的所有元素。此外,AddList()
返回附加到结尾的新列表元素,并存储在hash_table->table[hashkey]
中。
这就是为什么你只找到最后一个元素(正如Mudassir Razvi已经指出的那样)。
因此,您应该为每个哈希键创建一个列表(我认为最简单的解决方案),或者按照哈希键对列表进行排序,并仅在添加带有该键的第一个元素时分配hash_table->table[hashkey]
(==&gt; {{1} })
编辑:
如果您想为每个键创建单独的列表,当然您不能再拥有全局变量if( hash_table->table[hashkey] == NULL )
和head
,而是每个键一对。所以你可以定义:
current
让struct list {
Post *head;
Post *current;
}
成为hash_table->table
的代替,而不是struct list
。 Post
已经返回CreateList()
,因此您可以直接将其分配给head
和table[key].head
。现在,您需要做的其他事情就是将实际的table[key].current
传递给current
,然后将AddList()
设置为table[key].current
的返回值。
那是一种路线图,我想你会来的。
答案 2 :(得分:0)
我决定发布一个关于当前代码的新答案,因为我发现否则它会比现在更难以理解
当前代码中的语法错误如下:
struct list
{
Post *head = NULL;
Post *current;
};
这不是变量定义,而只是结构的声明。因此,您无法在此处执行任何分配(= NULL
),因为根本没有可分配的变量。
相反,您可以在分配数组后在循环中初始化hash_table->table[i].head
,或者只调用calloc()
而不是malloc()
,而'\0'
使用if ((new_table->table = malloc(sizeof(Post *) * size)) == NULL)
初始化分配的缓冲区。
我猜您的代码中有更多错误,至少我找到了
if ((new_table->table = malloc(sizeof(list stuct) * size)) == NULL) // or calloc()
应该是
{{1}}
但我现在无法审查所有内容。 希望能让你继续下去,
答案 3 :(得分:0)
好的,这里有一些关于你的代码的改动:我用我的标签'Leo'标记了它们
在list.c中:
struct post // structure of node
{
char name[30]; // stored data
int tel; // stored data
struct post *next; // reference to next node
};
typedef struct post Post; // Post = struct post
struct list
{
Post *head;
Post *current;
};
typedef struct list List;
struct hash_table
{
List *table;
int size;
};
typedef struct hash_table Post_table;
Post* CreateList(char tempname[30], int temptel);
Post* AddList(char tempname[30], int temptel, int emptyElement, Post *current);
void skrivMeny(void);
void PrintList(void);
int Delete(Post_table *hash_table, char tempname[30], unsigned int hashkey);
Post* Search(Post_table *hash_table, unsigned int hashkey, char tempname[30], Post **prev);
Post* CreateList(char tempname[30], int temptel)
{
Post *ptr = (Post*)malloc(sizeof(Post));
strcpy(ptr->name, tempname);
ptr->tel = temptel;
ptr->next = NULL;
printf("\n creating list with headnode as [%s]\n",tempname);
return ptr;
}
// Leo: emptyElement isn't neccessary, we use current==null
Post* AddList(char tempname[30], int temptel, Post *current)
{
if( current == null )
{
return (CreateList(tempname, temptel));
}
printf("\n Adding node to end of list with value [%s]\n",tempname);
Post *ptr = (Post*)malloc(sizeof(Post));
strcpy(ptr->name, tempname);
ptr->tel = temptel;
ptr->next = NULL;
// Leo: we must append the new element to current
current->next = ptr;
return ptr;
}
和hash.c
unsigned int Hash(Post_table *hash_table, char tempname[30])
{
int i;
int sum;
int key;
for(i = 0; i < strlen(tempname); i++)
{
sum += (int)tempname[i];
}
key = sum % hash_table->size;
return key;
}
Post_table *create_hash_table(int size)
{
int i;
Post_table *new_table;
if (size < 1)
{
return NULL;
}
//attempt to allocate memory for the table structure
if ((new_table = malloc(sizeof(Post_table))) == NULL)
{
return NULL;
}
//attempt to allocate memory for the table itself
// Leo: replaced malloc() by calloc() so all head and current are initialized with NULL
if ((new_table->table = calloc(size, sizeof(List *) )) == NULL)
{
return NULL;
}
//Initialize the elements of the table
/* Leo: What's that loop for ?
for(i = 0; i < size; i++)
{
new_table->table[i]; // Leo: that line doen't do anything
new_table->size = size; // Leo: once is enough, let's have it otside the loop
}
*/
new_table->size = size; // Leo: once is enough, let's have it otside the loop
return new_table;
}
Post *lookup_string(Post_table *hash_table, char tempname[30])
{
Post *list;
unsigned int hashkey = Hash(hash_table, tempname);
/* Go to the correct list based on the hash value and see if str is
* in the list. If it is, return return a pointer to the list element.
* If it isn't, the item isn't in the table, so return NULL.
*/
// Leo: we must start with head instead of current
for(list = hash_table->table[hashkey].head; list != NULL; list = list->next)
{
if (strcmp(tempname, list->name) == 0)
{
return list;
}
}
return NULL;
}
int add_string(Post_table *hash_table, char tempname[30], int temptel)
{
//Leo: emptyElement is not used any more (see AddList()
//int emptyElement = 0;
//Leo: new_list is never used
//Post *new_list;
Post *current_list;
unsigned int hashkey = Hash(hash_table, tempname);
/* Attempt to allocate memory for list */
/* Leo: new_list is never used
if ((new_list = malloc(sizeof(Post))) == NULL)
{
return 1;
}
*/
/* Does item already exist? */
current_list = lookup_string(hash_table, tempname);
/* item already exists, don't insert it again. */
if (current_list != NULL)
{
return 2;
}
/* Insert into list */
/* Leo: emptyElement isn't used any more
if (hash_table->table[hashkey].head == NULL)
{
emptyElement = 1;
}
*/
printf("\nHash-key: %d\n", hashkey);
//This line of code under used to store my element in the hash-table but gives now an error
// hash_table->table[hashkey] = AddList(tempname, temptel, emptyElement, hash_table->table[hashkey].current);
/* Leo: in case of emptyElement == 1 you have called AddList() twice and so created two new list elemens, we replace all of this by the code below
if (emptyElement == 1)
{
hash_table->table[hashkey].head = AddList(tempname, temptel, emptyElement, hash_table->table[hashkey].current);
hash_table->table[hashkey].current = AddList(tempname, temptel, emptyElement, hash_table->table[hashkey].current);
}
if (emptyElement == 0)
{
hash_table->table[hashkey].current = AddList(tempname, temptel, emptyElement, hash_table->table[hashkey].current);
}
*/
// Leo: Note: if the list for hashKey has not been created yet then both head and current are NULL, otherwise both are != NULL
hash_table->table[hashkey].current = AddList(tempname, temptel, hash_table->table[hashkey].current);
// Leo: if the list has been created just now, then both head and current must point to the only list element
if( hash_table->table[hashkey].head == NULL )
hash_table->table[hashkey].head = hash_table->table[hashkey].current;
return 0;
}
void free_entry(Post_table *hash_table, char tempname[30])
{
Post *del_list;
Post *temp;
int ret = 0;
unsigned int hashkey = Hash(hash_table, tempname);
del_list = lookup_string(hash_table, tempname);
ret = Delete(hash_table, tempname, hashkey);
if(ret != 0)
{
printf("\n delete [name = %s] failed, no such element found\n",tempname);
}
else
{
printf("\n delete [name = %s] passed \n",tempname);
}
}
void skrivMeny(void)
{
printf("\n1: Register name and telephone number\n");
printf("2: Remove name and telephone number\n");
printf("3: Search for name\n");
printf("5: Exit\n");
}
Post* Search(Post_table *hash_table, unsigned int hashkey, char tempname[30], Post **prev)
{
Post *ptr = hash_table->table[hashkey].head;
Post *tmp = NULL;
int found = 0;
char structname[sizeof(tempname)];
printf("\n Searching the list for value [%s] \n",tempname);
while(ptr != NULL)
{
if (strcmp(ptr->name, tempname) == 0)
{
found = 1;
break;
}
else
{
tmp = ptr;
ptr = ptr->next;
}
}
if(found == 1)
{
if(prev)
{
*prev = tmp;
}
return ptr;
}
else
{
return NULL;
}
}
int main()
{
printf("\nHej och välkommen till hashlistan\n\n");
int menyval = 1;
char tempname[30];
int temptel;
int key;
Post * ptr;
Post_table *hash_table;
int table_size = 10;
hash_table = create_hash_table(table_size);
while (menyval > 0 && menyval <= 5)
{
skrivMeny();
scanf("%d", &menyval);
if (menyval == 1)
{
printf("[Name] [Number] = ");
scanf("%s %d", &tempname[0], &temptel);//inmatning
add_string(hash_table, tempname, temptel);
}
if (menyval == 2)
{
printf("[Name] = ");
scanf("%s", &tempname[0]);
free_entry(hash_table, tempname);
}
if (menyval == 3)
{
printf("[Name] = ");
scanf("%s", &tempname[0]);
ptr = lookup_string(hash_table, tempname);
if(ptr == NULL)
{
printf("\n Search [name = %s] failed, no such element found\n",tempname);
}
else
{
printf("\n Search passed [name = %s tel = %d]\n",ptr->name, ptr->tel);
}
}
if (menyval == 5)
{
break;
}
}
return 0;
}
int Delete(Post_table *hash_table, char tempname[30], unsigned int hashkey)
{
Post *prev = NULL;
Post *del = NULL;
printf("\n Deleting value [%s] from list\n",tempname);
del = Search(hash_table, hashkey, tempname, &prev);
if(del == NULL)
{
return -1;
}
else
{
if(prev != NULL)
{
prev->next = del->next;
}
if(del == hash_table->table[hashkey].current && del != hash_table->table[hashkey].head)
{
hash_table->table[hashkey].current = prev;
}
else if(del == hash_table->table[hashkey].head)
{
hash_table->table[hashkey].head = del->next;
}
}
free(del);
del = NULL;
return 0;
}
我还没有编译它,所以现在可能会有一些语法错误,但我希望它清楚整个事情应该如何工作。如果您还有其他问题,请随时提出。