字典树是哈希树的一种变种。
有如下三个性质:
1.根节点不包含字符,除根节点外每一个节点都只包含一个字符;
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
3.每个节点的所有子节点包含的字符都不相同。
搜索字典的方法:
(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
(4) 迭代过程……
(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
/**
* 抽象一棵字典树,并且初始化
*
* @author zcsolf
*
*/
public class Trie1 {
private final int SIZE = 26;
private TrieNode root; // 定义一个根节点
public Trie1() {
root = new TrieNode();
}
public static void main(String[] args) {
// 程序入口:<span style="white-space:pre"> </span>根据学习情况进行测试
// Trie1 t = new Trie1();
// t.Insert("apple");
// System.out.println("**********");
// t.Insert("apm");
// System.out.println("**********");
// System.out.println(t.CountPrefix("ap"));
}
/*
* 抽象出树的节点
*/
class TrieNode {
private int num; // 统计有多少单词通过该节点
private boolean isEnd; // 标识位,判断是否为最后一个节点
private char value; // 该节点的值
private TrieNode[] TrieSons; // 节点的所有子节点
TrieNode() { // 节点的构造函数
num = 1;
isEnd = false;
TrieSons = new TrieNode[SIZE];
}
}
/**
* 向字典树中插入单词的方法
*
* @param word:传入要插入的单词,为String类型
*/
public void Insert(String word) {
// 如果插入单词为空,结束插入
if (word == null || "".equals(word.trim())) {
return;
}
TrieNode node = root; // 定义出根节点;
char[] letters = word.toCharArray(); // 将word转换为char数组
/**
* 遍历letters数组,如果
*/
for (int i = 0; i < word.length(); i++) {
int order = letters[i] - 'a'; // 子分支的位置
if (node.TrieSons[order] == null) {
node.TrieSons[order] = new TrieNode(); // 如果该根节点的子节点中没有该字母,则给其申请一个新的节点空间 将字母的ascii转换成int,-97
node.TrieSons[order].value = letters[i]; // 同时,给该节点的值域赋值为该字母.
System.out.println(node.TrieSons[order].value);
} else {
node.TrieSons[order].num++;
System.out.println("num:" + node.TrieSons[order].num);
}
node = node.TrieSons[order];
}
node.isEnd = true; // 插入完毕
}
/**
* 统计单词前缀的方法
*
* @param prefix:相同的前缀
* @return
*/
public int CountPrefix(String prefix) {
if (prefix == null || prefix.length() == 0) {
return -1;
}
TrieNode node = root;
char[] letters = prefix.toCharArray();
for (int i = 0; i < prefix.length(); i++) {
int order = letters[i] - 'a';
if (node.TrieSons[order] == null) { // 如果没有该字母的子节点,则表示该字母不是前缀中的字母,返回零
return 0;
} else {
node = node.TrieSons[order];
}
}
return node.num;
}
/**
* 输出前缀的单词
*
* @param prefix
* @return
*/
public String hasPrefix(String prefix) {
if (prefix == null || prefix.length() == 0) {
return null;
}
TrieNode node = root;
char[] letters = prefix.toCharArray();
for (int i = 0, len = prefix.length(); i < len; i++) {
int pos = letters[i] - 'a';
if (node.TrieSons[pos] == null) {
return null;
} else {
node = node.TrieSons[pos];
}
}
preTraverse(node, prefix);
return null;
}
/**
* 遍历经过此节点的单词的方法
*
* @param node
* @param prefix 用于存储遍历的值
*/
public void preTraverse(TrieNode node, String prefix) {
// TODO Auto-generated method stub
if (!node.isEnd) {
for (TrieNode child : node.TrieSons) {
if (child != null) {
preTraverse(child, prefix + child.value); // 递归调用
}
}
return;
}
System.out.println(prefix);
}
/**
* 在字典树中查找跟word完全匹配的单词
*
* @param word
* @return
*/
public boolean Match(String word) {
if (word == null || word.length() == 0) {
return false;
}
TrieNode node = root;
char[] letters = word.toCharArray();
for (int i = 0, len = word.length(); i < len; i++) {
int pos = letters[i] - 'a';
if (node.TrieSons[pos] != null) {
node = node.TrieSons[pos];
} else {
return false;
}
}
return node.isEnd;
}
/**
* 前序遍历字典树
*
* @param node
*/
public void preTraverse(TrieNode node) {
if (node != null) {
System.out.print(node.value + "-");
for (TrieNode child : node.TrieSons) {<span style="white-space:pre"> </span>//迭代过程
preTraverse(child);
}
}
}
public TrieNode getRoot() {
return this.root;
}
}