题目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; }