【C++前缀树学习记录】

前缀树:

Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。

前缀树的3个基本性质:

1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3.每个节点的所有子节点包含的字符都不相同。

Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
结构:
在这里插入图片描述


要点:

1.类型转换:string ——> char[] ,用c_str()函数后返回值为const char *,用mencpy进行内存拷贝初始化char[]后方便使用范围for遍历
2.删除节点时要释放掉堆区数据,避免出现内存泄漏。

代码:

参考左神代码编写:

#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#define MAX_BRANCH 26         //仅考虑26个字母组成的前缀树
using namespace std;
//节点
class TrieNode
{
public:
    int pass;                 //经过次数
    int end;                  //结束标记
    vector<TrieNode *> nexts; //节点有 MAX_BRANCH 个指针指向其他节点
    TrieNode() : pass(0), end(0), nexts(MAX_BRANCH, nullptr) {}
};

//前缀树
class TrieTree
{
private:
    TrieNode *root;

public:
    TrieTree();                     //构造函数
    ~TrieTree();                    //构造函数
    void insert(string word);       //插入函数
    int search(string word);        //查询字符出现次数
    int prefix_number(string pre); //查询含前缀字符的字符串个数
    void destory(TrieNode *node);   //销毁子节点函数
    void delete_data(string word);  //删除元素函数
};

//构造函数
TrieTree::TrieTree()
{
    root = new TrieNode;
}

//析构函数
TrieTree::~TrieTree()
{
    destory(root);
}

//销毁子节点函数
void TrieTree::destory(TrieNode *node)
{
    if (node == nullptr)
    {
        return;
    }
    for (int i = 0; i < MAX_BRANCH; i++)
    {
        destory(node->nexts[i]);
    }
    delete node;
    node = nullptr;
}

//插入函数
void TrieTree::insert(string word)
{
    if (word.empty())
    {
        return;
    }
    const char *cha = word.c_str(); // c_str() 返回类型为 const char * 类型
    char data[word.size()];         //用于接收转化为char类型之后的字符串
    memcpy(data, cha, strlen(cha)); // 内存拷贝初始化data
    TrieNode *node = root;
    node->pass++;
    int index = 0;
    for (char data_i : data)
    {
        index = data_i - 'a';
        if (node->nexts[index] == nullptr)
        {
            node->nexts[index] = new TrieNode;
        }
        node = node->nexts[index];
        node->pass++;
    }
    node->end++;
}

//查询字符出现次数
int TrieTree::search(string word)
{
    if (word.empty())
    {
        return 0;
    }
    TrieNode *node = root;
    const char *cha = word.c_str();
    char data[word.size()];
    memcpy(data, cha, strlen(cha));
    int index = 0;
    for (char data_i : data)
    {
        index = data_i - 'a';
        if (node->nexts[index] == nullptr)
        {
            return 0;
        }
        node = node->nexts[index];
    }
    return node->end;
}

//查询含前缀字符的字符串个数
int TrieTree::prefix_number(string pre)
{
    if (pre.empty())
    {
        return 0;
    }
    TrieNode *node = root;
    const char *cha = pre.c_str();
    char data[pre.size()];
    memcpy(data, cha, strlen(cha));
    int index = 0;
    for (char data_i : data)
    {
        index = data_i - 'a';
        if (node->nexts[index] == nullptr)
        {
            return 0;
        }
        node = node->nexts[index];
    }
    return node->pass;
}

//删除元素函数
void TrieTree::delete_data(string word)
{
    if (search(word) != 0)
    {
        TrieNode *node = root;
        --node->pass;
        const char *chu = word.c_str();
        char data[word.size()];
        memcpy(data, chu, strlen(chu));
        int index = 0;
        for (char data_i : data)
        {
            index = data_i - 'a';
            if (--node->nexts[index]->pass == 0) //进入分支,且是单一要删除的链路
            {
                destory(node->nexts[index]); //进入分支释放内存
                node->nexts[index] = nullptr;
                return;
            }
            node = node->nexts[index];
        }
        node->end--;
    }
}

int main()
{
    TrieTree tree1;
    tree1.insert("abcde");
    tree1.insert("abbbb");
    tree1.insert("abccc");
    cout << "abcde 出现的次数 :" << tree1.search("abcde") << endl
         << "以 abc 开头的字符串出现的次数 :" << tree1.prefix_number("abc") << endl;
    tree1.delete_data("abcde");
    cout << "删除 abcde 后" << endl
         << "abcde 出现的次数 :" << tree1.search("abcde") << endl
         << "以 abc 开头的字符串出现的次数 :" << tree1.prefix_number("abc");
    return 0;
}

结果:

在这里插入图片描述


引用:

链接: 李滚滚 – 前缀树及C++实现.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值