概述:
l TrieTree,又称Prefix Tree,是一个有序树结构,一般用来存储以字符串为Key的关联数组。
l TrieTree的节点中并不包含其所关联的Key,节点关联的Key由该节点所在树中位置定义。
l TrieTree中同一节点所有son节点所关联的Key,都以该节点所关联Key为前缀。每个son节点只能又一个parent节点。根节点关联的Key为空。
l 每个节点都可以决定一个Key,但并不是每个Key都需要对应的Value。通常只有叶子节点和少量内部节点会有对应的value
l TrieTree 以空间换时间,空间复杂度很大,时间效率很高。在Trie Tree中查询一个字符串时间为O(length),length为字符串长度。
l Trie树的节点可用多重链表表示,每个节点含有m个指针域,m是trie树的度(度:树中节点可以拥有的最大子树数曾为该树的度)。
l Trie树的度与关键字的每一位的基数相关,即关键字每一位字符可能取值的数目。假设,每位关键字可能取值为abcdefg中的一个,构建Trie树如下。对应树型如左图
l 每一层将关键字可能取值映射到一个指针域,即通过字符找到对应指针域的时间为O(1)。
l 每个节点保存一个value,该value值对应的键为该该层的前缀字符串。如图中的键值对分别为:
(“”,1),(“a”,2),(“d”,3),(“f”,4),(“ad”,5),(“df”,6),(“ag”,7),(“fc”,8),当然这只是一种表示方法,不同的表示手段可以有多种。
l 计算下这个结构的空间复杂度吧,假如关键字长度为n,关键字每位基数为m,如果该树的每个节点的指针域都不为空,那么每加深一层,规模是上一层的m倍,这样计算扩展len层后规模的总和为:
这种规模的膨胀,爆掉内存太容易了。
l 如果节点采用非随机访问策略,就可以减少每个节点的宽度,在空间的节省上有很大的优化,但是这样就牺牲了查找的效率,一个简单的比如,每个节点用一个map字符及对应的指针域,可以将没有出现的字符空间省掉,但在该节点通过字符查找指针域的时间就从O(1)变成了O(logk),k为该节点字符个数。而搜索一个字符的时间变成了O(len*logk)
原理:
l Trie树归属于搜索树,本质上是一个确定的有限状态自动机。
l 每个节点代表一种状态,每个节点所有匹配的字符表示一种状态迁移条件。
l 大致按照状态,条件,动作归纳一下:
状态:上图中的多重链表中每一个节点,包括初始态,a,ad,ag,d,df,f,fc,以及成功匹配结束与失败匹配结束状态。
条件:字符串结束,匹配到节点还有的字符映射,不能匹配
动作:状态转移,结束查询
状态转移表如下:
状态 |
状态描述 |
条件 |
动作 |
次态 |
初始态 |
未匹配第一个字符前 |
字符串结束 |
取关联值1返回 |
成功结束态 |
初始态 |
未匹配第一个字符前 |
匹配字符’a’ |
状态迁移 |
a |
初始态 |
未匹配第一个字符前 |
匹配字符’d’ |
状态迁移 |
d |
初始态 |
未匹配第一个字符前 |
匹配字符’f’ |
状态迁移 |
f |
a |
已匹配前缀a |
字符串结束 |
取关联值2返回 |
成功结束态 |
a |
已匹配前缀a |
匹配字符’d’ |
状态迁移 |
ad |
a |
已匹配前缀a |
匹配字符’g’ |
状态迁移 |
ag |
a |
已匹配前缀a |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
ad |
已匹配前缀ad |
字符串结束 |
取关联值5返回 |
成功结束态 |
ad |
已匹配前缀ad |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
ag |
已匹配前缀ag |
字符串结束 |
取关联值7返回 |
成功结束态 |
ag |
已匹配前缀ag |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
d |
已匹配前缀d |
字符串结束 |
取关联值3返回 |
成功结束态 |
d |
已匹配前缀d |
匹配字符’f’ |
状态迁移 |
df |
d |
已匹配前缀d |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
df |
已匹配前缀df |
字符串结束 |
取关联值6返回 |
成功结束态 |
df |
已匹配前缀df |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
f |
已匹配前缀f |
字符串结束 |
取关联值4返回 |
成功结束态 |
f |
已匹配前缀f |
匹配字符’c’ |
状态迁移 |
fc |
f |
已匹配前缀f |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
fc |
已匹配前缀fc |
字符串结束 |
取关联值8返回 |
成功结束态 |
fc |
已匹配前缀fc |
无待匹配字符映射 |
结束查询返回 |
失败结束态 |
应用:
l 主要用于 一些对时间效率要求较大的大型数据处理。如用于词典的构造和查询。
实现:
l 节点属性:
1. m_value:该节点在树中位置映射的value,只有在m_bHasValue为true时有意义。
2. m_bHasValue:该节点在树中位置是否有映射value
3. m_NumLeaf:子节点个数
4. m_Arr :指向子节点的指针数组
注1:确保m_NumLeaf为0时,m_Arr数组中所有元素都是null
注2:确保树中不存在m_NumLeaf为0,且m_bHasValue为false的节点,这种节点的存在无意义。
l 节点方法:
1. TrieNode() :默认构造函数确保初始化时,m_value 为类型默认值T(),m_bHasValue为false。m_NumLeaf为0,m_Arr数组中各指针为0。
2. TrieNode(constT& I_value) : 带参构造函数初始化时,m_value为参数传入值,m_bHasValue为true,其余同默认构造函数。
3. ~TrieNode() :析构函数,删除m_Arr数组中所有不为0的指针。
4. addReflex(intI_index,TSelf* pNode) : 该函数在m_Arr数组I_index位置指针为0的情况下,在该位置增加子节点*pNode的关联。且m_NumLeaf++。
5. delReflex(intI_index) : 该函数在m_Arr数组I_index位置指针不为0的情况下,删除该位置关联的子节点。且m_NumLeaf--。
6. setValue(constT& I_value) :在m_bHasvalue为false的条件下,设置当前节点的m_value值,并将m_bHasvalue置为true。
7. getValue() : 获取节点中关联的值。
8. getReflex(intI_index, TSelf*& O_pNode) : 获取当前节点在I_index处的关联子节点的指针,通过O_pNode传出。
9. HasReflex(intI_index) : 判断当前节点在I_index是都有关联子节点。
10. getNumLeaf () : 获取本节点关联节点的个数。
11. getbHasvalue() : 判断本节点是都有关联值。
12. setbHasvalue() : 设置节点关联的值
l 树方法:
1. AddItem(conststring& I_str,const T& I_value):增加键值对
2. DelItem(conststring& I_str):根据键删除一条记录
3. Search(conststring& I_str,T& O_value):根据键查询记录,通过O_value返回。
代码:
.h文件
#ifndef _TRIE_H_Y00183482_
#define _TRIE_H_Y00183482_
/**********************************************
$ Writen by Xiwen Yue : Clown
**********************************************/
#include
#include
#include
using namespace std;
const unsigned int little_char = 0;
const unsigned int big_char = 1;
enum BHasReflex
{
REFLEX_HAS,
REFLEX_NO_HAS,
REFLEX_ERROR,
};
template struct HashPolicy;
template > class TrieTree;
template >
class TrieNode
{
public:
typedef TrieNode TSelf;
typedef T TValue;
static const int m_length = BaseNum;
public:
TrieNode();
TrieNode(const T& I_value);
~TrieNode();
public:
bool addReflex(int I_index,TSelf* pNode);
bool delReflex(int I_index);
bool setValue(const T& I_value);
T getValue()const;
bool getbHasvalue()const;
void setbHasvalue(bool I_val);
bool getReflex(int I_index, TSelf*& O_pNode);
int getNumLeaf()const;
BHasReflex HasReflex(int I_index);
public:
T m_value;
int m_NumLeaf;
bool m_bHasvalue;
TSelf* m_Arr[BaseNum];
friend class TrieTree;
};
template
class TrieTree
{
public:
TrieTree();
~TrieTree();
public:
bool AddItem(const string& I_str, const T& I_value);
bool DelItem(const string& I_str);
bool Search(const string& I_str,T& O_value);
void display()const;
private:
void dsy(TrieNode* I_ptr, string I_str)const;
bool Srh(TrieNode* I_ptr, const string& I_str, int I_index, T& O_val);
bool Add(TrieNode* I_ptr, const string& I_str, int I_index, const T& I_val);
bool Del(TrieNode* I_ptr,const string& I_str, int I_index,bool& O_tag);
private:
TrieNode* m_root;
};
#include "trie.inl"
#endif
.inl文件
#define LIT_CHAR 0
#define BIG_CHAR 1
/**********************************************
$ Writen by Xiwen Yue : Clown
**********************************************/
template struct HashPolicy
{
static int proc(const T& I_val)
{
if(I_val < 'a' || I_val > 'z')
{
return -1;
}
return I_val - 'a';
}
};
template struct HashPolicy
{
static int proc(const T& I_val)
{
if(I_val < 'A' || I_val > 'Z')
{
return -1;
}
return I_val - 'A';
}
};
/*************************************************************
$ template class TrieNode;
$
*************************************************************/
template
inline TrieNode::TrieNode()
: m_value(T()),m_NumLeaf(0),m_bHasvalue(false)
{
for(int i = 0; i < BaseNum; ++i)
{
m_Arr[i] = 0;
}
}
template
inline TrieNode::TrieNode(const T& I_value)
: m_value(I_value),m_NumLeaf(0),m_bHasvalue(true)
{
for(int i = 0; i < BaseNum; ++i)
{
m_Arr[i] = 0;
}
}
template
inline TrieNode::~TrieNode()
{
cout<<"in the ~TrieNode : "<
inline bool TrieNode::addReflex(int I_index,TSelf* pNode)
{
if(0>I_index || BaseNum <= I_index || 0 != m_Arr[I_index])
{
return false;
}
m_Arr[I_index] = pNode;
m_NumLeaf++;
return true;
}
template
inline bool TrieNode::delReflex(int I_index)
{
if(0>I_index || BaseNum <= I_index || 0 == m_Arr[I_index])
{
return false;
}
delete m_Arr[I_index];
m_Arr[I_index] = 0;
m_NumLeaf--;
return true;
}
template
inline bool TrieNode::setValue(const T& I_value)
{
if(m_bHasvalue) return false;
m_bHasvalue = true;
m_value = I_value;
return true;
}
template
inline bool TrieNode::getReflex(int I_index, TSelf*& O_pNode)
{
if(0 >= I_index && BaseNum <= I_index)
{
return false;
}
O_pNode = m_Arr[I_index];
return true;
}
template
inline BHasReflex TrieNode::HasReflex(int I_index)
{
if(0 >= I_index && BaseNum <= I_index)
{
return REFLEX_ERROR;
}
if(0 == m_Arr[I_index])
{
return REFLEX_NO_HAS;
}
return REFLEX_HAS;
}
template
inline int TrieNode::getNumLeaf()const
{
return m_NumLeaf;
}
template
inline T TrieNode::getValue()const
{
return m_value;
}
template
inline bool TrieNode::getbHasvalue()const
{
return m_bHasvalue;
}
template
inline void TrieNode::setbHasvalue(bool I_val)
{
m_bHasvalue = I_val;
}
/*************************************************************
$ template class TrieTree;
$
*************************************************************/
template
inline TrieTree::TrieTree()
:m_root(0)
{
}
template
inline TrieTree::~TrieTree()
{
if(0 != m_root) delete m_root;
}
template
inline bool TrieTree::AddItem(const std::string& I_str, const T& I_value)
{
if(0 == m_root)
{
m_root = new TrieNode();
}
TrieNode* p = m_root;
return Add(p,I_str,0,I_value);
}
template
inline bool TrieTree::Add(TrieNode* I_ptr, const string& I_str, int I_index, const T& I_value)
{
if(I_str.length() == I_index)
{
if(I_ptr->getbHasvalue())
{
return false;
}
I_ptr->setValue(I_value);
return true;
}
int f_index = Policy::proc(I_str.c_str()[I_index]);
TrieNode* q = 0;
if(REFLEX_HAS != I_ptr->HasReflex(f_index))
{
q = new TrieNode();
if(false == I_ptr->addReflex(f_index,q))
{
return false;
}
}
if(!I_ptr->getReflex(f_index,q))
{
return false;
}
return Add(q,I_str,++I_index,I_value);
}
template
inline bool TrieTree::DelItem(const string& I_str)
{
TrieNode* p = m_root;
if(0 == p) return false;
bool flag = false;
bool retCode = Del(p,I_str,0,flag);
if(flag)
{
delete p;
m_root = 0;
}
return true;
}
template
inline bool TrieTree::Del(TrieNode* I_ptr,const string& I_str, int I_index,bool& O_tag)
{
if(I_index == I_str.length())
{
if(0 == I_ptr->getNumLeaf())
{
O_tag = true;
return true;
}
if(I_ptr->getbHasvalue())
{
I_ptr->setbHasvalue(false);
O_tag = false;
return true;
}
return false;
}
int f_index = Policy::proc(I_str.c_str()[I_index]);
if(REFLEX_HAS != I_ptr->HasReflex(f_index))
{
return false;
}
TrieNode* q = 0;
if(!I_ptr->getReflex(f_index,q))
{
return false;
}
bool retCode = Del(q,I_str,++I_index,O_tag);
if(O_tag)
{
if(!I_ptr->delReflex(f_index))
{
return false;
}
if(0 == I_ptr->getNumLeaf())
{
O_tag = true;
return true;
}
O_tag = false;
return true;
}
return retCode;
}
template
inline bool TrieTree::Search(const string& I_str,T& O_value)
{
TrieNode* p = m_root;
if(0 == p) return false;
return Srh(p,I_str,0,O_value);
}
template
inline bool TrieTree::Srh(TrieNode* I_ptr,const string& I_str, int I_index,T& O_val)
{
if(I_index == I_str.length())
{
if(!I_ptr->getbHasvalue())
{
return false;
}
O_val = I_ptr->getValue();
return true;
}
int f_index = Policy::proc(I_str.c_str()[I_index]);
if(REFLEX_HAS != I_ptr->HasReflex(f_index))
{
return false;
}
TrieNode* q = 0;
if(!I_ptr->getReflex(f_index,q))
{
return false;
}
return Srh(q,I_str,++I_index,O_val);
}
template
inline void TrieTree::display()const
{
TrieNode* p = m_root;
if(0 == p) return ;
string str;
dsy(p,str);
}
template
inline void TrieTree::dsy(TrieNode* I_ptr, string I_str)const
{
if(0 == I_ptr->getNumLeaf())
{
cout<getValue()<getbHasvalue())
{
cout<getValue()<HasReflex(i))
{
TrieNode* q = 0;
if(!I_ptr->getReflex(i,q))
{
return ;
}
string tmpstr;
tmpstr.assign(1,i+'a');
string tmpstr1 = I_str+ tmpstr;
dsy(q,tmpstr1);
}
}
}
.cpp 文件:
#include "trie.h"
int main()
{
//TrieNode<7,int> obj;
//cout<<"value = "<::m_length; i++)
//{
// cout<<"0x"<<(void*)obj.m_Arr[i]<* p1 = new TrieNode<7,int>(4);
//TrieNode<7,int>* p2 = new TrieNode<7,int>(5);
//TrieNode<7,int>* p3 = new TrieNode<7,int>(6);
//TrieNode<7,int>* p4 = new TrieNode<7,int>(7);
//cout<<"********************************"<::m_length; i++)
//{
// cout<<"0x"<<(void*)obj.m_Arr[i]<m_value<* p5 = new TrieNode<7,int>(14);
//TrieNode<7,int>* p6 = new TrieNode<7,int>(15);
//TrieNode<7,int>* p7 = new TrieNode<7,int>(16);
//TrieNode<7,int>* p8 = new TrieNode<7,int>(17);
//obj.m_Arr[1]->addReflex(2,p5);
//obj.m_Arr[2]->addReflex(4,p6);
//obj.m_Arr[3]->addReflex(1,p7);
//obj.m_Arr[4]->addReflex(5,p8);
//obj.delReflex(1);
cout<<"*****************************************"< Trieobj;
Trieobj.AddItem("abc",7);
Trieobj.AddItem("abd",4);
Trieobj.AddItem("a",1);
Trieobj.AddItem("bc",3);
Trieobj.AddItem("be",5);
Trieobj.AddItem("bcde",9);
Trieobj.AddItem("abf",10);
Trieobj.display();
int a = 0;
Trieobj.Search("abc",a);
cout<<"abc's value = "<