Chinaunix首页 | 论坛 | 博客
  • 博客访问: 660547
  • 博文数量: 220
  • 博客积分: 10487
  • 博客等级: 上将
  • 技术积分: 2072
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-09 00:25
文章分类

全部博文(220)

文章存档

2012年(5)

2011年(38)

2010年(135)

2009年(42)

我的朋友

分类: Java

2009-08-18 01:05:03


package test;

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

/**
 * 计算满足特定要求的所有组合结果

 * 算法应用场景:

 * 有如下输入{1,2,3,4,5,6,2,3,4,5,6,2,3,4,5,6,2,3,4,5,6},要求所有满足"和"在5和10之间的所有不重复组合
 * @author xiadehu
 * @version 1.0 2009-07-17
 */

public class CombinationCalculator {
 /*
     * 待计算数据
  */

 private int[] iniArr=null;
    /*
     * 组合最大值
     */

 private int max=0;
    /*
     * 组合最小值
     */

 private int min=0;
    /*
     * 组合大小,组合结果个数的映射关系,用于优化算法
     */

 private Map<Integer,Integer> resultMap = new HashMap<Integer,Integer>();
 
    /*
     * 计算后的结果
     */

 List<CalculateCell> result = new ArrayList<CalculateCell>();
 
    public CombinationCalculator(int[] initData,int sumMax,int sumMin){
        this.iniArr=initData;
        this.max=sumMax;
        this.min=sumMin;
    }
   
    //开始计算

    public void startCalculate(){
        iniArr = init(iniArr);
        loopCalculator(new int[]{iniArr[0]},new int[]{0},0);
    }
   
    //计算当前组合是否满足要求

    public void calculate(CalculateCell cell){
       
        int sum=sum(cell.getCurrCom());
        Integer count= resultMap.get(cell.getCurrCom().length);
        count = count==null?0:count;
        //该组合匹配要求

        if(isValid(sum)){
            if(!result.contains(cell)){
                result.add(cell);
            }
            resultMap.put(cell.getCurrCom().length, count+1);//用于优化算法,减少迭代次数,以后再做

        }
    }
   
 //计算单元

    class CalculateCell{
        //组合数据

        int[] currCom=null;
        //数据在全部组合数组中的下标

        int[] offIdx=null;
        //循环的第几层

        int currLoopIdx=0;
        public CalculateCell(int[] currCom,int[] offIdx,int currLoopIdx){
            this.currCom=currCom;
            this.currLoopIdx=currLoopIdx;
            this.offIdx=offIdx;
        }
        public int[] getCurrCom() {
            return currCom;
        }
        public void setCurrCom(int[] currCom) {
            this.currCom = currCom;
        }
        public int getCurrLoopIdx() {
            return currLoopIdx;
        }
        public void setCurrLoopIdx(int currLoopIdx) {
            this.currLoopIdx = currLoopIdx;
        }
        public int[] getOffIdx() {
            return offIdx;
        }
        public void setOffIdx(int[] offIdx) {
            this.offIdx = offIdx;
        }
       
        /**
         *
         * 覆盖equals方法,用于过滤重复结果
         *
         */

        public boolean equals(Object obj){
            if(obj==null){
                return false;
            }
            if(!(obj instanceof CalculateCell)){
                return false;
            }
            CalculateCell objNew=(CalculateCell)obj;
            if(this==obj){
                return true;
            }
            if(objNew.getCurrCom()==null || this.currCom==null){
                return false;
            }
            if(objNew.getCurrCom().length!=this.currCom.length){
                return false;
            }
            for(int i=0;i<this.currCom.length;i++){
                if(this.currCom[i]!=objNew.getCurrCom()[i]){
                    return false;
                }
            }
            return true;
        }
    }
   
    //克隆数组

    private int[] clone(int[] in){
        int[] out = new int[in.length];
        for(int i=0;i<in.length;i++){
            out[i]=in[i];
        }
       return out;
    }
   
    /**
     * 核心算法,利用栈转换多层循环实现了基本的要求,算法优化空间较大
     * @param currCom 当前组合数组
     * @param offIdx 当前组合数组在原数组中的下标
     * @param currLoopIdx 当前待循环的元素在currCom中的下标
     *
     */

 public void loopCalculator(int[] currComIn,int[] offIdxIn,int currLoopIdxIn){
        //定义栈

        Stack<CalculateCell> stack = new Stack<CalculateCell>();
        //添加第一个元素到栈

        stack.push(new CalculateCell(currComIn,offIdxIn,currLoopIdxIn));
        while(!stack.isEmpty()){
            CalculateCell cell = stack.pop();
            int[] currCom=clone(cell.getCurrCom());//克隆一个数组,

            int[] offIdx=clone(cell.getOffIdx());//克隆一个数组,

            int currLoopIdx=cell.getCurrLoopIdx();
            //计算,并将结果添加到集合内,便于计算完成后输出

            calculate(cell);
            //该层循环已到终点

            if(isArriveEnd(offIdx,currLoopIdx)){
                //是否有上层循环

                if(!hasUpLoop(offIdx,currLoopIdx)){
                    //循环层数是否达到最大

                    if(isMaxLevelLoop(offIdx,currLoopIdx)){
                        continue;
                    }
                    //循环层数未达到最大

                    currCom=new int[currCom.length+1];
                    offIdx=new int[currCom.length];
                    for(int i=0;i<currCom.length;i++){
                        currCom[i]=iniArr[i];
                        offIdx[i]=i;
                    }
                    currLoopIdx=currCom.length-1;
                    stack.push(new CalculateCell(currCom,offIdx,currLoopIdx));
                    continue;
                }
                //有上层循环

                currLoopIdx--;
                stack.push(new CalculateCell(currCom,offIdx,currLoopIdx));
                continue;
            }
            //循环未到终点,为最内层循环

            if(isInnerLoop(offIdx,currLoopIdx)){
                offIdx[currLoopIdx]++;
                currCom[currLoopIdx]=iniArr[offIdx[currLoopIdx]];
                stack.push(new CalculateCell(currCom,offIdx,currLoopIdx));
                continue;
            }
            //循环未到终点,非最内层循环

            offIdx[currLoopIdx]++;
            currCom[currLoopIdx]=iniArr[offIdx[currLoopIdx]];
            for(int i=currLoopIdx+1;i<currCom.length;i++){
                offIdx[i] = offIdx[i-1]+1;
                currCom[i]=iniArr[offIdx[i]];
            }
            currLoopIdx=currCom.length-1;
            stack.push(new CalculateCell(currCom,offIdx,currLoopIdx));
        }
 }
   
    /**
     *
     * 判断是否到达终点
     *
     */

    private boolean isArriveEnd(int[] offIdx,int currLoopIdx){
        return offIdx[currLoopIdx]+(offIdx.length-currLoopIdx)==iniArr.length?true:false;
    }
   
    /**
     *
     * 判断是否有上一层循环
     *
     */

    private boolean hasUpLoop(int[] offIdx,int currLoopIdx){
        return currLoopIdx==0?false:true;
    }
   
    /**
     *
     * 是否为最内层循环
     *
     */

    private boolean isInnerLoop(int[] offIdx,int currLoopIdx){
        return currLoopIdx+1==offIdx.length?true:false;
    }
   
    /**
     *
     * 循环层数是否达到最大
     *
     */

    private boolean isMaxLevelLoop(int[] offIdx,int currLoopIdx){
        return offIdx.length==iniArr.length?true:false;
    }
   
    /**
     *
     * 处理初始化数据,包括过滤重复和排序
     *
     */

    private int[] init(int[] a){
        List<Integer> lst = new ArrayList<Integer>();
        for(int i:a){
            if(lst.contains(i)){
                continue;
            }
            lst.add(i);
        }
        int[] result = new int[lst.size()];
        for(int i=0;i<result.length;i++){
            result[i]=lst.get(i);
        }
        Arrays.sort(result);
        return result;
    }
 
    /**
     *
     * 统计和
     *
     */

 private int sum(int[] data){
  int sum = 0;
  for(int item:data){
   sum += item;
  }
  return sum;
 }
 
    /**
     *
     * 判定是否满足组合的要求
     *
     */

 private boolean isValid(int sum){
  return sum<=max && sum >= min ? true:false;
 }
   

    public Map<Integer, Integer> getResultMap() {
        return resultMap;
    }

    public void setResultMap(Map<Integer, Integer> resultMap) {
        this.resultMap = resultMap;
    }
   
    public List<CalculateCell> getResult() {
        return result;
    }

    public void setResult(List<CalculateCell> result) {
        this.result = result;
    }

    public static void main(String[] args){
        int[] initdata = new int[]{1,2,3,4,5,6,2,3,4,5,6,2,3,4,5,6,2,3,4,5,6};
        int sumMax = 10;
        int sumMin = 5;
        CombinationCalculator cal = new CombinationCalculator(initdata,sumMax,sumMin);
        cal.startCalculate();
       
        List<CalculateCell> result = cal.getResult();
        for(CalculateCell cell:result){
            int[] com = cell.getCurrCom();
            int sum = 0;
            String outStr="";
            for(int i:com){
                outStr = outStr + i+"+";
                sum += i;
            }
            outStr = outStr.substring(0,outStr.length()-1);
            outStr = outStr.concat("=").concat(String.valueOf(sum));
            System.out.println(outStr);
        }
    }
}

阅读(788) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~