这题是hihoCoder第1014题,关于Trie树的,本来不想写博客的,但是实在是,改了一晚上和一下午,最终发现是有一处的指针弄错了,所以写个博客纪念一下。
原题链接:http://hihocoder.com/problemset/problem/1014
简单说明一下题目:
输入
输入的第一行为一个正整数n,表示词典的大小,其后n行,每一行一个单词(不保证是英文单词,也有可能是火星文单词哦),单词由不超过10个的小写英文字母组成,可能存在相同的单词,此时应将其视作不同的单词。接下来的一行为一个正整数m,表示小Hi询问的次数,其后m行,每一行一个字符串,该字符串由不超过10个的小写英文字母组成,表示小Hi的一个询问。
在20%的数据中n, m<=10,词典的字母表大小<=2.
在60%的数据中n, m<=1000,词典的字母表大小<=5.
在100%的数据中n, m<=100000,词典的字母表大小<=26.
本题按通过的数据量排名哦~
输出
对于小Hi的每一个询问,输出一个整数Ans,表示词典中以小Hi给出的字符串为前缀的单词的个数。
思想:利用Trie树,那么什么是Trie树呢?原题里已经提示了:
下图是一棵Trie树,树的每条边代表一个字母,黑色节点代表单词的结束
样例输入
5 babaab babbbaaaa abba aaaaabaa babaababb 5 babb baabaaa bab bb bbabbaab
1)插入
刚开始Trie树只有根节点Root,当输入第一个单词的时候,如输入app时,会新建一个节点2,并将通往这个节点的边记为a,
再对节点2,插入p此时会新建一个节点,并将边记为p,以此类推,当最后一个字母p插入时,就记录这个节点是个结尾。
计数:不妨称以T为根的子树中标记节点的个数为L[T],我在最开始置所有L[T]=0,然后每次添加一个新的单词的时候,都将它经过的所有结点的L[T]全部+1,这样我构建完这棵Trie树的时候,我也就能够同时统计到所有L[T]了
2)查询
题目要求查询以某个字符串为前缀的单词数目,只要顺着树往下查到字符串末尾字符的边指向的节点,它的L[T]就是答案了。
贴上代码:
#include <iostream>
#include <string>
#define MAXSIZE 26
using namespace std;
/*DS Defination*/
/*Tree DS*/
enum NODE_TYPE {
/*COMPLETED means the node is the end of a word.*/
COMPLETED,
UNCOMPLETED
};
typedef struct TrieNode {
int LetterNum;
enum NODE_TYPE NodeType;
struct TrieNode* child[MAXSIZE];
}TrieNode, *nodeptr;
typedef struct TrieTree {
TrieNode* Root;
}TrieTree, *TrieT;
bool InsertWord(string& Word, int pos, TrieNode* Root);
int SearchWord(string Word, nodeptr Root);
TrieNode* CreateNode();
TrieT CreateTrieTree();
int main() {
/*Build a trie tree.*/
int num;
string word;
TrieT T = CreateTrieTree();
/*Get number of words*/
cin >> num;
for (int i = 0; i < num; i++) {
cin >> word;
InsertWord(word, 0, T->Root);
}
/*Get number of words*/
cin >> num;
for (int i = 0; i < num; i++) {
cin >> word;
cout << SearchWord(word, T->Root) << endl;
}
return 0;
}
bool InsertWord(string& Word, int pos, TrieNode* Root) {
// have some problem.
if (Word.length() == pos)
return false;
int index = ((int)Word[pos]) - ((int)'a');
if (Root->child[index] == NULL) {
// 如果节点不存在
Root->child[index] = CreateNode();
InsertWord(Word, pos + 1, Root->child[index]);
}
else {
Root->child[index]->LetterNum += 1;
InsertWord(Word, pos + 1, Root->child[index]);
}
if (pos + 1 == Word.length())
Root->child[index]->NodeType = COMPLETED;
return true;
}
int SearchWord(string Word, nodeptr Root) {
if (0 == Word.length())
return 0;
for (int i = 0; i < Word.length(); i++) {
if (Root->child[Word[i] - 'a'] == NULL)
return 0;
Root = Root->child[Word[i] - 'a'];
}
return Root->LetterNum;
}
TrieNode* CreateNode() {
TrieNode* node = new TrieNode;
node->LetterNum = 1; // wait thinking
for (int i = 0; i < MAXSIZE; i++) {
node->child[i] = NULL;
node->NodeType = UNCOMPLETED;
}
return node;
}
TrieT CreateTrieTree() {
/*Create a trie tree*/
TrieT T = new TrieTree;
T->Root = new TrieNode;
T->Root->LetterNum = 0;
for (int i = 0; i < MAXSIZE; i++)
T->Root->child[i] = NULL;
T->Root->NodeType = UNCOMPLETED;
return T;
}