hihoCoder之Trie树

这题是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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值