几天前我发布了this question,大家都建议我使用void*
,我这样做了。我认为他们中的一些人还指出了我需要照顾的一些事情,但我不确定他们究竟是什么。但是,我遇到了一些问题......
我不打算发布所有代码,因为它非常大,相反,我会发布我认为很重要的内容,希望能够帮助我。
我的哈希表结构如下:
typedef void * HashKey;
typedef void * HashValue;
typedef struct sHashItem {
HashKey key;
HashValue value;
char status;
} HashItem;
typedef struct sHashTable {
HashItem *items;
int count;
float load;
int size;
Bool (*compare)(HashKey, HashKey);
unsigned (*hash)(void *);
} HashTable;
我的插入功能的签名如下:
Bool hashInsert(HashTable * const table, HashKey key, HashValue value);
在该函数内部,当我在哈希表中找到一个空闲桶时,我这样做:
table->items[index].key = key;
table->items[index].value = value;
table->items[index].status = USED;
table->load = ++table->count / (float)table->size;
这一切都存在一些问题:
1)正如您在上面所看到的,我只是将空闲存储桶的每个键/值对设置为与键/值hashInsert
函数参数传递的相同指针。这提出了一个问题,因为您可能已经注意到了......例如,做这样的事情:
char str[50];
scanf("%s%*c", str);
hashInsert(t1, (HashKey)str, (HashValue)5);
scanf("%s%*c", str);
hashInsert(t1, (HashKey)str, (HashValue)3);
如果输入是“KeyA”然后是“KeyB”,则两者都将具有“KeyB”作为桶密钥。同样的事情适用于值而不仅仅是键,因为它们基本上是相同的类型,因为我希望我的代码完全模块化,适用于任何数据类型。
我怎么解决这个问题?
我的第一个问题是使用strdup(str)
并将其传递给hashInsert
函数。那样可以解决问题。由于这是在主代码中处理的,因此我可以轻松地将malloc()
用于我需要传递的任何其他数据类型作为值(键可能始终是字符串或int)。
但是这个解决方案提出了另一个问题......
2)我该如何释放这个分配的内存?当然,它是由“主程序员”而不是“哈希表模块程序员”分配的,因此,“主程序员”应该在主代码中释放它,对吧?但是,这对我来说看起来不像模块化代码。
我的代码还有一个hashDestroy
函数,用于释放所有已分配的内存。但是我如何使用此功能来释放一切?我不能只迭代每个键/值并在它们上使用free()
因为其中一些程序员可能首先不是malloc'd
并且我不需要释放它们。
如何找出hashDestroy
必须免费哪些以及哪些不应该免费?
3)要完成,我想我也可以把这个问题混合起来......在第一点,我的建议是使用strdup()
或malloc
来“修复”那个特定的问题(同时引入另一个),但对我来说也看起来不那么模块化。这个内存分配应该在哈希表模块代码中完成,而不是由“主程序员”在主代码中完成。
你怎么建议我解决这个问题?我的意思是,数据类型可以是任何东西,虽然strdup()
的使用有很大帮助,但它只适用于字符串。如果我需要为某个特定结构或只是int分配内存怎么办?
对于这篇重要的帖子感到抱歉,但我认为这些问题都是相关的,我需要一些帮助来解决它们,因为我的C知识不是那么极端。我最近才了解void*
所以......
答案 0 :(得分:2)
答案 1 :(得分:2)
我会对所有数据进行malloc,并允许客户端在哈希表初始化时向哈希函数注册一个item_free()
函数。这就是“主程序员”如何处理它。
答案 2 :(得分:1)
在哈希表中处理冲突有两种通用的解决方案:
使用其中任何一个,何时释放从未出现过的问题,因为所有类型的数据都是由哈希表或哈希表的客户端分配的。如果你仍然很好奇,对这个困境的简短回答是使用smart pointers。
答案 3 :(得分:1)
答案 4 :(得分:0)
要实现哈希表,我们需要一组存储桶。由于多个元素可以散列到同一个存储桶,因此每个存储桶都需要一个链表。
确实
HashItem *items;
执行上面的第二个要求?
根据你的解释,不清楚是否确实如此。
有一个很好的例子,请参阅K& R第6.6节。 link其中name = HashKey,defn = HashValue。 alt text http://www.goldfish.org/books/The%20C%20Programming%20Language%20-%20K&R/pic64.gif