您的位置:首页 > 其它

Trie树、字典树

2015-07-30 11:57 232 查看
Trie树的特点:根节点为空值,剩下每一个节点保存一个字母,每个节点存在26个子节点(采用静态分配的方式,如果采用动态添加的方式则不需要),如果此节点是保存单词的最后一个字符需要设置一个标志(表示为一个单词的末尾)。

1.如果从根节点遍历到某一个节点把路径节点的值连在一起就构成了一个字符串,利用这个特点很容易想到这棵树的第一个功能能帮我们查找某一个单词是否在树中(需要在每一个节点设置一个标志,表示从根节点到此节点是否存在一个单词);

2.如果该单词存在,我们可以利用它实现第二个功能:去除重复单词;

3.同样如果该词存,在我们还可以看出它的第三个功能:统计单词频率;

4.因为这是一个树形结构我们利用这个特点很容易看出它的第四个功能能帮我们查找N个单词的最长公共前缀;

5.如果我们按顺序遍历输出整棵树,发现它的第五个功能:对字符串排序。

这棵树创建看起来比较容易,就有一个问题需要我们考虑:父节点如何保存孩子节点?

主要有两种方式供大家参考:

1.因为是英文字符,我们可以用Node[26]来保存孩子节点(如果是数字我们可以用Node[10]),

这种方式最快,但是并不是所有节点都会有很多孩子,所以这种方式浪费的空间太多

2.用一个链表根据需要动态添加节点。这样我们就可以省下不小的空间,但是缺点是搜

索的时候需要遍历这个链表,增加了时间复杂度。

#include <iostream>
using namespace std;
#define NUMBER 26
struct TrieNode //节点类
{
char _value ;       //字符
bool _isWord ;      //单词标识符
struct TrieNode**   _childern; //孩子节点
};
/*
插入新的单词
root:字典树
word:待插入的单词
*/
void insertTrieTree(TrieNode * root,char *word)
{
if(NULL==root ||NULL == word || ""==word)
return ;
int len = strlen(word) ;
for(int i = 0 ;i<len;++i) //将单词中的字符一个个的进行插入
{
int index = 0 ;
//定位子节点位置
if(word[i] >='A' && word[i] <='Z')
index = word[i] - 'A' ;
//定位子节点位置
else if(word[i] >='a'&&word[i] <='z')
index = word[i] - 'a' ;
else
return ;
//获取子节点index的指针
TrieNode *childNode = root->_childern[index] ;
//如果该子节点为NULL,则插入新节点
if(NULL == childNode)
{
//新节点
TrieNode * new_node = new TrieNode ;
//new_node的26个子节点
new_node->_childern = new TrieNode*[NUMBER] ;
//将26个子节点赋为NULL
memset(new_node>_childern,0,sizeof(TrieNode*)*NUMBER) ;

//new_node赋值word[i]
new_node->_value = word[i] ;

//如果已经是单词的最后一个字符
if(i==len-1)
new_node->_isWord = true;
else //如果不是单词的最后一个字符
new_node->_isWord = false ;

//插入节点
root->_childern[index] = new_node ;
root = new_node ;//更新节点位置
}
else//如果该节点已经存在,则更新节点
{
//如果已经是此单词的最后一个元素,
//则需要设置isWord为true
if(i==len-1)
childNode->_isWord  = true ;
root = childNode ;
}
}
}
/*
查询单词是否存在于TrieTree中
root:字典树
word:被查找的单词
*/
bool searchWord(TrieNode *root,char *word)
{
if(NULL== root || NULL == word)
return false ;
int len = strlen(word) ;
if(0==len)
return false ;
int index = 0 ;
int i ;
for( i= 0 ;i<len ;++i)
{
if(word[i] >='A' && word[i] <='Z')
index = word[i] -'A' ;
else if(word[i] >='a' && word[i] <='z')
index = word[i] -'a' ;
//获取子节点的指针
TrieNode *node = root->_childern[index] ;

if(NULL == node)//如果该子节点不存在,则返回false
return false ;
//如果已经是单词的最后一个字符并且节点的isWord==true,
//则返回true
if(i==len-1 && node->_isWord)
{
return true ;
}
root = node ;//更新节点
}
return false ;
}
/*
打印输出字典树中所有的单词
*/
void printfTree(TrieNode * root,char word[],int index)
{
if(NULL==root)
return ;
if(root->_isWord) //如果是单词
{
//输出此单词
for(int i =0 ;i<index;++i)
{
cout<<word[i];
}
cout<<endl;
}
//继续遍历子节点
for(int i=0;i<NUMBER;++i)
{
TrieNode *node = root->_childern[i] ;
if(node != NULL)
{
word[index] = node->_value ;
printfTree(node,word,index+1) ; //递归调用
}
}
}

int main()
{
TrieNode Root ;

Root._childern = new TrieNode*[NUMBER] ;
memset(Root._childern,0,sizeof(TrieNode*)*NUMBER);
Root._value =' ' ; //根节点为空
Root._isWord = false;//非单词

char *word[] ={"luo","luobin","luobinhan",
"luobing","binhan"} ;

//将单词插入树中
insertTrieTree(&Root,word[0]) ;
insertTrieTree(&Root,word[1]) ;
insertTrieTree(&Root,word[2]) ;
insertTrieTree(&Root,word[3]) ;
insertTrieTree(&Root,word[4]) ;

//输出树中的所有单词
char tempWord[20] ;
printfTree(&Root,tempWord,0) ;
//查询单词是否存在于树中
bool bRet = searchWord(&Root,"luobing") ;
if(bRet)
cout<<"The word of 'luobing' is exists in the TrieTree"<<endl;
system("pause") ;
return 0 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: