字典树模板及例题_模板计算公式

字典树模板及例题_模板计算公式转载:Trie树的常见应用大总结(面试+附代码实现)(一)Trie的简介Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。他的核心思想是空间换时间,空间消耗大但是插入和查询有着很优秀的时间复杂度。(二)Trie的定义Trie树的键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

转载:Trie树的常见应用大总结(面试+附代码实现)

(一)Trie的简介
Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树。他的核心思想是空间换时间,空间消耗大但是插入和查询有着很优秀的时间复杂度。

(二)Trie的定义

Trie树的键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀(prefix),从根节点到当前结点的路径上的所有字母组成当前位置的字符串,结点可以保存当前字符串、出现次数、指针数组(指向子树)以及是否是结尾标志等等。

struct Trie
{

    int count;//前缀出现的次数
    struct Trie *next[SIZE];//孩子节点的数目
    bool isEnd; //判断到这个位置是否是一个单词
    string name;
    
    Trie()//构造函数
    {

        count=0;
        memset(next,0,sizeof(next));
        isEnd=false;
        name.clear();
    }
};

Trie树可以利用字符串的公共前缀来节约存储空间,如下图所示:

字典树模板及例题_模板计算公式

它有3个基本性质:
(1) 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
(2) 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
(3) 每个节点的所有子节点包含的字符都不相同。 

 

(三)Trie树的基本操作
(1)插入操作
按下标索引逐个插入字母,若当前字母存在则继续下一个,否则new出当前字母的结点,所以插入的时间复杂度只和字符串的长度n有关,为O(n)。

void Insert(string s)
{

    int len=s.length();
    int pos;
    struct Trie *u=root;
    for(int i=0;i<len;i++)
    {

        pos=s[i]-‘0’;
        if(u->next[pos]==NULL)//数字在边上,或者说是以位置的方式体现,不需要存储
            u->next[pos]=new Trie;
        u=u->next[pos];
        u->count++;        
    }
    u->isEnd=true;//表明为一个单词的节点
    u->name=s;//同时存储单词
}

 

(2)查询操作
和插入操作相仿,若查询途中某一个结点并不存在,则直接就return返回。否则继续下去,当字符串结束时,trie树上也有结束标志,那么证明此字符串存在,return true;

int Search(string s)
{

    struct Trie *u=root;
    int len=s.length();
    for(int i=0;i<len;i++)
    {

        int pos=s[i]-‘0’;
        if(u->next[pos]==NULL)
            return 0;
        else
            u=u->next[pos];
    }
    return u->count;

(3)删除操作

一般来说,对Trie单个结点的删除操作不常见,所以我在这里也只提供递归删除整个树的操作

void del(struct Trie *u)
{

    for(int i=0;i<SIZE;i++)
    {

        if(u->next[i]!=NULL)
            del(u->next[i]);
    }
    delete(u);
}

 

(4)遍历操作

如果我们想要将trie中的字符串排序输出,直接先序遍历即可。

void print(struct Trie *u)
{

    if(u->isEnd)
        cout<<u->name<<“:”<<u->count<<endl;
    for(int i=0;i<SIZE;i++)
        if(u->next[i]!=NULL)
            print(u->next[i]);
}

 

上面整体的模板:

#include<iostream>
#include<cstring>
using namespace std;

const int SIZE=10; 
struct Trie
{
	int count;//前缀出现的次数
	struct Trie *next[SIZE];//孩子节点的数目 
	bool isEnd; //判断到这个位置是否是一个单词
	string name; 
	
	Trie()//构造函数 
	{
		count=0;
		memset(next,0,sizeof(next));
		isEnd=false;
	} 
}; 

struct Trie *root=new Trie;//建立根节点

void Insert(string s)
{
	int len=s.length();
	int pos;
	struct Trie *u=root;
	for(int i=0;i<len;i++)
	{
		pos=s[i]-'0';
		if(u->next[pos]==NULL)//数字在边上,或者说是以位置的方式体现,不需要存储 
			u->next[pos]=new Trie;
		u=u->next[pos];
		u->count++;		
	}
	u->isEnd=true;//表明为一个单词的节点
	u->name=s;//同时存储单词 
} 

int Search(string s)
{
	struct Trie *u=root;
	int len=s.length();
	for(int i=0;i<len;i++)
	{
		int pos=s[i]-'0';
		if(u->next[pos]==NULL)
			return 0;
		else
			u=u->next[pos];
	}
	return u->count;
} 

void del(struct Trie *u)
{
	for(int i=0;i<SIZE;i++)
	{
		if(u->next[i]!=NULL)
			del(u->next[i]);
	}
	delete(u);
}

void print(struct Trie *u)
{
	if(u->isEnd)
		cout<<u->name<<":"<<u->count<<endl;
	for(int i=0;i<SIZE;i++)
		if(u->next[i]!=NULL)
			print(u->next[i]); 
}

int main()
{
	int n;
	string s;

	cin>>n;
	while(n--)
	{
		cin>>s;
		Insert(s);
	}
		
	print(root);//打印检查下 
		
	del(root);//释放树,下次重新建立 

	return 0;
} 

 

对于不同的题目,将模板稍微改动就好。

下面是一个例题,用来判断是否存在前缀。

来源:POJ3630 HDU1671 ZOJ2876 UVA11362 Phone List【字典树】

字典树模板及例题_模板计算公式

字典树模板及例题_模板计算公式

 

代码:

#include<iostream>
#include<cstring>
using namespace std;

const int SIZE=10; 
struct Trie
{
	int count;//前缀出现的次数
	struct Trie *next[SIZE];//孩子节点的数目 
	bool isEnd; //判断到这个位置是否是一个单词
	string name; 
	
	Trie()//构造函数 
	{
		count=0;
		memset(next,0,sizeof(next));
		isEnd=false;
		name.clear();
	} 
}; 

struct Trie *root=new Trie;//建立根节点

bool Insert(string s)
{
	int len=s.length();
	int pos;
	struct Trie *u=root;
	for(int i=0;i<len;i++)
	{
		pos=s[i]-'0';
		if(u->next[pos]==NULL)//数字在边上,或者说是以位置的方式体现,不需要存储 
			u->next[pos]=new Trie;
		u=u->next[pos];
		u->count++;
		
		if(u->count>1&&u->isEnd==true)//如果出现前缀问题 
			return false;	 		
	}
	u->isEnd=true;//表明为一个单词的节点
	u->name=s;//同时存储单词 
	if(u->count>1&&u->isEnd==true)//如果出现前缀问题 
			return false;	
	return true;
} 

int Search(string s)
{
	struct Trie *u=root;
	int len=s.length();
	for(int i=0;i<len;i++)
	{
		int pos=s[i]-'0';
		if(u->next[pos]==NULL)
			return 0;
		else
			u=u->next[pos];
	}
	return u->count;
} 

void del(struct Trie *u)
{
	for(int i=0;i<SIZE;i++)
	{
		if(u->next[i]!=NULL)
			del(u->next[i]);
	}
	delete(u);
}

void print(struct Trie *u)
{
	if(u->isEnd)
		cout<<u->name<<":"<<u->count<<endl;
	for(int i=0;i<SIZE;i++)
		if(u->next[i]!=NULL)
			print(u->next[i]); 
}

int main()
{
	int t,n;
	bool flag;
	string s;
	cin>>t;
	while(t--)
	{
		flag=true;//开始没有前缀 
		cin>>n;
		while(n--)
		{
			cin>>s;
			if(flag)
				if(!Insert(s)) 
					flag=false;
		}
		
		//print(root);//打印检查下 
		
		if(flag)
			cout<<"YES"<<endl;
		else
			cout<<"NO"<<endl;
			 
		del(root);//释放树,下次重新建立 
	}
	return 0;
} 

 

 

阅读文章:hdu1251-字符前缀查找问题 map容器

#include<iostream>
#include<string>
#include<map>
using namespace std;
int main()
{

    string str,str1;
    map<string, int> map1;
    while(getline(cin, str)&& str.length() !=0)
    {

        for(int i = 1; i != str.size()+1; i++)
        {

            str1 = str.substr(0, i);               //把当作字典的单词从第一个字母依次增长的往后复制在map中
            map1[str1]++;                          
        }
    }
    while(cin >> str)
    {

        cout << map1[str] << endl;
    }
}
——————————————https://blog.csdn.net/imush/article/details/52039806

 

 

参考文章:

字典树(Trie树)实现与应用

Trie树的常见应用大总结(面试+附代码实现)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/196466.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm使用conda环境_anaconda运行python

    pycharm使用conda环境_anaconda运行python基础环境是ubuntu的。之前一直使用windows系统,新公司需要使用ubuntu环境,所以从头开始搭建一个python运行的环境。主要的步骤可以记为如下:1.安装anaconda2.配置一个conda的python36环境3.安装pycharm4.在pycharm中使用2中配置的环境作为项目的解释器5.其他一些注意事项1.安装anaconda1.2安装下载的安装包,我下载的最新版…

    2022年8月29日
    4
  • acwing1106. 山峰和山谷(宽搜bfs)「建议收藏」

    acwing1106. 山峰和山谷(宽搜bfs)「建议收藏」FGD小朋友特别喜欢爬山,在爬山的时候他就在研究山峰和山谷。为了能够对旅程有一个安排,他想知道山峰和山谷的数量。给定一个地图,为FGD想要旅行的区域,地图被分为 n×n 的网格,每个格子 (i,j) 的高度 w(i,j) 是给定的。若两个格子有公共顶点,那么它们就是相邻的格子,如与 (i,j) 相邻的格子有(i−1,j−1),(i−1,j),(i−1,j+1),(i,j−1),(i,j+1),(i+1,j−1),(i+1,j),(i+1,j+1)。我们定义一个格子的集合 S 为山峰(山谷)当且仅当:

    2022年8月9日
    6
  • spring boot自动配置原理面试题_Spring boot面试

    spring boot自动配置原理面试题_Spring boot面试前言SpringBoot框架是开发中的一大利器,其简化了spring的xml的配置,遵循了”约定大于配置“的原则,使用注解对常用的配置做默认配置,减少使用xml配置模式。SpringBoot为常用框架封装了大量的starter,比如spring-boot-starter-web会整合springmvc和内嵌的tomcat。SpringBoot在底层封装了默认的配置,修改配置在application.yml全局配置文件。如今在pom.xml文件中引用starter就可以使用这个框架,使用…

    2022年8月21日
    40
  • Pycharm安装cv2失败解决方法「建议收藏」

    Pycharm安装cv2失败解决方法「建议收藏」Pycharm安装cv2失败解决方法python中导入模块importcv2,提示没有该模块,安装提示:Non-zeroexitcode(1),上网查询说是pip版本过低的原因,需要pip版本升级,通过pycharm升级pip,报错AttributeError:‘NoneType’objecthasnoattribute‘bytes’—解决方法:进入终端,使用命令:easy_install-Upippip版本升级后,再次安装cv2,提示ERROR:Couldnotfin

    2022年8月27日
    3
  • 脑科学磁共振成像(MRI)初学者必看——功能脑网络、小世界网络、FDR校正、脑电信号频率变换、模板、假设检验、广义线性模型、独立成分分析、影像组学、任务态和静息态方法汇总「建议收藏」

    脑科学磁共振成像(MRI)初学者必看——功能脑网络、小世界网络、FDR校正、脑电信号频率变换、模板、假设检验、广义线性模型、独立成分分析、影像组学、任务态和静息态方法汇总「建议收藏」磁共振成像初学者必看一、浅谈功能脑网络二、不同模态脑网络的构建功能脑网络结构脑网络白质纤维束脑网络加权网络二值网络三、趣谈散点图与相关系数四、脑电信号频域变换五、fMRI中的FDR校正六、模板(mask)1、模板(mask)往往是与ROI联系在一起的2、mask作用的原理3、常见的mask七、假设检验和效果量八、组水平标准化九、由ALFF说开去十、计算机存取MRI影像的那些事十二、Linux基础命令十三、浅谈标准空间模板和空间变换一:标准空间模板二:空间变换十四、功能连接十五、大脑激活与功能连接的

    2022年7月24日
    51
  • VBA获取股票历史数据方法

    VBA获取股票历史数据方法Sub股票历史记录查询()Worksheets(“历史记录表”).Cells.Clear”输出结果表X=Application.CountA(Worksheets(“代码”).Range(“A:A”))”需要提取的股票代码Y=1Fori=2ToXdm=IIf(Worksheets(“代码”).Cells(i,1)<600000,…

    2022年6月24日
    44

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号