http://acm.hdu.edu.cn/showproblem.php?pid=1251
题意为:先给定一个单词列表,然后输入字符串,统计以该字符串为前缀的单词数量。
第一次接触字典树,这个题目就是要用字典树的插入、查询来做。
有几个地方要注意一下:
-
插入时候,不是字母结束时将p->cnt++,而是遇到字母:
没出现过:初始化1,表明此次出现
出现过:cnt++
这样,p->cnt记录的就是从根结点到head结点的前缀出现的次数
-
怎样判断空行:用strlen()计算字符串的长度,如果长度为0,说明为空行,退出输入循环。
-
关于内存的释放,虽然程序结束后会自动释放,但还是养成一个手动释放的好习惯吧。
贴上代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct Node
{
int cnt;
struct Node *child[26];
Node(){
cnt = 0;
for (int i = 0; i < 26; i++)
child[i] = NULL;
}
}*root;
//插入算法
void Insert(char s[])
{
Node *p = root;
int len = strlen(s);
for(int i = 0; i < len; i++) {
//求出当前字母的下标;
int index = (int)(s[i] - 'a');
//如果字母不存在,则插入
if (p->child[index] == NULL)
{
p->child[index] = new Node();
p = p->child[index];
p->cnt = 1; //将当前字母置位1,表示出现过一次
}
//当前字母存在,则继续寻找可插入的位置
else
{
p = p->child[index];
p->cnt++; //cnt代表的是已经经过的单词前缀数量
}
}
}
//查询算法
int Find(char s[])
{
int len = strlen(s);
Node *p = root;
for (int i = 0; i < len; i++)
{
int index = (int)(s[i] - 'a');
if (p->child[index] == NULL)
return 0;
else p = p->child[index];
}
return p->cnt;
}
//释放所申请的空间
void release(Node *root)
{
if (root == NULL)
return;
for (int i = 0; i < 26; i++)
{
if ( root->child[i] != NULL )
release( root->child[i] );
}
delete root;
root = NULL;
}
int main()
{
root = new Node();
char word[10], que[10];
while(gets(word) && strcmp(word, "") != 0)
{
Insert(word);
}
while (gets(que) && strcmp(que, "") != 0)
{
int num = Find(que);
cout << num << endl;
}
release(root);
return 0;
}