基于数值编码原理的组合算法思想:

本程序的思路是开一个数组,其下标表示1到m个数,数组元素的值为1表示其下标 代表的数被选中,为0则没选中。    
首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为 “01”组合,同时将其左边的所有“1”全部移动到数组的最左端。 当第一个“1”移动到数组的m-n的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。

该思想是基于数值编码原理的,在Java中可以使用BitSet来代替一个数组,用来表示某个字符串的某些位是否被占用,如果被占用,则为true,并根据上述思想构造的BitSet来确定某一个组合。

例如,对字符串12345进行5取2组合:

11100 -> ***45
11010 -> **3*5
10110 -> *2**5
01110
11001 -> **34*
10101 -> *2*4*
01101 -> 1**4*
10011 -> *23**
10100 -> 1*3**
00111 -> 12***

使用Java实现基于多线程的组合算法,更多的地方需要同步访问,在一定程度上能够提高并行度,提高计算速度。实现代码如下所示:

package org.shirdrn;
import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;/**
 * 组合拆分类
 * 
 * 根据从复式投注字符串经过拆分过滤后得到的单式投注字符串集合,对其中每一个单式投注字符串进行组合<br>
 * 例如:输入集合{31311133,33113330},Splitter类会遍历该集合,对每个单式投注注字符串,创建一个SplitterThread<br>
 * 线程来处理,如果是2串1组合,即starCount=8-2=6,经过线程处理得到类似******33,*****1*3等结果
 * 
 * @author shirdrn
 *
 */
 public class MySplitter {

 private Iterator<String> iterator;
 private int length;
 private int starCount;
 private boolean duplicate;
 private Collection<String> filteredContainer;
 private Boolean finished = false;
 private Integer threadCount;
 private int splitSize = 100;

 public Collection<String> getFilteredContainer() {
    while(!finished) {
     try {
      Thread.sleep(10);
     } catch (InterruptedException e) {
      e.printStackTrace();
     } 
    }
    return filteredContainer;
 }

 /**
 * 构造一个Spilitter实例
 * 
 * @param container 从复式投注字符串经过拆分过滤后得到的单式投注字符串集合
 * @param starCount 如果对于N长比赛,进行M组合过关,则starCount=N-M
 * @param duplicate 是否去重
 */
 public MySplitter(Collection<String> container, int starCount, boolean duplicate) {
    this.iterator = container.iterator();
    this.duplicate = duplicate;
    this.starCount = starCount;
    if(this.duplicate) { // 根据指定是否去重的选择,选择创建容器
     filteredContainer = Collections.synchronizedSet(new HashSet<String>());
    }
    else {
     filteredContainer = Collections.synchronizedList(new ArrayList<String>());
    }
    Iterator<String> it = container.iterator();
    this.length = it.next().trim().length();
   
    this.threadCount = container.size()/splitSize;
    for(int i=0; i<this.threadCount; i++) {
     new Thread(new SplitterThread()).start();
    }
 }

 /**
 * 对一个指定的N场比赛的长度为N的单式投注字符串进行组合<br>
 * 输入单式投注注字符串string,例如31311133,组合得到类似******33,*****1*3,... ...结果的集合
 * 
 * @author shirdrn
 *
 */
 class SplitterThread implements Runnable {
   
    public SplitterThread() {
    
    }
   
    public void run() {
     boolean flag = true;
     while(flag) {
      Collection<String> c;
      if(duplicate) { // 根据指定是否去重的选择,选择创建线程的私有容器
      c = new HashSet<String>();
      }
      else {
       c = new ArrayList<String>();
      }
      String string = "";
      synchronized(iterator) { // 需要同步待处理字符串集合的迭代器实例,迭代一条记录进行处理
       if(iterator.hasNext()) {
        string = iterator.next();
       }
       else {
        synchronized(threadCount) { // 同步线程统计变量,用于监测当前线程总数,即使Kill掉完成任务的线程
        threadCount--;
         if(threadCount == 0) {
          finished = true;
          flag = false;
         }
         break;
        }      
       }
      }
      this.split(string, c);
      synchronized(filteredContainer) { // 同步处理后的集合,将处理结果整合到容器中
       filteredContainer.addAll(c);
      }
     }   
    }
   
    public void split(String string, Collection<String> c) {
     char[] charArray = string.toCharArray();
     BitSet startBitSet = new BitSet(length); // 比特集合起始状态
     BitSet endBitSet = new BitSet(length); // 比特集合终止状态,用来控制循环
     // 初始化startBitSet,左侧占满*符号
     for (int i = 0; i < starCount; i++) {
      startBitSet.set(i, true);
     }
     // 初始化endBit,右侧占满*符号
     for (int i = length - 1; i > length - starCount - 1; i--) {
      endBitSet.set(i, true);
     }
     // 根据起始startBitSet,构造带*的组合字符串并加入容器
     char[] charArrayClone = charArray.clone();
     for (int i = 0; i < length - 1; i++) {
      if (startBitSet.get(i)) {
       charArrayClone[i] = '*';
      }
     }
     c.add(new String(charArrayClone));
    
    
     while (!startBitSet.equals(endBitSet)) {
      int zeroCount = 0; // 统计遇到10后,左边0的个数
      int oneCount = 0; // 统计遇到10后,左边1的个数
      int pos = 0; // 记录当前遇到10的索引位置
      charArrayClone = charArray.clone();
     
      // 遍历startBitSet来确定10出现的位置
      for (int i = 0; i < length - 1; i++) {
       if (!startBitSet.get(i)) {
        zeroCount++;
       }
       if (startBitSet.get(i) && !startBitSet.get(i + 1)) {
        pos = i;
        oneCount = i - zeroCount;
        startBitSet.set(i, false);
        startBitSet.set(i + 1, true);
        break;
       }
      }
      // 将遇到10后,左侧的1全部移动到最左侧
      int count = Math.min(zeroCount, oneCount);
      int startIndex = 0;
      int endIndex = pos - 1;
      for (int i = 0; i < count; i++) {
       startBitSet.set(startIndex, true);
       startBitSet.set(endIndex, false);
       startIndex++;
       endIndex--;
      }
      // 将遇到1的位置用*替换
      for (int i = 0; i < length; i++) {
       if (startBitSet.get(i)) {
        charArrayClone[i] = '*';
       }
      }
      c.add(new String(charArrayClone));
     }
    }
 }
 }测试用例如下所示:
package org.shirdrn;
import java.util.Collection;
import com.zucai310.Zucai310;
import junit.framework.TestCase;
public class TestMySplitter extends TestCase {
private MySplitter splitter;

 public void setMySplitter(Collection<String> container, int starCount, boolean duplicate) {
    this.splitter = new MySplitter(container, starCount, duplicate);
 }

 public void testMySplitter_8_310() {
    // 8 场:310
    String multiSeq = "310,310,310,310,310,310,310,310";
    Collection<String> container = Zucai310.getNSingleList(multiSeq);
    assertEquals(6561, container.size());
    int starCount = 4;
    boolean duplicate = false;
    this.setMySplitter(container, starCount, duplicate);
    assertEquals(459270, this.splitter.getFilteredContainer().size());
 }

 public void testMySplitter_9_1() {
    // 9 场:310,310,310,310,310,310,310,310,3
    String multiSeq = "310,310,310,310,310,310,310,310,3";
    Collection<String> container = Zucai310.getNSingleList(multiSeq);
    assertEquals(6561, container.size());
    int starCount = 4;
    boolean duplicate = false;
    this.setMySplitter(container, starCount, duplicate);
    assertEquals(826686, this.splitter.getFilteredContainer().size());
 }

 public void testMySplitter_9_2() {
    // 9 场:310,310,310,310,310,310,310,310,3
    String multiSeq = "310,310,310,310,310,310,31,31,31";
    Collection<String> container = Zucai310.getNSingleList(multiSeq);
    assertEquals(5832, container.size());
    int starCount = 4;
    boolean duplicate = false;
    this.setMySplitter(container, starCount, duplicate);
    assertEquals(734832, this.splitter.getFilteredContainer().size());
 }
 }