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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Trie树的常见应用大总结(面试+附代码实现)

發(fā)布時間:2025/3/15 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Trie树的常见应用大总结(面试+附代码实现) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
(一)Trie的簡介
Trie樹,又稱字典樹,單詞查找樹或者前綴樹,是一種用于快速檢索的多叉樹結構,如英文字母的字典樹是一個26叉樹,數字的字典樹是一個10叉樹。他的核心思想是空間換時間,空間消耗大但是插入和查詢有著很優(yōu)秀的時間復雜度。
(二)Trie的定義

Trie樹的鍵不是直接保存在節(jié)點中,而是由節(jié)點在樹中的位置決定。一個節(jié)點的所有子孫都有相同的前綴(prefix),從根節(jié)點到當前結點的路徑上的所有字母組成當前位置的字符串,結點可以保存當前字符串、出現次數、指針數組(指向子樹)以及是否是結尾標志等等。

[cpp]?view plain?copy
  • typedef?struct?Trie_Node??
  • {??
  • ????char?count[15];??????//單詞前綴出現的次數???
  • ????struct?Trie_Node*?next[MAXN];????//指向各個子樹的指針???
  • ????bool?exist;????//標記結點處是否構成單詞???
  • }Trie;??
  • Trie樹可以利用字符串的公共前綴來節(jié)約存儲空間,如下圖所示:


    它有3個基本性質:
    (1) 根節(jié)點不包含字符,除根節(jié)點外每一個節(jié)點都只包含一個字符。
    (2) 從根節(jié)點到某一節(jié)點,路徑上經過的字符連接起來,為該節(jié)點對應的字符串。
    (3) 每個節(jié)點的所有子節(jié)點包含的字符都不相同。
    (三)Trie樹的基本操作
    (1)插入操作
    按下標索引逐個插入字母,若當前字母存在則繼續(xù)下一個,否則new出當前字母的結點,所以插入的時間復雜度只和字符串的長度n有關,為O(n)。

    [cpp]?view plain?copy
  • void?Insert(Trie?*root,?char*?s,char?*add)??
  • {??
  • ????Trie?*p=root;??
  • ????while(*s!='\0')??
  • ????{??
  • ????????if(p->next[*s-'a']==NULL)??
  • ????????{??
  • ????????????p->next[*s-'a']=createNode();??
  • ????????}??
  • ????????p=p->next[*s-'a'];??
  • ???????//?p->count=add;??
  • ????????++s;???
  • ????}??
  • ????p->exist=true;???
  • ????strcpy(p->count,add);??
  • }??
  • (2)查詢操作
    和插入操作相仿,若查詢途中某一個結點并不存在,則直接就return返回。否則繼續(xù)下去,當字符串結束時,trie樹上也有結束標志,那么證明此字符串存在,return true;

    [cpp]?view plain?copy
  • int?Search(Trie*?root,const?char*?s)??
  • {??
  • ????Trie?*p=root;??
  • ????while(*s!='\0')??
  • ????{??
  • ????????p=p->next[*s-'a'];??
  • ????????if(p==NULL)??
  • ????????return?0;??
  • ????????++s;??
  • ????}??
  • ????return?p->count;??
  • }??
  • (3)刪除操作

    一般來說,對Trie單個結點的刪除操作不常見,所以我在這里也只提供遞歸刪除整個樹的操作

    [cpp]?view plain?copy
  • void?del(Trie?*root)??
  • {??
  • ????for(int?i=0;i<MAXN;i++)??
  • ????{??
  • ????????if(root->next[i]!=NULL)??
  • ????????{??
  • ???????????del(root->next[i]);?????
  • ????????}??
  • ????}??
  • //??free(root);?????
  • ???delete?root;??
  • }??
  • (4)遍歷操作

    如果我們想要將trie中的字符串排序輸出,直接先序遍歷即可。

    [cpp]?view plain?copy
  • void?Print(Trie?*root)??
  • {??
  • ????Trie?*p=root;??
  • ????if(p->exist)??
  • ????cout<<p->name<<":?"<<p->count<<endl;??
  • ????for(int?i=0;i<26;i++)??
  • ????{??
  • ????????if(p->next[i]!=NULL){??
  • ????????????Print(p->next[i]);??
  • ????????}??
  • ????}???
  • }???
  • (四)Trie樹的具體應用
    (1)統計前綴出現的次數
    這是Trie最基本的應用,每個結點的字母使用count記錄出現的次數即可。
    這里提供一道題目,hdu 1251供大家練習。

    [cpp]?view plain?copy
  • //hdu?1251???統計前綴出現次數???
  • #include?<cstdio>??
  • #include?<iostream>??
  • #include?<string>??
  • #include?<cstring>??
  • using?namespace?std;??
  • const?int?MAXN=26;??
  • typedef?struct?Trie_Node??
  • {??
  • ????int?count;??????//單詞前綴出現的次數???
  • ????struct?Trie_Node*?next[MAXN];????//指向各個子樹的指針???
  • ????bool?exist;????//標記結點處是否構成單詞???
  • }Trie;??
  • Trie*?createNode()??
  • {??
  • ????//Trie*?p?=(Trie*)malloc(sizeof(Trie));??
  • ????Trie?*p=new?Trie;??
  • ????p->count=0;??
  • ????p->exist=false;??
  • ????memset(p->next,0,sizeof(p->next));??
  • ????return?p;??
  • }??
  • void?Insert(Trie?*root,?const?char*?s)??
  • {??
  • ????Trie?*p=root;??
  • ????while(*s!='\0')??
  • ????{??
  • ????????if(p->next[*s-'a']==NULL)??
  • ????????{??
  • ????????????p->next[*s-'a']=createNode();??
  • ????????}??
  • ????????p=p->next[*s-'a'];??
  • ????????p->count+=1;??
  • ????????++s;???
  • ????}??
  • ????p->exist=true;???
  • }??
  • ??
  • int?Search(Trie*?root,const?char*?s)??
  • {??
  • ????Trie?*p=root;??
  • ????while(*s!='\0')??
  • ????{??
  • ????????p=p->next[*s-'a'];??
  • ????????if(p==NULL)??
  • ????????return?0;??
  • ????????++s;??
  • ????}??
  • ????return?p->count;??
  • }??
  • ??
  • void?del(Trie?*root)??
  • {??
  • ????for(int?i=0;i<MAXN;i++)??
  • ????{??
  • ????????if(root->next[i]!=NULL)??
  • ????????{??
  • ???????????del(root->next[i]);?????
  • ????????}??
  • ????}??
  • //??free(root);?????
  • ???delete?root;??
  • }??
  • int?main()??
  • {??
  • ????char?s[15];??
  • ????bool?flag=false;??
  • ????Trie*?root=createNode();??
  • ????while(gets(s))??
  • ????{??
  • ????????if(flag)??
  • ????????{??
  • ???????????int?ans=Search(root,s);??
  • ???????????printf("%d\n",ans);????
  • ????????}?????
  • ????????else??
  • ????????{??
  • ????????????if(strlen(s)!=0)??
  • ????????????Insert(root,s);??
  • ????????}??
  • ????????if(strlen(s)==0)??
  • ????????flag=true;????
  • ????}??
  • ????del(root);??
  • ????return?0;??
  • }??
  • (2)翻譯(密碼,明文)
    給定一組字符串s,k我們輸入k則需要翻譯成s,也就是說兩者是映射關系。接下來我們給出一段話,讓你翻譯出正常的文章。用map固然簡便,但是Trie的效率更加高。只需要在k的結尾結點出記錄下s即可。
    這里也提供一道題目,hdu 1075。(被注釋的是我原來的程序,wa了,有大神看出來麻煩告訴我一下,謝謝)。

    [cpp]?view plain?copy
  • /*?
  • //hdu?1075映射??
  • #include?<cstdio>?
  • #include?<iostream>?
  • #include?<string>?
  • #include?<cstring>?
  • #include?<stdlib.h>?
  • using?namespace?std;?
  • const?int?MAXN=26;?
  • typedef?struct?Trie_Node?
  • {?
  • ????char?count[15];??????//單詞前綴出現的次數??
  • ????struct?Trie_Node*?next[MAXN];????//指向各個子樹的指針??
  • ????bool?exist;????//標記結點處是否構成單詞??
  • }Trie;?
  • Trie*?createNode()?
  • {?
  • ????Trie*?p?=(Trie*)malloc(sizeof(Trie));?
  • ????p->exist=false;?
  • ????memset(p->next,0,sizeof(p->next));?
  • ????return?p;?
  • }?
  • void?Insert(Trie?*root,?char*?s,char?*add)?
  • {?
  • ????Trie?*p=root;?
  • ????while(*s!='\0')?
  • ????{?
  • ????????if(p->next[*s-'a']==NULL)?
  • ????????{?
  • ????????????p->next[*s-'a']=createNode();?
  • ????????}?
  • ????????p=p->next[*s-'a'];?
  • ???????//?p->count=add;?
  • ????????++s;??
  • ????}?
  • ????p->exist=true;??
  • ????strcpy(p->count,add);?
  • }?
  • ?
  • ?
  • ?
  • void?Search(Trie*?root,?const?char*?s)?
  • {?
  • ????Trie?*p=root;?
  • ????while(*s!='\0')?
  • ????{?
  • ????????if(p->next[*s-'a']==NULL)?
  • ????????{???
  • ????????????printf("%s",s);?
  • ????????????return?;?
  • ????????}?
  • ?????
  • ????????p=p->next[*s-'a'];?
  • ????????++s;?
  • ????}?
  • ????if(p->exist)?
  • ????printf("%s",p->count);?
  • ????else?
  • ????printf("%s",s);?
  • }?
  • ?
  • void?del(Trie?*root)?
  • {?
  • ????for(int?i=0;i<MAXN;i++)?
  • ????{?
  • ????????if(root->next[i]!=NULL)?
  • ????????{?
  • ???????????del(root->next[i]);????
  • ????????}?
  • ????}?
  • ????free(root);????
  • }?
  • int?main()?
  • {?
  • ????char?text[3013],from[15],to[15];?
  • ????Trie*?root=createNode();?
  • ????scanf("%s",from);?
  • ????while(scanf("%s",from),strcmp(from,"END"))?
  • ????{?
  • ????????scanf("%s",to);?
  • ????????Insert(root,to,from);?
  • ????}?
  • ????scanf("%s",from);?
  • ????getchar();?
  • ????while(gets(text),strcmp(text,"END"))?
  • ????{?
  • ????????int?len=strlen(text);?
  • ????????for(int?i=0;i<len;i++)?
  • ????????{?
  • ????????????if(islower(text[i]))?
  • ????????????{?
  • ????????????????int?j=0;?
  • ????????????????char?temp[15];?
  • ????????????????memset(temp,'\0',sizeof(temp));?
  • ????????????????while(islower(text[i]))?
  • ????????????????temp[j++]=text[i++];?
  • ????????????????Search(root,temp);?
  • ??????????????
  • ????????????}?
  • ????????????if(!islower(text[i]))?
  • ????????????printf("%c",text[i]);?
  • ????????}?
  • ????????printf("\n");?
  • ????}?
  • ????return?0;?
  • }?
  • */??
  • ??
  • #include<stdio.h>??
  • #include<string.h>??
  • #include<stdlib.h>??
  • #include<string>??
  • ??
  • using?namespace?std;??
  • ??
  • struct?node{??
  • ????char?dic[15];??
  • ????node?*?next[26];??
  • ????bool?flag;??
  • }*root;??
  • ??
  • node?*build()??
  • {??
  • ????node?*p=(node?*)malloc(sizeof(node));??
  • ????for(int?i=0;i<26;i++)??
  • ????????p->next[i]=NULL;??
  • ????p->flag=false;??
  • ????return?p;??
  • }??
  • ??
  • void?insert(char?*earth,char?*mars)??
  • {??
  • ????int?len=strlen(mars);??
  • ????node?*p;??
  • ????p=root;??
  • ????for(int?i=0;i<len;i++)??
  • ????{??
  • ????????if(p->next[mars[i]-'a']==NULL)??
  • ????????????p->next[mars[i]-'a']=build();??
  • ????????p=p->next[mars[i]-'a'];??
  • ????}??
  • ????p->flag=true;??
  • ????strcpy(p->dic,earth);??
  • }??
  • ??
  • void?query(char?*earth)??
  • {??
  • ????int?len=strlen(earth);??
  • ????node?*p;??
  • ????p=root;??
  • ????for(int?i=0;i<len;i++)??
  • ????{??
  • ????????if(p->next[earth[i]-'a']==NULL)??
  • ????????{??
  • ????????????printf("%s",earth);??
  • ????????????return;??
  • ????????}??
  • ????????p=p->next[earth[i]-'a'];??
  • ????}??
  • ????if(p->flag)??
  • ????????printf("%s",p->dic);??
  • ????else??
  • ????????printf("%s",?earth);??
  • }??
  • ??
  • ??
  • int?main()??
  • {??
  • ????char?earth[15],mars[15],ask[3010];??
  • ??
  • ??
  • ????scanf("%s",earth);??
  • ????root=build();??
  • ????while(scanf("%s",earth),strcmp(earth,"END"))??
  • ????{??
  • ????????scanf("%s",mars);??
  • ????????insert(earth,mars);??
  • ????}??
  • ??
  • ??
  • ????scanf("%s",earth);??
  • ????getchar();??
  • ????while(gets(ask),strcmp(ask,"END"))??
  • ????{??
  • ????????int?len=strlen(ask);??
  • ????????for(int?i=0;i<len;i++)??
  • ????????{??
  • ????????????if(islower(ask[i]))??
  • ????????????{??
  • ????????????????int?j=0;??
  • ????????????????memset(earth,'\0',sizeof(earth));??
  • ????????????????while(islower(ask[i]))??
  • ????????????????????earth[j++]=ask[i++];??
  • ????????????????query(earth);??
  • ????????????}??
  • ????????????if(!islower(ask[i]))??
  • ????????????????printf("%c",ask[i]);??
  • ????????}??
  • ????????printf("\n");??
  • ????}??
  • ??
  • ????return?0;??
  • }??
  • (3)實現搜索引擎的熱門搜索排名
    我的初步想法是和(1)類似,對(1)中的trie進行先序遍歷,將字符串和出現次數存進一個結構體,最后對這個數組進行快速排序,時間復雜度為O(nlogn),看網上說可以利用分治+trie
    +最小堆,我還沒有仔細搞清楚,以后研究完在添加。
    (4)輸入自動補全
    其實原理都差不多,把字符串結尾處的結點當作root,進行先序遍歷,即可得出所有以輸入的字符串為前綴的答案。

    [cpp]?view plain?copy
  • /?自動補全???
  • #include?<cstdio>??
  • #include?<iostream>??
  • #include?<string>??
  • #include?<cstring>??
  • using?namespace?std;??
  • const?int?MAXN=26;??
  • typedef?struct?Trie_Node??
  • {??
  • ????int?count;??????//單詞出現的次數???
  • ????struct?Trie_Node*?next[MAXN];????//指向各個子樹的指針???
  • ????bool?exist;????//標記結點處是否構成單詞???
  • ????char?name[15];??
  • }Trie;??
  • Trie*?createNode()??
  • {??
  • ????Trie*?p?=(Trie*)malloc(sizeof(Trie));??
  • ????p->count=0;??
  • ????p->exist=false;??
  • ????memset(p->next,0,sizeof(p->next));??
  • ????return?p;??
  • }??
  • void?Insert(Trie?*root,char*?word)??
  • {??
  • ????Trie?*p=root;??
  • ????char?*s=word;??
  • ????while(*s!='\0')??
  • ????{??
  • ????????if(p->next[*s-'a']==NULL)??
  • ????????{??
  • ????????????p->next[*s-'a']=createNode();??
  • ????????}??
  • ????????p=p->next[*s-'a'];??
  • ????????++s;???
  • ????}??
  • ?????p->exist=true;???
  • ??????p->count+=1;??
  • ???strcpy(p->name,word);??
  • }??
  • ??
  • Trie*?Search(Trie*?root,?char*?s)??
  • {??
  • ????Trie?*p=root;??
  • ????while(*s!='\0')??
  • ????{??
  • ????????p=p->next[*s-'a'];??
  • ????????if(p==NULL)??
  • ????????return?0;??
  • ????????++s;??
  • ????}??
  • ????return?p;??
  • }??
  • ??
  • void?del(Trie?*root)??
  • {??
  • ????for(int?i=0;i<MAXN;i++)??
  • ????{??
  • ????????if(root->next[i]!=NULL)??
  • ????????{??
  • ???????????del(root->next[i]);?????
  • ????????}??
  • ????}??
  • ????free(root);?????
  • ??
  • }??
  • void?Print(Trie?*root)??
  • {??
  • ????Trie?*p=root;??
  • ????if(p->exist)??
  • ????cout<<p->name<<":?"<<p->count<<endl;??
  • ????for(int?i=0;i<26;i++)??
  • ????{??
  • ????????if(p->next[i]!=NULL){??
  • ????????????Print(p->next[i]);??
  • ????????}??
  • ????}???
  • }???
  • int?main()??
  • {??
  • ????char?s[15];??
  • ????Trie*?root=createNode();??
  • ????for(int?i=0;i<5;i++)??
  • ????{??
  • ????????cin>>s;??
  • ????????Insert(root,s);??
  • ????}??
  • ????while(cin>>s)??
  • ????{??
  • ????????Trie?*ans=Search(root,s);??
  • ????????if(ans)??
  • ????????Print(ans);??
  • ????}??
  • ????del(root);??
  • ????return?0;??
  • }??
  • 原文地址:?http://blog.csdn.net/nk_test/article/details/47836119

    總結

    以上是生活随笔為你收集整理的Trie树的常见应用大总结(面试+附代码实现)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。