数据结构与算法——字典(前缀)树的实现

参考视频:左程云--算法讲解044【必备】前缀树原理和代码详解

类实现:

cpp 复制代码
class Trie {
  private:
    class TrieNode {
      public:
        int pass;
        int end;
        vector<TrieNode*> nexts;
        TrieNode(): pass(0), end(0), nexts(26, nullptr) {}
    };

    TrieNode* root;  // 根指针

  public:
    Trie() {
        root = new TrieNode();
    }

    void insert(const string& word) {
        TrieNode* node = root;
        node->pass++;
        int path;
        for(char c : word){
            path = c - 'a';
            if (node->nexts[path] == nullptr) {
                node->nexts[path] = new TrieNode();
            }
            node = node->nexts[path];
            node->pass++;
        }
        node->end++;
    }

    void mydelete(const string& word) {
        if (countWordsEqualTo(word) > 0) {
            TrieNode* node = root;
            node->pass--;
            int path;
            for (char c : word) {
                path = c - 'a';
                if (--node->nexts[path]->pass == 0) {
                    funcDelete(node, path);
                    return;
                }
                node = node->nexts[path];
            }
            node->end--;
        }
    }

    void funcDelete(TrieNode* node, int path) {
        TrieNode* target = node->nexts[path];
        node->nexts[path] = nullptr;
        delete (target);
    }

    bool search(const string& word) {
        return countWordsEqualTo(word) > 0 ? true : false;
    }

    int countWordsEqualTo(const string& word) {
        TrieNode* node = root;
        int path;
        for (char c : word) {
            path = c - 'a';
            if (node->nexts[path] == nullptr) {
                return 0;
            }
            node = node->nexts[path];
        }
        return node->end;
    }

    int prefixNumber(const string& pre) {
        TrieNode* node = root;
        int path;
        for (char c : pre) {
            path = c - 'a';
            if (node->nexts[path] == nullptr) {
                return 0;
            }
            node = node->nexts[path];
        }
        return node->pass;
    }
};

类实现基础上进行哈希表的优化:

cpp 复制代码
class Trie {
private:
    class TrieNode {
    public:
        int pass;
        int end;
        unordered_map<int, TrieNode*> nexts;
        TrieNode() : pass(0), end(0) {}
    };

    TrieNode* root;  // 根指针

public:
    Trie() {
        root = new TrieNode();
    }

    void insert(const string& word) {
        TrieNode* node = root;
        node->pass++;
        int path;
        for (char c : word) {
            path = c - 'a';
            if (node->nexts.find(path) == node->nexts.end()) {
                node->nexts.insert({ path, new TrieNode() });
            }
            node = node->nexts[path];
            node->pass++;
        }
        node->end++;
    }

    void mydelete(const string& word) {
        if (countWordsEqualTo(word) > 0) {
            TrieNode* node = root;
            node->pass--;
            int path;
            for (char c : word) {
                path = c - 'a';
                if (--node->nexts[path]->pass == 0) {
                    node->nexts.erase(path);
                    return;
                }
                node = node->nexts[path];
            }
            node->end--;
        }
    }

    bool search(const string& word) {
        return countWordsEqualTo(word) > 0 ? true : false;
    }

    int countWordsEqualTo(const string& word) {
        TrieNode* node = root;
        int path;
        for (char c : word) {
            path = c - 'a';
            if (node->nexts.find(path) == node->nexts.end()) {
                return 0;
            }
            node = node->nexts[path];
        }
        return node->end;
    }

    int prefixNumber(const string& pre) {
        TrieNode* node = root;
        int path;
        for (char c : pre) {
            path = c - 'a';
            if (node->nexts.find(path) == node->nexts.end()) {
                return 0;
            }
            node = node->nexts[path];
        }
        return node->pass;
    }
};

静态数组实现 + 牛客测试

测试链接:牛客题霸--字典树的实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const static int N = 1e6 + 5;
int trieArr[N][26];
int passArr[N];
int endArr[N];
int cnt;
void helpFunc(int op, string& word);
class trie{
public:
    void static buildTrie(){
        cnt = 1;
    }

    void static insert(const string& word){
        int cur = 1;
        passArr[cur]++;
        int path;
        for(char c : word){
            path = c - 'a';
            if(trieArr[cur][path] == 0){
                trieArr[cur][path] = ++cnt;
            }
            cur = trieArr[cur][path];
            passArr[cur]++;
        }
        endArr[cur]++;
    }

    int static searchCount(const string& word){
        int cur = 1, path;
        for(char c : word){
            path = c - 'a';
            if(trieArr[cur][path] == 0){
                return 0;
            }
            cur = trieArr[cur][path];
        }
        return endArr[cur];
    }

    bool static search(const string& word){
        return searchCount(word) > 0 ? true : false;
    }

    int static prefixCount(const string& pre){
        int cur = 1, path;
        for(char c : pre){
            path = c - 'a';
            if(trieArr[cur][path] == 0){
                return 0;
            }
            cur = trieArr[cur][path];
        }
        return passArr[cur];
    }

    void static deleteWord(const string& word){
        if(searchCount(word) > 0){
            int cur = 1, path;
            passArr[cur]--;
            for(char c : word){
                path = c - 'a';
                if(--passArr[trieArr[cur][path]] == 0){
                    trieArr[cur][path] = 0;
                    return;
                }
                cur = trieArr[cur][path];
            }
            endArr[cur]--;
        }
    }

    void static rebuildTrie(){
        for(int i = 1; i <= cnt; i++){
            fill(&trieArr[i][0], &trieArr[i][0] + 26, 0);
            passArr[i] = 0;
            endArr[i] = 0;
        }
    }
};

int main() {
    int m;
    cin >> m;
    trie::buildTrie();
    while(m--){
        int op;
        string word;
        cin >> op >> word;
        helpFunc(op, word);
    }
    trie::rebuildTrie();
    return 0;
}

void helpFunc(int op, string& word){
    switch(op){
        case 1 :
            trie::insert(word);
            break;
        case 2 :
            trie::deleteWord(word);
            break;
        case 3 :
            if(trie::search(word)){
                cout << "YES" << endl;
            }else{
                cout << "NO" << endl;
            }
            break;
        case 4 :
            cout << trie::prefixCount(word) <<endl;
            break;
        default:
            break;
    }
}
相关推荐
C++业余爱好者2 分钟前
Java 中的数据结构详解及应用场景
java·数据结构·python
ouliten9 分钟前
《Linux C编程实战》笔记:mmap
linux·c++·笔记
小尧嵌入式9 分钟前
深入理解C/C++指针
java·c语言·开发语言·c++·qt·音视频
ULTRA??13 分钟前
字符串处理小写字母转换大写字母
c++·python·rust
fish_xk13 分钟前
c++的字符串string
开发语言·c++
拼好饭和她皆失18 分钟前
二分答案算法详解:从理论到实践解决最优化问题
数据结构·算法·二分·二分答案
DeltaTime22 分钟前
一 图形学概述, 线性代数
c++·图形渲染
月明长歌22 分钟前
【码道初阶】Leetcode234进阶版回文链表:牛客一道链表Hard,链表的回文结构——如何用 O(1) 空间“折叠”链表?
数据结构·链表
CoderYanger29 分钟前
C.滑动窗口-求子数组个数-越长越合法——2962. 统计最大元素出现至少 K 次的子数组
java·数据结构·算法·leetcode·职场和发展
小满、34 分钟前
Redis:高级数据结构与进阶特性(Bitmaps、HyperLogLog、GEO、Pub/Sub、Stream、Lua、Module)
java·数据结构·数据库·redis·redis 高级特性