字典树和基数树

2023-10-18 13:10
文章标签 字典 基数

本文主要是介绍字典树和基数树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、字典树

    1、概述

字典树是一种前缀查找树,在前缀匹配查找中应用比较多,查找树的层级取决于字符串长度,时间复杂度O(1),但是他要求每个节点要有26各分支,所以空间开销比较高,是一种典型的以空间换时间的数据结构。

   2、实现原理

1)、字典树快速查找是依赖于将一个字符串分解成单个字符,然后每个字符单独作为一个节点,按字符串顺序链接,到达单词结尾时做一个结束标记。一个单词构成一个链表,多个单词时相同位置层级的节点可以合并,就能形成一个树,这个树就是字典树。

字典树
字典树

 

如上图,字典树要求所有字符串共用一个根起始点,起始点为空不存数据。到达单词结尾点用红色标记。

2)、结构定义

typedef struct Trie
{int count;  /*用于计数当前节点作为末尾的单词数量,同时作为查找时判断单词到达末尾的标记*/Trie *node[26]; /*节点的26个分支*/
}Trie;

3)、实现

 1、初始化

   一棵空Trie仅包含一个根节点,该点的字符指针均指向空

Trie* TrieNodeInit()
{Trie* head = (Trie*)calloc(1, sizeof(Trie));head->count = 0;return head;
}

2、插入

当需要插入一个字符串S时,我们令一个指针P起初指向根节点。然后,一次扫描S中的每个字符c:
    1.当P的c字符指针指向一个已存在的节点Q,则令P=Q。
    2.当P的c字符指针指向空,则新建一个节点Q,令P的c字符指针指向Q,然后令P=Q。
    当S中的字符扫描完毕时,在当前节点P上标记它是一个字符串的末尾。

/*输入的统一是小写26个字母组成的字符串,这里就不做判断了*/
int TrieInsert(char* str, Trie* head)
{char* p = str;Trie* node = head;int idx = 0;/*循环遍历字符串,将每个字符加入到指定节点*/while(*p != '\0'){/*取当前字符相对'a'字符的偏移*/idx = *p - 'a';/*node指向下一层树节点*/node = node[idx];/*如果下一层树为空,则初始化该节点*/if(!node){node = TrieNodeInit(); }p++;}/*此时node处就是该字符串的结尾,结尾标记自增*/node->count++;return 0;
}

3、查找

当需要检索一个字符串S在Trie中是否存在时,我们令一个指针P起初指向根节点,然后一次扫描s中的每个字符c:
    1.若P的c字符指针指向空,则说明S没有被插入过Trie,结束检索。
    2.若P的c字符指针指向一个已经存在的节点Q,则令P=Q。
    当S中的字符扫描完毕时,若当前节点P被标记为一个字符串的末尾,则说明S在Trie中存在,否则说明S没有被插入过Trie.
    可以看出在Trie中,字符数据都体现在树的边(指针)上,树的节点仅保存一些额外信息。例如单词结尾标记等。

int TrieSearch(Trie* head, const char* str)
{char* p = str;Trie* node = head;int idx = 0;while(*p != '\0'){idx = *p - 'a';node = node[idx];/*当前字符串不在树内,直接返回0*/if(!node)return 0;p++;}/*返回当前字符串计数个数*/return node->count;
}

3、字典树的应用

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

(2)文本预测

trie树常用于搜索提示。如当输入一个网址,可以自动搜索出可能的选择。当没有完全匹配的搜索结果,可以返回前缀最相似的可能。

(3)词频统计

统计加入字典树内的每个单词的计数

(4)排序

Trie树是一棵多叉树,只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果。
比如给你N 个互不相同的仅由一个单词构成的英文名,让你将它们按字典序从小到大排序输出。

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

 

二、基数树

1、概述

radix Tree(基数树) 其实就差不多是传统的二叉树,只是在寻找方式上,利用比如一个unsigned int的类型的每一个比特位作为树节点的判断。 可以这样说,比如一个数1000101010101010010101010010101010,那么按照Radix 树的插入就是在根节点,如果遇到0,就指向左节点,如果遇到1就指向右节点,在插入过程中构造树节点,在删除过程中删除树节点
使用一个比特位判断,会使树的高度过高,非叶节点过多。故在实际应用中,我们一般是使用多个比特位作为树节点的判断,但多比特位会使节点的子节点槽变多,增大节点的体积,一般选用2个或4个比特位作为树节点即可) 

基数树构建图
基数树

 

2、作用

基数树(radix tree)是将long整数与指针键值相关联的机制,它存储有效率,并且可快速查询,用于整数值与指针的映射,对于长整型数据的映射,如何解决Hash冲突和Hash表大小的设计是一个很头疼的问题,利用radix树可以根据一个长整型(比如一个长ID)快速查找到其对应的对象指针。这比用hash映射来的简单,也更节省空间,使用hash映射hash函数难以设计,不恰当的hash函数可能增大冲突,或浪费空间。

基数树和字典树的实现机制很像,都是将key拆分成一部分映射到树形结构中,基数树是将key按指针地址bit位拆分,而字典树是将key的字符串值按字符拆分。但是基数树的层高是相对固定的(因为指针地址的bit位是固定的),而字典树的高度与字符串的长度相关,而树的高度决定了树的空间占用情况,所以基数树明显更节约空间。

 

这篇关于字典树和基数树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/232777

相关文章

POJ2001字典树

给出n个单词,求出每个单词的非公共前缀,如果没有,则输出自己。 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;

对Powerdesigner中的Cardinality基数理解

原文链接:http://blog.sina.com.cn/s/blog_9bbafb790101bxwj.html 基数(Cardinality)用实体间实例的数值对应关系表示,它反映了两个实体间的数值联系,它从父实体的角度描述了一对实体间的数量维度,换句话说,基数中的数字是描述父实体在子表中可能出现的次数范围,基数实际是1个闭区间。基数可能是: (1)0,1 一个父实体,在子表中可能出现1

python 实现第k个字典排列算法

第k个字典排列算法介绍 "第k个字典排列"算法通常指的是在给定的字符集合(例如,字符串中的字符)中,找到所有可能排列的第k个排列。这个问题可以通过多种方法解决,但一个常见且高效的方法是使用“下一个排列”算法的变种,或称为“第k个排列”的直接算法。 方法一:使用“下一个排列”的变种 生成所有排列:首先生成所有排列,但显然这种方法对于较大的输入集合是不切实际的,因为它涉及到大量的计算和存储。 排序

POJ3617(字典序最小问题)

书中43页 此题有坑点,PE了40分钟.也是醉了....题目要求每80个字符才换行,而且最后一个如果恰好就不用换,这不是无聊嘛....... #include <iostream>#include <cstdio>#include <cstring>using namespace std;int n,m;char S[2100],P[2100];int main(){#ifd

POJ 2001 Shortest Prefixes(字典树入门)

题目: http://poj.org/problem?id=2001 题意: 找到多个字符串中,各自唯一的最短子串,例如 carte 与 carce 各自唯一的最短子串为cart与carc,即不会与其它字符串的子串重复。 思路: 字典树 解题心得: 更新关键值的时机很重要 代码: #include<stdio.h>#include<string>typedef str

Oracle数据库(数据字典、表空间、表的创建、视图)

知识点引用: http://www.2cto.com/database/201207/142874.html http://blog.csdn.net/haiross/article/details/11772847 一. 彻底卸载Oracle 方式1、重装操作系统 方式2、 2.1 DBCA删除数据库开始 → 程序 → Oracle → 开发与移植工具 → Datab

Python的字符串,list,tuple,set,字典操作详解

1.字符串python是要创建成字符串的元素,其中的每个字母都是单一的子串,把它放在' '单引号或是'' ''引号中,就完成了python 字符串的创建。#str强制转换>>> a=123>>> b=str(a) #将整数转化为字符串>>> b'123'>>> a=[1,2,3]>>> b=str(a) #将list转化为字符串>>> b'[1, 2, 3]'#字符串下

OC中数组、字典、集合常用方法的运用

/* ====================== 一 NSArray========================          1.创建对象          1.1初始化方法(2) //一般程序有问题先检查初始化          1.2类方法          1.3字面量方法          2.数组查找          2.1通过下标访问对象[ .[i]]

python pickle 模块用于保存python内存数据(包括实例对象、字典、列表等所有python中的数据)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言基本用法 前言 Python 的 pickle 模块用于序列化和反序列化 Python 对象。这意味着你可以将 Python 对象(如列表、字典、类实例等)转换为字节流(序列化),并将其保存到文件中或在网络上传输,然后在需要的时候将其恢复为原始 Python 对象(反序列化)。 常见用途

Python 从入门到实战8(字典)

我们的目标是:通过这一套资料学习下来,通过熟练掌握python基础,然后结合经典实例、实践相结合,使我们完全掌握python,并做到独立完成项目开发的能力。       上篇文章我们通过举例学习了python 中元组的定义及相关操作。今天详细讲述字典的定义及相关的操作,也是经常使用到的。 1、字典的定义 字典是由{}括住的,内容以“键-值对”的形式存储的无序序列。 字典的主要特点如下: