淺談「踹」字典樹

字典樹,顧名思義它是棵樹,是棵處理字符串的樹,具體是棵什麼樣的樹呢,咱們能夠舉個栗子:c++

假設如今有四個字符串:ych,yk,devot:數組

那麼這棵樹大概長這個亞子:spa

而圖中加黑的點,也就是每一個單詞的終點;code

主要用於查詢前綴與單詞?blog

而後我們康實現:遞歸

1.插入一個單詞:字符串

首先咱們設置了一個\(trie[i][j]\)數組(這裏設trie樹中全是小寫英文字母,那這樣對於每一個節點,名義上是有26個子節點的。可是顯然咱們不必將空間開的這麼大,由於可能在一組數據中,有些字母是沒有出現過的,因此咱們用多少,開多少),表示以i爲根的子樹裏,第j個字符的編號是多少。get

可能有點抽象,咱們以上圖爲例:it

假設加入單詞的順序是:ych,yk,devotclass

那麼(設1爲根:
\[ trie[1][24]=2;\to y\\ trie[2][2]=3;\ \ \to c\\ trie[3][7]=4;\ \ \to h\\ trie[2][10]=5;\to k\\ trie[1][3]=6;\ \ \to d\\ trie[6][4]=7; \ \ \to e\\ trie[7][14]=8;\to o\\ trie[8][19]=9;\to t \]
從這裏能夠看出,對於一個字母來講,它擁有兩個編號,一個編號是固定不變的,也就是咱們上面數組中的j,而另外一個編號,同一個字母能夠不一樣,取決於加入字典樹的順序,也就是\(trie[i][j]\)的值。

插入時,咱們先判斷是否有這個字母的節點,若是有,就直接在這個節點上繼續操做,若是沒有,新建一個節點,如此下去,一直插入到詞尾

int tot=1;
void insert(char *s,int rt/*根*/) {
    for(int i=0;i<strlen(s);i++) {
        int x=s[i]-'a';
        if(trie[rt][x]==0) trie[rt][x]=++tot;//沒有這個節點,新建
        rt=trie[rt][x];//遞歸下去
    }
    vis[rt]=1;//標記這是一個單詞的最後
}

2.查詢操做與插入操做殊途同歸:

從根開始掃描某個字母是否出現過,順着字典樹往下找,若是中途發現沒有某個節點,則證實沒有;

若是找到最後,但vis[rt]=0,證實字典樹中沒有這個單詞,可是有這個前綴;

bool search(char *s,int rt) {
  for(int i=0;i<strlen(s);i++) {
      int x=s[i]-'a';
      if(trie[rt][x]==0) return 0;
      rt=trie[rt][x];
  }
  if(vis[rt]) 
      return 1;
  return 0;
}

一道很簡單的板子題:

Luogu P2580 因而他錯誤的點名開始了

(記得把數組開大

#include<bits/stdc++.h>

using namespace std;

int n,m;
char a[55];
int vis[1000000],talk[1000000];
int tot=1;
int trie[1000000][27];

void insert(char *s,int rt) {
    for(int i=0;i<strlen(s);i++) {
        int x=s[i]-'a';
        if(trie[rt][x]==0) 
            trie[rt][x]=++tot;
        rt=trie[rt][x];
    }
    vis[rt]=1;
}

int search(char *s,int rt) {
    for(int i=0;i<strlen(s);i++) {
        int x=s[i]-'a';
        if(trie[rt][x]==0) {return 0;}
        rt=trie[rt][x];
    }
    if(talk[rt]&&vis[rt]) 
        return 2;
    if(vis[rt]) {
        talk[rt]=1;
        return 1;
    }
    else {
        return 0;
    }
}

int main() {
    scanf("%d",&n);
    int rt=1;
    for(int i=1;i<=n;i++) {
        scanf("%s",a);
        insert(a,rt);
    }
    scanf("%d",&m);
    int bj;
    for(int i=1;i<=m;i++) {
        scanf("%s",a);
        bj=search(a,rt);
        if(bj==0) printf("WRONG\n");
        if(bj==1) printf("OK\n");
        if(bj==2) printf("REPEAT\n");
    }
    return 0;
}
相關文章
相關標籤/搜索