我正在尝试在C中实现一个节省空间的trie。这是我的结构:
struct node {
char val; //character stored in node
int key; //key value if this character is an end of word
struct node* children[256];
};
当我添加一个节点时,它的索引是该字符的unsigned char cast。例如,如果我想添加“c”,那么
children[(unsigned char)'c']
是指向新添加节点的指针。但是,这个实现要求我声明一个256个元素的节点*数组。我想做的是:
struct node** children;
然后在添加节点时,只需要节点的malloc空间并具有
children[(unsigned char)'c']
指向新节点。问题是,如果我先没有为孩子们提供malloc空间,那么我显然无法引用任何索引,否则这是一个很大的错误。
所以我的问题是:我如何实现一个trie,使它只存储非子指针给它的子节点?
答案 0 :(得分:5)
您可以尝试使用de la Briandais trie,其中每个节点只有一个子指针,并且每个节点也有一个指向“兄弟”的指针,因此所有兄弟节点都有效地存储为链接列表而不是而不是由父母直接指出。
答案 1 :(得分:2)
你无法真正拥有它,并且既节省空间又在子节点中进行O(1)查找。
当你只为实际添加的条目而不是空指针分配空间时,你就不能再做了
children[(unsigned char)'c']
因为您无法再直接索引到数组中。
另一种方法是简单地通过孩子进行线性搜索。并存储children
数组有多少条目的附加计数,即
children[(unsigned char)'c'] = ...;
必须成为
for(i = 0; i < len; i++) {
if(children[i] == 'c')
break;
}
if(i == len) {
//...reallocate and add space for one item in children
}
children[i] = ...;
如果您的树在一个级别上有很多非空条目,您可以按排序顺序插入子级并进行二分查找。或者您可以将子项添加为链接列表而不是数组。
答案 2 :(得分:1)
通过使每个节点的子节点成为节点的哈希表,您可以节省空间并保持不变的查找时间。特别是当涉及到Unicode字符时,字典中可以包含的字符集不限于52 +,这更像是一种要求,而不是一种精确的要求。通过这种方式,您可以保持使用trie的优势,同时节省时间和空间。
我还必须补充一点,如果您正在使用的字符集接近无限制,则可能只有一个链接的节点列表可以正常工作。如果你喜欢无法控制的噩梦,你可以选择混合方法,其中前几个级别将他们的孩子保留在哈希表中,而较低级别有一个链表。对于真正的错误服务器场,请选择动态服务器场,当每个链接列表超过阈值时,您可以将其转换为动态哈希表。您可以轻松摊还成本。
可能性无穷无尽!
答案 3 :(得分:0)
如果您只是想进行英语关键词搜索,我认为您可以将孩子的大小从256减少到26,这足以覆盖26个字母a-z。
此外,您可以使用链接列表来保持子项数量更小,以便我们可以进行更有效的迭代。
我还没有通过图书馆,但我认为trie implementation会有所帮助。