java 创建多模快項目_java实现多模匹配算法

在上一篇关于多模式匹配AC的算法中,有一点失误的地方,在这里更正一下。 上篇中的运行结果如下: 不仔细看完全没有问题,可是如果细心的你仔细看下对字符串“hao”的匹配的下标时就会发现问题了... 下图为更正代码后的结果: 经过两个图片的对比,应该很明显

这个是好几年前写的了.都统一放到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 sons = new HashMap();

// 指向失败链

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 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 result = new ArrayList();

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 --------------------------------具体原理参照《算法导论》,这里做了一点小修改。时间复杂度 O(n+m) 个人感觉,BF算法是当当前不匹配时同时回溯了匹配字串与模式字串,于是时间复杂度是O(n*m),而KMP算法改进的地方就是两点: 1.匹配字串指针不回溯,但模式字串指针会回溯。 2.种用模式字串

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 keywords = new ArrayList();

/**

* 添加关键词,生成一个查找树

*

* 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 search(String exp, Set 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 res = new HashSet();

System.out

.print(tree

.search(

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

res));

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值