这个是好几年前写的了.都统一放到cnblogs上面.

--------------------------------Node ----------------------------------

package com;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @desc ac节点
* @date 2012-08-04
*
*/
public class Node {
private Map<String, Node> sons = new HashMap<String, Node>();
// 指向失败链
private Node fail;
private Node parent;
// 输出标志
private boolean out;
// 字符
private String val;

public void addSon(String val, Node son) {
sons.put(val, son);
}

public Map<String, Node> getSons() {
return sons;
}

public Node getFail() {
return fail;
}

public void setFail(Node fail) {
this.fail = fail;
}

public Node getParent() {
return parent;
}

public void setParent(Node parent) {
this.parent = parent;
}

public boolean isOut() {
return out;
}

public void setOut(boolean out) {
this.out = out;
}

public String getVal() {
return val;
}

public void setVal(String val) {
this.val = val;
}

public String toString() {

List<String> result = new ArrayList<String>();
result.add(this.getVal());
Node parent = this.getParent();
while (parent != null) {
result.add(parent.getVal());
parent = parent.getParent();
}
StringBuffer res = new StringBuffer();
for (int i = result.size() - 1; i >= 0; i--) {
res.append(result.get(i));
}

return res.toString();
}

}

-------------------------------------------------------------SearchTree --------------------------------

package com;

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

import com.sohu.fortune.talk.admin.util.ac.Node;

/**
* @desc 查找树
*
* AC 多模匹配 分为三步
* 1. 字典树的构造,
* 按照关键志生成一个查找树.
* 2.失败链的构造,
* 最大后缀表示,生成查找失败节点的下一跳(和kmp模式匹配差不多)
* 3.输出
*
*/
public class SearchTree {
// 跟节点
private Node root = new Node();
// 生成fail,遍历用
private List<String> keywords = new ArrayList<String>();

/**
* 添加关键词,生成一个查找树
*
* 1. 字典树的构造
* @param keyword
*/
public void add(String keyword) {
if (keyword == null || keyword.length() == 0) {
return;
}
keywords.add(keyword);
Node currNode = root;
for (int i = 0, j = keyword.length(); i < j; i++) {
char c = keyword.charAt(i);
String value = String.valueOf(c);
if (currNode.getSons().containsKey(value)) {
Node selectNode = currNode.getSons().get(value);
if (i == j - 1) {
selectNode.setOut(true);
}
currNode = selectNode;
} else {
Node sNode = new Node();
sNode.setVal(value);
sNode.setParent(currNode);
currNode.addSon(value, sNode);
if (i == j - 1) {
sNode.setOut(true);
}
currNode = sNode;
}
}

}

/**
* 失败链的构造
*/
public void buildFail() {

root.setFail(root);
for (String keyword : keywords) {
// 最大后缀表示
Node fail = root;
String prefix = "";
for (char c : keyword.toCharArray()) {
prefix += c;
Node currNode = searchNode(prefix);
String sval = String.valueOf(c);
if (fail.getSons().containsKey(sval)) {
if (fail.getSons().get(sval) != currNode) {
fail = fail.getSons().get(sval);
currNode.setFail(fail);
} else {
fail = root;
currNode.setFail(fail);
}

} else {
// 查找后缀,匹配最大
boolean hasfound = false;
for (int i = 1; i < prefix.length(); i++) {
String suffix = prefix.substring(i);
Node sufNode = searchNode(suffix);
if (sufNode != null) {
currNode.setFail(sufNode);
fail = sufNode;
hasfound = true;
break;
}
}
if (!hasfound) {
currNode.setFail(root);
fail = root;
}
}
}
}
}

/**
* 根据字符串 查找node
*
* @param keyword
* @return
*/
private Node searchNode(String keyword) {

if (keyword.length() == 1) {
return root.getSons().get(keyword);
} else {
Node tree = root.getSons().get(keyword.substring(0, 1));
for (int i = 1, j = keyword.length(); i < j; i++) {
char c = keyword.charAt(i);
String value = String.valueOf(c);

if (tree != null) {
if (tree.getSons().containsKey(value)) {
tree = tree.getSons().get(value);
} else {
return null;
}
} else {
return null;
}

}
return tree;
}
}

// 查找关键词
public Set<String> search(String exp, Set<String> levelSet) {

Node pathNode = root;
for (int i = 0, j = exp.length(); i < j; i++) {
char c = exp.charAt(i);
String value = String.valueOf(c);
if (pathNode.getSons().containsKey(value)) {
pathNode = pathNode.getSons().get(value);
if (pathNode.isOut()) {
levelSet.add("[" + pathNode.toString() + "]");
}
} else {
do {
if (pathNode.isOut()) {
if (pathNode.isOut()) {
levelSet.add("[" + pathNode.toString() + "]");
}
}
if (pathNode.getSons().containsKey(value)) {
pathNode = pathNode.getSons().get(value);
if (pathNode.isOut()) {
levelSet.add("[" + pathNode.toString() + "]");
}
break;
}
} while ((pathNode = pathNode.getFail()) != root);

if (pathNode == root) {
if (pathNode.getSons().containsKey(value)) {
pathNode = pathNode.getSons().get(value);
if (pathNode.isOut()) {
levelSet.add("[" + pathNode.toString() + "]");
}
}
}
}
}

return levelSet;
}

public Node getRoot() {
return root;
}

public static void main(String args[]) {

SearchTree tree = new SearchTree();

tree.add("ai.aaa");
tree.add("美国");
tree.add("ai.oa");
tree.add("ai.vcv5");
tree.add(".org");
// tree.add("baid.us");
tree.buildFail();
//
Set<String> res = new HashSet<String>();
System.out
.print(tree
.search(
"用来ai.aaa自美ai.aaa国ai.aaa的页岩.org气革命打压大秦不成立:1、中国埋藏3000米左右,远大于美国1000米;2、西煤东运2020年之前留有3500万吨缺口;3、美国的天然气发电成本低而我国高且缺少资源;4、美国2015年前不是停止发电使用煤,而是采取了碳发电新技术即煤气化发电;5、我国的电力需求总体上是增长趋势。",
res));

}
}

最新文章

  1. VueJS取得URL参数
  2. c++ 小知识总结 .xml
  3. hdu 4711 动态规划
  4. iOS 使用COPY声明NSSTRING属性
  5. Delphi - XP扫雷外挂制作
  6. 恶意软件&amp;quot;跨平台&amp;quot; 小心钱包很受伤
  7. PHP字节格式化
  8. iBatis.net技术实践
  9. 【SPOJ】Distinct Substrings(后缀自动机)
  10. 利用python开发app实战
  11. MySQL命令窗口下中文显示乱码的解决过程
  12. itextsharp html转成pdf 特殊符号异常处理
  13. Java中string.equalsIgnoreCase(&quot;0&quot;)与&quot;0&quot;.equalsIgnoreCase(string)的区别:
  14. QWaiteCondition 思考5
  15. basename
  16. webStorm的使用
  17. loadrunner&#160;场景设计-手工场景方案(Schedule)设计
  18. QT QProgressBar QProgressDialog 模态,位置设置,无边框,进度条样式
  19. protocol buffer c#
  20. mysql的wait_timeout配置(此处处理方法是有问题的,不建议作为操作参考)

热门文章

  1. PHP获取解析URL方法
  2. F5 负载均衡
  3. 在Linux使用mingw32来编写win32程序
  4. PHP 正则表达式语法
  5. Rating
  6. nodejs的mysql模块学习(四)断开数据库连接
  7. Java Bean validation specification...
  8. autoscan; aclocal; autoconf; automake --add-missing; ./configure; make
  9. Mysql打开日志信息
  10. Java操作zip压缩和解压缩文件工具类