我正在尝试将(键,值)对添加到哈希图中,但是在插入后无法访问这些值。
该哈希表应该处理冲突,因为每当发生冲突时,我都会沿着每个哈希索引进行迭代。然后,在到达该索引的(键,值)对列表的末尾时,将其插入。
从本质上讲,它是一个基本的链表哈希表。
问题是,当我再次尝试访问该值时,我一直遇到分段错误(并且我的showTable()
函数也失败了)。在此测试中,我只是在尝试在每个哈希索引处添加了一些东西之后,尝试访问每个哈希索引处的第一对(键,值)。我可能正在做一些非常愚蠢的事情,但我看到了。
我尚未评论,但我希望代码能自我解释。重要的一点是InsertKeyValuePair()
,但是我添加了所有内容,因为代码审查也将是有益的。
#include <stdlib.h>
#include <stdio.h>
typedef struct TVal KeyValue;
typedef struct TVal {
char *value;
char *key;
KeyValue *next;
} KeyValue;
typedef KeyValue **HashTable;
int MAX_SIZE = 200;
int HashKey(char *Key, int Max);
void InsertKeyValuePair(char *key, char *value, int Index, HashTable table);
int insert(char *Key, char *value, HashTable table, int size);
void showTable(HashTable table, int size);
int HashKey(char *Key, int Max) {
char c = *Key;
int Hash = 0;
int n = 1;
while (c != 0) {
Hash += n * ((int)c);
c = *(Key + n);
n++;
}
return Hash % MAX_SIZE;
}
void InsertKeyValuePair(char *key, char *value, int Index, HashTable table) {
KeyValue *cursor = *(table + Index);
while (cursor != NULL) {
cursor = cursor->next;
}
cursor = malloc(sizeof(KeyValue));
cursor->value = value;
cursor->key = key;
printf("insert <K,V>(%s,%s) HashIndex = %i\n", cursor->key, cursor->value, Index);
//Trying to access value previously inserted
KeyValue *cursor2 = *(table + Index);
printf("<K,V>(%s,%s)\n", cursor2->key, cursor2->value);
}
int insert(char *Key, char *value, HashTable table, int size) {
int Index = HashKey(Key, MAX_SIZE);
InsertKeyValuePair(Key, value, Index, table);
return size + 1;
}
void showTable(HashTable table, int size) {
int i;
for (i = 0; i < size; i++) {
KeyValue *cursor = *(table + i);
if (cursor == NULL)
continue;
while (cursor != NULL) {
printf("==============");
printf("<K,V>(%s,%s)\n", cursor->key, cursor->value);
cursor = cursor->next;
}
printf("==============");
}
}
int main() {
HashTable HTbl = malloc(sizeof(HashTable) * MAX_SIZE);
int size = 0;
size = insert("yeuydfdan", "wesfg", HTbl, size);
size = insert("ywere", "rdgg", HTbl, size);
size = insert("ye4", "3244", HTbl, size);
//showTable(HTbl, MAX_SIZE);
}
答案 0 :(得分:0)
此声明
HashTable HTbl = malloc(sizeof(HashTable)*MAX_SIZE);
不正确,而且分配的内存未初始化。应该有
HashTable HTbl = calloc( MAX_SIZE, sizeof( KeyValue * ) );
或喜欢
HashTable HTbl = calloc( MAX_SIZE, sizeof( *HTbl ) );
表中的索引应计算为一些无符号整数。否则,通常您会得到一个负索引。
在功能HashKey
中未使用参数Max
。
在函数InsertKeyValuePair
中,更改了局部变量cursor
而不是数据成员cursor->next
或*(table+Index)
。
函数showTable
中的循环在循环条件下应使用MAX_SIZE
而不是size
。也就是说,您必须将MAX_SIZE
的值而不是size
的值作为参数传递。
这里是一个演示程序,显示了如何更新程序。
#include <stdio.h>
#include <stdlib.h>
typedef struct TVal KeyValue;
typedef struct TVal
{
const char *value;
const char *key;
KeyValue *next;
} KeyValue;
typedef KeyValue **HashTable;
const size_t MAX_SIZE = 200;
static size_t HashKey( const char *key, size_t max_slots )
{
size_t Hash = 0;
for ( size_t i = 0; key[i]; i++ ) Hash += ( i + 1 ) * ( unsigned char )key[i];
return Hash % max_slots;
}
static int InsertKeyValuePair( HashTable table, const char *key, const char *value, size_t index )
{
KeyValue **cursor = &table[index];
while ( *cursor != NULL ) cursor = &( *cursor )->next;
*cursor = malloc( sizeof( KeyValue ) );
int success = *cursor != NULL;
if ( success )
{
( *cursor )->value = value;
( *cursor )->key = key;
( *cursor )->next = NULL;
}
return success;
}
int insert( HashTable table, const char *key, const char *value, size_t *size )
{
size_t index = HashKey( key, MAX_SIZE );
int success = InsertKeyValuePair( table, key, value, index );
if ( success ) ++*size;
return success;
}
void showTable( HashTable table, size_t size )
{
for ( size_t i = 0; i < size; i++ )
{
KeyValue *cursor = table[i];
if ( cursor != NULL )
{
do
{
puts( "==============" );
printf( "<K,V>(%s, %s)\n", cursor->key, cursor->value );
cursor = cursor->next;
} while ( cursor != NULL );
puts( "==============\n" );
}
}
}
int main( void )
{
HashTable HTbl = calloc( MAX_SIZE, sizeof( *HTbl ) );
size_t size = 0;
insert( HTbl, "yeuydfdan", "wesfg", &size );
insert( HTbl, "ywere", "rdgg", &size );
insert( HTbl, "ye4", "3244", &size );
showTable( HTbl, MAX_SIZE );
}
程序输出为
==============
<K,V>(ywere, rdgg)
==============
==============
<K,V>(ye4, 3244)
==============
==============
<K,V>(yeuydfdan, wesfg)
==============
当然,您应该添加一些其他功能,例如删除表及其节点的功能。
如果每个节点都将为键和值分配内存并在其中复制传递的参数,那将更好。否则,该表通常只能处理字符串文字,因为它们具有静态的存储期限。
如果您将重写表的实现方式,使其复制表节点中的键和值,那么结构应定义为
typedef struct TVal KeyValue;
typedef struct TVal
{
char *value;
const char *key;
KeyValue *next;
} KeyValue;
在任何情况下,都不应更改密钥,而应使用限定符const
声明密钥。
答案 1 :(得分:0)
您的代码中存在多个问题:
NULL
,因此在尝试取消对其包含的指针的引用时会导致分段错误。与calloc()
分配将解决此问题。main
中的分配应为HashTable HTbl = calloc(sizeof(*HTbl), MAX_SIZE);
InsertKeyValuePair
中的插入代码不会在哈希表存储桶列表的末尾或开头链接新对。unsigned
算法来计算哈希键,以避免溢出问题。*(table + Index)
令人困惑。您应该改为使用数组符号table[Index]
。MAX_SIZE
)和哈希表中的条目数(size
)之间似乎有些混淆。适当重命名变量可以提高可读性。最好按地址传递计数并返回成功指示符。这是更正的版本:
#include <stdlib.h>
#include <stdio.h>
typedef struct TVal KeyValue;
typedef struct TVal {
const char *value;
const char *key;
KeyValue *next;
} KeyValue;
typedef KeyValue **HashTable;
static unsigned int HASH_SIZE = 200;
static unsigned int HashKey(const char *key);
static KeyValue *InsertKeyValuePair(const char *key, const char *value, int index, HashTable table);
static int insert(const char *Key, const char *value, HashTable table, int *countp);
static void showTable(HashTable table);
static unsigned int HashKey(const char *key) {
unsigned int hash = 0;
size_t n;
for (n = 0; key[n] != 0; n++) {
hash += n * (unsigned char)key[n];
}
return hash % HASH_SIZE;
}
static KeyValue *InsertKeyValuePair(const char *key, const char *value, int index, HashTable table) {
KeyValue *cursor;
cursor = malloc(sizeof(KeyValue));
if (cursor != NULL) {
KeyValue **cursorp = &table[index];
while (*cursorp != NULL) {
cursorp = &(*cursorp)->next;
}
cursor->value = value;
cursor->key = key;
cursor->next = NULL;
*cursorp = cursor;
}
return cursor;
}
static int insert(const char *key, const char *value, HashTable table, int *countp) {
int index = HashKey(key);
if (InsertKeyValuePair(key, value, index, table)) {
*countp += 1;
return 1;
}
return 0;
}
static void showTable(HashTable table) {
unsigned int i;
for (i = 0; i < HASH_SIZE; i++) {
KeyValue *cursor = table[i];
if (cursor == NULL)
continue;
while (cursor != NULL) {
printf("==============");
printf("<K,V>(%s,%s)\n", cursor->key, cursor->value);
cursor = cursor->next;
}
printf("==============\n");
}
}
int main() {
HashTable HTbl = calloc(sizeof(*HTbl), HASH_SIZE);
int count = 0;
insert("yeuydfdan", "wesfg", HTbl, &count);
insert("ywere", "rdgg", HTbl, &count);
insert("ye4", "3244", HTbl, &count);
showTable(HTbl);
return 0;
}