题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1671
转自:http://blog.csdn.net/zkzxmzk/article/details/8914860;http://www.cppblog.com/hunter/archive/2011/09/30/67039.html;http://www.cnblogs.com/dlutxm/archive/2011/10/26/2225660.html
字典树:
又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。字典树的基本功能是用来查询某个单词(前缀)在所有单词中出现次数的一种数据结构,它的插入和查询复杂度都为O(len),Len为单词(前缀)长度,但是它的空间复杂度却非常高,如果字符集是26个字母,那每个节点的度就有26个,典型的以空间换时间结构。
假设有b,abc,abd,bcd,abcd,efg,hii这6个单词,我们构建的树就是这样的。
对于每一个节点,从根遍历到他的过程就是一个单词,如果这个节点被标记为红色,就表示这个单词存在,否则不存在。
那么,对于一个单词,我只要顺着他从跟走到对应的节点,再看这个节点是否被标记为红色就可以知道它是否出现过了。把这个节点标记为红色,就相当于插入了这个单词。
1671 AC 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAX 10
typedef struct Trie
{
int v;
Trie *next[MAX];
};
Trie *root;
char a[15];
void createTrie(char *str)
{
int len = strlen(str);
Trie *p = root , *q;
for(int i = 0 ; i < len ; i++)
{
int id = str[i] - '0';
if(p ->next[id] == NULL)
{
q = (Trie*)malloc(sizeof(Trie));
q ->v = 1;
for(int j = 0; j < MAX ; j++)
{
q ->next[j] = NULL;
}
p ->next[id] = q;
p = p ->next[id];
}
else
{
p ->next[id] ->v++;
p = p ->next[id];
}
}
p ->v = -1;
}
int findTrie(char *str)
{
int len = strlen(str);
Trie *p = root;
for(int i = 0 ; i < len ; i++)
{
int id = str[i] - '0';
p = p ->next[id];
if(p == NULL)
{
return 0;
}
if(p ->v == -1)
{
return -1;
}
}
return -1;
}
int deal(Trie* T)
{
int i;
if(T == NULL)return 0;
for(int i = 0 ; i < 10 ; i++)
{
if(T -> next[i] != NULL)
{
deal(T ->next[i]);
}
}
free(T);
return 0;
}
int main()
{
int T , n ;
cin >> T;
while(T--)
{
scanf("%d",&n);
root = (Trie *)malloc(sizeof(Trie));
for(int i = 0 ; i < MAX ; i++)
{
root ->next[i] = NULL;
}
int ok = 1;
for(int i = 0 ; i < n ; i++)
{
scanf("%s" , a);
if(findTrie(a) == -1)
{
ok = 0;
}
if(!ok)
{
continue;
}
createTrie(a);
}
printf(ok ? "YES\n" : "NO\n");
deal(root);
}
return 0;
}