首先,前缀树是一个保存关键词的一种数据结构。它每一个节点都有26个子结点,每一个子结点对应一个英文字母,每一个子结点又有26个子结点,如此递归生成。每一个节点都由子结点序列和终止变量isEnd组成。当我们从根节点向下走到一个子结点的时候,这个子结点的isEnd值为true,则表示前缀树中保存了从根节点到该结点的这条路径上所走过的字母组成的单词。
那么,我们的插入和查找操作都很简单。
对于插入操作,我们从头逐字符遍历要插入的字符串word, 然后从根节点开始不断往下走。每次往后遍历一个字符,在当前节点的子结点序列中找对应的子结点,当对应的子结点为null的时候就新建一个节点。然后再继续往下搜索。。。当word 遍历结束时,记得要将最后一个节点的isend置为true,表示插入了一个单词。注意,我们插入一个单词的时候,从根节点到最后一个节点这条路径上所有节点都不为空。而反过来,如果一条路径上的节点都不为空,那么这条路径就是某个单词路径的一部分。
对于查找操作,和插入操作唯一不同的地方就是当子结点为null的时候直接返回false,表示没有找到。如果word遍历到最后时,对应的节点的isend不为true,也返回false。
还有一个操作就算找前缀。这个操作最简单,就直接遍历前缀字符串prefix,然后从根节点开始往下走,如果从根节点能走通,路径上的节点都不为null,那就说明这条路是通路,是某个单词的路径的一部分。那么就返回true。如果路径上有节点为空,说明这条路还没被走过,并不是某个单词路径的一部分。
class Trie {
private Trie[] children;
boolean isEnd;
/** Initialize your data structure here. */
public Trie() {
this.children = new Trie[26];
this.isEnd = false;
}
/** Inserts a word into the trie. */
public void insert(String word) {
Trie t = this;//从根节点开始
for(char s: word.toCharArray())//逐字符遍历word
{
int index = (int)(s-'a');//找到对应的节点位置
if(t.children[index]==null)//如果该子结点为null就新建一个节点
{
t.children[index] = new Trie();
}
t = t.children[index];
}
t.isEnd = true;
}
/** Returns if the word is in the trie. */
public boolean search(String word) {
Trie t = this;
for(char s: word.toCharArray())
{
int index = (int)(s-'a');
t = t.children[index];
if(t==null)
return false;
}
if(t.isEnd==true)
return true;
else
return false;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
public boolean startsWith(String prefix) {
Trie t = this;
for(char s: prefix.toCharArray())
{
int index = (int)(s-'a');
t = t.children[index];
if(t==null)
return false;
}
return true;
}
}