首页 > 编程语言 >C++ 非STL数据结构学习——1.4 字典树

C++ 非STL数据结构学习——1.4 字典树

时间:2024-10-13 11:21:02浏览次数:10  
标签:1.4 index node curr STL word C++ return children

1.字典树的定义

  • 字典树是一种多叉树结构,每个节点代表一个字符,从根节点到某个节点的路径表示一个字符串。
  • 每个节点包含若干指向子节点的指针,通常使用数组、哈希表或其他数据结构来实现。

2. 字典树的基本操作

  • 插入:将一个字符串插入到字典树中。
  • 查找:在字典树中查找一个字符串是否存在。
  • 删除:从字典树中删除一个字符串。

3. 字典树的节点结构

struct TrieNode {
    TrieNode* children[26]; // 26个英文字母
    bool isEndOfWord;       // 标记是否是一个单词的结束
};

 4. 字典树的实现

//插入操作
void insert(string word) {
    TrieNode* curr = root;
    for (char c : word) {
        int index = c - 'a';
        if (!curr->children[index]) {
            curr->children[index] = new TrieNode();
        }
        curr = curr->children[index];
    }
    curr->isEndOfWord = true; // 标记单词结束
}
//查找操作
bool search(string word) {
    TrieNode* curr = root;
    for (char c : word) {
        int index = c - 'a';
        if (!curr->children[index]) {
            return false; // 字符不存在
        }
        curr = curr->children[index];
    }
    return curr != nullptr && curr->isEndOfWord; // 判断是否是一个完整的单词
}
//删除操作部分
//辅助函数,判断是否有子节点
bool nodeIsEmpty(TrieNode* node) {
    for (int i = 0; i < 26; i++) {
        if (node->children[i]) {
            return false; // 仍有子节点,不能删除
        }
    }
    return true; // 没有子节点,可以删除
}

bool deleteWord(string word, int depth, TrieNode* node) {
    if (depth == word.length()) {
        if (!node->isEndOfWord) {
            return false; // 单词不存在
        }
        node->isEndOfWord = false; // 标记单词结束
        return nodeIsEmpty(node); // 判断当前节点是否可以删除
    }

    int index = word[depth] - 'a';
    if (!node->children[index]) {
        return false; // 字符不存在
    }

    // 递归删除下一个字符
    if (deleteWord(word, depth + 1, node->children[index])) {
        delete node->children[index]; // 删除节点
        node->children[index] = nullptr;

        // 如果当前节点没有子节点并且不是单词的结束,则可以删除
        return !node->isEndOfWord && nodeIsEmpty(node);
    }

    return false;
}

完整代码,写成类的形式:

#include <iostream>
#include <string>

using namespace std;

struct TrieNode {
    TrieNode* children[26];
    bool isEndOfWord;
    
    TrieNode() {
        isEndOfWord = false;
        for (int i = 0; i < 26; i++) {
            children[i] = nullptr;
        }
    }
};

class Trie {
private:
    TrieNode* root;
    
public:
    Trie() {
        root = new TrieNode();
    }
    
    void insert(string word) {
        TrieNode* curr = root;
        for (char c : word) {
            int index = c - 'a';
            if (!curr->children[index]) {
                curr->children[index] = new TrieNode();
            }
            curr = curr->children[index];
        }
        curr->isEndOfWord = true;
    }
    
    bool search(string word) {
        TrieNode* curr = root;
        for (char c : word) {
            int index = c - 'a';
            if (!curr->children[index]) {
                return false;
            }
            curr = curr->children[index];
        }
        return curr != nullptr && curr->isEndOfWord;
    }
    
    bool deleteWord(string word) {
        return deleteWordHelper(word, 0, root);
    }
    
private:
    bool deleteWordHelper(string word, int depth, TrieNode* node) {
        if (depth == word.length()) {
            if (!node->isEndOfWord) {
                return false;
            }
            node->isEndOfWord = false;
            return nodeIsEmpty(node);
        }

        int index = word[depth] - 'a';
        if (!node->children[index]) {
            return false;
        }

        if (deleteWordHelper(word, depth + 1, node->children[index])) {
            delete node->children[index];
            node->children[index] = nullptr;
            return !node->isEndOfWord && nodeIsEmpty(node);
        }

        return false;
    }
    
    bool nodeIsEmpty(TrieNode* node) {
        for (int i = 0; i < 26; i++) {
            if (node->children[i]) {
                return false;
            }
        }
        return true;
    }
};

P1. 洛谷p1481魔族密码

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
int finalans=0;
int curans=0;

using namespace std;

struct TrieNode {
    TrieNode* children[26];
    bool isEndOfWord;
    bool visited;
    
    TrieNode() {
        isEndOfWord = false;
        visited=0;
        for (int i = 0; i < 26; i++) {
            children[i] = nullptr;
        }
    }
};

class Trie {
private:
    TrieNode* root;
    
public:
    Trie() {
        root = new TrieNode();
    }
    
    void insert(string word) {
        TrieNode* curr = root;
        for (char c : word) {
            int index = c - 'a';
            if (!curr->children[index]) {
                curr->children[index] = new TrieNode();
            }
            curr = curr->children[index];
        }
        curr->isEndOfWord = true;
    }
    
    bool search(string word) {
        TrieNode* curr = root;
        for (char c : word) {
            int index = c - 'a';
            if (!curr->children[index]) {
                return false;
            }
            curr = curr->children[index];
        }
        return curr != nullptr && curr->isEndOfWord;
    }
    
    bool deleteWord(string word) {
        return deleteWordHelper(word, 0, root);
    }

    void dfs(TrieNode* cur)
    {
        if(cur->visited==1) return;
        cur->visited=1;
        if(cur->isEndOfWord==true)
        {
            curans++;
            finalans=max(finalans,curans);
            //cout<<"当前搜到有效单词尾:"<<"当前ans是:"<<finalans<<endl;
        }

        for(int i=0;i<25;i++)
        {
            if(cur->children[i]) dfs(cur->children[i]);
        }
        if(cur->isEndOfWord==true) curans--;
    }
    void dfs()
    {
        dfs(root);
    }
    
private:
    bool deleteWordHelper(string word, int depth, TrieNode* node) {
        if (depth == word.length()) {
            if (!node->isEndOfWord) {
                return false;
            }
            node->isEndOfWord = false;
            return nodeIsEmpty(node);
        }

        int index = word[depth] - 'a';
        if (!node->children[index]) {
            return false;
        }

        if (deleteWordHelper(word, depth + 1, node->children[index])) {
            delete node->children[index];
            node->children[index] = nullptr;
            return !node->isEndOfWord && nodeIsEmpty(node);
        }

        return false;
    }
    
    bool nodeIsEmpty(TrieNode* node) {
        for (int i = 0; i < 26; i++) {
            if (node->children[i]) {
                return false;
            }
        }
        return true;
    }
};

int main()
{
    int n;cin>>n;
    vector<string> inputs;
    for(int i=1;i<=n;i++)
    {
        string p;cin>>p;
        inputs.push_back(p);
    }
    Trie mytree=Trie();
    for(int i=0;i<inputs.size();i++)
    {
        mytree.insert(inputs[i]);
    }
    mytree.dfs();
    cout<<finalans;
    return 0;
}

 

标签:1.4,index,node,curr,STL,word,C++,return,children
From: https://blog.csdn.net/William_Edmund/article/details/142894261

相关文章

  • Linux下C++程序瘦身
    目录一.前言二.如何瘦身三.如何读取调试信息文件四.其他一.前言我们知道,C++程序如果带着调试信息的话会比较大,所以一般发布版本都会去掉调试信息,但是我们又希望如果程序崩溃了可以使用core转储文件进行调试,如果不带调试信息就不能方便的进行调试,那要怎么办呢,这篇文章......
  • 高中生学习c/c++指导
    一、c与c++关系参考图示:可见,c与c++的基本部分是相同的,会有一些小区别,不妨一起学。DEV-C++能支持C++和C语言编程二、学习资料网站介绍1、C语言初阶——手把手教零基础/新手入门2、C++教程从入门到实战3、C++从0到1入门编程......
  • Springboot在线学习辅导管理系统--49101(免费领源码)可做计算机毕业设计JAVA、PHP、爬虫
    摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对在线学习辅导管理系统等问题,对在线学习辅导管理系统进行研究分析,然后开发设计出在线学习辅......
  • Springboot一个小说阅读APP的设计与实现--48151(免费领源码)可做计算机毕业设计JAVA、PH
    摘 要大数据时代下,数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求,利用互联网服务于其他行业,促进生产,已经是成为一种势不可挡的趋势。在小说在线阅读的需求下,开发一款小说阅读APP,将复杂的系统进行拆分,能够实现对需求的变化快速响应、系统稳定性的保障,能保......
  • 基于SaaS的小区物业管理系统设计与实现--47357(免费领源码)可做计算机毕业设计JAVA、PHP
    摘 要本论文主要论述了如何使用SpringBoot开发一个基于SaaS的小区物业管理系统小程序,本系统将严格按照软件开发流程进行各个阶段的工作,面向对象编程思想进行项目开发。在引言中,作者将论述小区物业管理系统小程序的当前背景以及系统开发的目的,后续章节将严格按照软件开发流程......
  • 每日OJ题_牛客_比那名居的桃子_滑动窗口/前缀和_C++_Java
    目录牛客_比那名居的桃子_滑动窗口/前缀和题目解析C++代码Java代码牛客_比那名居的桃子_滑动窗口/前缀和比那名居的桃子(nowcoder.com)描述:        小红有一天看到了一只桃子,由于桃子看上去就很好吃,小红很想把它吃掉。已知吃下桃子后,每天可以获得ai​的......
  • 从0开始的vscode安装及环境配置教程(C/C++)Windows系统
    1.vscode简介VSCode是微软出的一款轻量级编辑器,它本身只是一款文本编辑器而已,并不是一个集成开发环境(IDE),几乎所有功能都是以插件扩展的形式所存在的。因此,我们想用它编程,不只是把vscode下载下来就行,还需要安装对应编程语言的扩展以及相应的编译器。2.安装vscode进入vscode......
  • C++中比较方便的几个有关字符串的函数
    以下是一些个人总结的C++中对新手来说比较方便使用的几个有关字符串的函数。注意,说的是字符串而不是字符数组。如果有其他,欢迎在评论区留言。1.getline(),这个函数可以输入一行字符串,通常情况下,这个函数的使用通常如下://getline(cin,字符串名);     注意:getline()的......
  • 生产者消费者c++ 讲解和代码示例
    生产者-消费者问题的C++讲解和代码示例一、问题描述生产者-消费者问题是经典的多线程同步问题,涉及两个类型的线程:生产者线程:负责生成数据并放入共享缓冲区。消费者线程:负责从共享缓冲区取出数据进行处理。关键挑战在于:同步:确保生产者和消费者在访问共享缓冲区时不发生......
  • 107-免杀对抗-C&C++&溯源ShellCode上线&混淆变异算法&回调编译执行
    知识点#知识点:1、ShellCode-分析&朔源&感知2、ShellCode-混淆&编码&算法3、回调执行解析-API&汇编&句柄#章节点:编译代码面-ShellCode-混淆编译代码面-编辑执行器-编写编译代码面-分离加载器-编写程序文件面-特征码定位-修改程序文件面-加壳花指令-资源代码加载面-Dll......