您的位置:首页 > 理论基础 > 数据结构算法

【字典树】字典树的创建(入门详细介绍)

2016-07-29 15:12 204 查看

Part one【何谓字典树】

又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

字典树与字典很相似,当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的话用同样的方法继续查找.字典树不仅可以用来储存字母,也可以储存数字等其它数据。

比如我们创建一个字典树包含下列单词:

inn, int, at, age, adv, ant



是不是非常的类似于新华字典的拼音查词的顺序啊,比如查“生”就要从sh声母开始找e再找n再找g。

Part two【字典树的数据结构】

专门以小写字母为例,可以用数据结构为:

typedef struct Trie_node{
int count;                    // 统计单词前缀出现的次数
struct Trie_node* next[26];   // 指向各个子树的指针
bool exist;                   // 标记该结点处是否构成单词
}TrieNode , *Trie;


简单版本:

typedef struct Trie{
int v;
bool exist;
Trie *next[maxn];//maxn是由你规定好的字符串的字符来源决定的,比如小写字母26就够了。
}Trie;


Part three【字典树的生成】

我们需要用到字典树来对字符串进场分析的时候就要将这个字符串放进我们的字典树(就像字典收录新词一样)但是没真正像收录新词那么难。我们只需要2步。

1.定义指向根节点的指针P,和一个交换用的指针Q

2.从字符串开始下标到结束(0-len)我们依次将字符做出节点。方法是:将字母由字典序化为数字,则指针next[该字典序]指向的地方为空时我们开辟一个指针空间给Q,将其计数初始化为1。然后从0-MAXN将他next[]指向的全部初始化为NULL。再将P的next[字典序]指针指向Q,P更新为P的next[字典序]。若指针next[字典序]指向的地方已经有节点了,我们将其节点的计数++;更新P为P的NEXT。

符合简单数据结构的版本:

void createTrie(char *str)
{
int len = strlen(str);
Trie *p = &root, *q;
for(int i = 0; i < len; i++)
{
int id = str[i]-'a';
if(p->next[id] == NULL)
{
q = (Trie *)malloc(sizeof(root));
q->v = 1;//初始v==1
for(int j = 0; j < MAXN; j++)
q->next[j] = NULL;
p->next[id] = q;
p = p->next[id];
}
else
{
p->next[id]->v++;
p = p->next[id];
}
}
// p->v = -1;//若为结尾,则将v改成-1表示
}


符合第一个数据结构的版本(分成两个函数):

TrieNode* createTrieNode(){ //其实就是创建根节点
TrieNode* node = (TrieNode *)malloc(sizeof(TrieNode));
node->count = 0;
node->exist = false;
memset(node->next , 0 , sizeof(node->next));    // 初始化为空指针
return node;
}

void Trie_insert(Trie root, char* word){
Trie node = root;
char *p = word;
int id;
while( *p ){
id = *p - 'a';
if(node->next[id] == NULL){
node->next[id] = createTrieNode();
}
node = node->next[id];  // 每插入一步,相当于有一个新串经过,指针向下移动
++p;
node->count += 1;      // 这行代码用于统计每个单词前缀出现的次数(也包括统计每个单词出现的次数)
}
node->exist = true;        // 单词结束的地方标记此处可以构成一个单词
}


Part four【一些功能】

1.查找以特定字符串作为前缀的数目(符合第二个简单数据结构)

int findTrie(char *str){
int len = strlen(str);
Trie *p = &root;
for(int i = 0; i < len; i++){
int id = str[i]-'a';
p = p->next[id];
if(p == NULL) //若为空集,表示不存以此为前缀的串
return 0;
//  if(p->v == -1)   //字符集中已有串是此串的前缀
//    return -1;
}
return p->v;
//return -1;   //此串是字符集中某串的前缀
}


2.查找某字符串在不在字典中(符合第一个数据结构)

void search_str(Trie_node root,char *str){ //查找串是否在该trie树中
if(NULL==root || *str=='\0'){
printf("trie is empty or str is null\n");
return;
}

c
ac6a
har *p=str;
Node *t=root;
while(*p!='\0'){
if(t->child[*p-'a']!=NULL){
t=t->child[*p-'a'];
p++;
}
else
break;
}
if(*p=='\0'){
if(t->count==0)
cout<<"该字符串不在trie树中,但该串是某个单词的前缀\n";
else
cout<<"该字符串在该trie树中\n";
}
else
cout<<"该字符串不在trie树中\n";
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息