一棵用List来存储子结点的字典树——当然,也可以用哈希表等形式存储。
这篇笔记记录了构建思路,文末是源码
我们需要该结点能够存储以下数据:
public class Trie {
private Character ch;//字符
private Boolean isLeaf=false;//是否是词结点
private List<Trie> children=new ArrayList<>();//子结点
//此处省略构造方法、getter&setter、toString方法
}
思路:
public Boolean searchWord(String text){
Boolean found=false;//是否匹配到该字
Boolean isLeaf=false;//该字是否是词结点
List<Trie> offspring=this.children;
for(int i=0;i<text.length();i++){
found=false;
for(Trie t:offspring){
if (t.getCh()==text.charAt(i)){
found=true;
isLeaf=t.isLeaf;
offspring=t.children;
break;
}
}
if (!found)
return false;
}
return (found&&isLeaf);
}
思路:
PS 增删改这里可能会遇到一个知识点可以注意一下:
public Boolean insertWord(String text){
Boolean found=false;//是否匹配到该字
Boolean isLeaf=false;//该字是否是词结点
Trie root=this;
for (int i=0;i<text.length();i++){
found=false;
for(Trie t:root.children){
if (t.getCh()==text.charAt(i)){
found=true;
isLeaf=t.isLeaf;
//ATTENTION!这里root=t操作是引用对象的浅拷贝,即root与t将指向同一数据
//正是利用这一点,我们得以通过操作root从而操作this这棵原始子树的子结点
root=t;
break;
}
}
if (!found){
root.children.add(addSubChild(text.substring(i)));
return true;
}
}
if (found&&!isLeaf){
root.isLeaf=true;
}
return false;
}
private Trie addSubChild(String subText){
Trie subLastChild=new Trie(subText.charAt(subText.length()-1),true);
Trie subChild;
for (int i=subText.length()-2;i>-1;i--){
subChild=new Trie(subText.charAt(i));
subChild.addChild(subLastChild);
subLastChild=subChild;
}
return subLastChild;
}
思路:
public Boolean deleteWord(String text){
Boolean found=false;//是否匹配到该字
int deleteVal=-1;//需要删除的字符层
Trie deleteTrie=this;
Trie root=this;
for (int i=0;i<text.length();i++){
found=false;
for(Trie t:root.children){
if (t.getCh()==text.charAt(i)){
found=true;
root=t;
if((root.isLeaf||root.children.size()>1)&&(i!=text.length()-1)){
deleteVal=i;
deleteTrie=root;
}
break;
}
}
if (!found){
return false;
}
}
if(found){
if (root.children.size()>0){
root.isLeaf=false;
}
else {
for (int r=0;r<deleteTrie.children.size();r++){
if (deleteTrie.children.get(r).ch==text.charAt(deleteVal+1)){
deleteTrie.children.remove(r);
break;
}
}
}
return true;
}
return false;
}
//感觉这个代码块还能优化一下,等之后有时间再继续叭
思路:
public Boolean updateWord(String preText,String posText){
if (this.searchWord(preText)){
//原词必须存在
this.deleteWord(preText);//删了原词
this.insertWord(posText);//添加新词
return true;
}
return false;
}
import java.util.ArrayList;
import java.util.List;
public class Trie {
private Character ch;//字符
private Boolean isLeaf=false;//是否是词结点
private List<Trie> children=new ArrayList<>();//子结点
protected Trie(){
}
public Trie(Character ch){
this.ch=ch;
}
public Trie(Character ch, Boolean isLeaf){
this.ch=ch;
this.isLeaf=isLeaf;
}
public List<Trie> getChildren() {
return children;
}
public void setChildren(List<Trie> children) {
this.children = children;
}
public Character getCh() {
return ch;
}
public void setCh(Character ch) {
this.ch = ch;
}
public Boolean getLeaf() {
return isLeaf;
}
public void setIsLeaf(Boolean isLeaf) {
this.isLeaf = isLeaf;
}
/**
* 添加子结点
* @param child
* @return
*/
public Trie addChild(Trie child){
//遍历子结点,查看该孩子是否已存在
for (int i=0;i<this.children.size();i++){
Trie oldChild=this.children.get(i);
if (oldChild.getCh().equals(ch)){
this.children.set(i,oldChild);
return oldChild;
}
}
//如果该孩子不存在,则添加该孩子
this.children.add(child);
return child;
}
/**
* 搜索词语
* @param text
* @return
*/
public Boolean searchWord(String text){
Boolean found=false;//是否匹配到该字
Boolean isLeaf=false;//该字是否是词结点
List<Trie> offspring=this.children;
for(int i=0;i<text.length();i++){
found=false;
for(Trie t:offspring){
if (t.getCh()==text.charAt(i)){
found=true;
isLeaf=t.isLeaf;
offspring=t.children;
break;
}
}
if (!found)
return false;
}
return (found&&isLeaf);
}
/**
* 添加词语
* @param text
* @return
*/
public Boolean insertWord(String text){
Boolean found=false;//是否匹配到该字
Boolean isLeaf=false;//该字是否是词结点
Trie root=this;
for (int i=0;i<text.length();i++){
found=false;
for(Trie t:root.children){
if (t.getCh()==text.charAt(i)){
found=true;
isLeaf=t.isLeaf;
root=t;
break;
}
}
if (!found){
root.children.add(addSubChild(text.substring(i)));
return true;
}
}
if (found&&!isLeaf){
root.isLeaf=true;
}
return false;
}
/**
* 删除词语
* @param text
* @return
*/
public Boolean deleteWord(String text){
Boolean found=false;//是否匹配到该字
int deleteVal=-1;//需要删除的字符层
Trie deleteTrie=this;
Trie root=this;
for (int i=0;i<text.length();i++){
found=false;
for(Trie t:root.children){
if (t.getCh()==text.charAt(i)){
found=true;
root=t;
if((root.isLeaf||root.children.size()>1)&&(i!=text.length()-1)){
deleteVal=i;
deleteTrie=root;
}
break;
}
}
if (!found){
return false;
}
}
if(found){
if (root.children.size()>0){
root.isLeaf=false;
}
else {
for (int r=0;r<deleteTrie.children.size();r++){
if (deleteTrie.children.get(r).ch==text.charAt(deleteVal+1)){
deleteTrie.children.remove(r);
break;
}
}
}
return true;
}
return false;
}
/**
* 修改词语
* @param preText
* @param posText
* @return
*/
public Boolean updateWord(String preText,String posText){
if (this.searchWord(preText)){
//原词必须存在
this.deleteWord(preText);
this.insertWord(posText);
return true;
}
return false;
}
/**
* 添加词语方法的添加子串操作
* @param subText
* @return
*/
private Trie addSubChild(String subText){
Trie subLastChild=new Trie(subText.charAt(subText.length()-1),true);
Trie subChild;
for (int i=subText.length()-2;i>-1;i--){
subChild=new Trie(subText.charAt(i));
subChild.addChild(subLastChild);
subLastChild=subChild;
}
return subLastChild;
}
/**
* IDE自动生成的ToString,便于测试
* @return
*/
@Override
public String toString() {
return "Trie{" +
"ch=" + ch +
", isLeaf=" + isLeaf +
", children=" + children +
'}';
}
}