nyoj 163 phonelist 字典树(2)

这是我做的字典树第二题,纠结了几天,终于做出来了,感觉真爽大笑

主题思想:把每个经过的结点进行标记,没走之前都把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;
}


你可能感兴趣的:(nyoj 163 phonelist 字典树(2))