这是我做的字典树第二题,纠结了几天,终于做出来了,感觉真爽
主题思想:把每个经过的结点进行标记,没走之前都把flag标记为0,走过的标记为1,一串电话号的末尾标记为2;
举个例子 123和12
1.先插123;然后再插12,当插到最后2时,发现2已经被标记为1了,说明已经走过,即已经存在比他更长的有公共前缀短的电话号,此时说明电话薄不能建立,把判断能否建立的变量Flag置为1,;
2.先插12;在插到2时发现,flag为2,说明已经出现过比他短的且有公共前缀的电话号,不能建立(只要在插入的途中遇到2就说明不能建立)
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int Flag;//标记电话薄是否能建立,如果可以为0,否则为1
typedef struct node
{
node *next[10];
int flag;//用来标记,初始为0,如果走过标记为1,末尾标记为2
}node;
node *root;
node *newset()
{
node *p=(node *)malloc(sizeof(node));//动态分配内存
for(int i=0;i<10;i++)
{p->next[i]=NULL;
}
p->flag=0;//初始为0
return p;
}
void insert(char *a)
{
node *p;
p=root;
int k=strlen(a);
for(int i=0;i<k;i++)
{
if(p->next[a[i]-48]==NULL)//建立结点
p->next[a[i]-48]=newset();
p=p->next[a[i]-48];
if(p->flag==0&&i<k-1) p->flag=1;//经过就标记,但不标记最后一个
if(p->flag==2) {Flag=1;}//如果途中遇到2,说明不能建立,Flag为1
if(i==k-1)//最后一个
{
if(p->flag==1||p->flag==2)//末尾如果走过,Flag为1
{ p->flag=2;
Flag=1;
}
if(p->flag==0) p->flag=2;//如果没走过,把末尾标记为2
}
}
}
void clear(node *t)//清空
{
if(t!=NULL)
{
for(int i=0;i<10;i++)
clear(t->next[i]);
free(t);//释放内存
}
}
int main()
{
int n,m;
char a[12];
scanf("%d",&n);
while(n--)
{
root=newset();//此处卡了好久,根结点一定要分配内存
scanf("%d",&m);
Flag=0;
while(m--)
{
scanf("%s",a);
insert(a);
}
if(Flag==0) printf("YES\n");
else printf("NO\n");
clear(root);//清空
}
return 0;
}