Trie,又称字典树、单词查找树,是一种树形结构,用于保存大量的字符串。它的优点是:利用字符串的公共前缀来节约存储空间。
它有3个基本性质:
1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3. 每个节点的所有子节点包含的字符都不相同。
Trie的实现见下面的代码,具体操作见注释。这个写的有些垃圾,期待改进。
//
结点类型
typedef struct node
... {
bool isStr; //记录此处是否有串,目的是:如果插入"abc",那么"ab"如果不作标记的话,也是存在的
int count; //记录子结点的个数
node* next[26]; //孩子的指针
node()
: count(0), isStr(false)
...{
memset(next, NULL, sizeof(next)); //初始化为空
}
} * nodeptr;
// Trie类
// insert:插入一个字符串,重复插入无效
// remove:删除指定的字符串,如果不存在,则不进行操作
// find:判断是否有指定的字符串
class Trie
... {
private:
nodeptr root;
//删除t的孩子的孩子
//这样做的原因是
//delete一个指针,这个指针就不确定了,不能继续向上操作
//所以只能删除t的孩子的孩子
//有待改进
void remove(nodeptr t, const char* key, int i)
...{
//孩子的指针,key[i]为孩子
nodeptr pnext = t -> next[key[i] - 'a'];
if (key[i+1] && pnext) //不是最后一个结点
...{
pnext -> count--;
remove(pnext, key, i+1); //递归删除
}
if (!pnext -> count) //子结点是空的,直接删除
delete pnext;
else //否则删除子结点的孩子的指针
pnext -> next[key[i+1] - 'a'] = NULL;
}
public:
Trie()
...{
root = new node;
}
//插入操作
void insert(const char* key)
...{
nodeptr location = root;
do
...{
if (location -> next[*key - 'a'] == NULL) //不存在则新建
...{
nodeptr tmp = new node;
location -> next[*key - 'a'] = tmp;
}
if (*key) //不是0
...{
location -> count++;
location = location -> next[*key - 'a'];
}
} while (*key++);
location -> isStr = true; //到达尾部
}
//删除操作
void remove(const char* key)
...{
if (!find(key)) //找不到则不操作
return;
//预处理根
root -> count--;
//删除根的子结点
remove(root, key, 0);
//尾处理
if (!root -> next[*key - 'a'] -> count)
delete root -> next[*key - 'a'];
else
root -> next[*key - 'a'] = NULL;
}
//查找
bool find(const char* key)
...{
nodeptr location = root;
while (*key && location)
location = location -> next[*key++ - 'a'];
return (location != NULL && location -> isStr);
}
} ;
typedef struct node
... {
bool isStr; //记录此处是否有串,目的是:如果插入"abc",那么"ab"如果不作标记的话,也是存在的
int count; //记录子结点的个数
node* next[26]; //孩子的指针
node()
: count(0), isStr(false)
...{
memset(next, NULL, sizeof(next)); //初始化为空
}
} * nodeptr;
// Trie类
// insert:插入一个字符串,重复插入无效
// remove:删除指定的字符串,如果不存在,则不进行操作
// find:判断是否有指定的字符串
class Trie
... {
private:
nodeptr root;
//删除t的孩子的孩子
//这样做的原因是
//delete一个指针,这个指针就不确定了,不能继续向上操作
//所以只能删除t的孩子的孩子
//有待改进
void remove(nodeptr t, const char* key, int i)
...{
//孩子的指针,key[i]为孩子
nodeptr pnext = t -> next[key[i] - 'a'];
if (key[i+1] && pnext) //不是最后一个结点
...{
pnext -> count--;
remove(pnext, key, i+1); //递归删除
}
if (!pnext -> count) //子结点是空的,直接删除
delete pnext;
else //否则删除子结点的孩子的指针
pnext -> next[key[i+1] - 'a'] = NULL;
}
public:
Trie()
...{
root = new node;
}
//插入操作
void insert(const char* key)
...{
nodeptr location = root;
do
...{
if (location -> next[*key - 'a'] == NULL) //不存在则新建
...{
nodeptr tmp = new node;
location -> next[*key - 'a'] = tmp;
}
if (*key) //不是0
...{
location -> count++;
location = location -> next[*key - 'a'];
}
} while (*key++);
location -> isStr = true; //到达尾部
}
//删除操作
void remove(const char* key)
...{
if (!find(key)) //找不到则不操作
return;
//预处理根
root -> count--;
//删除根的子结点
remove(root, key, 0);
//尾处理
if (!root -> next[*key - 'a'] -> count)
delete root -> next[*key - 'a'];
else
root -> next[*key - 'a'] = NULL;
}
//查找
bool find(const char* key)
...{
nodeptr location = root;
while (*key && location)
location = location -> next[*key++ - 'a'];
return (location != NULL && location -> isStr);
}
} ;