1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 struct node{ 6 node *next[10]; 7 int end; 8 node(){ //构造函数,方便初始化数据 9 memset(next,NULL,sizeof(next)); 10 end=0; //end=0表示一般节点,end=1标志一个电话号的结束 11 } 12 }; 13 node *root; 14 bool insert(char *s) 15 { 16 int i,k,flag; 17 node *p=root; 18 for(flag=i=0;s[i];++i){ 19 k=s[i]-'0'; 20 if(p->next[k]==NULL){ 21 p->next[k]=new node(); 22 flag=1; //标记建立过一个新节点 23 } 24 p=p->next[k]; 25 if(p->end) return 0; //碰到结束标志,则返回0 26 } 27 p->end=1; //一个电话号的结束标志 28 if(!flag) return 0;//字符串插入完毕未出现新建节点的操作,返回0 29 return 1; 30 } 31 int del(node *p) //释放字典树空间,否则占用空间太大 32 { 33 if(p==NULL) return 0; 34 for(int i=0;i<10;i++) 35 if(p->next[i]) del(p->next[i]); 36 delete p; 37 return 0; 38 } 39 int main() 40 { 41 int n,T; 42 char s[11]; 43 scanf("%d",&T); 44 while(T--){ 45 bool flag=1; 46 root=new node(); 47 scanf("%d",&n); 48 while(n--){ 49 scanf("%s",s); 50 if(flag) flag=insert(s);//假如出现过混乱情况,则不再进行插入操作 51 } 52 del(root); 53 if(flag) puts("YES"); 54 else puts("NO"); 55 } 56 return 0; 57 }
如果字符串Xn=X1X2....Xn是字符串Ym=Y1Y2....Ym的前缀,有在插入的时候有两种情况:Xn在Yn之前插入,Xn在Yn之后插入。
(1)如果Xn在Yn之前插入,那么在插入Yn的时候必然经过Xn的路径,此时可以根据判断在这条路径上是否已经有结点被标记已经构成完成的字符串序列来判断是否存在Yn的前缀;
(2)如果Xn在Yn之后插入,那么插入完成之后当前指针指向的结点的next数组中的元素必定不全为NULL。