前缀树Trie

一.基础知识

        前缀树(字典树),是一种多叉树。一般用于查找和存储字符串,这种数据结构可以很快查询到一个字符串出现过几次,一个前缀出现过几次。

        例如:字符串"aa", "ab","aab", "aac", "bc"组成的前缀树如下图所示。        

        多叉树的每条边代表出现的字符,节点中可以根据所要实现的功能加入不同的数据。如上图所示,若有一条边经过一个节点,则该节点p值+1,若有一条路径以此节点结束,则该节点e值+1。

二.前缀树的基本原理

        插入时:

        开始时,前缀树中仅有root节点。此时,root节点中p值为0,e值为0。

        

        现在插入"aa"

        每当插入一个新字符串时,root节点的p值都应当++。

        来到首个字符'a',当发现字符'a'没有对应的边相连时,则创建一个新节点。并且来到新创建的节点,将该节点p值+1

        之后来到第二个字符'a',发现字符'a'没有对应的边相连,继续创建一个新节点。来到新创建的节点,将该节点p值+1,由于该字符为字符串的最后一个字符,所以e值+1。如下图所示:

        查找指定字符时:

        按照对应路径向下寻找,若中途发现对应路径节点为空,则没有该字符串。

        若没有发生上述情况,则找到对应节点,该节点e值为给定字符串个数。

        查找指定前缀时:

        按照对应路径向下寻找,若中途发现对应路径节点为空,则没有该字符串。   

        若没有发生上述情况,则找到对应节点,该节点p值为给定字符串前缀个数。

三.实现

#include <unordered_map>

struct Node {
  int pass;
  int end;
  std::unordered_map<int, Node *> next;

  Node() {
    pass = 0;
    end = 0;
  }
};

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

  // 前缀树插入
  void insert_trie(std::string s);
  // 前缀树删除
  void delete_trie(std::string s);
  // 前缀树搜索(字符串出现次数)
  int search_trie(std::string s);
  // 前缀树搜索(字符串作为前缀次数)
  int prefix_trie(std::string s);

 private:
  // 前缀树根节点
  struct Node *root;
};

#endif //TRIE__TRIE_H_
#include "Trie.h"

Trie::Trie() {
  root = new Node;
}

Trie::~Trie() {
  delete root;
}

void Trie::insert_trie(std::string s) {
  if (s.empty()) {
    return;
  }
  Node *node = root;
  node->pass++;
  for (int i = 0; i < s.size(); i++) {
    int index = s[i];
    if (node->next.find(index) == node->next.end()) {
      node->next[s[i]] = new Node;
    }
    node = node->next[s[i]];
    node->pass++;
  }
  node->end++;
}

void Trie::delete_trie(std::string s) {
  Node *node = root;
  node->pass--;
  if (search_trie(s)) {
    for (int i = 0; i < s.size(); i++) {
      if (--node->next[s[i]]->pass == 0) {
        node->next.erase(s[i]);
        return;
      }
      node = node->next[s[i]];
    }
    node->end--;
  }
}

int Trie::search_trie(std::string s) {
  Node *node = root;
  for (int i = 0; i < s.size(); i++) {
    if (node->next.find(s[i]) == node->next.end()) {
      return 0;
    }
    node = node->next[s[i]];
  }
  return node->end;
}

int Trie::prefix_trie(std::string s) {
  Node *node = root;
  for (int i = 0; i < s.size(); i++) {
    if (node->next.find(s[i]) == node->next.end()) {
      return 0;
    }
    node = node->next[s[i]];
  }
  return node->pass;
}

      

        

        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值