字典树模板

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);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值