1. 简述

Trie 树是一种高效的字符串查找的数据结构。可用于搜索引擎中词频统计,自动补齐等。

在一个Trie 树中插入、查找某个单词的时间复杂度是 O(len), len是单词的长度。

如果采用平衡二叉树来存储的话,时间复杂度是 O(lgN), N为树中单词的总数。

此外,Trie 树还特别擅长 前缀搜索,比方说现在输入法中的自动补齐,输入某个单词的前缀,abs,

立刻弹出 abstract 等单词。

Trie 树优良的查找性能是建立在 牺牲空间复杂度的基础之上的。

本文将给出一个 Trie树的简单实例,并用这个Trie建立了一个单词数目是 7000+的英语词典。

从而分析 Trie 树所占的空间。

2. 定义

一棵典型的 Trie 树,如下图所示:

每一个节点包含一个长度是 26 的指针数组。这 26 个指针分别代表英文 26 个字母。

同时,每个节点拥有一个红色标记,表示 root 到当前的路径是否是一个单词。

例: 下图中最左边的一个路径表示单词 abc 和 abcd.

3.  性能

本人做了一个小测试,当建立一个 7000+ 的词典时,Trie 树共分配了 22383 个节点,每个节点占了 27 * 4 BYTE,

所以共消耗了大约 22383 * 27 * 4 BYTE = 2.4 M

而这 7000 个单词平均长度假设是 8 个字母,那么总共占 7000 * 8 BYTE= 5.6 KB

两者相差 42 倍!!!

从上述小测试可以看到,Trie 树需要占用大量的空间,特别是如果考虑大小写,或者建立汉字的 Trie树时,每个节点所需要的指针数目将更大。

其实,大伙一眼就能发现,Trie 树中,每个节点包含了大量的空指针,因而造成了大量的空间消耗。

可以采用 三叉树(Ternary Search Tree), 改进 Trie 树。将在下一篇文章中讨论。

4. 源码

// Last Update:2014-04-16 23:24:47
/**
* @file trie.h
* @brief Trie
* @author shoulinjun@126.com
* @version 0.1.00
* @date 2014-04-16
*/ #ifndef TRIE_H
#define TRIE_H #include <iostream>
#include <fstream>
#include <string>
#include <cstring>
using std::string;
using std::cout;
using std::endl; const int branchNum = 26; struct TrieNode
{
TrieNode(): isStr(false)
{
memset(next, 0, sizeof(next));
}
bool isStr;
TrieNode* next[branchNum];
}; string ToLower(const string &s)
{
string str;
string::const_iterator it = s.begin();
while(it != s.end())
{
str += (char)tolower(*it);
++ it;
}
return str;
} /**
* a simple data stucture
* usefull for AutoComplete
*/
class Trie
{
public:
Trie(): root(new TrieNode()) {}
~Trie() {
cout << "# of nodes allocated: " << count << endl;
destroy(root); } void Insert(const string &str);
bool Search(const string &str) const;
void AutoComplete(const string &str);
void Input(const string &file); private:
TrieNode* find(const string &str) const;
void dfs(TrieNode *root, string &path);
void destroy(TrieNode * &root); TrieNode *root;
static size_t count;
}; size_t Trie::count = 0; void Trie::destroy(TrieNode * &root)
{
for(int i=0; i<branchNum; ++i)
{
if(root->next[i])
destroy(root->next[i]);
}
delete root;
root = NULL;
} void Trie::Insert(const string &s)
{
if(s.empty()) return; /* support lower cases now */
string str = ToLower(s);
string::const_iterator it = str.begin();
TrieNode *location(root); // bypassing existing nodes
while(it != str.end() && location->next[*it - 'a'] != NULL)
{
location = location->next[*it - 'a'];
++ it;
} // Insert
while(it != str.end() && location->next[*it - 'a'] == NULL)
{
location->next[*it - 'a'] = new TrieNode();
++ count;
location = location->next[*it - 'a'];
++ it;
}
location->isStr = true;
} void Trie::Input(const string &str)
{
std::ifstream ifile(str.c_str()); string word; while(ifile >> word)
{
Insert(word);
} ifile.close();
} bool Trie::Search(const string &s) const
{
TrieNode *location = root; string str = ToLower(s);
location = find(str);
return (location) && location->isStr;
} TrieNode* Trie::find(const string &str) const
{
TrieNode *location = root;
string::const_iterator it = str.begin();
while(it != str.end() && location->next[*it - 'a'] != NULL)
{
location = location->next[*it - 'a'];
++ it;
}
return (it == str.end()) ? location : NULL;
} void Trie::dfs(TrieNode *root, string &path)
{
if(root == NULL) return; if(root->isStr)
cout << path << endl;
for(char x='a'; x<='z'; ++x)
{
if(root->next[x-'a'] != NULL)
{
path += x;
dfs(root->next[x-'a'], path);
path.resize(path.size()-1);
}
}
} void Trie::AutoComplete(const string &str)
{
TrieNode *location(root);
string path; location = find(str);
path = str;
dfs(location, path);
} #endif /*TRIE_H*/

数据结构《16》----自动补齐实现《一》----Trie 树的更多相关文章

  1. CocoaPods 导入第三方库头文件自动补齐

    使用了一段时间CocoaPods来管理Objective-c的类库,方便了不少.但是有一个小问题,当我在xcode输入import关键字的时候,没有自动联想补齐代码的功能,需要手工敲全了文件名,难以适 ...

  2. 为Debian/Ubuntu的apt-get install添加自动补齐/完成功能

    Debian/Ubuntu的apt-get太常用了,不过偶尔可能也会碰到不太熟悉,想不起来的包的名称,除了去debian packages去查找,另外的方法就是给Debian/Ubuntu添加自动补齐 ...

  3. jquery.autocomplete自动补齐和自定义格式

    1.简单的下拉自动补齐,可以使用本地或远程数据源 <input name="autoTag" id="autoTag" /> var source ...

  4. HTML5的数据自动补齐功能

    使用datalist元素,HTML5允许使用一组数据来生成自动补齐功能,现在你不需要使用第三方js代码或者类库啦! <input name="frameworks" list ...

  5. Android Studio-设置switch/case代码块自动补齐

    相信很多和我一样的小伙伴刚从Eclipse转到Android Studio的时候,一定被快捷键给搞得头晕了,像Eclipse中代码补齐的快捷键是Alt+/ ,但是在AS中却要自己设置,这还不是问题的关 ...

  6. CocoaPods导入第三方库头文件自动补齐

    使用了一段时间CocoaPods来管理Objective-c的类库,方便了不少.但是有一个小问题,当我在xcode输入import关键字的时候,没有自动联想补齐代码的功能,需要手工敲全了文件名,难以适 ...

  7. GBin1插件推荐之马可波罗(Marco Polo),jQuery的自动补齐插件 - Autocomplete Plugin

    让我们Google一下"jQuery autocomplete plugin"(jquery自动补齐插件).在过去的4年中,我已经Google了很多次这个组合了.然而结果并没有变化 ...

  8. 关闭浏览器输入框自动补齐 兼容IE,FF,Chrome等主流浏览器

    这篇文章主要介绍了关闭浏览器输入框自动补齐 兼容IE,FF,Chrome等主流浏览器,需要的朋友可以参考下.希望对大家有所帮助   Firefox 和 IE 的浏览器各自实现了input历史记录的功能 ...

  9. Android Studio 中设置代码块自动补齐

    AS中很多提示键,并不如Eclipse中做的好,需要我们自己去自定义.这里以switch...case为例,讲解一下如何设置代码自动补全. 1.进入settings -->  Editor -- ...

随机推荐

  1. 图片上传本地预览。兼容IE7+

    基于JQUERY扩展,图片上传预览插件 目前兼容浏览器(IE 谷歌 火狐) 不支持safari 预览地址:http://www.jinbanmen.com/test/1.html js代码:/**名称 ...

  2. 2016 ACM/ICPC Asia Regional Dalian Online

    1009 Sparse Graph(hdu5876) 由于每条边的权值都为1,所以最短路bfs就够了,只是要求转置图的最短路,所以得用两个set来维护,一个用来存储上次扩散还没访问的点,一个用来存储这 ...

  3. Python3基础 index 返回一个元素在列表中第一次出现的索引值

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  4. linux ls -l命令结果含义解析

    ls -l 中显示的内容如下: -rw-r--r--.  1 root root  192 Jan 30 09:55 text.txt - 10个字符确定不同用户能对文件干什么 - 第一个字符代表文件 ...

  5. PHP文本框的值随下拉框改变

    初学PHP,下面是实现文本框内容随下拉框变化的代码实现: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&q ...

  6. iOS开发 火星坐标转百度坐标

    CLLocationCoordinate2D coor = CLLocationCoordinate2DMake(latitude, longitude);//原始坐标 //转换 google地图.s ...

  7. Python_Day2_基础2

    python基础之数据类型与变量 一.变量 变量作用:保存状态(程序的运行本质是一系列状态的变化,变量的目的就是用来保存状态,变量值的变化就构成了程序运行的不同结果.) Age=10 ----> ...

  8. android 破解工具

    来记录一下本人在平时工作中使用的android上的破解工具 静态破解: apktool: apk包 -> dex dex2jar和enjarify(google官方出品): dex->ja ...

  9. javascript中对象的深度克隆

    记录一个常见的面试题,javascript中对象的深度克隆,转载自:http://www.2cto.com/kf/201409/332955.html 今天就聊一下一个常见的笔试.面试题,js中对象的 ...

  10. 根据屏幕的宽度使用不同的css-文件

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...