上圖來自luogu題解ios
這是一種字典樹,不過本文講的不是這種圖,本文要講一種更通俗易懂的(博主我的觀點)spa
我要講的是每一個節點只存一個字母或數字,經過打標記的方法實現find的指針
像這樣
上圖來自百度百科code
我不想寫那些很難搞的指針,雖然用指針會使程序簡單明瞭,可能之後會更新上指針版的吧,咕咕咕blog
我的認爲存儲字符串只須要按順序就能夠了,這應該也是字典樹的精髓字符串
如要順序存儲下面的字符串:"lyqalioi","orzliuzitong","zbqisredsun","orztzt".......get
只需用tree[i][j]來表示以i爲根的j號孩子的編號(仔細搞搞這裏,比較難懂)
用flag[i]來表示以i號節點爲結束的字符串有沒有(前面的描述不太準確,就是到i號節點的字符串有沒有)
而後就能夠迭代根編號root了博客
void add(char *s) { int len=strlen(s),root=0/*root爲根節點,初始化0*/,id/*id是編號用char-'a'表示*/; for(int i=0;i<len;++i) { id=s[i]-'a'; if(!tree[root][id]) tree[root][id]=++sum; root=tree[root][id];//更新根節點,以前在博客裏寫了 } flag[root]=true;//更新標記 }
若是完全懂了上面這裏就不用看了string
這裏就不解釋了和上面同樣
bool find(char *s) { int len=strlen(s),root=0/*root爲根節點,初始化0*/,id/*id是編號用char-'a'表示*/; for(int i=0;i<len;++i) { id=s[i]-'a'; if(!tree[root][id]) return false; root=tree[root][id]; } if(flag[root]==true) return true;//看有沒有出現以root結束的字符串 else return false; }
代碼比較複雜,不過效率比上文的高不少,因此本文也會講解
大多數字典樹的題目都不會直接讓你搞一棵樹就完一般會帶有一些附加條件,會在下面的例題中有涉及
就是統計了個sum[root]沒什麼好說的
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> #define int long long int using namespace std; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } const int MAXN=2e6+5; int tree[MAXN][30],tot,sum[MAXN]; void add(char *s) { int root=0,id,len=strlen(s); for(int i=0; i<len; ++i) { id=s[i]-'a'; if(!tree[root][id]) tree[root][id]=++tot; sum[tree[root][id]]++; root=tree[root][id]; } } int find(char *s) { int root=0,id,len=strlen(s); for(int i=0; i<len; ++i) { id=s[i]-'a'; if(!tree[root][id]) return 0; root=tree[root][id]; } return sum[root]; } char s[MAXN]; signed main() { while(gets(s)) { if(s[0]=='\0') break; add(s); } while(scanf("%s",s)!=EOF) { cout<<find(s)<<'\n'; } return 0; }