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. listivew 动态刷新单个item

    使用ViewHolder来刷新某项数据,而不用每次都全部刷新数据. 继承BaseAdapter,新建ViewHolder类. public class TestListAdapter extends  ...

  2. jquery中没有innerHTML

    本人正在学习使用jQuery. 发现如果我在div或者其他非表单的标签中赋值,原本用普通的js就直接document.getElementById("id").innerHtml( ...

  3. redis安装与基本配置

    获取下载包 wget http://download.redis.io/releases/redis-2.8.24.tar.gz 解压和编译 tar -zxvf redis-2.8.24.tar.gz ...

  4. RCP:如何移除Toolbar中的Quick Access

    问题 自4.x开始,Quick Access搜索框成为Toolbar的"标准装备",一般删除Actionset的方式似乎不起作用,通过Quick Access,用户很容易访问到RC ...

  5. 。【自学总结 3】------3ds Max 主工具栏

    1.选择并链接:选择对象,使其和其他对象建立父子关系. 2.断开选择链接:撤销链接关系. 3.选择过滤器列表:可以限制要选择的对象的特定类型和组合.例如,我们选择几何体后,其他对象就无法被选择. 4. ...

  6. [bzoj3155]Preprefix sum(树状数组)

    3155: Preprefix sum Time Limit: 1 Sec  Memory Limit: 512 MBSubmit: 1183  Solved: 546[Submit][Status] ...

  7. iOS 键盘

    http://blog.sina.com.cn/s/blog_7018d3820101djut.html 一.键盘风格 UIKit框架支持8种风格键盘. typedef enum { UIKeyboa ...

  8. Android 之计算控件颜色透明度

    Android 之计算控件颜色透明度 1.UI会给一个数值,例如:#EFE000,透明度30% 2.用255乘以30%等于76.5,然后四舍五入等于77 3.用计算器将十进制的77转成十六进制的数据为 ...

  9. Android Studio UML 插件 PlantUML 使用语法

    活动标签(activity label)以冒号开始,以分号结束. 文本格式支持creole wiki语法. 活动默认安装它们定义的顺序就行连接. @startuml :Hello world; :Th ...

  10. JS历史

    JavaScript伴随着互联网的发展一起发展.互联网周边技术的快速发展,刺激和推动了JavaScript语言的发展. 2006年,jQuery函数库诞生,作者为John Resig.jQuery为操 ...