海量数据处理---Trie树

trie树又被称为前缀树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串,所以经常被搜索引擎系统用于文本词频统计。

它的3个基本性质:

  1. 根节点不包括字符,除根节点外每个节点都只包含一个字符
  2. 从根节点到某一节点,路径上经过的字符连接起来,就是该节点对应的字符串
  3. 每个节点的所有子节点包含的字符都不相同

 

树的构建

假设有 b,abc,abd,bcd,abcd,efg,hil这6个单词,建树的过程如下:

对于每一个节点,从根节点到它的过程就是一个单词,如果这个节点标记为已存在,就表示这个单词已经出现过,可以设计一个计数器count记录该单词出现的次数。对于一个单词,我们只要顺着根走到对应的节点,再看看这个节点是否存在,就可以知道它是否出现过。把这个节点标记为已存在,相当于插入这个单词。这样可以达到查询和插入是一起完成的。(实际上就是一个26叉树,每个节点里是26大小的字符数组)

代码实现:

#include<iostream>
#include<string>
#include<assert.h>
using namespace std;

#define MAX 26
typedef struct TireNode
{
	bool isstr;//是否存在
	int count;//计数器表示出现次数
	TireNode* next[MAX];///下一个节点
}Trie;

Trie* Buynode()
{
	Trie* s=(Trie*)malloc(sizeof(Trie));
	if(s==NULL) exit(1);
	for(int i=0;i<MAX;i++)
	{
		s->next[i]=NULL;
	}
	return s;
}
void Freenode(Trie* root)
{
	free(root);
}
void Insert(Trie* root,const char* s)
{
	if(root==NULL || *s=='\0')
	{
		return ;
	}
	int i=0;
	Trie *p=root;
	while(*s!='\0')
	{
		if(p->next[*s-'a']==NULL)//之前没有出现过,就创建新节点
		{
			Trie* tmp=Buynode();
			tmp->isstr=false;
			tmp->count=0;
			p->next[*s-'a']=tmp;
			p=p->next[*s-'a'];
		}
		else
		{
			p=p->next[*s-'a'];
		}
		s++;
	}
	p->isstr=true;//将该词该称已存在
	p->count++;//计数器+1
}

typedef struct
{
	bool is;
	int count;
}Res;
Res Search(Trie* root,const char* s)
{
	Res res={false,0};
	Trie* p=root;
	while(p!=NULL && *s!='\0')
	{
		p=p->next[*s-'a'];
		s++;
	}
	if(p!=NULL && p->isstr==true)
	{
		res.is=true;
		res.count=p->count;
	}
	return res;
}

int main()
{
	const char* a[]={"data","date","eye","data","hello","world","data","date","eye",
		"data","hello","world","data","date","eye","data","hello","world","data"};
	int len=sizeof(a)/sizeof(a[0]);
	Trie* root=Buynode();
	root->isstr=false;
	root->count=0;
	for(int i=0;i<len;i++)
	{
		Insert(root,a[i]);
	}
	Res res=Search(root,"data");

	cout<<res.is<<" "<<res.count<<endl;
	Freenode(root);
	return 0;
}

运行结果:

猜你喜欢

转载自blog.csdn.net/ShWe_yayaya/article/details/81836384