日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

字符串处理——字典树

發(fā)布時(shí)間:2025/3/17 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 字符串处理——字典树 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

【概述】

字典樹(shù),又稱為單詞查找樹(shù),Tire 樹(shù),是一種樹(shù)形結(jié)構(gòu),它是哈希樹(shù)的變種。

字典樹(shù)與字典很相似,當(dāng)要查一個(gè)單詞是不是在字典樹(shù)中,首先看單詞的第一個(gè)字母是不是在字典的第一層,如果不在,說(shuō)明字典樹(shù)里沒(méi)有該單詞,如果在就在該字母的孩子節(jié)點(diǎn)里找是不是有單詞的第二個(gè)字母,沒(méi)有說(shuō)明沒(méi)有該單詞,有的話用同樣的方法繼續(xù)查找,以此類推。

基本性質(zhì):

  • 字典樹(shù)用邊表示字符
  • 有相同前綴的單詞共用前綴結(jié)點(diǎn)
  • 根節(jié)點(diǎn)不包含字符
  • 每個(gè)單詞結(jié)束的時(shí)候都用一個(gè)特殊字符表示,圖中用的紅色 $ 符
  • 從根節(jié)點(diǎn)到一個(gè)紅點(diǎn)所經(jīng)過(guò)的所有邊的字母就是一個(gè)字符串

應(yīng)用:其常用于統(tǒng)計(jì)、排序和保存大量的字符串(不僅限于字符串),所以經(jīng)常被搜索引擎系統(tǒng)用于文本詞頻統(tǒng)計(jì)。

優(yōu)點(diǎn):其利用字符串的公共前綴來(lái)節(jié)約存儲(chǔ)空間,最大限度地減少無(wú)謂的字符串比較,查詢效率比哈希表高。?

【構(gòu)建過(guò)程】

1.插入

1)思路

對(duì)于字典樹(shù),從左到右掃描一個(gè)單詞,若字母在相應(yīng)根節(jié)點(diǎn)下沒(méi)有出現(xiàn),就插入這個(gè)字母,若出現(xiàn)過(guò),則沿著樹(shù)走下去,看單詞的下一個(gè)字母。

那么此時(shí)產(chǎn)生一個(gè)問(wèn)題,對(duì)于從左到右掃描的這個(gè)單詞,若字母在相應(yīng)根節(jié)點(diǎn)下沒(méi)有出現(xiàn)過(guò),如何去選擇位置插入?計(jì)算機(jī)不會(huì)自動(dòng)選擇位置,因此需要給他指定一個(gè)位置,這樣就需要對(duì)每個(gè)字母進(jìn)行編號(hào)。

設(shè)數(shù)組 tire[i][j]=k,表示編號(hào)為 i 的結(jié)點(diǎn)的第 j 個(gè)孩子是編號(hào)為 k 的結(jié)點(diǎn),此時(shí)有兩種編號(hào):

  • i、k:表示結(jié)點(diǎn)位置的編號(hào),相對(duì)整棵樹(shù)而言,此處相同字母編號(hào)不同
  • j:表示幾點(diǎn) i 的第 j 個(gè)孩子,相對(duì)結(jié)點(diǎn) i 而言,此處編碼應(yīng)按照 ASCLL 碼來(lái)編,用到哪個(gè)編哪個(gè),相同字母編號(hào)相同

以單詞 cat,cash,app,apple,aply,ok 為例,按照輸入順序?qū)ζ溥M(jìn)行編號(hào)?

第一種編號(hào)結(jié)果:

第二種編號(hào)結(jié)果:

經(jīng)過(guò)這樣的編號(hào)后,這樣數(shù)組?trie[i][j]=k,表示編號(hào)為 i 的節(jié)點(diǎn)的第 j 個(gè)孩子是編號(hào)為 k 的節(jié)點(diǎn),那么第一種編號(hào)即為 i、k,第二種編號(hào)即為 j,從而可以實(shí)現(xiàn)插入

2)實(shí)現(xiàn)

int tot=0;//編號(hào) int trie[N][26];//字典樹(shù) int val[N];//字符串結(jié)尾標(biāo)記,val[i]=x表示第i個(gè)節(jié)點(diǎn)的權(quán)值為x void insert(char *s){//插入單詞sint len=strlen(s);//單詞s的長(zhǎng)度int root=0;//字典樹(shù)上當(dāng)前匹配到的結(jié)點(diǎn)for(int i=0;i<len;i++){int id=s[i]-'a';//子節(jié)點(diǎn)編號(hào)if(trie[root][id]==0)//如果之前沒(méi)有從root到id的前綴 trie[root][id]=++tot;//插入root=trie[root][id];//順著字典樹(shù)往下走}val[root]=n; }

2.查找

1)思路

查找有很多種,可以查找某一個(gè)前綴,也可以查找整個(gè)單詞。一般來(lái)說(shuō),對(duì)于一個(gè)單詞,從左到右依次掃描每個(gè)字母,順著字典樹(shù)往下找,能找到這個(gè)字母,往下走,否則結(jié)束查找,即沒(méi)有這個(gè)單詞;單詞掃完了,表示有這個(gè)單詞。

如果是查詢某個(gè)單詞是否在字典樹(shù)中的話,可用布爾變量 vis[i] 表示節(jié)點(diǎn) i 是否是單詞結(jié)束的標(biāo)志,那么返回的是 vis[root],所以在插入操作中插入完每個(gè)單詞時(shí),要對(duì)單詞最后一個(gè)字母的 vis[i] 置為 true

如果是查詢前綴出現(xiàn)的次數(shù)的話,那就在開(kāi)一個(gè)數(shù)組 sum[i],表示位置 i 被訪問(wèn)過(guò)的次數(shù),那么最后返回的是 sum[root],所以插入操作中每訪問(wèn)一個(gè)節(jié)點(diǎn),都要讓他的 sum++。在這里,前綴的次數(shù)是標(biāo)記在前綴的最后一個(gè)字母所在位置的后一個(gè)位置上。

例如:前綴 abc 出現(xiàn)的次數(shù)標(biāo)記在 c 所在位置的后一個(gè)位置上

2)實(shí)現(xiàn)

bool find(char *s){//查詢單詞是否在樹(shù)中int len=strlen(s);//單詞長(zhǎng)度int root=0;//從根結(jié)點(diǎn)開(kāi)始找for(int i=0;s[i];i++){int x=s[i]-'a';if(trie[root][x]==0)//以root為頭結(jié)點(diǎn)的x字母不存在return false;root=trie[root][x];//為查詢下個(gè)字母做準(zhǔn)備,往下走 }return val[root];//找到 }

3.刪除

1)思路

對(duì)于一個(gè)單詞,如果要在樹(shù)中將其刪除,有三種情況:

  • 沒(méi)找到這個(gè)單詞
  • 找到葉節(jié)點(diǎn)的時(shí),葉節(jié)點(diǎn)的 cnt 標(biāo)志清零,代表不是葉節(jié)點(diǎn)
  • 當(dāng)前節(jié)點(diǎn)沒(méi)有其他孩子節(jié)點(diǎn)的時(shí),可直接刪除這個(gè)節(jié)點(diǎn)

2)實(shí)現(xiàn)

void del(char *str,int word){//word為要?jiǎng)h除的單詞的標(biāo)號(hào),一般為seach("單詞");int len=strlen(str);int root=0;if(word==0)//沒(méi)找到單詞return;for(int i=0;i<len;i++){int x=str[i]-'a';if(tire[root][x]==0)//沒(méi)有子節(jié)點(diǎn)return;sum[root]-=cnt;//減去前綴root=tire[root][x];}sum[root]=0;//前綴清零for(int i=0;i<26;i++)//刪除節(jié)點(diǎn)tire[root][i]=0; }

【模版】

1.查詢單詞/前綴是否出現(xiàn)

int tot; int trie[N][26];//trie[rt][x]=tot,root是上個(gè)節(jié)點(diǎn)編號(hào),x是字母,tot是下個(gè)節(jié)點(diǎn)編號(hào) //bool vis[N];//查詢整個(gè)單詞用 void insert(char *s,int root){for(int i=0;s[i];i++){int x=s[i]-'a';if(trie[root][x]==0)//現(xiàn)在插入的字母在之前同一節(jié)點(diǎn)處未出現(xiàn)過(guò) trie[root][x]=++tot;//字母插入一個(gè)新的位置,否則不做處理 root=trie[root][x];//為下個(gè)字母的插入做準(zhǔn)備 }//vis[root]=true;//標(biāo)志該單詞末位字母的尾結(jié)點(diǎn),在查詢整個(gè)單詞時(shí)用 } bool find(char *s,int root){for(int i=0;s[i];i++){int x=s[i]-'a';if(trie[root][x]==0)return false;//以root為頭結(jié)點(diǎn)的x字母不存在,返回0 root=trie[root][x];//為查詢下個(gè)字母做準(zhǔn)備 }return true;//return vis[root];//查詢整個(gè)單詞時(shí) }int main(){int n,m;char s[22];tot=1;cin>>n;//插入單詞個(gè)數(shù)for(int i=1;i<=n;i++){cin>>s;insert(s,1);}cin>>m;//查詢單詞個(gè)數(shù)for(int i=1;i<=n;i++){cin>>s;if(find(s,1))printf("YES\n");else printf("NO\n");}return 0; }

2.查詢前綴出現(xiàn)次數(shù)

int trie[400001][26],tot; int sum[400001]; void insert(char *s){int root=0;int len=strlen(s);for(int i=0;i<len;i++){int id=s[i]-'a';if(!trie[root][id]) trie[root][id]=++tot;sum[trie[root][id]]++;//前綴保存 root=trie[root][id];} } int search(char *s){int root=0;int len=strlen(s);for(int i=0;i<len;i++){//root經(jīng)過(guò)循環(huán)后變成前綴最后一個(gè)字母所在位置int id=s[i]-'a';if(!trie[root][id]) return 0;root=trie[root][id];}return sum[root]; } int main(){int n,m;char s[11];tot=1;cin>>n;//插入單詞個(gè)數(shù)for(int i=1;i<=n;i++){cin>>s;insert(s);}cin>>m;//查詢次數(shù)for(int i=1;i<=m;i++){cin>>s;printf("%d\n",search(s));} }

3.結(jié)構(gòu)體實(shí)現(xiàn)的增刪查字典樹(shù)

struct Node{int sum;//前綴int next[26];//子節(jié)點(diǎn)void init(){sum=0;memset(next,-1,sizeof next);} }tire[N]; int tot; void insert(char *str){int len=strlen(str);int root=0;for(int i=0;i<len;i++){int x=str[i]-'a';if(tire[root].next[x]==-1)tire[root].next[x]=tot++;root=tire[root].next[x];tire[root].sum++;} } int search(char *str){int len=strlen(str);int root=0;for(int i=0;i<len;i++){int x=str[i]-'a';if(tire[root].next[x]==-1)return 0;root=tire[root].next[x];}return tire[root].sum; } void del(char *str,int word){int len=strlen(str);int root=0;if(word<0)return;for(int i=0;i<len;i++){int x=str[i]-'a';if(tire[root].next[x]==-1)return;tire[root].sum-=word;root=tire[root].next[x];}tire[root].sum=0;for(int i=0;i<26;i++)tire[root].next[i]=-1; }int main(){tot=1;for(int i=0;i<N;i++)tire[i].init();int t;scanf("%d",&t);while(t--){char str[10],word[35];scanf("%s%s",str,word);if(str[0]=='i')//插入insert(word);else if(str[0]=='d')//刪除del(word,search(word));else{//查詢if(search(word)>0)printf("Yes\n");elseprintf("No\n");}}return 0; }

4.輸出唯一前綴

int tot; int trie[N][26];//trie[rt][x]=tot,root是上個(gè)節(jié)點(diǎn)編號(hào),x是字母,tot是下個(gè)節(jié)點(diǎn)編號(hào) int val[N]; void insert(char *s,int root){int len=strlen(s);for(int i=0;i<len;i++){int x=s[i]-'a';if(trie[root][x]==0){//現(xiàn)在插入的字母在之前同一節(jié)點(diǎn)處未出現(xiàn)過(guò)trie[root][x]=tot;//字母插入一個(gè)新的位置,否則不做處理val[tot]=0;//記錄以當(dāng)前結(jié)點(diǎn)為根的子樹(shù)下單詞個(gè)數(shù)tot++;}root=trie[root][x];//為下個(gè)字母的插入做準(zhǔn)備val[root]++;} } void find(char *s,int root){int len=strlen(s);for(int i=0;i<len;i++){int x=s[i]-'a';root=trie[root][x];//為查詢下個(gè)字母做準(zhǔn)備printf("%c",s[i]);//輸出當(dāng)前字母if(val[root]==1)//為1時(shí)直接返回return;} } char word[N][50]; int main(){int cnt=0;tot=1;while(scanf("%s",word[cnt])!=EOF)insert(word[cnt++],0);for(int i=0;i<cnt;i++){//枚舉所有單詞printf("%s ",word[i]);find(word[i],0);printf("\n");}return 0; }

【例題】

  • 統(tǒng)計(jì)難題(HDU-1251)(查詢前綴次數(shù)):點(diǎn)擊這里
  • Hat’s Words(HDU-1247)(字典樹(shù)+單詞劃分):點(diǎn)擊這里
  • Problem C(HDU-5687)(帶刪除的字典樹(shù)):點(diǎn)擊這里
  • Phone List(HDU-1671)(有限空間+指針的靈活應(yīng)用):點(diǎn)擊這里
  • Shortest Prefixes(POJ-2001)(輸出唯一前綴):點(diǎn)擊這里

總結(jié)

以上是生活随笔為你收集整理的字符串处理——字典树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产色站| www夜片内射视频日韩精品成人 | 性歌舞团一区二区三区视频 | 人人澡人人爱 | 亚洲综合一区二区 | xxxxwww国产 | 久久久久玖玖 | 操极品美女| 骚狐网站 | 性欧美8khd高清极品 | 日本黄在线观看 | 五月天久久久久久 | 日韩在线观看视频一区二区三区 | 17c国产精品一区二区 | 日韩精品无码一区二区三区久久久 | 久草视频在线播放 | 美日韩一区二区三区 | 在线a视频| 河北彩花中文字幕 | 国产色影院 | 男受被做哭激烈娇喘gv视频 | 亚洲精品一区二区三区在线观看 | 大地资源二中文在线影视免费观看 | 亚洲一区二区三区在线视频 | 国产精品乱码 | 一区二区日韩国产 | 成年人免费视频观看 | 欧美日日夜夜 | 五月婷婷六月激情 | 午夜性刺激免费视频 | 大肉大捧一进一出好爽动态图 | 成人国产精品免费观看视频 | 色臀| jizzjizz视频 | 久久精品国产亚洲av无码娇色 | 亚洲激情成人 | 麻豆影视av | 久久久久国色av免费观看性色 | 国产成人av网站 | 根深蒂固在线观看 | 99精品区 | 色在线视频| 国产精品一区二区自拍 | 久久精品免费看 | 日本免费网站视频 | 久久久网 | 涩视频在线观看 | 日韩精品中文在线 | 性欧美极品另类 | 亚洲一线二线在线观看 | 国产精品久久久91 | 色综综| 男受被做哭激烈娇喘gv视频 | 亚洲精品福利网站 | 特黄老太婆aa毛毛片 | 精品无码人妻少妇久久久久久 | 亚洲精品成人 | 漂亮少妇高潮午夜精品 | 99福利在线 | 久久久久国产精 | 丰满av| 国产人妻互换一区二区 | 中文字幕亚洲欧美日韩在线不卡 | 夜夜操国产 | 丰满人妻翻云覆雨呻吟视频 | www.av在线视频 | 久久777| 一区二区高清在线 | 精品国产一区二区三区久久久蜜月 | 日批视频网站 | 黄色av网站在线观看 | 成人性生生活性生交3 | 免费爱爱网站 | 日韩av在线看 | 国产情侣免费视频 | 亚洲免费一区二区 | 欧美特黄| 黄色片在线看 | 丰满人妻一区二区三区四区53 | 色欧美在线| 成人91在线| 男女超碰 | 国产一级片免费看 | 草1024榴社区成人 | 自拍偷拍专区 | 国产在线观看一区 | 噜噜噜视频 | 日韩一级 | jizz在线看| 好看的国产精品 | 婷婷综合五月天 | 成人影视在线播放 | 91欧美亚洲 | 成年网站免费在线观看 | 免费的黄网站 | 五月天综合在线 | 国产精品天天看 | 狠狠爱亚洲 | 爱综合网 |