Trie树

Trie树

Trie树

单模式串匹配有 BF、RK、naive-BM和KMP这四种算法。

本节实现的是一种 naive-Trie
Trie树适合多模式串公共前缀较多的匹配(O(n*k))或者 根据公共前缀进行查找 O(k)的经典场景,比如搜索框的自动补全提示。

针对一组字符串中查找字符串的问题,在工程中,更倾向于用散列表或者红黑树。Trie树不适合精确匹配查找。
Trie树比较适合的是查找前缀匹配的字符串。

Java代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package com.ludepeng.datastruct.base.datastruct.charMath.trie;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* @description:
* @author: rhsphere
* @since: 2019-10-28 10:51 by jdk 1.8
*/
public class MyTrie {
/** 字符a的asc码值 */
private static final char CHARA = 'a';

private TrieNode root = new TrieNode('/');


/** trie 树的基本节点信息 */
public class TrieNode {
/** 当前节点的值 */
public char data;
/** 子节点的信息 */
public TrieNode[] children = new TrieNode[26];
/** 用来标识当前是否被全完匹配 */
public boolean isEndChar = false;

public TrieNode(char data) {
this.data = data;
}
}

/**
* 向trie树中插入一个字符
* @param addVal 字符信息
*/
public void insert(String addVal) {
char[] charData = addVal.toCharArray();

TrieNode procNode = root;

for (int i = 0; i < charData.length; i++) {
//计算当前字符的asc码值
int ascVal = charData[i] - CHARA;
if (procNode.children[ascVal] == null) {
TrieNode newNode = new TrieNode(charData[i]);
procNode.children[ascVal] = newNode;
}
procNode = procNode.children[ascVal];
}
procNode.isEndChar = true;
}

/**
* 查找一个trie树
*
* @param pat 字符信息
* @return 是否能被查找到
*/

public boolean search(String pat) {
char[] charsData = pat.toCharArray();

TrieNode procNode = root;

for (int i = 0; i < charsData.length; i++) {
int ascVal = charsData[i] - CHARA;
if (procNode.children[ascVal].data != charsData[i]) {
return false;
}

procNode = procNode.children[ascVal];
}

if (!procNode.isEndChar) {
return false;
} else {
return true;
}
}

public Set<String> search2(String pat) {
char[] charsData = pat.toCharArray();

TrieNode proc = root;

for (int i = 0; i < charsData.length; i++) {
int index = charsData[i] - CHARA;

if (proc.children[index] == null) {
return null;
}
proc = proc.children[index];
}

List<Character> matchOthers = new ArrayList<>();

for (int i = 0; i <= charsData.length - 1; i++) {
matchOthers.add(charsData[i]);
}

Set<String> mvalueSet = new HashSet<>();
addMatches(matchOthers, mvalueSet, proc);

return mvalueSet;
}

public void addMatches(List<Character> matchOthers, Set<String> matchValue, TrieNode node) {
if (node != null) {
matchOthers.add(node.data);

//检查是否是最后一级
boolean isLast = true;

for (int i = 0; i < node.children.length; i++) {
if (node.children[i] != null)
isLast = false;
}

if (isLast) {
char[] msgChars = new char[matchOthers.size()];

for (int i = 0; i < matchOthers.size(); i++) {
msgChars[i] = matchOthers.get(i);
}
matchValue.add(new String(msgChars));
return;
}

} else {
return;
}

for (TrieNode nodeItem : node.children) {
int befSize = matchOthers.size();

addMatches(matchOthers, matchValue, nodeItem);

int afterSize = matchOthers.size();

if (afterSize > befSize) {
// 完成后需要移除最后一次添加的内容,数据,防止数据重复
matchOthers.remove(matchOthers.size() - 1);
}
}
}
}

0%