一般的trie树

trie树是一个字典,可以容纳大量的字符串,可以快速查找某个特定的字符串或它的前缀。
trie树以空间换时间,但空间上的浪费还是很明显的,必要时可以考虑优化trie树,如使用双数组的trie

树,以节省空间。
trie树的优势的基础是数组的a[i]优势。
trie树查找一个字符串的最差的时间复杂度是O(h),h是树的高度,这时未必就比二分法好,更没有B树快

trie树有一个基本数组,数组的每一个元素指向一个结点。结点也是一个数组,数组的每个元素也指向一

个结点......

基本数组跟结点数组初始化时各个元素置为空。创建trie树时,对加进来的字符串进行逐个字符扫描;每

个字符对应一个hash值,根据这个hash值迅速定位到一个数组元素,如果这个元素为空就创建一个结点数

组,并指定它的前缀等然后在这个结点上定位下一个字符;如果元素不为空则在这个元素指向的结点数组

上定位下一个字符。如此递归,直至所有字符都定位完为止。

查找一个字符串时,也是逐个字符进行。根据第一个字符的hash值快速在基本数组上定位,然后根据下一

个字符在结点数组上定位,直到所有字符查找完毕或找到结点的结束标志或数组元素为空为止。


以下的例子“抄袭”了网上的一些代码。
这里的trie树是一般的trie树,只考虑一次性的静态创建,然后只用于查找。只用于Ascii字符。

vc++8.0  console application

/ trie.h

#pragma  once

namespace bluesky_base_adt
{
 const int TOP_ARRAY_MAX_SIZE = 256;

 class Node
 {
 public:
  Node( int  nLevel );
  ~Node( );

 public:
  char m_chPreCharactor;  // 前缀
  bool m_bIsEnd; // 是否该词已经终止
  Node** m_pSubNode; // 存放子结点指针的数组
 };

 class Trie
 {
 public:
  Trie( );
  ~Trie( );

 public:
  void AddOneString( char* str );
  int FindOneString( char* str );

  void DeleteTrieTree( );

 private:
  void Add( Node * & pNode, char* str, int nLevel );
  int Find( Node* pNode, char* str, int nLevel );

  int GetHashValue( char str, int nLen );
  
  void DeleteTrie( Node* pNode, int  nLevel );

 protected:
 private:
  Node* m_pRootNodes[TOP_ARRAY_MAX_SIZE];
 };
}


trie.cpp

#include "trie.h"
using namespace bluesky_base_adt;


// 计算子结点数组的长度
inline int SubNodeLength( int  nLevel )
{
 // return nLevel > 5 ? 1 : 256 / ( nLevel * nLevel * nLevel );
 return TOP_ARRAY_MAX_SIZE;
}


Node::Node(int nLevel ) : m_bIsEnd( false ), m_chPreCharactor('/0')
{
 int nSubNodeLen = SubNodeLength( nLevel );
 m_pSubNode  = new Node* [nSubNodeLen ];
 for ( int nPos = 0; nPos < nSubNodeLen; nPos ++ )
 {
  m_pSubNode[nPos] = NULL;
 }
}

Node::~Node( )
{
 // add code here
 delete m_pSubNode;
}


/

Trie::Trie()
{
 for ( int nPos = 0; nPos < TOP_ARRAY_MAX_SIZE; nPos ++ )
 {
  m_pRootNodes[nPos]  = NULL;
 }
}

Trie::~Trie( )
{
 // add code here
}

/************************************************************************/
/* 内部函数
/************************************************************************/
// add one string
void Trie::Add( Node * & pNode, char* str, int nLevel )
{
 Node* pCurrentNode = NULL;

 if ( pNode == NULL )
 {
  pNode = new Node( nLevel + 1 );
  pNode -> m_chPreCharactor = *str;
  
 }
 
 pCurrentNode = pNode;

 if ( *(str + 1) == '/0' )
 {
  pCurrentNode->m_bIsEnd = true;
  return;
 }

 int hashValue = GetHashValue( *(str + 1), SubNodeLength( nLevel + 1 ) );
 Add( pCurrentNode->m_pSubNode[hashValue], str + 1, nLevel + 1 ); 

 return;
}

// find one string
int Trie::Find( Node* pNode, char* str, int nLevel )
{
 if ( pNode == NULL || *str == '/0' )
  return 0;
 
 if ( pNode->m_chPreCharactor == *str )
 {
  if ( pNode->m_bIsEnd && *(str+1) == '/0' )
   return nLevel;

  int nHashValue = GetHashValue( *(str + 1), SubNodeLength( nLevel + 1 ) );
  return Find( pNode->m_pSubNode[nHashValue], str + 1, nLevel + 1 );
 }

 return 0;
}

// get hash value; each charactor has one hash_value different from others
int Trie::GetHashValue( char str, int nLen )
{
 return int(str) % nLen;
}

// delete the trie tree
void Trie::DeleteTrie( Node* pNode, int  nLevel )
{
 if ( pNode == NULL )
  return;

 int  nNodeLen = SubNodeLength( nLevel + 1 );
 for ( int nPos = 0; nPos < nNodeLen; nPos ++ )
 {
  DeleteTrie( pNode->m_pSubNode[nPos], nLevel+1 );
 }

 delete pNode;
}


/************************************************************************/
/* 对外接口                                                            
/************************************************************************/
// add one string to the Trie_Tree
void Trie::AddOneString( char* str )
{
 int  nHashValue = GetHashValue( *str, TOP_ARRAY_MAX_SIZE );
 Add( m_pRootNodes[nHashValue], str, 1 );
}

// Find one string from the Trie_Tree
int Trie::FindOneString( char* str )
{
 int nHashValue =  GetHashValue( *str, TOP_ARRAY_MAX_SIZE );
 return Find( m_pRootNodes[nHashValue], str, 1 );
}

// delete the Trie_Tree
void Trie::DeleteTrieTree()
{
 for ( int nPos = 0; nPos < TOP_ARRAY_MAX_SIZE; nPos ++ )
 {
  if ( m_pRootNodes[nPos] != NULL )
  {
   DeleteTrie( m_pRootNodes[nPos], 1 );
  }
 }
}


/// test code

#include <iostream>
using namespace std;

#include "trie.h"
using namespace bluesky_base_adt;

const int  MAX_LEN = 560;

// test trie
void test_trie( )
{
 Trie trieTest;
 trieTest.AddOneString( "apple" );
 trieTest.AddOneString( "appler" );
 trieTest.AddOneString( "at" );
 trieTest.AddOneString( "basket ball" );
 trieTest.AddOneString( "bell" );
 trieTest.AddOneString( "God" );
 trieTest.AddOneString( "123" );

 int nFindCode = trieTest.FindOneString( "apple" );
 if ( nFindCode == 0 )
  cout << "not found" << endl;
 else
  cout << "got it, pos: " << nFindCode << endl;

 trieTest.DeleteTrieTree();

 cout << "******** end *******" << endl;


}

int _tmain(int argc, _TCHAR* argv[])
{
 //for ( int nPos = 0; nPos < 100000; nPos ++ ) // no mem leak
  test_trie( );

 return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值