题目1 : Trie树
题目原文:http://hihocoder.com/contest/hiho2/problem/1
【题目解读】
提示说明使用Trie树(即,字母树,前缀树)已经很清楚了,难度就在实现。鄙人不才,树结构和指针学的跟翔没有两样。。。求助大神和查阅资料之后,憋了几天才写出来。
【hiho提示】
【提示一】【提示二】是介绍使用Trie树。每次拿到前缀之后,在树上找到对应的结点,然后统计这个节点以及其子树里有多少个标记成单词的节点。
【提示三】提出,【二】中“统计”单词数量的方法:在最开始置所有L[T]=0,然后每次添加一个新的单词的时候,都将它经过的所有结点的L[T]全部+1,这样构建完这棵Trie树的时候,我也就能够同时统计到所有L[T]了。即在创建时遍历。
【编写细节】
编写树一般有两种思路:
(1)父节点表示法,每个节点只记录自己的父节点。
(2)孩子链表表示法,每个节点记录自己的所有孩子节点,并且将其串入一个链表。为节省存储空间我选用后者。
之后,创建Trie树的方式有:
(1)每个节点有最大分支数个指针,指针指向另一个新节点。另外每个节点保存一个token值。我选用这种。
(2)Trie本质是一个DFS树,其实常用数据结构是转移矩阵,但是太费空间,所以用指针。
(3)看到一种二叉树表示的数据结构:每个节点的左子树是儿子节点链表,指向大儿子;右子树是兄弟节点链表,指向与父节点同级的下一个兄弟。父节点不与大儿子之外的儿子连接,通过大儿子连接。
以上是树的整体结构,接下来是一些编写的细节问题:
(1)C++ struct 与 C 中的 struct 不同,struct name{}; 后 name 可以直接作为类型名使用,并且可以写构造函数、析构函数;
(2)结构体如果有对于自身的引用,只能引用指针不能引用实例;例如以下是错误的
struct A
{
A test;
};
但是这样就是正确的
struct A
{
A* test;
};
(3)
全局变量的初始值一定为0 / NULL,局部变量的初始值则不一定;
(4)指针定义时并不分配内存,C/C++ 分配内存使用 malloc 或 new,两者具体差别见:http://blog.163.com/yangjun1988422@126/blog/static/4741291720084305615602/
使用 malloc 格式:type* p = (type*)malloc(sizeof(type))
这次我反正是体会到了他俩的一个区别:malloc 根本不调用构造函数、析构函数啊尼玛!
所以,也有人理解:new = malloc + 构造函数;delete = free + 析构函数。
【AC代码】
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
const int branch = 26;
struct tnode
{
int n;
tnode* child[branch];
//tnode():n(0) // malloc不能调用构造函数
//{
// for(int k=0; k<26; k++)
// child[k] = NULL;
//}
};
long n, m;
char str[35];
char base = 'a';
int len;
tnode* create()
{
tnode* tnew = (tnode*)malloc(sizeof(tnode));
tnew->n = 0;
for(int k=0; k<branch; k++)
tnew->child[k] = NULL;
return tnew;
}
int main()
{
scanf("%ld", &n);
tnode* root = create();
root->n = -1; // flag -1: root
tnode* tmp = NULL;
while(n--)
{
scanf("%s", str);
len = strlen(str);
tmp = root;
for(int i=0; i<len; i++)
{
if(tmp->child[str[i]-base] == NULL)
{
tmp->child[str[i] - base] = create();
}
tmp->child[str[i]-base]->n++;
tmp = tmp->child[str[i] - base];
}
}
scanf("%ld", &m);
while(m--)
{
scanf("%s", str);
tmp = root;
len = strlen(str);
for(int j=0; j<len; j++)
{
tmp = tmp->child[str[j] - base];
// if the predixs never appear
if(tmp == NULL)
break;
}
if(tmp == NULL)
printf("0\n");
else
printf("%d\n", tmp->n);
}
return 0;
}