C++ TrieTree(字典树)容器的实现
最近研究了一下C++线程池,在网上看了一下别人的代码,写的很不错,参见:http://www.cnblogs.com/lidabo/p/3328646.html
其中,他用了STL的set容器管理线程池中的线程,在线程池运行的过程中需要频繁的进行插入、查找和删除的操作,我个人觉得这些操作会是线程池中的很大的时间开销,想起了大学老师讲过的一个TireTree(字典树)的数据结构,利用多叉树
可以快速的实现元素的插入、查找和删除,稍加改动也可以支持自动排序,唯一的缺点就是多叉树的结构空间开销较大,所以要控制好内存操作,防止内存泄露。
经测试,再插入元素和删除元素的方面,TrieTree比set有明显优势,在相同的元素数量下,内存开销也不过是set的1.5~2倍,时间却是1/10左右。
#ifndef _MY_TRIE_TREE
#define _MY_TRIE_TREE template<class T,class K>
class TrieTree{
public:
TrieTree();
virtual ~TrieTree();
bool insert(T *data,K key,bool overwrite = false);
bool remove(K key,bool free_memory = false);
bool find(K key,T *& pData);
private:
enum
{
Dimension = ,
};
typedef struct tagNode
{
tagNode *child[Dimension];
T *data;
tagNode()
{
for(int i = ;i < Dimension;i++)
{
child[i] = NULL;
}
data = NULL;
}
~tagNode()
{
if(child == NULL)
{
delete[] child;
}
if(data != NULL)
{
delete data;
}
}
}Node;
Node *m_pHead;
unsigned int m_nElementCnt;
unsigned int m_nNodeCnt;
void destory(Node *p_head);
public:
void free();
void dump();
void trival( Node *pNode,int &nodeCnt );
}; template<class T,class K>
bool TrieTree<T, K>::find( K key,T *& pData )
{
int m = ;
Node **p_find = NULL;
if(m_pHead == NULL)
{
return false;
}
p_find = &m_pHead;
while( key > )
{
m = key%;
if((*p_find) != NULL)
{
p_find = &(*p_find)->child[m];
}
else
{
break;
}
key /= ;
}
if((*p_find) != NULL)
{
// 数据为空
if((*p_find)->data == NULL)
{
return false;
}
pData = (*p_find)->data;
return true;
}
else
{
return false;
}
} template<class T,class K>
void TrieTree<T, K>::free()
{
destory(m_pHead);
} template<class T,class K>
void TrieTree<T, K>::destory( Node *p_head )
{
if(p_head != NULL)
{
for(int i = ;i < Dimension;i++)
{
destory(p_head->child[i]);
}
delete p_head;
m_nNodeCnt--;
}
} template<class T,class K>
void TrieTree<T, K>::trival( Node *pNode,int &nodeCnt )
{
if(pNode != NULL)
{
nodeCnt++;
if(pNode->data != NULL)
{
//cout<<*(pNode->data)<<" ";
}
for(int i = ;i < Dimension;i++)
{
trival(pNode->child[i],nodeCnt);
}
}
} template<class T,class K>
void TrieTree<T, K>::dump()
{
int nodeCnt = ;
trival(m_pHead,nodeCnt);
cout<<endl;
//cout<<endl<<"size = "<<sizeof(Node)<< " * "<<nodeCnt<<" = "<<sizeof(Node)*nodeCnt<<endl;
//cout<<endl<<"data = "<<sizeof(T)<< " * "<<m_nElementCnt<<" = "<<sizeof(T)*m_nElementCnt<<endl;
//cout<<endl<<"rate = "<<((double)sizeof(T) * m_nElementCnt)/(sizeof(Node)*nodeCnt)<<endl;
cout<<"m_nNodeCnt = "<<m_nNodeCnt;
cout<<",m_nElementCnt = "<<m_nElementCnt;
cout<<",nodeCnt = "<<nodeCnt<<endl;
} template<class T,class K>
TrieTree<T,K>::TrieTree()
{
m_pHead = new Node();
m_nElementCnt = ;
m_nNodeCnt = ;
} template<class T,class K>
TrieTree<T,K>::~TrieTree()
{
destory(m_pHead);
} template<class T,class K>
bool TrieTree<T, K>::remove( K key ,bool free_memory)
{
int m = ;
Node **p_find = NULL;
if(m_pHead == NULL)
{
return false;
}
p_find = &m_pHead;
while( key > )
{
m = key%;
if((*p_find) != NULL)
{
p_find = &(*p_find)->child[m];
}
else
{
break;
}
key /= ;
}
if((*p_find) != NULL)
{
// 不释放节点空间
if( free_memory == false )
{
if((*p_find)->data == NULL)
{
return false;
}
delete (*p_find)->data;
(*p_find)->data = NULL;
m_nElementCnt--;
return true;
}
// 释放节点空间
else
{
//并不是所有节点都能释放,没有子节点的节点才能释放
bool hasChild = false;
for(int i = ;i < Dimension;i++)
{
if((*p_find)->child[i] != NULL)
{
hasChild = true;
}
}
// 释放节点,直接delete
if(hasChild == false)
{
delete (*p_find);
(*p_find) = NULL;
m_nElementCnt--;
m_nNodeCnt--;
}
// 不能释放节点,释放data,data = NULL
else
{
if((*p_find)->data == NULL)
{
return false;
}
T *pData = (*p_find)->data;
(*p_find)->data = NULL;
delete pData;
pData = NULL;
m_nElementCnt--;
return true;
}
}
}
else
{
return false;
}
} template<class T,class K>
bool TrieTree<T, K>::insert( T *data,K key,bool overwrite)
{
int m = ;
Node **p_find = NULL;
if(m_pHead == NULL)
{
return false;
}
p_find = &m_pHead;
while( key > )
{
m = key%;
if((*p_find) == NULL)
{
(*p_find) = new Node();
m_nNodeCnt++;
}
p_find = &(*p_find)->child[m];
key /= ;
}
if((*p_find) == NULL)
{
(*p_find) = new Node();
(*p_find)->data = data;
m_nNodeCnt++;
m_nElementCnt++;
return true;
}
else
{
if((*p_find)->data == NULL)
{
(*p_find)->data = data;
m_nElementCnt++;
return true;
}
else
{
if(overwrite == false)
{
return false;
}
else
{
(*p_find)->data = data;
m_nElementCnt++;
return true;
}
}
}
} #endif
测试代码:
void test1()
{
int cnt = ;
time_t s,e;
int n = ,m = ;
TrieTree<R,int> a;
set<R*> b;
for(m = ;m < ;m++)
{
cout<<"item count:"<<n<<endl;
s = clock();
for(int i = ;i < n;i++)
{
R *r = new R(i);
a.insert(r,i);
}
//a.dump();
for(int i = ;i < n/;i++)
{
a.remove(i,true);
}
e = clock();
cout<<"TrieTree Use Time:"<<e-s<<endl;
s = clock();
for(int i = ;i < n;i++)
{
R *r = new R(i);
b.insert(r);
}
b.clear();
e = clock();
cout<<"Set Use Time:"<<e-s<<endl;
cout<<"-------------------"<<endl;
n*=;
}
}
int main()
{
test1();
system("pause");
return ;
}
测试结果:

以上仅是我个人的观点,代码也仅仅是练练手而已,不保证理论和实现完全正确,仅供参考。
C++ TrieTree(字典树)容器的实现的更多相关文章
- 剑指Offer——Trie树(字典树)
剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种的单词.对于每一个单词,我们要判断他出没出现过,如果出现了,求第一次出现在第几个位 ...
- 初级字典树查找在 Emoji、关键字检索上的运用 Part-2
系列索引 Unicode 与 Emoji 字典树 TrieTree 与性能测试 生产实践 在有了 Unicode 和 Emoji 的知识准备后,本文进入编码环节. 我们知道 Emoji 是 Unico ...
- BestCoder Round #92 1001 Skip the Class —— 字典树 or map容器
题目链接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=748&pid=1001 题解: 1.trie树 关 ...
- 012-数据结构-树形结构-哈希树[hashtree]、字典树[trietree]、后缀树
一.哈希树概述 1.1..其他树背景 二叉排序树,平衡二叉树,红黑树等二叉排序树.在大数据量时树高很深,我们不断向下找寻值时会比较很多次.二叉排序树自身是有顺序结构的,每个结点除最小结点和最大结点外都 ...
- trie字典树详解及应用
原文链接 http://www.cnblogs.com/freewater/archive/2012/09/11/2680480.html Trie树详解及其应用 一.知识简介 ...
- 字典树(Trie Tree)
在图示中,键标注在节点中,值标注在节点之下.每一个完整的英文单词对应一个特定的整数.Trie 可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的.键不需要被显式地保存在节点中. ...
- 算法导论:Trie字典树
1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...
- [数据结构]字典树(Tire树)
概述: Trie是个简单但实用的数据结构,是一种树形结构,是一种哈希树的变种,相邻节点间的边代表一个字符,这样树的每条分支代表一则子串,而树的叶节点则代表完整的字符串.和普通树不同的地方是,相同的字符 ...
- Trie树/字典树题目(2017今日头条笔试题:异或)
/* 本程序说明: [编程题] 异或 时间限制:1秒 空间限制:32768K 给定整数m以及n个数字A1,A2,..An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大 ...
随机推荐
- BZOJ1807 : [Ioi2007]Pairs 彼此能听得见的动物对数
一维的情况: 排序后维护一个单调指针即可,时间复杂度$O(n\log n)$. 二维的情况: 旋转坐标系后转化为二维数点问题,扫描线+树状数组维护即可,时间复杂度$O(n\log n)$. 三维的情况 ...
- Quartz将Job保存在数据库中所需表的说明
http://blog.iqbon.com/doc/364.html (将Quartz持久化到数据库的做法) QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calen ...
- 8.20 css样式表:样式分类,选择器。样式属性,
样式表分类: 1.内联样式表, 和html联合显示,例:<p style="font-size:14px;">内联样式表</p> 2.内嵌样式表 作为一个独 ...
- 8.0 Qweb 报表编写步骤
8.0 采用的是Qweb报表,摒弃了7.0中的RML报表. 1.首先在xml文件中注册一个报表: <report id="qweb_test_report" model=&q ...
- java.lang.String 类的所有方法
java.lang.String 类的所有方法 方法摘要 char charAt(int index) 返回指定索引处的 char 值. int codePointAt(int index) 返回指定 ...
- Servlet 编程 请求的转发
在上篇的基础上,修改servlet *转发只能在同一应用内转发. 将forward 地址改为:youku.com 不能访问 重定向是可以访问外部应用的
- /etc/named/named.conf.options中的Options参数
listen-on port 53 { any; }; 监听在这部主机系统上面的哪个网路介面.预设是监听在localhost,亦即只有本机可以对DNS 服务进行查询,那当然是很不合理啊!所以这里要将大 ...
- HDU 1114 完全背包+判断能否装满
题意 给出一个存钱罐里的钱币重量 给出可能的n种钱币重量以及价值 求存钱罐中钱币的最小价值 若不可能另有输出 在裸的完全背包上加了一点东西 即判断这个背包能否被装满 初始化 dp[0]=0 其余的都使 ...
- twitter storm源码走读之4 -- worker进程中线程的分类及用途
欢迎转载,转载请注明出版,徽沪一郎. 本文重点分析storm的worker进程在正常启动之后有哪些类型的线程,针对每种类型的线程,剖析其用途及消息的接收与发送流程. 概述 worker进程启动过程中最 ...
- PHP 常用函数库和一些实用小技巧
PHP 常用函数库和一些实用小技巧 作者: 字体:[增加 减小] 类型:转载 包括文件读取函式,文件写入函式,静态页面生成函式,目录删除函式等 文件读取函式 //文件读取函式 function ...