Trie树及其应用

一,知识简介

  Trie树,又称单词查找树、键树或前缀树。典型应用是用于排序和统计大量字符串,但不仅限于于字符串,所以经常被搜索引擎用于文本词频统计。它的优点是:最大限度的减少无谓的字符串比较,查询效率比哈希表高。

  字典树的核心思想是以空间换时间,利用字符串的公共前缀来降低查询时间开销来达到提高效率的目的。

  Trie树的特点:

 (1)根节点不包含字符,除根节点外每个节点只包含一个字符;

 (2)从根节点到某一节点,路径上的字符连接起来,为该节点对应的字符串;

 (3)每个节点所包括的子节点所包含的字符都不相同。

  Trie树插入过程,以字母树为例,对于一个单词,从根开始沿着对应的各个子树节点分支向下遍历,知道单词遍历结束,对最后一个节点做标记,表示该单词已插入到Trie中;

  Trie树查询过程,类似插入过程,从根节点开始按照单词的字母顺序向下遍历,直到某一个节点标记不存在或者单词遍历结束而最后节点并没有单词结束标记,查询结束,表示该单词不存在;若最后节点有标记,表示该单词存在。

二,Trie树的数据结构

  Trie节点结构,如图所示:

     

  next是一个指针数组,指向各个孩子节点的指针。

  简单介绍一个插入过程,给定几个字符串:b    abc   abd  bcd   abcd   efg  hii,所构建的的Trie树如图所示:

                     

  现在又来一个单词abe,我们首先从根节点开始查找,a这条边存在,查找第二个字母,b这条边也存在,接着查找第三个字母e,发现,不存在e这条边,我们就要在节点b的孩子节点中插入节点e,并对节点e作标记,表示单词abe已插入。

三,Trie树操作

  在Trie树中主要有3个操作,插入、查找和删除。一般情况下Trie树中很少存在删除单独某个结点的情况,因此只考虑删除整棵树。
1、插入
  假设存在字符串str,Trie树的根结点为root。i=0,p=root。
  1)取str[i],判断p->next[str[i]-97]是否为空,若为空,则建立结点temp,并将p->next[str[i]-97]指向temp,然后p指向temp;
   若不为空,则p=p->next[str[i]-97];
  2)i++,继续取str[i],循环1)中的操作,直到遇到结束符'\0',此时将当前结点p中的 exist置为true。
2、查找
  假设要查找的字符串为str,Trie树的根结点为root,i=0,p=root
  1)取str[i],判断判断p->next[str[i]-97]是否为空,若为空,则返回false;若不为空,则p=p->next[str[i]-97],继续取字符。
  2)重复1)中的操作直到遇到结束符'\0',若当前结点p不为空并且 exist 为true,则返回true,否则返回false。
3、删除
  删除可以以递归的形式进行删除。

四,Trie树应用

  (1)给定n个平均长度为len的单词,判断是否存在某一个为另一个的前缀子串,下面是三种解决方法: 

     

  (2)对n个单词进行字典序排序,解决方法:把n个单词读入字典树,然后先序遍历字典树即可。

  实现代码:

#include "StdAfx.h"
#include "Trie.h"
#include "TrieNode.h"
#include<iostream>
#include<string>
using namespace std;


Trie::Trie(void)
{
}


Trie::~Trie(void)
{
}


TrieNode* Trie::CreatTrie()//构建字典树根节点
{
	TrieNode *temp = NULL;
	temp = new TrieNode();
	return temp;
}


void Trie::Trie_Insert(TrieNode* root, string str)//插入字符串
{
	TrieNode *p;
	p = root;
	int i = 0,j = 0;
	while(i < str.size())
	{
		if(p->next[str.at(i)-'a'] == NULL)
		{
			p->next[str.at(i)-'a'] = new TrieNode();
		}
		p = p->next[str.at(i)-'a'];
		p->count += 1;
		++i;
	}
	p->exist = true;
}


void Trie::Trie_Search(TrieNode* root, string str)//查询字符串
{
	TrieNode *p;
	p = root;
	int i = 0;
	while(i < str.size())
	{
		if(p->next[str.at(i) - 'a'])
		{
			p = p->next[str.at(i) - 'a'];
			++i;
		}
		else 
		{
			cout<<"所查单词不存在字典树中"<<endl;
		}
	}
	if(p->exist == true)
		cout<<"所查单词存在字典树中"<<endl;
	 cout<<p->count<<endl;
}


  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值