您的位置:首页 > 其它

基于逻辑表达式的集合运算

2012-07-04 19:40 337 查看
课题:基于逻辑表达式的集合运算

需求:

实际项目开发中,我们可能会有这样的需求,有A、B、C、D四个集合,需要对这四个集合进行一定的逻辑运算,从而得到经过该表达式运算之后的最终的集合情况。

实例:

1、假设现在有四个集合元素分别为:

A集合:20,50,60

B集合:70,80

C集合:90,100

D集合:30,70,80

2、运算表达式为:(A∪B)∩(C∪D)

3、我们想要的最终集合为:70,80.

A∪B = 20,50,60,70,80

C∪D = 90,100,70,80,30

(A∪B)∩(C∪D)= 70,80

步骤:

1、建立操作模型。

逻辑表达式的解析,一般思路就是依据运算符号(包括括号)优先级下坠,构建成树状结构。所以我们建立的模型如下:

LogicExpression{

LogicExpression left;//左分支

LogicExpression right;//右分支

Collection data;//数据集合



2、解析逻辑表达式,根据表达式初始化操作模型的树状结构。

3、根据集合索引,向树状结构的操作模型中各个节点分发数据集合。

4、根据树模型的中序遍历规则,将各个节点的左右俩分支的数据集合进行运算。

5、最后得到根节点的数据集合,即为所求。

源码:

package tools;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

/**
* 逻辑表达式或数值表达式的解析成表达式树结构
*
* @author 高伟
* @date May 29, 2012 8:51:49 AM
* @description:
*/
public class LogicExpression {

private String separators = "∩∪()";
private String[] operators = { "∩", "∪" };

/*
* 树节点数据
*/
private String data = null;
/*
* 树节点左分支
*/
private LogicExpression left = null;
/*
* 树节点右分支
*/
private LogicExpression right = null;
/*
* 树节点集合数据
*/
private Collection<Object> dataList = new ArrayList<Object>();

private String exp = "";
private List<String> parts = new ArrayList<String>();
private int numOperators = 0;

public LogicExpression(String exp) throws RuntimeException {
this(exp, "∩∪()", new String[]{ "∩", "∪" });
}

private LogicExpression(String exp, String separators, String[] operators) throws RuntimeException {
this.separators = separators;
this.operators = operators;
this.exp = exp;
splitExpression(exp);
parseSyntax();
}

/**
* 打印解析后表达式树结构,按照前序遍历。
*
* printTree
* 高伟
* May 29, 2012 8:59:43 AM
*/
public void printTree()
{
System.out.println(data);
if ( left !=null ) left.printTree();
if ( right != null ) right.printTree();
}

/**
* 将集合Map分发到树的每个节点
*
* walkMap
* @param map
* 高伟
* May 29, 2012 9:00:26 AM
*/
public void walkMap(Map<String, Collection<Object>> map)
{
if ( left != null ) left.walkMap(map);
if("∩".equals(data) || "∪".equals(data) || "(".equals(data) || ")".equals(data)){
}else{
dataList = map.get(data);
}
if ( right != null ) right.walkMap(map);
}

/**
* 按照先左后右的顺序合并所有节点的集合
*
* combin
* 高伟
* May 29, 2012 9:00:55 AM
*/
public void combin()
{
if(left != null ){
left.combin();
dataList.addAll(left.dataList);
}
if(right != null ){
right.combin();
if("∩".equals(data)){
dataList.retainAll(right.dataList);
}else if("∪".equals(data)){
dataList.addAll(right.dataList);
}
}
}

/**
* 分隔表达式
*
* splitExpression
* @param Expression
* 高伟
* May 29, 2012 9:03:55 AM
*/
private void splitExpression(String Expression) {
StringTokenizer statements = new StringTokenizer(Expression, separators, true);
String tempToken;

parts.clear();
numOperators = 0;

while (statements.hasMoreElements()) {
tempToken = (String) statements.nextElement();

for (int i = 0; i < operators.length; i++)
if (tempToken.equals(operators[i]))
numOperators++;

parts.add(tempToken);
}
}

/**
* 解析表达式为树结构
*
* parseSyntax
* @throws RuntimeException
* 高伟
* May 29, 2012 9:04:07 AM
*/
private void parseSyntax() throws RuntimeException {
String actToken = "";
int level = 0;
int foundPriority = Integer.MAX_VALUE;
int foundLevel = Integer.MAX_VALUE;
int foundPosition = -1;
String foundOperator = "";

if (numOperators == 0) {
setData((String) parts.get(0));
return;
}

for (int position = 0; position < parts.size(); position++) {
actToken = (String) parts.get(position);

if (actToken.equals("(")) {
level++;
continue;
}
if (actToken.equals(")")) {
level--;
continue;
}

for (int prior = 0; prior < operators.length; prior++)
if (actToken.equals(operators[prior]))
if (level < foundLevel || (level == foundLevel && prior < foundPriority)) {
foundLevel = level;
foundPriority = prior;
foundPosition = position;
foundOperator = actToken;
break;
}
}

if (level != 0)
throw new RuntimeException("parseSyntax error");

if (foundLevel != Integer.MAX_VALUE && foundLevel > 0) {
if (!((String) parts.get(0)).equals("(") || !((String) parts.get(parts.size() - 1)).equals(")"))
throw new RuntimeException("parseSyntax error");

exp = exp.substring(1, exp.length() - 1);

splitExpression(exp);
parseSyntax();

return;
}

String leftPart = "";
String rightPart = "";

for (int i = 0; i < parts.size(); i++)
if (i < foundPosition)
leftPart = leftPart.concat((String) parts.get(i));
else if (i != foundPosition)
rightPart = rightPart.concat((String) parts.get(i));

setData(foundOperator);

if (leftPart.equals("") && !foundOperator.equals("")) {
setRight(new LogicExpression(rightPart));
} else {
setLeft(new LogicExpression(leftPart));
setRight(new LogicExpression(rightPart));
}
}

//get set method

public String getData() {
return data;
}

public void setData(String data) {
this.data = data;
}

public LogicExpression getLeft() {
return left;
}

public void setLeft(LogicExpression left) {
this.left = left;
}

public LogicExpression getRight() {
return right;
}

public void setRight(LogicExpression right) {
this.right = right;
}

public Collection<Object> getDataList() {
return dataList;
}

public void setDataList(Collection<Object> dataList) {
this.dataList = dataList;
}

@Override
public String toString() {
return data;
}
}


测试:

public static void main(String[] args) {
{//多层次测试
LogicExpression logExp = new LogicExpression("(A∪B)∩(C∪D)");//1、建立操作模型。2、解析逻辑表达式
logExp.printTree();//打印操作模型。
Map<String, Collection<Object>> map = new HashMap<String, Collection<Object>>();
{
List<Object> list = new ArrayList<Object>();
list.add(new Integer(20));
list.add(new Integer(50));
list.add(new Integer(60));
map.put("A", list);
}
{
List<Object> list = new ArrayList<Object>();
list.add(new Integer(70));
list.add(new Integer(80));
map.put("B", list);
}
{
List<Object> list = new ArrayList<Object>();
list.add(new Integer(90));
list.add(new Integer(100));
map.put("C", list);
}
{
List<Object> list = new ArrayList<Object>();
list.add(new Integer(30));
list.add(new Integer(70));
list.add(new Integer(80));
map.put("D", list);
}
logExp.walkMap(map);//3、根据集合索引,向树状结构的操作模型中各个节点分发数据集合。
logExp.combin();//4、根据树模型的中序遍历规则,将各个节点的左右俩分支的数据集合进行运算。
Collection<Object> list = logExp.getDataList();//5、最后得到根节点的数据集合,即为所求。
for (Object obj : list) {
System.out.println(obj);
}
}
}


结果:

70
80


总结:

godway

com.gaowei@msn.com

2012-07-04
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: