http://acm.hdu.edu.cn/showproblem.php?pid=1671
问题概述: 输入n个电话号码,判断所有的电话号码中是否有号码是其他号码的前缀,若有输出NO,否则输出YES
输入样例: 对应输出:
2 NO
3 YES
911 97625999 91125426
5
113 12340 123440 12345 8346
字典树:
http://www.cnblogs.com/tanky_woo/archive/2010/09/24/1833717.html
→意义:用于统计,排序和保存大量的字符串,以及字符串的查找与搜索
→优点:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高
→运作:当你要查一个单词是不是在字典树中,首先看单词的第一个字母是不是在字典的第一层,如果不在,说明
字典树里没有该单词,如果在就在该字母的孩子节点里找是不是有单词的第二个字母,没有说明没有该单词,有的
话用同样的方法继续查找……字典树不仅可以用来储存字母,也可以储存数字等其它数据
→主要操作:看程序
题解:设X是Y的前缀,则会有两种情况:
1:X在Y前面就已经插入,这时插入Y后一定会遍历X的路径,插入Y时一定经过了final为1的点
2:X在Y后面插入,当X插入完毕后当前结点的next数组必定存在不为NULL的元素
#include<stdio.h>
#include<stdlib.h>
using namespace std;
int flag;
typedef struct Trie_Node
{
int final; /*final用来标记是否有串字符到这里结束(即这个节点是否为某个字符串的最后一个字符)*/
Trie_Node *next[12]; /*字典树每个节点有12个子节点,*/
}Trie;
void insert(Trie *root,char *phone);
void Del(Trie *root); /*记得释放内存*/
int main(void)
{
int T, i, n;
char phone[22];
scanf("%d", &T);
while(T--)
{
Trie *root = new Trie; /*初始化字典树,目前只有一个根节点(没有实际意义)*/
flag = 0;
root->final = 0;
for(i=0;i<=9;i++)
root->next[i] = NULL;
scanf("%d", &n);
for(i=1;i<=n;i++)
{
scanf("%s", phone);
if(flag!=1) /*如果还没有确定有号码是其他号码的前缀,将新号码加入字典树*/
insert(root, phone);
}
if(flag==1)
printf("NO\n");
else
printf("YES\n");
Del(root);
}
return 0;
}
void insert(Trie *root, char *phone)
{
int i;
Trie *p = root; /*p为Trie游历指针*/
for(;*phone!='\0';phone++) /*依次读入整个号码的所有数字*/
{
if(p->next[*phone-'0']==NULL) /*如果没有这个节点*/
{
Trie *temp = new Trie;
temp->final = 0; /*建立节点,初始化这个节点标记,这个节点不是该号码的最后一个数字*/
for(i=0;i<=9;i++)
temp->next[i] = NULL;
p->next[*phone-'0'] = temp; /*连接该节点*/
}
if(p->final==1) /*情况①*/
flag = 1;
p = p->next[*phone-'0']; /*指针p到下一个节点*/
}
p->final = 1;
for(i=0;i<=9;i++)
{
if(p->next[i]!=NULL) /*情况②*/
{
flag = 1;
break;
}
}
}
void Del(Trie *root)
{
int i;
for(i=0;i<=9;i++)
{
if(root->next[i]!=NULL)
Del(root->next[i]);
}
free(root);
}