主要转自 http://blog.csdn.net/hackbuteer1/article/details/7964147
前缀查询的典型应用:
http://acm.hdu.edu.cn/showproblem.php?pid=1251
#include
#include
using namespace std;
struct trieNode{
int count;//统计单词前缀出现的次数
trieNode* next[26];//指向各子树的指针
bool exit;//标记该结点处是否构成单词
trieNode():count(0),exit(false){
for (int i = 0; i < 26; i++){
next[i] = NULL;
}
}
};
void trieInsert(trieNode* root, string &word){
trieNode *node = root;
int id;
int len = word.size();
int i = 0;
while (i < len){
id = word[i]-'a';
if (node->next[id] == NULL){
node->next[id] = new trieNode();
}
node = node->next[id];
node->count += 1;
i++;
}
node->exit = true;//单词结束,可以构成一个单词
}
int trieSearch(trieNode*root, string &word){
trieNode* node = root;
int len = word.size();
int i = 0;
while (i < len){
int id = word[i] - 'a';
if (node->next[id] != NULL){
node = node->next[id];
i++;
}
else{
return 0;
}
}
return node->count;
}
int main()
{
trieNode *root = new trieNode();
string word;
int flag = false;
while (getline(cin, word)){
if (flag){
cout << trieSearch(root, word) << endl;
}
else{
if (!word.empty()){
trieInsert(root, word);
}
else{
flag = true;
}
}
}
return 0;
}
#include
#include
using namespace std;
struct trieNode{
int count;//统计单词前缀出现的次数
trieNode* next[26];//指向各子树的指针
bool exit;//标记该结点处是否构成单词
string traslate;
trieNode() :count(0), exit(false){
for (int i = 0; i < 26; i++){
next[i] = NULL;
}
}
};
void trieInsert(trieNode* root, string &word, string &eng){
trieNode *node = root;
int id;
int len = word.size();
int i = 0;
while (i < len){
id = word[i] - 'a';
if (node->next[id] == NULL){
node->next[id] = new trieNode();
}
node = node->next[id];
node->count += 1;
i++;
}
node->exit = true;//单词结束,可以构成一个单词
node->traslate = eng;
}
string trieSearch(trieNode*root, string &word){
trieNode* node = root;
int len = word.size();
int i = 0;
while (i < len){
int id = word[i] - 'a';
if (node->next[id] != NULL){
node = node->next[id];
i++;
}
else{
return "";
}
}
string res;
if (node->exit){
res = node->traslate;
}
else{
res = "";
}
return res;
}
int main()
{
trieNode *root = new trieNode();
string eng;
string word;
cin >> eng;
while (cin >> eng && eng != "END"){
cin >> word;
trieInsert(root, word, eng);
}
cin.get();//去掉上一行的换行符
while (getline(cin, word)){
if (word == "START"){
continue;
}
if (word == "END"){
break;
}
string tmpWord = "";
int len = word.size();
for (int i = 0; i < len; i++){
if (word[i] >= 'a' && word[i] <= 'z'){
tmpWord += word[i];
}
else{
string res = trieSearch(root, tmpWord);
if (!res.empty()){
cout << res;
}
else{
cout << tmpWord;
}
cout << word[i];
tmpWord = "";
}
}
cout << endl;
}
return 0;
}
适用范围:数据量大,重复多,但是数据种类小可以放入内存
基本原理及要点:实现方式,节点孩子的表示方式
1、一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析.
答:先用trie树统计每个词出现的次数,时间复杂度是O(n*le)(le表示单词的平均长度);
然后是用小顶堆找出出现最频繁的前10个词,时间复杂度是O(n*lg10)。
2、寻找热门查询
原题:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。
答: 利用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小推来对出现频率进行排序。3.1000万字符串,其中有些是相同的(重复),需要把重复的全部去掉,保留没有重复的字符串。
参考 点击打开链接
答:使用hash_map或者trie树。
比如trie树,在构建trie树的过程中,如果某个字符串已经存在于trie中则不输出,否则输出到文本中,这样就可以得到不重复的字符串。
hash_map的速度会要快一些,因为在添加一个字符串的时候,hashmap直接用哈希函数就能定位,然后选择是否写入文件,但是trie树需要在子节点中比较。
trie树对hashmap的优势是,在大量重复的单词中,trie树需要的内存会低一些