高级数据结构 Trie树(字典树)

这篇具有很好参考价值的文章主要介绍了高级数据结构 Trie树(字典树)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

高级数据结构 Trie树(字典树)

(Trie Tree)字典树_Rkun18的博客-CSDN博客

字典树节点表示

#define TRIE_MAX_CHAR_NUM 26
//这里你可以自由设置 根据不同需求设置 如果有大小或者其他符号你就需要增大这个数字

struct TrieNode{
    TrieNode *child[TRIE_MAX_CHAR_NUM];
    bool isEnd;
    TrieNode():isEnd(false){
        for (int i = 0; i < TRIE_MAX_CHAR_NUM; ++i) {
            child[i]=0;
        }
    }
};

构造字典树

这里使用维基百科里的一幅图举例,由于只是举例,使用较小的26个字母,把大小写统一规定成小写,图里’A’变成’a’,方便构造树

高级数据结构 Trie树(字典树)

int main() {
    TrieNode root;//根
    TrieNode n1,n2,n3;//树的第一层
    root.child['t'-'a']=&n1;
    root.child['a'-'a']=&n2;
    root.child['i'-'a']=&n3;
    n2.isEnd= true;//单个字符串走到末尾
    n3.isEnd= true;
    TrieNode n4,n5,n6;//第二层
    n1.child['o'-'a']=&n4;
    n4.isEnd= true;
    n1.child['e'-'a']=&n5;
    n3.child['n'-'a']=&n6;
    n6.isEnd= true;
    TrieNode n7,n8,n9,n10;//最后一层
    n5.child['a'-'a']=&n7;
    n7.isEnd= true;
    n5.child['d'-'a']=&n8;
    n8.isEnd= true;
    n5.child['n'-'a']=&n9;
    n9.isEnd= true;
    n6.child['n'-'a']=&n10;
    n10.isEnd= true;
    preorder(&root,0);//先序遍历







    return 0;
}

先序遍历

void preorder(TrieNode *node,int layer){
    for (int i = 0; i < TRIE_MAX_CHAR_NUM; ++i) {
        if(node->child[i]){
            for (int j = 0; j <layer ; ++j) {
                printf("-");
            }
            printf("%c",i+'a');
            if(node->child[i]->isEnd){
                printf("[done]");
            }
            printf("\n");
            preorder(node->child[i],layer+1);
        }


    }

}

main方法运行:

a[done]  
i[done]  
-n[done] 
--n[done]
t        
-e       
--a[done]
--d[done]
--n[done]
-o[done] 

Trie获取所有单词

  • 深度搜索trie树,对于正在搜索的节点node

  • 遍历该节点的所有孩子指针child[i],如果指针不为空,将child[i]对应字符放入栈里

  • 如果孩子指针isEnd为真,从栈底到栈顶对栈遍历,生成字符串,将它保存至结果数组中去

  • 深度搜索child[i]

  • 弹出栈顶字符

void get_all_word(TrieNode *node, string &word, vector<string> &wordList) {
    for (int i = 0; i < TRIE_MAX_CHAR_NUM; ++i) {
        if (node->child[i]) {
            word.push_back((char) i + 'a');//字符入栈
            if (node->child[i]->isEnd) {
                wordList.push_back(word);
            }
            get_all_word(node->child[i], word, wordList);
            word.erase(word.length() - 1, 1);//弹出栈顶字符

        }

    }
}

int main() {
    TrieNode root;//根
    TrieNode n1, n2, n3;//树的第一层
    root.child['t' - 'a'] = &n1;
    root.child['a' - 'a'] = &n2;
    root.child['i' - 'a'] = &n3;
    n2.isEnd = true;//单个字符串走到末尾
    n3.isEnd = true;
    TrieNode n4, n5, n6;//第二层
    n1.child['o' - 'a'] = &n4;
    n4.isEnd = true;
    n1.child['e' - 'a'] = &n5;
    n3.child['n' - 'a'] = &n6;
    n6.isEnd = true;
    TrieNode n7, n8, n9, n10;//最后一层
    n5.child['a' - 'a'] = &n7;
    n7.isEnd = true;
    n5.child['d' - 'a'] = &n8;
    n8.isEnd = true;
    n5.child['n' - 'a'] = &n9;
    n9.isEnd = true;
    n6.child['n' - 'a'] = &n10;
    n10.isEnd = true;
    vector<string> wordList;
    string word = "";
    get_all_word(&root, word, wordList);
    for (int i = 0; i < wordList.size(); ++i) {
        cout << wordList[i] << endl;
    }


    return 0;
}
a
i  
in 
inn
tea
ted
ten
to 

整体功能

class Trie{
public:
    Trie(){
    }
    ~Trie(){
        for (int i = 0; i <_node_vec.size() ; ++i) {
             delete _node_vec[i];
        }
    } //插入
    void insert(const char *word){

    }//查找
    bool search(const char *word){

    }//是否有以某个字符串为前缀的
    bool startsWith(const char *prefix){

    }
    TrieNode *root(){
        return &_root;
    }


private:
    TrieNode *newNode(){
        TrieNode *node=new TrieNode();
        _node_vec.push_back(node);
        return node;

    }
    vector<TrieNode *>_node_vec;
    TrieNode _root;
};

插入

  • 使用指针ptr指向root

  • 逐个遍历待插入字符串中的各个字符

  • 计算下标pos=’正在遍历字符’-‘a’

  • 如果ptr指向第pos孩子为假:

  • 创建该节点第pos个孩子

  • ptr指向该节点的第pos个孩子

  • 标记ptr指向节点的isEnd为true

   void insert(const char *word){
        TrieNode *ptr=&_root;
        while (*word){
            int pos=*word-'a';
            if(!ptr->child[pos]){
                ptr->child[pos]=newNode();
                
            }
            ptr=ptr->child[pos];
            word++;
            
        }
        ptr->isEnd= true;

    }

搜索

  • 使用ptr指针指向root

  • 逐个遍历带搜索字符各个字符

  • 计算下标pos=’正在遍历字符’-‘a’

  • 如果ptr指向节点第pos个孩子为假:返回假

  • ptr指向第pos个孩子

  • 返回ptr指向节点的isEnd

 bool search(const char *word){
        TrieNode *ptr=&_root;
        while (*word){
            int pos=*word-'a';
            if(!ptr->child[pos]){
                return false;
            }
            ptr=ptr->child[pos];
            word++;
        }
        return ptr->isEnd;

    }

判断前缀是否存在

bool startsWith(const char *prefix){
        TrieNode *ptr=&_root;
        while (*prefix){
            int pos=*prefix-'a';
            if(!ptr->child[pos]){
                return false;
            }
            ptr=ptr->child[pos];
            prefix++;
        }
        return true;

    }

前缀树代码

class Trie{
public:
    Trie(){
    }
    ~Trie(){
        for (int i = 0; i <_node_vec.size() ; ++i) {
             delete _node_vec[i];
        }
    }
    void insert(const char *word){
        TrieNode *ptr=&_root;
        while (*word){
            int pos=*word-'a';
            if(!ptr->child[pos]){
                ptr->child[pos]=newNode();

            }
            ptr=ptr->child[pos];
            word++;

        }
        ptr->isEnd= true;

    }
    bool search(const char *word){
        TrieNode *ptr=&_root;
        while (*word){
            int pos=*word-'a';
            if(!ptr->child[pos]){
                return false;
            }
            ptr=ptr->child[pos];
            word++;
        }
        return ptr->isEnd;

    }
    bool startsWith(const char *prefix){
        TrieNode *ptr=&_root;
        while (*prefix){
            int pos=*prefix-'a';
            if(!ptr->child[pos]){
                return false;
            }
            ptr=ptr->child[pos];
            prefix++;
        }
        return true;

    }
    TrieNode *root(){
        return &_root;
    }


private:
    TrieNode *newNode(){
        TrieNode *node=new TrieNode();
        _node_vec.push_back(node);
        return node;

    }
    vector<TrieNode *>_node_vec;
    TrieNode _root;
};

测试

int main() {
    Trie trie;
    trie.insert("hello");
    trie.insert("echo");
    trie.insert("eleven");
    trie.insert("how");
    cout<<"preorder_trie:"<<endl;
    preorder(trie.root(),0);
    vector<string>ls;
    string word;
    cout<<"All words:"<<endl;
    get_all_word(trie.root(),word,ls);
    for (int i = 0; i < ls.size(); ++i){
        cout<<ls[i]<<endl;
    }
    cout<<"Search:"<<endl;
    printf("hello :%d\n",trie.search("hello"));
    printf("hel :%d\n",trie.search("hel"));
    cout<<"StartsWith:"<<endl;
    printf("hello :%d\n",trie.startsWith("hello"));
    printf("hel :%d\n",trie.startsWith("hel"));




    return 0;
}
e             
-c            
--h           
---o[done]    
-l            
--e           
---v          
----e         
-----n[done]  
h             
-e            
--l           
---l          
----o[done]   
-o            
--w[done]     
All words:    
echo          
eleven        
hello         
how           
Search:       
hello :1      
hel :0        
StartsWith:
hello :1
hel :1

208. 实现 Trie (前缀树)

力扣

直接使用Trie类,改个名,调用方法把string通过c_str(),变成字符数组

#define TRIE_MAX_CHAR_NUM 26
//这里你可以自由设置 根据不同需求设置 如果有大小或者其他符号你就需要增大这个数字

struct TrieNode{
    TrieNode *child[TRIE_MAX_CHAR_NUM];
    bool isEnd;
    TrieNode():isEnd(false){
        for (int i = 0; i < TRIE_MAX_CHAR_NUM; ++i) {
            child[i]=0;
        }
    }
};


using namespace std;
class Trie1{
public:
    Trie1(){
    }
    ~Trie1(){
        for (int i = 0; i <_node_vec.size() ; ++i) {
             delete _node_vec[i];
        }
    }
    void insert(const char *word){
        TrieNode *ptr=&_root;
        while (*word){
            int pos=*word-'a';
            if(!ptr->child[pos]){
                ptr->child[pos]=newNode();

            }
            ptr=ptr->child[pos];
            word++;

        }
        ptr->isEnd= true;

    }
    bool search(const char *word){
        TrieNode *ptr=&_root;
        while (*word){
            int pos=*word-'a';
            if(!ptr->child[pos]){
                return false;
            }
            ptr=ptr->child[pos];
            word++;
        }
        return ptr->isEnd;

    }
    bool startsWith(const char *prefix){
        TrieNode *ptr=&_root;
        while (*prefix){
            int pos=*prefix-'a';
            if(!ptr->child[pos]){
                return false;
            }
            ptr=ptr->child[pos];
            prefix++;
        }
        return true;

    }
    TrieNode *root(){
        return &_root;
    }


private:
    TrieNode *newNode(){
        TrieNode *node=new TrieNode();
        _node_vec.push_back(node);
        return node;

    }
    vector<TrieNode *>_node_vec;
    TrieNode _root;
};







class Trie {
public:
    Trie() {

    }
    
    void insert(string word) {
       trie.insert(word.c_str());
    }
    
    bool search(string word) {
       return trie.search(word.c_str());
    }
    
    bool startsWith(string prefix) {
        return trie.startsWith(prefix.c_str());
    }
private:
   Trie1 trie;
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj->insert(word);
 * bool param_2 = obj->search(word);
 * bool param_3 = obj->startsWith(prefix);
 */

211. 添加与搜索单词 - 数据结构设计

力扣

这里考虑搜索遇到’.'如何

  • 当遍历到单词结束时

  • 如果node指向的节点标记为单词的结尾(isEnd==true)返回真,否则返回假

  • 如果word遇到’.’

  • 遍历所有node的孩子指针,继续递归搜索,单词指针向前移动一个位置,如果递归搜索结果为真,返回真

  • 如果不是’.’

  • 计算孩子位置pos,pos指向当前孩子为真,继续深搜,指针向前移动一个位置,如果搜索结果为真,返回真

下面来改写这个search方法文章来源地址https://www.toymoban.com/news/detail-430451.html

#define TRIE_MAX_CHAR_NUM 26
//这里你可以自由设置 根据不同需求设置 如果有大小或者其他符号你就需要增大这个数字

struct TrieNode {
    TrieNode *child[TRIE_MAX_CHAR_NUM];
    bool isEnd;

    TrieNode() : isEnd(false) {
        for (int i = 0; i < TRIE_MAX_CHAR_NUM; ++i) {
            child[i] = 0;
        }
    }
};




class Trie {
public:
    Trie() {
    }

    ~Trie() {
        for (int i = 0; i < _node_vec.size(); ++i) {
            delete _node_vec[i];
        }
    }

    void insert(const char *word) {
        TrieNode *ptr = &_root;
        while (*word) {
            int pos = *word - 'a';
            if (!ptr->child[pos]) {
                ptr->child[pos] = newNode();

            }
            ptr = ptr->child[pos];
            word++;

        }
        ptr->isEnd = true;

    }

    bool search_tire(TrieNode *node, const char *word) {
        if (*word == '\0') {
            if (node->isEnd) {
                return true;
            }
            return false;
        }
        if (*word == '.') {
            for (int i = 0; i < TRIE_MAX_CHAR_NUM; ++i) {
                if (node->child[i] && search_tire(node->child[i], word + 1)) {
                    return true;
                }

            }
        } else {
            int pos = *word - 'a';
            if (node->child[pos] && search_tire(node->child[pos], word + 1)) {
                return true;
            }
        }
        return false;


    }

    bool startsWith(const char *prefix) {
        TrieNode *ptr = &_root;
        while (*prefix) {
            int pos = *prefix - 'a';
            if (!ptr->child[pos]) {
                return false;
            }
            ptr = ptr->child[pos];
            prefix++;
        }
        return true;

    }

    TrieNode *root() {
        return &_root;
    }


private:
    TrieNode *newNode() {
        TrieNode *node = new TrieNode();
        _node_vec.push_back(node);
        return node;

    }

    vector<TrieNode *> _node_vec;
    TrieNode _root;
};



class WordDictionary {
public:
    WordDictionary() {

    }
    
    void addWord(string word) {
        trie.insert(word.c_str());


    }
    
    bool search(string word) {
       return trie.search_tire(trie.root(),word.c_str());
    }
private:
      Trie trie;
};

/**
 * Your WordDictionary object will be instantiated and called as such:
 * WordDictionary* obj = new WordDictionary();
 * obj->addWord(word);
 * bool param_2 = obj->search(word);
 */

到了这里,关于高级数据结构 Trie树(字典树)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构基础】树 - 前缀树(Trie Tree)

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

    2024年02月07日
    浏览(45)
  • LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】

    博主介绍:✌目前全网粉丝2W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技术内容:Java后端、算法、分布式微服务、中间件、前端、运维、ROS等。 博主所有博客文件目录索引:博客目录索引(持续更新) 视频平台:

    2024年02月19日
    浏览(41)
  • 数据结构---字典树(Tire)

    字典树是一种能够快速插入和查询字符串的多叉树结构,节点的编号各不相同,根节点编号为0 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。 核心思想也是通过空间来换取时间上的效率 在一定情况下字典树的效率要比哈希表要高 字典树

    2024年02月21日
    浏览(48)
  • 字典树的数据结构

    Trie字典树主要用于存储字符串, Trie 的每个 Node 保存一个字符。用链表来描述的话,就是一个字符串就是一个链表。每个Node都保存了它的所有子节点。 例如我们往字典树中插入 see、pain、paint 三个单词,Trie字典树如下所示: 也就是说如果只考虑小写的26个字母,那么Trie字典

    2024年02月12日
    浏览(45)
  • 【Redis】基础数据结构-字典

    基本语法 字典是Redis中的一种数据结构,底层使用哈希表实现,一个哈希表中可以存储多个键值对,它的语法如下,其中KEY为键,field和value为值(也是一个键值对): 根据Key和field获取value: 哈希表 数据结构 dictht dictht是哈希表的数据结构定义: table:哈希表数组,数组中的

    2024年02月07日
    浏览(37)
  • 一键导出数据库中表结构定义(数据字典)的工具

    导出数据库中标的定义,即所谓的数据字典 一、新建maven工程中加入依赖 在maven工程的pom.xml中添加依赖 二、在maven工程,将如下GenerateDocument .java文件加入工程中; 修改想要导出的mysql链接参数,直接执行即可导入数据库设计的word文档

    2024年02月06日
    浏览(70)
  • 【Python】基础数据结构:列表——元组——字典——集合

    Python提供了多种内置的数据结构,包括列表( List )、元组( Tuple )和字典( Dictionary )。这些数据结构在Python编程中都有着广泛的应用,但它们各有特点和适用场景。 列表是一种有序的集合,可以随时添加和删除其中的元素。列表是可变的,也就是说,你可以修改列表的

    2024年02月10日
    浏览(51)
  • Python-基础篇-数据结构-列表、元组、字典、集合

    列表、元组 字典、集合 💬正如在现实世界中一样,直到我们拥有足够多的东西,才迫切需要一个储存东西的容器,这也是我坚持把数据结构放在最后面的原因一一直到你掌握足够多的技能,可以创造更多的数据,你才会重视数据结构的作用。这些储存大量数据的容器,在

    2024年01月21日
    浏览(129)
  • 211. 添加与搜索单词 - 数据结构设计---------------字典树

    211. 添加与搜索单词 - 数据结构设计 https://leetcode.cn/problems/design-add-and-search-words-data-structure/description/

    2024年02月14日
    浏览(37)
  • Python中列表,元组,集合,字典哪些数据结构支持双向索引?

    在Python中,我们常用的内置数据结构有列表、元组、集合和字典。其中,只有列表和元组支持双向索引,可以通过正向索引和负向索引访问元素。而字典和集合不支持索引。 在Python中,内置的数据结构主要包括: 列表(list):有序,可变的数据集合,可以通过索引访问元素。 元组(tuple)

    2024年02月08日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包