Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Trie树:应用于统计和排序

Trie树:应用于统计和排序

作者头像
黄规速
发布于 2022-06-30 07:48:46
发布于 2022-06-30 07:48:46
73100
代码可运行
举报
运行总次数:0
代码可运行

 1. 什么是trie树

  1.Trie树 (特例结构树)

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

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

Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.

2.  三个基本特性:

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

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

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

3 .例子

       和二叉查找树不同,在trie树中,每个结点上并非存储一个元素。        trie树把要查找的关键词看作一个字符序列。并根据构成关键词字符的先后顺序构造用于检索的树结构。        在trie树上进行检索类似于查阅英语词典。

      一棵m度的trie树或者为空,或者由m棵m度的trie树构成。

例如,电子英文词典,为了方便用户快速检索英语单词,可以建立一棵trie树。例如词典由下面的单词成:a、b、c、aa、ab、ac、ba、ca、aba、abc、baa、bab、bac、cab、abba、baba、caba、abaca、caaba

           再举一个例子。给出一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie:

        可以看出:

  • 每条边对应一个字母。
  • 每个节点对应一项前缀。叶节点对应最长前缀,即单词本身。
  • 单词inn与单词int有共同的前缀“in”, 因此他们共享左边的一条分支,root->i->in。同理,ate, age, adv, 和ant共享前缀"a",所以他们共享从根节点到节点"a"的边。

查询操纵非常简单。比如要查找int,顺着路径i -> in -> int就找到了。

 2. trie树的实现

1.插入过程

对于一个单词,从根开始,沿着单词的各个字母所对应的树中的节点分支向下走,直到单词遍历完,将最后的节点标记为红色,表示该单词已插入trie树。

2. 查找过程

其方法为:

(1) 从根结点开始一次搜索;

(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;

(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。

(4) 迭代过程……

(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。其他操作类似处理.

       即从根开始按照单词的字母顺序向下遍历trie树,一旦发现某个节点标记不存在或者单词遍历完成而最后的节点未标记为红色,则表示该单词不存在,若最后的节点标记为红色,表示该单词存在。如下图中:trie树中存在的就是abc、d、da、dda四个单词。在实际的问题中可以将标记颜色的标志位改为数量count等其他符合题目要求的变量。  

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include <stdio.h>  
#include "stdlib.h"
#include <iostream>
#include <string.h>
using namespace std;

//宏定义    
#define TRUE   1    
#define FALSE   0   
#define NULL 0
#define OK    1    
#define ERROR   0  
#define INFEASIBLE -1    
#define OVERFLOW -2  

const int num_chars = 26;
class Trie {
public:
    Trie();
    Trie(Trie& tr);
    virtual ~Trie();
    int trie_search(const char* word, char* entry ) const;
    int insert(const char* word, const char* entry);
    int remove(const char* word, char* entry);
protected:
     struct Trie_node{
           char* data; //若不为空,表示从root到此结点构成一个单词 
           Trie_node* branch[num_chars]; //分支 
           Trie_node(); //构造函数 
     };
     
     Trie_node* root; //根结点(指针) 

};
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Test.cpp : Defines the entry point for the console application.  
//  
#include "stdafx.h" 
Trie::Trie_node::Trie_node() {
	data = NULL;    
	for (int i=0; i<num_chars; ++i) 
		branch[i] = NULL;
}
Trie::Trie():root(NULL) {}
Trie::~Trie(){}
int Trie::trie_search(const char* word, char* entry ) const {  
	int position = 0;  //层数 
	char char_code;    

	Trie_node *location = root;  //从根结点开始 
	while( location!=NULL && *word!=0 ) {     
		if (*word >= 'A' && *word <= 'Z') 
			char_code = *word-'A';     
		else if (*word>='a' && *word<='z') 
			char_code = *word-'a';     
		else return 0;// 不合法的单词   
		//转入相应分支指针 
		location = location->branch[char_code];     
		position++;     
		word++;  
	}  
	//找到,获取数据,成功返回 
	if ( location != NULL && location->data != NULL ) {     
		strcpy(entry,location->data);     
		return 1;  
	}  
	else  return 0;// 不合法的单词
}
int Trie::insert(const char* word, const char* entry) {   
	int result = 1, position = 0;   
	if ( root == NULL ) root = new Trie_node;   //初始插入,根结点为空 
	char char_code;   
	Trie_node *location = root;   //从根结点开始 
	while( location!=NULL && *word!=0 ) {       
		if (*word>='A' && *word<='Z') char_code = *word-'A';       
		else if (*word>='a' && *word<='z') char_code = *word-'a';       
		else return 0;// 不合法的单词    

		//不存在此分支 
		if( location->branch[char_code] == NULL )            
			location->branch[char_code] = new Trie_node;    //创建空分支   

		//转入分支 
		location = location->branch[char_code];       
		position++;word++;   }   
	if (location->data != NULL) result = 0;//欲插入的单词已经存在    
	else {    //插入数据     
		location->data = new char[strlen(entry)+1];     //分配内存    
		strcpy(location->data, entry);    //给data赋值表明单词存在 
	}   
	return result;	
}
int main(){   
	Trie t;   
	char entry[100];   
	t.insert("a", "DET");        
	t.insert("abacus","NOUN");   
	t.insert("abalone","NOUN");   
	t.insert("abandon","VERB");   
	t.insert("abandoned","ADJ");  
	t.insert("abashed","ADJ");   
	t.insert("abate","VERB");    
	t.insert("this", "PRON");   
	if (t.trie_search("this", entry))      
		cout<<"'this' was found. pos: "<<entry<<endl;   
	if (t.trie_search("abate", entry))      
		cout<<"'abate' is found. pos: "<<entry<<endl;   
	if (t.trie_search("baby", entry))      
		cout<<"'baby' is found. pos: "<<entry<<endl;   
	else      
		cout<<"'baby' does not exist at all!"<<endl;
}

3. 查找分析

       在trie树中查找一个关键字的时间和树中包含的结点数无关,而取决于组成关键字的字符数。而二叉查找树的查找时间和树中的结点数有关O(log2n)。

       如果要查找的关键字可以分解成字符序列且不是很长,利用trie树查找速度优于二叉查找树。如:        若关键字长度最大是5,则利用trie树,利用5次比较可以从26^5=11881376个可能的关键字中检索出指定的关键字。而利用二叉查找树至少要进行

次比较。

3. trie树的应用:

1. 字符串检索,词频统计,搜索引擎的热门查询

        事先将已知的一些字符串(字典)的有关信息保存到trie树里,查找另外一些未知字符串是否出现过或者出现频率。

        举例:

       1)有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。

       2)给出N 个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。

       3)给出一个词典,其中的单词为不良单词。单词均为小写字母。再给出一段文本,文本的每一行也由小写字母构成。判断文本中是否含有任何不良单词。例如,若rob是不良单词,那么文本problem含有不良单词。

       4)1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串

       5)寻找热门查询:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。

2. 字符串最长公共前缀

       Trie树利用多个字符串的公共前缀来节省存储空间,反之,当我们把大量字符串存储到一棵trie树上时,我们可以快速得到某些字符串的公共前缀。举例:

      1) 给出N 个小写英文字母串,以及Q 个询问,即询问某两个串的最长公共前缀的长度是多少.  解决方案:

        首先对所有的串建立其对应的字母树。此时发现,对于两个串的最长公共前缀的长度即它们所在结点的公共祖先个数,于是,问题就转化为了离线  (Offline)的最近公共祖先(Least Common Ancestor,简称LCA)问题。

       而最近公共祖先问题同样是一个经典问题,可以用下面几种方法:

        1. 利用并查集(Disjoint Set),可以采用采用经典的Tarjan 算法;

        2. 求出字母树的欧拉序列(Euler Sequence )后,就可以转为经典的最小值查询(Range Minimum Query,简称RMQ)问题了;

3.  排序

       Trie树是一棵多叉树,只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。

        举例: 给你N 个互不相同的仅由一个单词构成的英文名,让你将它们按字典序从小到大排序输出。

4 作为其他数据结构和算法的辅助结构

       如后缀树,AC自动机等。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2012-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
trie树(字典树)-HDU1251
举一个例子,给50000个由小写字母构成的长度不超过10的单词,然后问某个公共前缀是否出现过。如果我们直接从字符串集中从头往后搜,看给定的字符串是否为字符串集中某个字符串的前缀,那样复杂度为O(50000^2),这样显然会TLE。又或是我们对于字符串集中的每个字符串,我们用MAP存下它所有的前缀。然后询问时可以直接给出结果。这样复杂度为O(50000*len),最坏情况下len为字符串最长字符串的长度。而且这没有算建立MAP存储的时间,也没有算用MAP查询的时间,实际效率会更低。但如果我们用trie的话,当查询如字符串abcd是否为某字符串的前缀时,显然以b,c,d....等不是以a开头的字符串就不用查找了。实际查询复杂度只有O(len),建立trie的复杂度为O(50000).这是完全可以接受的。
ACM算法日常
2018/08/07
1.2K0
trie树(字典树)-HDU1251
剑指Offer——Trie树(字典树)
Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
全栈程序员站长
2022/10/03
9230
剑指Offer——Trie树(字典树)
Trie树
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
全栈程序员站长
2022/07/14
2570
一种好用的树结构:Trie树
在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。
致Great
2022/05/13
5320
一种好用的树结构:Trie树
深入理解Trie树
前面的文章介绍过各种高效的的数据结构,比如二叉搜索树,AVL树,红黑树,B树,跳跃表等,今天我们再来学习一种多路树,叫做Trie树。
我是攻城师
2019/06/03
2.1K0
Trie树分析
Trie树 Trie树介绍 Trie,又称单词查找树或键树,是一种树形结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。 它有3个基本性质: 1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。 2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。 3.每个节点的所有子节点包含的字符都不相同。 Trie中每个节点有一个特殊标记作为结束符号,通过该标记可以判断当前节
汤高
2018/03/28
1.2K0
Trie树分析
数据结构之Trie树
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_35512245/article/details/53463971
大黄大黄大黄
2018/09/14
6490
数据结构之Trie树
Trie树(字典树) [模板]------------Five-菜鸟级
  又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
Fivecc
2022/11/21
6820
Trie树(字典树) [模板]------------Five-菜鸟级
Trie树的基本原理与实现以及改进
本文介绍了关于Trie树的基本原理与实现,维基百科中的说明如下:trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。
大学里的混子
2018/11/08
1.4K0
从Trie树到双数组Trie树
Trie树 原理 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,能在常数时间O(len)内实现插入和查
JadePeng
2018/03/12
3.2K0
从Trie树到双数组Trie树
Trie树模板与应用
Trie树是用来快速存储和查找 字符串集合的数据结构。某个字符串集合对应的有根树。树的每条边上对应有恰好一个字符,每个顶点代表从根到该节点的路径所对应的字符串(将所有经过的边上的字符按顺序连接起来)。利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
timerring
2023/06/13
2470
Trie树模板与应用
【图解算法】模板+变式——带你彻底搞懂字典树(Trie树)
接下来将对经典的字典树进行代码实现;接着做几个变体题目深入理解字典树的强大;最后回到日常生活,瞧瞧字典树怎样融入到了我们的生活之中 >_<
全栈程序员站长
2022/10/04
1.3K0
【图解算法】模板+变式——带你彻底搞懂字典树(Trie树)
DS哈希查找--Trie树
它是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来节约存储空间,最大限度地减少无谓的字符串比较,查询效率比哈希表高。
叶茂林
2023/07/30
2060
DS哈希查找--Trie树
Trie树
这周将Trie树看了一下下面进行总结 概念:Trie,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本
用户1624346
2018/04/11
7600
Trie树
Trie树实现自动补全功能
Trie树,也叫字典树,又称单词查找树,是一种树形结构, 是一种哈希树的变种。典型应用是用于统计, 排序和保存大量的字符串(但不仅限于字符串), 所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间, 最大限度地减少无谓的字符串比较,查询效率比哈希树高
每天学Java
2020/06/01
1.4K0
Trie树
他会自动显示相关的搜索,不知道有没有想过这个功能是如何实现的呢?面对海量的数据,它怎么能在我输入的同时,如此快速的检索到相关内容呢?当我查找资料后,就遇到了它,Trie树。
烟草的香味
2019/11/11
6480
Trie树
动画Trie树
Trie树也称之为前缀树,适合处理前缀匹配问题。也因为每一个节点都存储26个字母,也称之为字典树,发明Trie树的人喜欢把这个单词读成/ˈtriː/tree,其他人喜欢读成/ˈtraɪ/ "try"。
ACM算法日常
2021/07/16
4170
前端学数据结构与算法(八): 单词前缀匹配神器-Trie树的实现及其应用
继二叉树、堆之后,接下来介绍另外一种树型的数据结构-Trie树,也可以叫它前缀树、字典树。例如我们再搜索引擎里输入几个关键字之后,后续的内容会自动续上。此时我们输入的关键词也就是前缀,而后面的就是与之匹配的内容,而这么一个功能底层的数据结构就是Trie树。那到底什么是Trie树?还是三个步骤来熟悉它,首先了解、然后实现、最后应用。
飞跃疯人院
2020/10/14
8870
字符串匹配算法(Trie树)
Trie树是一个多叉树;二叉树的数据结构里存放着左右子节点的指针; Trie树采用的一种经典的存储方式是散列表。
Michael阿明
2021/02/20
1.1K0
字符串匹配算法(Trie树)
Trie树的原理及应用
在做用户 query 理解的过程中,有许多需要使用词典来”识别”的过程。在此期间,就避免不了使用 Trie 树这一数据结构。
呼延十
2019/12/19
1.1K0
相关推荐
trie树(字典树)-HDU1251
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文