当前位置:编程学习 > C/C++ >>

Trie树及其应用

Trie树

--------------------------------------------------------------------------------

Trie树,又称单词查找树、字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。

Trie树的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。 Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 Trie树也有它的缺点,Trie树的内存消耗非常大.

 


Trie树的结构特点:
1.root结点没有数据

2.除根结点外每个结点只包含一个字符

3.从根结点到某一个结点正好组成一个字符串

Trie树的大致结构如下:

 

 

\


 

 Trie树的实现

 

下面是一个简单的Trie树的实现,假定只包括26个字符,忽略大小写。


--------------------------------------------------------------------------------
 

 #include <stdlib.h>  
 
class Trie{ 
public: 
    Trie(); 
    ~Trie(); 
 
    int insert(const char* str); 
    int search(const char* str)const; 
    int remove(const char* str); 
 
    static const int CharNum = 26; 
 
protected: 
    typedef struct s_Trie_Node{ 
        bool isExist; 
        struct s_Trie_Node* branch[Trie::CharNum]; 
        s_Trie_Node(); 
    }Trie_Node; 
 
    Trie_Node* root; 
}; 
 
Trie::Trie():root(NULL){} 
Trie::~Trie(){} 
 
Trie::s_Trie_Node::s_Trie_Node():isExist(false){ 
    for(int i = 0; i < Trie::CharNum; ++i){ 
        branch[i] = NULL; 
    } 
} 
 
int Trie::insert(const char* str){ 
 
    if(root == NULL){ 
        root = new Trie_Node(); 
    } 
 
    Trie_Node* pos = root; 
    int char_pos; 
 
    while(pos != NULL && *str != '\0'){ 
        if(*str >= 'a' && *str <= 'z'){ 
            char_pos = *str - 'a'; 
        } else if(*str >= 'A' && *str <= 'Z'){ 
            char_pos = *str - 'A'; 
        } else { 
            return -1; 
        } 
 
        if(pos->branch[ char_pos]  == NULL){ 
            pos->branch[ char_pos ] = new Trie_Node(); 
        } 
 
        pos = pos->branch[ char_pos ]; 
 
        str++; 
    } 
 
    if(pos->isExist){ 
        return 0; 
    } else { 
        pos->isExist = true; 
        return 1; 
    } 
} 
 
int Trie::search(const char* str)const{ 
    Trie_Node* pos = root; 
 
    int char_pos; 
    while(pos != NULL && *str != '\0'){ 
        if(*str >= 'a' && *str <= 'z'){ 
            char_pos = *str - 'a'; 
        } else if(*str >= 'A' && *str <= 'Z'){ 
            char_pos = *str - 'A'; 
        } else { 
            return -1; 
        } 
 
        pos = pos->branch[char_pos]; 
        str++; 
    } 
 
    if(pos != NULL && pos->isExist){ 
        return 1; 
    } else { 
        return 0; 
    } 
} 
 
int Trie::remove(const char* str){ 
    Trie_Node* pos = root; 
 
    int char_pos; 
 
    while(pos != NULL && *str != '\0'){ 
        if(*str >= 'a' && *str <= 'z'){ 
            char_pos = *str - 'a'; 
        } else if(*str >= 'A' && *str <= 'Z'){ 
            char_pos = *str - 'A'; 
        } else { 
            return -1; 
        } 
 
        pos = pos->branch[ char_pos ]; 
        str++; 
    } 
 
    if(pos != NULL && pos->isExist){ 
        pos->isExist = false; 
        return 1; 
    } else { 
        return 0; 
    } 
} 

#include <stdlib.h>

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

 int insert(const char* str);
 int search(const char* str)const;
 int remove(const char* str);

 static const int CharNum = 26;

protected:
 typedef struct s_Trie_Node{
  bool isExist;
  struct s_Trie_Node* branch[Trie::CharNum];
  s_Trie_Node();
 }Trie_Node;

 Trie_Node* root;
};

Trie::Trie():root(NULL){}
Trie::~Trie(){}

Trie::s_Trie_Node::s_Trie_Node():isExist(false){
 for(int i = 0; i < Trie::CharNum; ++i){
  branch[i] = NULL;
 }
}

int Trie::insert(const char* str){

 if(root == NULL){
  root = new Trie_Node();
 }

 Trie_Node* pos = root;
 int char_pos;

 while(pos != NULL && *str != '\0'){
  if(*str >= 'a' && *str <= 'z'){
   char_pos = *str - 'a';
  } else if(*str >= 'A' && *str <= 'Z'){
   char_pos = *str - 'A';
  } else {
   return -1;
  }

  if(pos->branch[ char_pos]  == NULL){
   pos->branch[ char_pos ] = new Trie_Node();
  }

  pos = pos->branch[ char_pos ];

  str++;
 }

 if(pos->isExist){
  return 0;
 } else {
  pos->isExist = true;
  return 1;
 }
}

int Trie::search(const char* str)const{
 Trie_Node* pos = root;

 int char_pos;
 while(pos != NULL && *str != '\0'){
  if(*str >= 'a' && *str <= 'z'){
   char_pos = *str - 'a';
  } else if(*str >= 'A' && *str <= 'Z'){
   char_pos = *str - 'A';
  } else {
   return -1;
  }

  pos = pos->branch[char_pos];
  str++;
 }

 if(pos != NULL && pos->isExist){
  return 1;
 } else {
  return 0;
 }
}

int Trie::remove(const char* str){
 Trie_Node* pos = root;

 int char_pos;

 while(pos != NULL && *str != '\0'){
  if(*str >= 'a' && *str <= 'z'){
   char_pos = *str - 'a';
  } else if(*str >= 'A' && *str <= 'Z'){
   char_pos = *str - 'A';
  } else {
   return -1;
  }

  pos = pos->branch[ char_pos ];
  str++;
 }

 if(pos != NULL && pos->isExist){
  pos->isExist = false;
  return 1;
 } else {
  return 0;
 }
}

Trie树的应用

--------------------------------------------------------------------------------

 1. 大量字符串的统计,查找
用的比较多的场合,例如:搜索引擎对文本中词频的统计,搜索引擎日志对用户关键词搜索频率的统计,等等。下面讨论两道经典的面试题:

1.找出大量日志文件中,出现次数前10的网址。

这个问题使用Trie树再适合不过了,对于大量日志文件的统计,使用trie树速度相当快。结合最小堆和trie树,对日志文件搜索一次就可以得到结果。

2.实现一个网站的输入提示功能

这个问题需要在用户输入的时候,实时展示输入建议,使用trie树可以轻松实现。

2.字符串的排序
对于大规模字符串的排序,只需要统计一次字符串,构造trie树,然后遍历输出就得到排序结果。

3.找字符串的最长公共前缀
这个问题显而易见。

 

 

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,