为了实现项目中必需的字符串解析与单词补全/建议功能,我在这里利用哈希表实现了一个简易的字典树结构。在字符串解析中,我们需要匹配最长的命令符号,用树形结构的字典很容易实现这一点。而我们利用字典词汇的公共前缀与树形结构,实现了单词补全与建议功能。
项目中首先需要实现的功能就是命令字符串的解析。对于出现在指令间的符号(如管道连接符、指令连接符、重定向符号等),我们应该遵循最长匹配原则。例如,我们读取了 ls &&&
这个输入,就不能把第一个 &
符号视作后台进程符号,而应该优先解析出前两个符号结合起来的指令连接符 &&
。
一个树形结构的符号表容易满足该需求。我们可以设计一个 n 叉树,根节点 a 为空,子节点 b 保存 &
字符,节点 b 的子节点 c 同样保存 &
字符。在字符串匹配时,尽量往树的深处匹配,则上面的输入就能够匹配到 &&
符号。
项目要实现的另一个功能就是单词补全与建议。与前面一样,字典树容易求出单词的公共前缀,进而进行补全,利用树的分枝,容易求出单词建议。
为了兼顾时间与空间复杂度,我们使用哈希表实现了字典树。
trie_tree
除了默认构造函数以外,还提供了一个列表初始化的方法。其效果相当于对列表中的字符串逐一调用 add
接口,该构造函数主要是方便开发者构造一个 const
的字典树。
这里我把拷贝构造函数和赋值构造函数设置为删除,只是为了偷懒,毕竟在该项目中没有“复制”字典树的需求,以及避免意外操作带来的致命错误。
函数名 | 操作 |
---|---|
add | 添加字符串 |
del | 删除字符串 |
clear | 清空字典树 |
query | 查询字典树是否包含某字符串 |
tab | 返回以特定字符串为前缀的所有字符串集合 (不包含给定的前缀字符串) |
next | 返回tab 返回集合中所有字符串的公共前缀 |
longest_match | 从字符串给定位置开始的最大匹配长度 |
struct trie_tree_node {
const char _c;
bool _end_of_word = false;
std::unordered_map<char, trie_tree_node*> _children;
};
树节点使用哈希表保存子节点集合。
字典树几乎所有函数都依赖于节点定位功能,即根据给定字符串,找到最接近的节点(拥有公共前缀)。