您似乎想要实现一个具有两个级别的映射:第一级将字符串映射到第二级映射,第二级将另一个键映射到一个值。例如,在 Javascript 语法中:
data = {
"London": {
"Paris": 450
},
"Paris": {
"Madrid": 600,
"Algiers": 700
}
}
有几种方法可以实现这一点。
Javascript 变量带有它们的类型,因此 yozu 可以对两个级别使用相同的 Map 实现。在 C 中,您可以实现两个具有不同值类型的哈希表,例如:
struct OItem { // Outer map item
const char *key; // string key
struct IMap *value; // inner map value
struct OItem *next;
};
struct OMap { // Outer map
struct OItem *head[oSize]; // hash table
};
struct IItem { // Inner map item
const char *key; // string key
int value; // integer value
struct IItem *next;
};
struct IMap { // Inner map
struct IItem *head[iSize]; // hash table
};
这将为您提供上面的两级结构。 (这些哈希表具有固定的大小,因此当二级映射稀疏时,您最终可能会浪费大量空间。也许在这里只使用单个列表或平衡树可能会更好。如果您使用二级映射只是模拟一个总是散列相同或相似数据的对象,请考虑在此处使用结构。)
例如,您可以使用此结构和lookup("London", "Paris")。如果您不需要访问内部映射,您还可以使用两个键将两个级别打包到一个大哈希表中:
struct Item {
const char *key1;
const char *key2;
int value;
struct Item *next;
};
struct Map {
struct Item *head[hSize];
};
计算哈希时,使用两个键,例如:
static unsigned int hash(const char *s1, const char *s2)
{
unsigned long hash = 5381u;
while (*s1) hash = hash * 33 ^ *s1++;
hash = hash *33;
while (*s2) hash = hash * 33 ^ *s2++;
return hash;
}
查找项目时,确保两个键匹配:
int map_find(const struct Map *map,
const char *k1, const char *k2)
{
unsigned int h = hash(k1, k2) % hSize;
struct Item *item = map->head[h];
while (item) {
if (strcmp(item->key1, k1) == 0
&& strcmp(item->key2, k2) == 0) {
return item->value;
}
item = item->next;
}
return 0;
}
这种方法可能限制性更强,但优点是您没有很多可能超大的哈希表,而只有一个数据结构。
最后,无论你做什么,都不要使用你在 GitHub 上找到的哈希表实现。作者承认这更像是一个编码练习。不处理使用后释放内存,哈希函数较差。
在您在实际用例中进行编辑后,很明显您需要trie。您可以按照您的建议实施 trie。键和值可以是您实现中的任何内容,因此它们也可以是字符串和 trie 节点。您可以调整现有实现以使用指向 trie 节点结构的指针作为值。 (幸运的是,所有比较的东西都保持不变。)
我看到的一个问题是,使用固定的哈希表大小,最终会浪费大量空间。如果你的树是稀疏的,最好只使用链表或平衡二叉树作为映射。在任何情况下,您都必须找到合适的库或自行开发。