何为前缀树?如何生成前绿树?

    又称单词查找树,字典树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

    前缀树 - 图1前缀树 - 图2

    来自百度百科

    例子:
    一个字符串类垒的数组arr1,另一个字符串类型的数组 arr2。

    • arr2 中有哪些字符,是 arr1 中出现的?请打印。
    • arr2 中有哪些字符,是作为 arr1 中某个字符串前缀出现的?请打印。
    • arr2 中有哪些字符,是作为 arr1 中某个字符前缀出现的?请打印 arr2 中出现次数最大的前缀。
    1. import java.util.Arrays;
    2. public class TrieTree {
    3. public static class TrieNode {
    4. // 单词经过的数量
    5. public int pass;
    6. // 单词截止的数量
    7. public int end;
    8. // 这里是位英文准备的,如果需要中文的话要使用 Map<Char, Node> next
    9. public TrieNode[] nexts;
    10. public TrieNode() {
    11. pass = 0;
    12. end = 0;
    13. // 26 个字母
    14. nexts = new TrieNode[26];
    15. }
    16. }
    17. public static class Trie {
    18. private TrieNode root;
    19. public Trie() {
    20. this.root = new TrieNode();
    21. }
    22. public void insert(String word) {
    23. if (word == null || word.length() == 0) return;
    24. TrieNode node = root;
    25. node.pass++;
    26. for (char c : word.toCharArray()) {
    27. int i = c - 'a';
    28. if (node.nexts[i] == null) {
    29. node.nexts[i] = new TrieNode();
    30. }
    31. node = node.nexts[i];
    32. node.pass++;
    33. }
    34. node.end++;
    35. }
    36. public void delete(String word) {
    37. if (word == null || word.length() == 0) return;
    38. if (search(word) == 0) return;
    39. TrieNode node = root;
    40. node.pass--;
    41. for (char c : word.toCharArray()) {
    42. int i = c - 'a';
    43. node = node.nexts[i];
    44. node.pass--;
    45. if (node.pass == 0) {
    46. node.nexts = null;
    47. return;
    48. }
    49. }
    50. node.end--;
    51. }
    52. // word 这个单词加入过几次
    53. public int search(String word) {
    54. if (word == null || word.length() == 0) return 0;
    55. TrieNode node = root;
    56. for (char c : word.toCharArray()) {
    57. int i = c - 'a';
    58. if (node.nexts[i] == null) return 0;
    59. node = node.nexts[i];
    60. }
    61. return node.end;
    62. }
    63. // 所有字符串中多少是以 pre 这个字符串作为前缀的
    64. public int prefixNumber(String pre) {
    65. if (pre == null || pre.length() == 0) return 0;
    66. TrieNode node = root;
    67. for (char c : pre.toCharArray()) {
    68. int i = c - 'a';
    69. if (node.nexts[i] == null) return 0;
    70. node = node.nexts[i];
    71. }
    72. return node.pass;
    73. }
    74. }
    75. public static void main(String[] args) {
    76. String[] arr1 = new String[]{"abc", "bcd", "cde", "def", "ab", "ac", "bd"};
    77. System.out.println(Arrays.toString(arr1));
    78. String[] arr2 = new String[]{"a", "b", "c", "d", "e", "f", "g"};
    79. System.out.println(Arrays.toString(arr2));
    80. Trie trie = new Trie();
    81. for (String s : arr1) {
    82. trie.insert(s);
    83. }
    84. System.out.println("arr2 中有哪些字符,是 arr1 中出现的?请打印");
    85. for (String s : arr2) {
    86. if (trie.search(s) > 0) System.out.print(s + "\t");
    87. }
    88. System.out.println();
    89. System.out.println("arr2 中有哪些字符,是作为 arr1 中某个字符串前缀出现的?请打印。");
    90. for (String s : arr2) {
    91. if (trie.prefixNumber(s) > 0) System.out.print(s + "\t");
    92. }
    93. System.out.println();
    94. System.out.println("arr2 中有哪些字符,是作为 arr1 中某个字符前缀出现的?请打印 arr2 中出现次数最大的前缀。");
    95. String maxTimePrefix = "";
    96. int num = -1;
    97. for (String s : arr2) {
    98. int prefixNumber = trie.prefixNumber(s);
    99. if (prefixNumber > num) {
    100. num = prefixNumber;
    101. maxTimePrefix = s;
    102. }
    103. }
    104. System.out.println(maxTimePrefix);
    105. }
    106. }

    结果

    1. [abc, bcd, cde, def, ab, ac, bd]
    2. [a, b, c, d, e, f, g]
    3. arr2 中有哪些字符,是 arr1 中出现的?请打印
    4. arr2 中有哪些字符,是作为 arr1 中某个字符串前缀出现的?请打印。
    5. a b c d
    6. arr2 中有哪些字符,是作为 arr1 中某个字符前缀出现的?请打印 arr2 中出现次数最大的前缀。
    7. a