当前位置:   article > 正文

trie-字典树及实现

trie-字典树及实现

trie树

又称为字典树、单词查找树。是一种树形结构,哈希树的变种。典型应用是用于统计、排序和保存大量的字符串(不仅仅限于字符串),经常被搜索引擎系统用于文本词频统计。trie树是用空间换取时间的典型数据结构。

性质

根节点不包含字符,除了根节点外,每个节点都只包含一个字符;

从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;

每个节点的所有子节点包含的字符都不相同。

基本操作

基本操作有:树的创建、删除;节点的插入、查找、删除(好像这种操作比较少见)。

优点

利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高

缺点

每个节点需要包含一些额外的字段来保存节点信息,浪费空间。

应用

串的快速检索、“串”排序、最长公共前缀

 

trie树实现

本文实现了trie树的创建、删除;字符串的插入、查找、删除。另外,本文限定单词仅仅由26个小写字母组成。具体实现将在本文最后给出完整代码。

结构体设计

  1. typedef struct TrieNode
  2. {
  3. int isStr; /*word flag*/
  4. int elemcount; /*word number*/
  5. int passcount; /*pass by number*/
  6. struct TrieNode *next[MAX];
  7. }Trie;

其中,isStr 单词结束标记;elemcount是单词被插入的次数;passcount是所有单词经过该节点的次数;next是该节点的孩子节点。

trie树创建

创建trie树与trie树初始化,分开实现。

  1. Trie * trie_malloc();
  2. void trie_init(Trie *p);

trie树删除

删除整棵树,释放其拥有的所有资源

void trie_del(Trie *root);

字符串插入

将字符串s插入trie树root

void trie_insert(Trie *root,const char *s);

字符串查找

从trie树中查找字符串s,如果能找到则返回s在trie中出现的次数(即被插入的次数),否则返回0

int trie_search(Trie *root,const char *s);

字符串删除

trie树中删除字符串s(s是整个单词,并不会删除一个完整单词的一部分)

void trie_node_del(Trie *root, const char *s);

辅助函数

这些辅助函数相当于C++的private成员,仅仅用来辅助实现基本的用户功能。分别为:验证字符串的合法性、根据字符获取在孩子节点中的索引、递归删除trie树、递归删除字符串对应的节点

  1. static int verify_str(const char *s);
  2. static int get_index(char ch);
  3. static void delete_subtrie(Trie **root);
  4. static void delete_node(Trie **node, const char *chr);

具体的代码实现trie.h如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define MAX 26
  5. #define IDXERR -1
  6. #define INVALID 0
  7. #define VALID 1
  8. #define true 1
  9. #define false 0
  10. typedef struct TrieNode
  11. {
  12. int isStr; /*word flag*/
  13. int elemcount; /*word number*/
  14. int passcount; /*pass by number*/
  15. struct TrieNode *next[MAX];
  16. }Trie;
  17. Trie * trie_malloc();
  18. void trie_init(Trie *p);
  19. void trie_insert(Trie *root,const char *s);
  20. int trie_search(Trie *root,const char *s);
  21. void trie_del(Trie *root);
  22. void trie_node_del(Trie *root, const char *s);
  23. static int verify_str(const char *s);
  24. static int get_index(char ch);
  25. static void delete_subtrie(Trie **root);
  26. static void delete_node(Trie **node, const char *chr);
  27. void trie_init(Trie *p)
  28. {
  29. int i=0;
  30. if(NULL == p)
  31. return;
  32. memset(p,0x0,sizeof(Trie));
  33. for(i=0;i<MAX;i++)
  34. {
  35. p->next[i] = NULL;
  36. }
  37. p->isStr = false;
  38. p->elemcount = 0;
  39. p->passcount = 0;
  40. }
  41. Trie * trie_malloc()
  42. {
  43. Trie *temp=(Trie *)malloc(sizeof(Trie));
  44. return temp;
  45. }
  46. void trie_insert(Trie *root,const char *s)
  47. {
  48. if(NULL == root || NULL == s || *s == '\0')
  49. return;
  50. if(INVALID == verify_str(s))
  51. return;
  52. Trie *p = root;
  53. int idx = 0;
  54. while(*s!='\0')
  55. {
  56. idx = get_index(*s);
  57. if(NULL == p->next[idx])
  58. {
  59. Trie *temp = trie_malloc();
  60. trie_init(temp);
  61. p->next[idx]=temp;
  62. p=p->next[idx];
  63. }
  64. else
  65. {
  66. p=p->next[idx];
  67. }
  68. s++;
  69. p->passcount++;
  70. }
  71. p->isStr=true;
  72. p->elemcount++;
  73. }
  74. int trie_search(Trie *root,const char *s)
  75. {
  76. Trie *p=root;
  77. int idx = 0;
  78. if(NULL == root || NULL == s)
  79. return 0;
  80. while(p != NULL && *s != '\0')
  81. {
  82. idx = get_index(*s);
  83. if(IDXERR == idx)
  84. return 0;
  85. p=p->next[idx];
  86. s++;
  87. }
  88. if(p != NULL && true == p->isStr)
  89. return p->elemcount;
  90. else
  91. return 0;
  92. }
  93. void trie_del(Trie *root)
  94. {
  95. if(NULL == root)
  96. return;
  97. delete_subtrie(&root);
  98. }
  99. static int verify_str(const char *s)
  100. {
  101. if(NULL == s)
  102. return INVALID;
  103. while(*s!='\0')
  104. {
  105. if(IDXERR == get_index(*s))
  106. return INVALID;
  107. s++;
  108. }
  109. return VALID;
  110. }
  111. static int get_index(char ch)
  112. {
  113. int idx = ch-'a';
  114. if(idx < 0 || idx >= MAX)
  115. {
  116. idx = IDXERR;
  117. }
  118. return idx;
  119. }
  120. static void delete_subtrie(Trie **root)
  121. {
  122. int i = 0;
  123. if(root != NULL && *root != NULL)
  124. {
  125. for(i = 0; i < MAX; i++)
  126. {
  127. if((*root)->next[i]!=NULL)
  128. {
  129. delete_subtrie(&((*root)->next[i]));
  130. }
  131. }
  132. }
  133. if(NULL != root)
  134. {
  135. free(*root);
  136. *root = NULL;
  137. }
  138. }
  139. static void delete_node(Trie **node, const char *chr)
  140. {
  141. int idx = 0;
  142. if(NULL == node || NULL == *node || NULL == chr)
  143. return;
  144. if(*chr != '\0'&& *(chr+1) != '\0' && *node != NULL)
  145. {
  146. chr++;
  147. idx = get_index(*chr);
  148. delete_node(&((*node)->next[idx]), chr);
  149. }
  150. if(*node != NULL)
  151. {
  152. free(*node);
  153. *node = NULL;
  154. }
  155. return;
  156. }
  157. void trie_node_del(Trie *root, const char *s)
  158. {
  159. if(NULL == root || NULL == s || *s == '\0')
  160. return;
  161. int elemcount=0;
  162. Trie *p = root;
  163. Trie *q = p;
  164. int remain=0;
  165. int idx = 0;
  166. if((elemcount=trie_search(root,s))<= 0)
  167. return;
  168. while(*s != '\0' && p != NULL)
  169. {
  170. idx = get_index(*s);
  171. q = p;
  172. p = p->next[idx];
  173. remain = p->passcount - elemcount;
  174. if(remain <= 0)
  175. {
  176. delete_node(&p, s);
  177. q->next[idx] = p; // important
  178. p = NULL;// can delete "p = NULL"
  179. break;
  180. }
  181. else
  182. {
  183. p->passcount = remain;
  184. }
  185. s++;
  186. }
  187. /*clear word flag*/
  188. if(p != NULL)
  189. {
  190. p->isStr = false;
  191. }
  192. }


测试代码main.c

  1. #include "trie.h"
  2. #define STR1 "hello"
  3. #define STR2 "hell"
  4. #define STR3 "helloworld"
  5. #define STR4 "world"
  6. #define STARLINE "****"
  7. int main(int argc, char *argv[])
  8. {
  9. Trie *root= trie_malloc();
  10. if(NULL == root)
  11. {
  12. printf("malloc trie failed\n");
  13. exit(0);
  14. }
  15. trie_init(root);
  16. /*insert*/
  17. printf("\n %sinsert string%s\n",STARLINE,STARLINE);
  18. trie_insert(root,STR1);
  19. printf("%s\n",STR1);
  20. trie_insert(root,STR2);
  21. printf("%s\n",STR2);
  22. trie_insert(root,STR3);
  23. printf("%s\n",STR3);
  24. trie_insert(root,STR4);
  25. printf("%s\n",STR4);
  26. trie_insert(root,STR2);
  27. printf("%s\n",STR2);
  28. /*search*/
  29. printf("\n %ssearch string%s\n",STARLINE,STARLINE);
  30. printf("%s, %d times\n",STR1, trie_search(root,STR1));
  31. printf("%s, %d times\n",STR2, trie_search(root,STR2));
  32. printf("%s, %d times\n",STR3, trie_search(root,STR3));
  33. printf("%s, %d times\n",STR4, trie_search(root,STR4));
  34. /*delete*/
  35. printf("\n %sdelete string%s\n",STARLINE,STARLINE);
  36. trie_node_del(root, STR1);
  37. printf("%s\n", STR1);
  38. printf("search %s, %d times\n",STR1, trie_search(root,STR1));
  39. trie_node_del(root, STR2);
  40. printf("%s\n", STR2);
  41. printf("search %s, %d times\n",STR2, trie_search(root,STR2));
  42. trie_node_del(root, STR3);
  43. printf("%s\n", STR3);
  44. printf("search %s, %d times\n",STR3, trie_search(root,STR3));
  45. trie_node_del(root, STR4);
  46. printf("%s\n", STR4);
  47. printf("search %s, %d times\n",STR4, trie_search(root,STR4));
  48. /*free trie*/
  49. printf("\n %sfree trie%s\n",STARLINE,STARLINE);
  50. trie_del(root);
  51. root = NULL;
  52. return 0;
  53. }


gcc -g -o test main,c

执行结果如下图:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/994714
推荐阅读
相关标签
  

闽ICP备14008679号