数据结构——trie

概述:

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<#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]< 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 = "<


你可能感兴趣的:(trie,前缀树)