为了娱乐和练习,我尝试使用C实现哈希映射来存储字符串。出于某种原因,它适用于某些字符串而不是其他字符串,我很好奇我的结构是否合乎逻辑?我认为问题可能是我如何分配内存,但我不确定,所以如果有人能够告诉我我的一般方法是否正确或者我是否对指针一无所知,我会非常感激!
基本上有一个哈希映射结构,其成员是指向链表节点的指针数组,头文件代码如下:
#ifndef DataStructures_hash_map_h
#define DataStructures_hash_map_h
#define INITIAL_HASHMAP_CAPACITY 5
#define INITIAL_TABLE_STRING_LENGTH 40
#include <string.h>
#include <limits.h>
// linked list node struct
struct ll_string_node {
char* value;
struct ll_string_node* next;
};
struct hash_map {
struct ll_string_node** table;
int size;
int capacity;
};
struct hash_map* hm_build_map() {
struct hash_map* new_map = malloc(sizeof(struct hash_map));
new_map->table = malloc(sizeof(struct ll_string_node)*INITIAL_HASHMAP_CAPACITY);
new_map->size = 0;
new_map->capacity = INITIAL_HASHMAP_CAPACITY;
return new_map;
}
int hm_hash_me(char* value, int capacity) {
unsigned long long int hashcode = 0;
for (int i = 0; value[i] != '\0'; i++) {
hashcode = hashcode*31 + value[i];
}
return hashcode % capacity;
}
int hm_put(char* value, struct hash_map** my_map) {
struct ll_string_node* new_node = malloc(sizeof(struct ll_string_node));
int hashcode = 0;
if (new_node) {
new_node->value = malloc(sizeof(char)*INITIAL_TABLE_STRING_LENGTH);
if (new_node->value) {
new_node->next = NULL;
strcpy(new_node->value, value); //value is now stored in new_node->value
hashcode = hm_hash_me(value, (*my_map)->capacity);
if ((*my_map)->table[hashcode] == NULL) {
(*my_map)->table[hashcode] = new_node;
} else {
new_node->next = (*my_map)->table[hashcode];
(*my_map)->table[hashcode] = new_node;
}
(*my_map)->size++;
return 1;
} else {
return 0;
}
} else {
return 0;
}
}
struct ll_string_node* hm_get(char* value, struct hash_map* my_map) {
int hashcode = hm_hash_me(value, my_map->capacity);
while (my_map->table[hashcode] != NULL) {
if (strcmp(my_map->table[hashcode]->value, value) == 0) {
printf("%s\t", my_map->table[hashcode]->value);
return my_map->table[hashcode];
} else {
printf("%s\t", my_map->table[hashcode]->value);
my_map->table[hashcode] = my_map->table[hashcode]->next;
}
}
return my_map->table[hashcode];
}
#endif
然后main.c文件为:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash_map.h"
int main(int argc, const char * argv[]) {
struct hash_map* my_map = hm_build_map();
hm_put("law and order", &my_map); //hashcode of 1
hm_put("Batman", &my_map); //
hm_put("CSI Miami", &my_map);
hm_put("The Flash", &my_map);
hm_get("Snoopy", my_map);
hm_get("Pinwheel", my_map); //causes program to crash
hm_get("Snoopy", my_map);
hm_get("law and order", my_map);
hm_get("Snoopy", my_map);
hm_get("CSI Miami", my_map);
hm_get("Snoopy", my_map); //causes program to crash
return 0;
}
答案 0 :(得分:1)
我还没有测试过你的代码,但是明显的错误出现在 hm_build_map()中。 table
是指向结构的指针,所以
new_map->table = malloc(sizeof(struct ll_string_node)*INITIAL_HASHMAP_CAPACITY);
错了。首先,您必须分配5个(INITIAL_HASHMAP_CAPACITY)指针,例如INITIAL_HASHMAP_CAPACITY * 4个字节
new_map->table = malloc(sizeof(int)*INITIAL_HASHMAP_CAPACITY);
然后为每个指针分配内存
for(i = 0; i < INITIAL_HASHMAP_CAPACITY; i++)
{
new_map->table[i] = malloc(sizeof(struct ll_string_node));
}
修改强>
为5个指针分配内存的部分不是必需的,因为它们是标题。只需将它们设置为NULL
for(i = 0; i < INITIAL_HASHMAP_CAPACITY; i++)
{
new_map->table[i] = NULL;
}
更改 hm_get :
struct ll_string_node* hm_get(char* value, struct hash_map* my_map) {
struct ll_string_node *temp;
int hashcode = hm_hash_me(value, my_map->capacity);
temp = my_map->table[hashcode]; //<- here use a temp so you dont move the header
while (temp != NULL) {
if (strcmp(temp->value, value) == 0) {
printf("%s\t", temp->value);
return temp;
} else {
printf("%s\t", temp->value);
temp = temp->next;
}
}
return temp;
}
<强> EDIT2 强>
首先
node0 -> node1 -> node3 ->....
^
|
my_map->table[hashcode]
my_map-&gt; table [hashcode] = my_map-&gt; table [hashcode] - &gt; next;
node0 -> node1 -> node3 ->....
^
|
my_map->table[hashcode]
你丢了标题!
node0 -> node1 -> node3 ->....
^ ^
| |
| temp
my_map->table[hashcode]
在 temp = temp-&gt; next;
之后node0 -> node1 -> node3 ->....
^ ^
| |
| temp
my_map->table[hashcode]
一切都好!