字典树(前缀树)

字典树==前缀树==Trie树:

查询某个单词(前缀)在所有单词中出现次数的一种数据结构

查询和插入时间复杂度都是O(n),是一种以空间换时间的方法。

(字典树)

字典树基本模板:

  1. #define  MAX    26 //字符集大小  
  2.   
  3. typedef struct TrieNode  
  4. {  
  5.     int nCount; //记录该字符出现次数  
  6.     struct TrieNode *next[MAX];  
  7. }TrieNode;  
  8.   
  9. TrieNode Memory[1000000];  
  10. int allocp = 0;  
  11.   
  12. /*初始化*/  
  13. void InitTrieRoot(TrieNode **pRoot)  
  14. {  
  15.     *pRoot = NULL;  
  16. }  
  17.   
  18. /*创建新结点*/  
  19. TrieNode *CreateTrieNode()  
  20. {  
  21.     int i;  
  22.     TrieNode *p;  
  23.   
  24.     p = &Memory[allocp++];  
  25.     p->nCount = 1;  
  26.     for(i = 0 ; i < MAX ; i++)  
  27.     {  
  28.         p->next[i] = NULL;  
  29.     }  
  30.   
  31.     return p;  
  32. }  
  33.   
  34. /*插入*/  
  35. void InsertTrie(TrieNode **pRoot , char *s)  
  36. {  
  37.     int i , k;  
  38.     TrieNode *p;  
  39.   
  40.     if(!(p = *pRoot))  
  41.     {  
  42.         p = *pRoot = CreateTrieNode();  
  43.     }  
  44.     i = 0;  
  45.     while(s[i])  
  46.     {  
  47.         k = s[i++] - 'a'//确定branch  
  48.         if(p->next[k])  
  49.             p->next[k]->nCount++;  
  50.         else  
  51.             p->next[k] = CreateTrieNode();  
  52.         p = p->next[k];  
  53.     }  
  54. }  
  55.   
  56. //查找  
  57. int SearchTrie(TrieNode **pRoot , char *s)  
  58. {  
  59.     TrieNode *p;  
  60.     int i , k;  
  61.   
  62.     if(!(p = *pRoot))  
  63.     {  
  64.         return 0;  
  65.     }  
  66.     i = 0;  
  67.     while(s[i])  
  68.     {  
  69.         k = s[i++] - 'a';   
  70.         if(p->next[k] == NULL)    return 0;  
  71.         p = p->next[k];  
  72.     }  
  73.     return p->nCount;  
  74. }  

1.统计难题(这里都用数组分配结点,用malloc分配太慢了)
这题就是统计一组字符串中某前缀出现次数(字典树第一类应用),因此只要简单的套模板就行了(在节点中设置一个成员变量nCount,来记录该字符出现次数) 

  1. #include <stdio.h>  
  2. #define  MAX    26   
  3.   
  4. typedef struct TrieNode  
  5. {  
  6.     int nCount;   
  7.     struct TrieNode *next[MAX];  
  8. }TrieNode;  
  9.   
  10. TrieNode Memory[1000000];  
  11. int allocp = 0;  
  12.   
  13. void InitTrieRoot(TrieNode **pRoot)  
  14. {  
  15.     *pRoot = NULL;  
  16. }  
  17.   
  18. TrieNode *CreateTrieNode()  
  19. {  
  20.     int i;  
  21.     TrieNode *p;  
  22.   
  23.     p = &Memory[allocp++];  
  24.     p->nCount = 1;  
  25.     for(i = 0 ; i < MAX ; i++)  
  26.     {  
  27.         p->next[i] = NULL;  
  28.     }  
  29.   
  30.     return p;  
  31. }  
  32.   
  33. void InsertTrie(TrieNode **pRoot , char *s)  
  34. {  
  35.     int i , k;  
  36.     TrieNode *p;  
  37.   
  38.     if(!(p = *pRoot))  
  39.     {  
  40.         p = *pRoot = CreateTrieNode();  
  41.     }  
  42.     i = 0;  
  43.     while(s[i])  
  44.     {  
  45.         k = s[i++] - 'a'//确定branch  
  46.         if(p->next[k])  
  47.             p->next[k]->nCount++;  
  48.         else  
  49.             p->next[k] = CreateTrieNode();  
  50.         p = p->next[k];  
  51.     }  
  52. }  
  53.   
  54. int SearchTrie(TrieNode **pRoot , char *s)  
  55. {  
  56.     TrieNode *p;  
  57.     int i , k;  
  58.   
  59.     if(!(p = *pRoot))  
  60.     {  
  61.         return 0;  
  62.     }  
  63.     i = 0;  
  64.     while(s[i])  
  65.     {  
  66.         k = s[i++] - 'a';   
  67.         if(p->next[k] == NULL)    return 0;  
  68.         p = p->next[k];  
  69.     }  
  70.     return p->nCount;  
  71. }  
  72.       
  73. int main(void)  
  74. {  
  75.     char s[11];      
  76.       
  77.     TrieNode *Root = NULL;     
  78.     InitTrieRoot(&Root);      
  79.     while(gets(s) && s[0])    
  80.     {         
  81.         InsertTrie(&Root , s);   
  82.     }      
  83.   
  84.     while(gets(s))     
  85.     {          
  86.         printf("%d\n", SearchTrie(&Root , s));     
  87.     }      
  88.       
  89.     return    0;  
  90. }  


2.Phone List

这道题就是判断一组字符串中是否有一个字符串是另一个字符串的前缀(字典树第二类应用)。

分析:我们只要在结点中添加一个nEndFlag成员变量即可。若nEndFlag == 1,说明该结点字符是某一字符串的结尾(假设为A),若在插入B字符串的过程中经过这一结点,则说明A是B的前缀;还有一种情况,当要插入最后一个字符c时,却发现p->next[c-'0']为真,则说明该字符串是一个前缀字符串,eg:先插入abcde,再插入abc这种情况



  1. #include <stdio.h>  
  2. #define  MAX    10   
  3.   
  4. typedef struct TrieNode  
  5. {  
  6.     int nEndFlag; //标记该字符是否是某一字符串的结尾  
  7.     struct TrieNode *next[MAX];  
  8. }TrieNode;  
  9.   
  10. TrieNode Memory[1000000];  
  11. int allocp = 0 , nFlag = 0;  
  12.   
  13. void InitTrieRoot(TrieNode **pRoot)  
  14. {  
  15.     *pRoot = NULL;  
  16. }  
  17.   
  18. TrieNode *CreateTrieNode()  
  19. {  
  20.     int i;  
  21.     TrieNode *p;  
  22.   
  23.     p = &Memory[allocp++];  
  24.     p->nEndFlag = 0;  
  25.     for(i = 0 ; i < MAX ; i++)  
  26.     {  
  27.         p->next[i] = NULL;  
  28.     }  
  29.   
  30.     return p;  
  31. }  
  32.   
  33. void InsertTrie(TrieNode **pRoot , char *s)  
  34. {  
  35.     int i , k;  
  36.     TrieNode *p;  
  37.   
  38.     if(!(p = *pRoot))  
  39.     {  
  40.         p = *pRoot = CreateTrieNode();  
  41.     }  
  42.     i = 0;  
  43.     while(s[i])  
  44.     {  
  45.         k = s[i++] - '0';   
  46.         if(p->next[k])  
  47.         {  
  48.             if(p->next[k]->nEndFlag == 1 || s[i] == '\0'//先短后长 || 先长后短  
  49.             {  
  50.                 nFlag = 1;  
  51.                 return;  
  52.             }  
  53.         }  
  54.         else  
  55.         {  
  56.             p->next[k] = CreateTrieNode();  
  57.         }  
  58.         p = p->next[k];  
  59.     }  
  60.     p->nEndFlag = 1;  //标记结尾  
  61. }  
  62.   
  63.   
  64. int main(void)  
  65. {  
  66.     int  z , n , i;  
  67.     char s[11];      
  68.     TrieNode *Root;    
  69.   
  70.     scanf("%d", &z);  
  71.     while(z-- > 0)    
  72.     {         
  73.         nFlag = allocp = 0;  
  74.         InitTrieRoot(&Root);   
  75.         scanf("%d" , &n);    getchar();  
  76.         for(i = 0 ; i < n ; i++)  
  77.         {  
  78.             gets(s);  
  79.             if(!nFlag)    InsertTrie(&Root , s);   
  80.         }  
  81.         nFlag ? printf("NO\n") : printf("YES\n");  
  82.     }      
  83.     
  84.     return    0;  

Exercise:

http://acm.hdu.edu.cn/showproblem.php?pid=1671

http://acm.hdu.edu.cn/showproblem.php?pid=1075

http://acm.hdu.edu.cn/showproblem.php?pid=1251


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值