最近研究了一下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(字典树)容器的实现的更多相关文章

  1. 剑指Offer——Trie树(字典树)

    剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种的单词.对于每一个单词,我们要判断他出没出现过,如果出现了,求第一次出现在第几个位 ...

  2. 初级字典树查找在 Emoji、关键字检索上的运用 Part-2

    系列索引 Unicode 与 Emoji 字典树 TrieTree 与性能测试 生产实践 在有了 Unicode 和 Emoji 的知识准备后,本文进入编码环节. 我们知道 Emoji 是 Unico ...

  3. BestCoder Round #92 1001 Skip the Class —— 字典树 or map容器

    题目链接:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=748&pid=1001 题解: 1.trie树 关 ...

  4. 012-数据结构-树形结构-哈希树[hashtree]、字典树[trietree]、后缀树

    一.哈希树概述 1.1..其他树背景 二叉排序树,平衡二叉树,红黑树等二叉排序树.在大数据量时树高很深,我们不断向下找寻值时会比较很多次.二叉排序树自身是有顺序结构的,每个结点除最小结点和最大结点外都 ...

  5. trie字典树详解及应用

    原文链接    http://www.cnblogs.com/freewater/archive/2012/09/11/2680480.html Trie树详解及其应用   一.知识简介        ...

  6. 字典树(Trie Tree)

    在图示中,键标注在节点中,值标注在节点之下.每一个完整的英文单词对应一个特定的整数.Trie 可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的.键不需要被显式地保存在节点中. ...

  7. 算法导论:Trie字典树

    1. 概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. Trie一词来自retrieve,发音为/tr ...

  8. [数据结构]字典树(Tire树)

    概述: Trie是个简单但实用的数据结构,是一种树形结构,是一种哈希树的变种,相邻节点间的边代表一个字符,这样树的每条分支代表一则子串,而树的叶节点则代表完整的字符串.和普通树不同的地方是,相同的字符 ...

  9. Trie树/字典树题目(2017今日头条笔试题:异或)

    /* 本程序说明: [编程题] 异或 时间限制:1秒 空间限制:32768K 给定整数m以及n个数字A1,A2,..An,将数列A中所有元素两两异或,共能得到n(n-1)/2个结果,请求出这些结果中大 ...

随机推荐

  1. Xamarin.Android编译CPU类型选择方式

    Xamarin.Android编译CPU类型选择方式 在Xamarin.Android编译的时候,默认提供了5种CPU类型供大家选择.它们分别为armeabi.armeabi-v7a.arm64-v8 ...

  2. 直接操作游戏对象C#游戏开发

    直接操作游戏对象C#游戏开发 2.2.3  直接操作游戏对象 在Inspector视图里通过设置属性而改变游戏场景中游戏对象的状态,太过抽象,毕竟数字并不够直观.其实,改变游戏对象的状态,完全有最最直 ...

  3. LightOJ1068 Investigation(数位DP)

    这题要求区间有多少个模K且各位数之和模K都等于0的数字. 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解. 考虑到数据规模 ...

  4. Revit二次开发示例:HelloRevit

    本示例实现Revit和Revit打开的文件的相关信息. #region Namespaces using System; using System.Collections.Generic; using ...

  5. 游戏 slider

    using UnityEngine; using System.Collections; public class La : MonoBehaviour { float verticalValue=0 ...

  6. 【POJ】2828 Buy Tickets(线段树+特殊的技巧/splay)

    http://poj.org/problem?id=2828 一开始敲了个splay,直接模拟. tle了.. 常数太大.. 好吧,说是用线段树.. 而且思想很拽.. (貌似很久以前写过貌似的,,) ...

  7. 【wikioi】1913 数字梯形问题(费用流)

    http://wikioi.com/problem/1913/ 如果本题没有询问2和3,那么本题和蚯蚓那题一模一样.http://www.cnblogs.com/iwtwiioi/p/3935039. ...

  8. POJ 1177 Picture(求周长并)

    题目链接 看的HH的题解..周长有两部分组成,横着和竖着的,横着通过,sum[1] - last来计算,竖着的通过标记,记录有多少段. #include <cstdio> #include ...

  9. jdk+myeclipse配置安装相关步骤

    1.JDK的安装JDK  版本:7u25  安装路径:c:\java(注意:装不装公共jre都可,自己可以选择安装到哪里)环境变量配置:(1)JAVA_HOME:C:\Java(就是你安装jdk的目录 ...

  10. explicit关键字

    C++中,explicit关键字用来修饰类只有一个参数的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换. explicit使用注意事项: explicit 关 ...