本来想用vector来写一个更方便的版本来着,但是考虑到效率问题和现场编写的复杂程度问题觉得还是算了……
简单介绍下字典树吧。
问这么一个问题:给出很多很多很多的字符串,如何查询某一字符串是否存在?这个好说,用哈希嘛,数据结构课上教的。
那把这个问题加强一下:给出很多很多很多的字符串,如何查询前缀为s的字符串是否存在或者有多少个?这个用哈希就不好整了,但是用字典树就比较好实现。
字典树也是树形结构的一种,最基本的形态看上去就是下面图的这个样子。它是基于这么一个思路,比如我要查abcd,那么我先查有没有a开头的字符串,然后在a开头的字符串中查有没有b是第二个字符的,然后以此类推一直查完。当然这些结点上还可以附上信息以实现别的目的,比如它是第几个出现的啊,或者它是不是个完整的单词啊,诸如此类。
代码就在下面了,这只是个十分简单的版本,只有一个插入和查询操作。
#include
#include
class Trie {
private:
static const int T_MAXSIZE = 20000000; // 字典树的容量
static const int T_NEXTSIZE = 10; // 字典树每个节点有多少个子节点
private:
int node[T_MAXSIZE];
int next[T_MAXSIZE][T_NEXTSIZE];
int size;
public:
Trie() : size(0) {
node[size] = 0;
memset(node, 0, sizeof(node));
memset(next, 0, sizeof(next));
}
private:
int ID(const char &c) {
// to do...
} // 传入的参数对应某一结点的第几个子结点
int newnode() { return size += 1; } // 创建新结点
public:
void insert(char *s, int l, int id) { // 将字符串s的前l个字符放入字典树,附在结点上的信息为ID
int cur = 0;
for(int i = 0; i != l; ++i) {
const int num = ID(s[i]);
if(!next[cur][num]) {
int pt = newnode();
next[cur][num] = pt;
node[pt] = id;
}
cur = next[cur][num];
}
if(!node[cur]) node[cur] = id;
}
int query(char *s) { // 查询字符串s是否在字典树中,如果在,返回附在结点上的信息
int cur = 0;
for(int i = 0; s[i]; ++i) {
const int num = ID(s[i]);
if(!next[cur][num]) return -1;
cur = next[cur][num];
}
return node[cur];
}
};