字符串匹配

package com.oooo3d.trie;

import java.util.ArrayList;
import java.util.List;

/**
* 树的最大匹配
*
* @author bob
* @创建时间:2013-1-30上午11:33:42
* @version 2.0
*/
public class TrieTree
{

/**
* 根节点,不存储数据
*/
private TrieNode root = new TrieNode("`");

/**
* 查找数据
*
* @param data
* @return
*/

public boolean find(String data)
{
TrieNode firstChild = root.firstChild();

if (firstChild == null)
{
return false;
}
TrieNode node = find(firstChild, data);

return node != null ? node.exists() : false;

}

/**
* 插入数据
*
* @param data
* @return
*/

public void insert(String data)
{

TrieNode firstChild = root.firstChild();
if (firstChild == null)
{
root.firstChild(new TrieNode(data, true));
}
else
{
insert(firstChild, data);
}

}

/**
* 删除数据
*
* @param node
* @param data
*/
public void delete(String data)
{

TrieNode firstChild = root.firstChild();

if (firstChild == null)
{
return;
}

TrieNode node = find(firstChild, data);
if (node != null)
{
node.exists(false);
}


}

/**
* 匹配数据
* @param data
* @return
*/
public List<String> searchData(String data)
{

List<String> list = new ArrayList<String>();
TrieNode firstChild = root.firstChild();
if (firstChild != null)
{
TrieNode node = searchFuzzyWord(firstChild, data);
if (node != null)
{
pathes(node, list, new StringBuilder(data));
}
}

return list;

}

/**
* 从指定节点开始插入数据
*
* @param node
* @param data
* @return
*/

private void insert(TrieNode node, String data)
{

String value = node.value();
if (data.equals(value))
{
// 插入数据存在
node.exists(true);
{
return;
}

}

int index = maxLenth(data, value);

if (index == 0)
{
// 没有公共开始部分,将数据插入兄弟节点
TrieNode brother = node.nextBrother();

if (brother != null)
{
insert(brother, data);
}
else
{
node.nextBrother(new TrieNode(data, true));
}

}
else
{

if (value.length() > index)
{
// 节点数据多于公共部分,则节点进行纵向分裂
// 将多余部分插入孩子节点
TrieNode temp = new TrieNode(value.substring(index),
node.exists());
TrieNode child = node.firstChild();

// 将原节点的孩子节点变为孙子节点
if (child != null)
{
temp.firstChild(child);
}

// 原节点的数据更新为公共部分
node.value(value.substring(0, index));

// 公共部分是否为插入数据
node.exists(node.value().equals(data));

node.firstChild(temp);

}

if (data.length() > index)
{
// 插入数据多于公共部分,则多余部分插入孩子节点
TrieNode firstChild = node.firstChild();

if (firstChild == null)
{
// 如果没有孩子节点,则创建孩子节点
node.firstChild(new TrieNode(data.substring(index), true));
}
else
{
// 否则直接插入孩子节点
insert(firstChild, data.substring(index));

}

}

}

}

/**
* 从指定节点开始查找数据
*
* @param node
* @param data
*/

private TrieNode find(TrieNode node, String data)
{

String value = node.value();

if (data.equals(value))
{
// 查询数据存在
return node;

}

int index = maxLenth(data, value);

if (index == 0)
{
// 不存在公共部分,查询兄弟节点
TrieNode brother = node.nextBrother();

return brother != null ? find(brother, data) : null;

}

TrieNode firstChild = node.firstChild();

// 节点数据为查询数据的前缀,则继续查询子节点
return data.startsWith(value) && firstChild != null ? find(firstChild,

data.substring(value.length())) : null;

}


/**
* 两个字符串公共开始部分的长度
* @param str1
* @param str2
* @return
*/
private static int maxLenth(String str1, String str2)
{

int len = str1.length() < str2.length() ? str1.length() : str2.length();

int index = -1;

for (int i = 0; i < len; i++)
{

if (str1.charAt(i) != str2.charAt(i))

break;
index = i;
}
return index + 1;

}

/**
* <模糊匹配>
* 比如存在主题词,中华人民共和国,当输入中华或者中华人民,都可以匹配到该词
* 但如果存在两个主题词中华人民共和国和中华,输入中华时,应该匹配到中华
* 而输入中华人民时应该匹配到中华人民共和国,满足正向最大匹配需要
*
* @param node
* node
* @return String String
* @see [类、类#方法、类#成员]
*/
private TrieNode searchFuzzyWord(TrieNode node, String data)
{
String value = node.value();
if (value.startsWith(data))
{
TrieNode temp = new TrieNode(value.substring(data.length()));

temp.firstChild(node.firstChild);

temp.exists(node.exists() && !temp.value().isEmpty());

return temp;

}

int index = maxLenth(data, value);

if (index == 0)
{
// 不存在公共部分,查询兄弟节点
TrieNode brother = node.nextBrother();
return brother != null ? searchFuzzyWord(brother, data) : null;

}

TrieNode firstChild = node.firstChild();

// 节点数据为查询数据的前缀,则继续查询子节点
return data.startsWith(value) && firstChild != null ? searchFuzzyWord(
firstChild,
data.substring(value.length())) : null;

}

/**
* 获取指定节点存在的全部子路径
*
* @param node
* @param list
* @param sb
*/
private void pathes(TrieNode node, List<String> list, StringBuilder sb)
{
sb.append(node.value());

if (node.exists())
{
// 将匹配到的都放到集合中
list.add(sb.toString());
}
else
{
// 如果全量匹配到则结束匹配
list.add(sb.toString());
return;
}

if (node.firstChild() != null)
{
pathes(node.firstChild(), list, sb);
}

sb.delete(sb.length() - node.value().length(), sb.length());
if (node.nextBrother() != null)
{
pathes(node.nextBrother(), list, sb);
}

}

public static void main(String[] args)
{
TrieTree t = new TrieTree();
String str = "中国";
String str1 = "中国人民";
String str2 = "中国人民共和国";
t.insert(str);
t.insert(str1);
t.insert(str2);
List<String> list = t.searchData("中国人");
System.out.println(list);
}

}


package com.oooo3d.trie;

/**
*
* @author bob
* @创建时间:2013-1-30下午01:29:11
* @version 2.0
*/
public class TrieNode
{

/**
* 当前节点数据
*/

private String value;

/**
* 第一个子节点
*/
public TrieNode firstChild;

/**
* 下一个节点
*/
private TrieNode nextBrother;

/**
* 节点数据存在标志
*/
private boolean exists= true;

/**
* 构造方法
*
* @param value
* 节点数据
*/
public TrieNode(String value)
{
this(value, true);
}

/**
* 构造方法
*
* @param value
* 节点数据
* @param exists
* 节点数据是否存在
*/
public TrieNode(String value, boolean exists)
{
this.value = value;
this.exists = exists;

}

/**
* 节点数据
*
* @return
*/

public String value()
{

return value;

}

/**
* 设置节点数据
*
* @param value
*/

public void value(String value)
{

this.value = value;

}

public boolean exists()
{

return exists;

}

public void exists(boolean exists)
{

this.exists = exists;

}

public TrieNode firstChild()
{

return firstChild;

}

public void firstChild(TrieNode node)
{

this.firstChild = node;

}

public TrieNode nextBrother()
{

return nextBrother;

}

public void nextBrother(TrieNode node)
{

this.nextBrother = node;

}

public String toString()
{

return value + "[" + exists + "]";

}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值