问题:统计词典中以给定字符串为前缀的单词数量
http://hihocoder.com/problemset/problem/1014
(1)数据结构
cnt:记录词典中所有单词经过该节点的次数
flag:标识是否构成以该节点结尾的单词
ptr:指向子节点的指针数组,假设字符集是小写英文字母,ptr[0]!=NULL隐式地表示该节点指向的下一节点对应字符'a'
根节点不包含字符,其余每个节点只包含一个字符
(2)插入单词
待插入的字符串word,指针p指向根节点,下标i指向word[0]
若字符串为空,不用处理;
否则,检查word[i]对应的指针p->ptr[word[i]-'a']是否为空;(记该指针为pNext)
若pNext为空,说明这个字符是第一次在树中出现,为该节点开辟一个新内存,并让pNext指向该新节点;
若pNext不为空,说明该字符在树中的节点已经建过了,令p = pNext即可;
把当前p所指的节点的cnt加1
重复以上过程,word中所有字符都处理完。
PS:最后,若p->cnt!=0,说明以p指向的节点字符是一个单词的尾部字符。可令p->flag=true。
对于长度为n的单词,插入单词的时间复杂度为O(n)。
(3)查询单词(查询前缀)
待查询单词prefix(若该prefix是一个完整单词,用布尔变量isWord标识它)
指针p指向根节点,下标i指向prefix[0]
若单词为空,不用处理;(以空串为前缀的单词数量为0)
否则,依次匹配每个prefix[i]
若p->ptr[prefix[i]-'a']为空,说明不存在以prefix为前缀的单词
若p->ptr[prefix[i]-'a']非空,继续i+1位置的下一次匹配,若直到匹配完prefix中所有字符,这个过程都没有断定匹配失败,也就是匹配成功,最终p指向树中节点的字符就是prefix的尾部字符。
PS:最后,若p->flag为true,说明prefix是一个完整单词。
对于长度为n的单词,查询单词的时间复杂度同样为O(n)。
(4)实现代码
1 class Trie 2 { 3 private: 4 int cnt; 5 bool flag; 6 Trie* ptr[26]; 7 public: 8 Trie() 9 { 10 cnt = 0, flag = false; 11 memset(ptr,0,sizeof(ptr)); //NULL 12 } 13 14 void add(const string& word) 15 { 16 if(word == "") return; 17 Trie* p = this; 18 for(int i = 0; i < word.size(); ++i) 19 { 20 int c = word[i] - 'a'; 21 if(p->ptr[c] == NULL) 22 p->ptr[c] = new Trie; 23 p = p->ptr[c]; 24 ++p->cnt; 25 } 26 p->flag = true; 27 } 28 29 int query(const string& prefix, bool& isWord) 30 { 31 isWord = false; 32 if(prefix == "")return 0; 33 Trie* p = this; 34 for(int i = 0; i < prefix.size(); ++i) 35 { 36 int c = prefix[i] - 'a'; 37 if(p->ptr[c] == NULL) 38 return 0; 39 else 40 p = p->ptr[c]; 41 } 42 43 if(p->flag) isWord = true; 44 return p->cnt; 45 } 46 47 };
PS:对字典树进行先序遍历即可对单词进行字典序排序