【字典树应用】联想用户最想输入的词汇

第一章:抛砖引玉

字典树是一种基于链表的数据结构,以统计词频并返回用户最想输入的词汇为例,分享一下字典树的应用心得。

刚建立的用户词库,用户输入两次“hilili”, 输入一次“hilucy”,此时用户再次输入“hi”,我们应该联想到用户可能要输入的单词是“hilili”,以下为统计示例图。

字典树是一种兼顾空间和时间的数据结构,利用公共前缀节约空间,减少比较次数以提高查询和插入效率。

字典树的常见用途:保存大量字符串并进行统计(静态字典树,猜测金山词霸或xxx单词王都有利用到字典树) 、统计用户输入词频和联想用户想要输入的词汇(动态字典树,即用户词库)、字符串排序(域名排序等)。

第二章:小试牛刀

1.定义一个字典树:

1 struct TrieNode
2 {
3     struct TrieNode* next[26];
4     unsigned int     count;
5 };

View
Code

2.创建一个字典树:

1 TrieNode* CreateTrieNode()
2 {
3     TrieNode* head = (TrieNode*)malloc(sizeof(TrieNode));
4     memset(head, 0, sizeof(TrieNode));
5     return head;
6 }

3.查找字典树:

1 //遍历字符串,如果字符串未全部写入路径则查找失败,否则返回词频
 2 unsigned int FindTrieNode(TrieNode* head, char* str)
 3 {
 4     if(NULL == head)
 5         return 0;
 6     TrieNode* tmphead = head;
 7     int i = 0, cnt = 0;
 8     while(str[i])
 9     {
10         cnt = str[i] - ‘a‘;
11         if(NULL != tmphead->next[cnt])
12         {
13             tmphead = tmphead->next[cnt];
14             i++;
15         }
16         else
17         {
18             return 0;
19         }
20     }
21     return tmphead->count;
22 }

View
Code

4.插入字典树:

1 //遍历整个字符串,创建不存在的字典树路径,并将整个路径的词频++
 2 //如果malloc失败,表示进程内存不足,插入字符串失败
 3 BOOL InsertTrieNode(TrieNode* head, char* str)
 4 {
 5     if(NULL == head)
 6     {
 7         head = (TrieNode*)malloc(sizeof(TrieNode));
 8         memset(head, 0, sizeof(TrieNode));
 9     }
10     int i = 0, cnt = 0;
11     TrieNode* tmphead = head;
12     while(str[i])
13     {
14         cnt = str[i] - ‘a‘;
15         if(NULL == tmphead->next[cnt])
16         {
17             if(NULL != (tmphead->next[cnt] = (TrieNode*)malloc(sizeof(TrieNode))))
18                 memset(tmphead->next[cnt], 0, sizeof(TrieNode));
19             else
20                 return FALSE;
21         }
22         tmphead = tmphead->next[cnt];
23         i++;
24         tmphead->count++;
25     }
26     return TRUE;
27 }

5.统计用户输入频率

1 //更新用户输入频率
 2 void UpdateFrequence(TrieNode* head, char* str)
 3 {
 4     int i = 0, cnt = 0;
 5     while(str[i])
 6     {
 7         cnt = str[i] - ‘a‘;
 8         head->next[cnt]->count++;
 9         head = head->next[cnt];
10         i++;
11     }
12 }

View
Code

6.联想最可能的词汇

1 //根据已输入的字符串联想出词频最高的一个字符串,即最有可能是用户想要输入的完整字符串。
 2 //已输入的字符串必须已经插入字典树
 3 //如果存在路径包含的情况,则总是返回最长路径:比如先插入pretty,再插入prettygirl,输入pr则联想词汇为prettygirl
 4 char* GetWantedWord(TrieNode* head, char* szSrc, char* szDes, size_t stDesLen)
 5 {
 6     if(NULL == head || NULL == szSrc || stDesLen <= strlen(szSrc))
 7         return szSrc;
 8     TrieNode* tmphead = head;
 9     int i = 0, cnt = 0;
10     unsigned int uiMax = 0, len = 0;
11     char         cMax = ‘a‘;
12     while(szSrc[i])
13     {
14         cnt = szSrc[i] - ‘a‘;
15         tmphead = tmphead->next[cnt];
16         szDes[i] = szSrc[i];
17         len++;
18         i++;
19     }
20     while(1)
21     {
22         uiMax = 0;
23         cMax = ‘a‘;
24         for(int j = 0; j < 26; j++)
25         {
26             if(NULL != tmphead->next[j] && tmphead->next[j]->count > uiMax)
27             {
28                 uiMax = tmphead->next[j]->count;
29                 cMax = j + ‘a‘;
30             }
31         }
32         if(len < stDesLen && uiMax > 0)
33             szDes[i] = cMax;
34         else
35         {
36             szDes[i] = ‘\0‘;
37             return szDes;
38         }
39         cnt = cMax - ‘a‘;
40         tmphead = tmphead->next[cnt];
41         len++;
42         i++;
43     }
44     szDes[i] = ‘\0‘;
45     return szDes;
46 }

7.只是功能测试,不涉及性能,测试代码略。

第三章:写在结束

程序还有待完善,随着程序的运行时间,用户输入越来越多,也出现了不少手误,怎么剔除掉次数较少的手误统计,如果两到三个用户在轮流使用该程序,怎么在用户切换时迅速反应过来?

字典树和hash表都能显著提高程序设计和code的效率,可以说是程序员手中的利器,值得善加利用。

多扯一句吧:怎样才能天然拥有贝克汉姆的经典发型,梳子往右梳,睡觉右躺,左右头发聚一线,这就有了。

时间: 2024-11-12 19:32:30

【字典树应用】联想用户最想输入的词汇的相关文章

字典树的基础,以及在实际项目中对于敏感词的替换的应用

最近刷题时连续遇到两道字典树的题目,所以做一下这个数据结构的总结. 首先什么叫做字典树? 叫 是 我   想 看 听 这种树结构并且把文字或者英文放在里面组成的叫做字典树. 那么字典树有什么用呢? 通过几道题目的练习我发现,字典树主要应用在,对于字符串的分级匹配和查询. 比如在我们如果有三句话,1:我是人,2:我是男人,3:我是中国人 如果一般的我们用三个字符串去存放他们,然后当我们要寻找在这些字符串中是否存在我是中国人的时候,那么就需要一句句匹配过来,如果有1000条这样的数据,那么匹配的速度

poj 2804 词典 (字典树 或者 快排+二分)

2804:词典 总时间限制:  3000ms  内存限制:  65536kB 描述 你旅游到了一个国外的城市.那里的人们说的外国语言你不能理解.不过幸运的是,你有一本词典可以帮助你. 输入 首先输入一个词典,词典中包含不超过100000个词条,每个词条占据一行.每一个词条包括一个英文单词和一个外语单词,两个单词之间用一个空格隔开.而且在词典中不会有某个外语单词出现超过两次.词典之后是一个空行,然后给出一个由外语单词组成的文档,文档不超过100000行,而且每行只包括一个外语单词.输入中出现单词只

Light OJ 1114 Easily Readable 字典树

题目来源:Light OJ 1114 Easily Readable 题意:求一个句子有多少种组成方案 只要满足每个单词的首尾字符一样 中间顺序可以变化 思路:每个单词除了首尾 中间的字符排序 然后插入字典树 记录每个单词的数量 输入一个句子 每个单词也排序之后查找 根据乘法原理 答案就是每个单词的数量之积 #include <iostream> #include <cstring> #include <cstdio> #include <algorithm>

字典树用于单词联想

最近要做一个单词联想的功能,经过调研选择使用字典树,节省空间,查找快. 贴上代码 class Trie(object): def __init__(self): self.path = {} self.value = None self.valid = False def __setitem__(self, key, val): head = key[0] if head in self.path: node = self.path[head] else: node = Trie() self.

Tire树(字典树)

from:https://www.cnblogs.com/justinh/p/7716421.html Trie,又经常叫前缀树,字典树等等.它有很多变种,如后缀树,Radix Tree/Trie,PATRICIA tree,以及bitwise版本的crit-bit tree.当然很多名字的意义其实有交叉. 定义 在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串.与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定.一个节点的所有

字典树 &amp;&amp; 例题 Xor Sum HDU - 4825 (板子)

一.字典树描述:Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高. Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的.它有3个基本性质: 1.根节点不包含字符,除根节点外每一个节点都只包含一个字符.2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字

51nod round3# 序列分解(折半枚举+字典树)

小刀和大刀是双胞胎兄弟.今天他们玩一个有意思的游戏. 大刀给小刀准备了一个长度为n的整数序列.小刀试着把这个序列分解成两个长度为n/2的子序列. 这两个子序列必须满足以下两个条件: 1.他们不能相互重叠. 2.他们要完全一样. 如果小刀可以分解成功,大刀会给小刀一些糖果. 然而这个问题对于小刀来说太难了.他想请你来帮忙. Input 第一行给出一个T,表示T组数据.(1<=T<=5) 接下来每一组数据,输入共2行. 第一行包含一个整数n (2<=n<=40且为偶数). 第二行给出n

白话算法与数据结构之【字典树】

1. 什么是trie树 1.Trie树 (特例结构树) Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高.      Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类