杭电ACM1251——统计难题~简单字典树的应用

字典树

又称单词查找树,Trie,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

(以上的摘自百度百科~)

题目的意思:给出一些单词,让你统计以某个字符串为前缀的单词有多少个。

一开始,我用暴力来做,结果超时了。很明显,时间复杂度高。用字典树,可以高效的进行查找,减少无谓的字符的比较。

比如给出单词banana和band,生成的字典树应该是这样的:

杭电ACM1251——统计难题~简单字典树的应用_第1张图片

每一个结点有一个长度为26的指针数组,可以连接每一个字母。如果再加如单词abc,则应该是这样的:

杭电ACM1251——统计难题~简单字典树的应用_第2张图片

每一个结点有26个指针,可以包含所以的单词。

下面是AC代码,有注释:

#include 
#include 
#include 
using namespace std;

class node
{
public:
	node* p[26];                  //指针数组
	int count;                    //以该结点为终点的前缀相同有多少个
};

node *root;                       //定义根节点
void insert(char *str)            //插入函数
{
	int len = strlen(str);
	node* q = root, *p;
	for(int i = 0; i < len; i++)  //遍历单词的字符串
	{	
		int id = str[i] - 'a'; //表示第几个字符
		if(q->p[id] == NULL)      //如果该字符不存在,增添一个结点
		{
			p = new node;
			p->count = 1;         //初始化count
			for(int j = 0; j < 26; j++)   //初始化指针数组
				p->p[j] = NULL;
			q->p[id] = p;
			q = q->p[id];
		}
		else                      //该字符存在
		{
			q->p[id]->count++;    //count自增就OK了
			q = q->p[id];		  //指向下一个指针
		}
	}
}
node* finds(char *str)          //查找函数
{
	int len = strlen(str);
	node *q = root;
	for(int i = 0; i < len; i++)
	{
		if(q->p[str[i] - 'a'] != NULL)  //如果不为空,则该前缀存在
			q = q->p[str[i] - 'a'];
		else
			return NULL;
	}
	return q;                          //返回该结点
}
int main()
{
	root = new node;
	for(int i = 0; i < 26; i++)
		root->p[i] = NULL;
	root->count = 0;
	char str[15];
	while(1)
	{
		gets(str);
		if(!str[0])                //题目要求的是一个空行为标记,这里应该是这样的。
			break;                 //一开始以为是一个空格,WR了一次
		insert(str);
	}
	while(cin >> str)
	{
		node *s = finds(str);
		if(s != NULL)              //查找,不为空,则存在,输出该结点的count,
			printf("%d\n", s->count);
		else
			printf("0\n");           //否则,不存在
	}
	return 0;
}

好久没有写过类似链表的操作了,有点生疏了~~

你可能感兴趣的:(杭电,acm,杭电)