trie数组模拟

自闭

数组模拟trie

1.trie存的是字符串,从s[0],开始存

  • 二维数组,第一维记录节点的编号,第二维的索引代表字符,数组值存 节点编号(26个指针,指向下一个节点)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    const int maxn=1e6;
    int tot = 0;//全局变量,记录所以节点的数量
    int endp[maxn];//每个节点编号都可能作为一个字符串的末尾,
    void inserts(string s){
    int ch,p=0;//p=0,代表从空的根节点开始插入值
    for (int i=0;i<s.size();i++) {
    ch = s[i] - 'a';
    if ( trie[p][ch] == 0 )//说明该节点没有走过,给它编号
    trie[p][ch] = ++tot;
    p = trie[p][ch];//p到了下一节点
    }
    endp[p] += 1;//标记该节点为字符串的末尾,或者记录信息
    }
    int query(string s){
    int p=0;
    for (int i=0;i<s.size();i++ ) {
    // p是编号,字符理解为指针的方向
    p = trie[p][s[i] - 'a'];//第2个字符节点的编号
    if ( !p ) //该字符没有节点编号,说明没有存
    return false;
    }
    return true;
    }
  1. trie存数字,按二进制位从高位到低位存,(题目数据会小于第32位符号位的)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    int tot = 0;
    const int maxn=1e5+10;
    int trie[maxn][2];
    void insertn(int num) {
    int p=0;
    for (int i=30;i>=0;i--) {
    int ch = (num>>i) & 1;
    if ( !trie[p][ch] ) trie[p][ch] = ++tot;
    p = trie[p][ch];
    }
    }
    // query()根据题目的需要写
    bool query(int num) {
    int p=0;
    for (int i=30;i>=0;i--) {
    int ch = (num>>i) & 1;
    if ( trie[p][ch] ) p = trie[p][ch];
    else return false;
    }
    return true;
    }

例题:字符串的前缀统计

  • trie的建树,查询
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    #include <iostream>
    #include <string>
    using namespace std;
    const int maxn=1e6+10;
    int tot = 0;
    int trie[maxn][26];
    int endnum[maxn];
    void inserts(string s){
    int p=0,ch;
    for (int i=0;i<s.size();i++) {
    ch = s[i]-'a';
    if (!trie[p][ch]) trie[p][ch]=++tot;
    p = trie[p][ch];
    }
    ++endnum[p];//以编号p结尾的字符串 个数+1
    }

    int query(string s){
    int p=0;
    int ans = 0;//统计字符串前缀的个数
    for (int i=0;i<s.size();i++) {
    // endnum[0] 不可能作为string的节点
    p = trie[p][s[i]-'a']; // p点时该字符的下一个字符的地址,
    if ( !p ) break; // p==0 没有下一个字符
    ans += endnum[p];
    }
    return ans;
    }
    char ch[maxn];
    string s;
    int main() {
    // freopen("a.txt","r",stdin);
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;i++) {
    scanf("%s",ch);
    s=ch;
    inserts(s);
    }
    for (int i=0;i<m;i++) {
    scanf("%s",ch);
    s=ch;
    printf("%d\n",query(s));
    }
    return 0;
    }

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!