JAVA组合函数Combination

来源:互联网 发布:oppoa59的手动网络在哪 编辑:程序博客网 时间:2024/05/22 02:22

JDK,Apache commons math里都没有发现组合函数,因而自己写了一个。

首先定义接口

package math.combination;import java.util.Collection;import java.util.List;/** * the interface for combination * @author jhren * * @param <T> */public interface Combinationable<T> {/** * get combinations from start to end [start, end] * it equals findCombiantions(start),findCombiantions(start+1),  * ...... * findCombinations(end-1), findCombinations(end) */public List<List<T>> findCombinations(int start, int end);/** * get all combinations * it equals findCombinations(0, size) */public List<List<T>> findCombinations();/** * find a combinations for size * @param size * @return */public List<List<T>> findCombinations(int size);public Collection<T> getElements();}

第一个个实现,输出的组合会按照类型T升序排列

例如输入为[3,2,1]的全组合为

[]
[3]
[2]
[1]
[2, 3]
[1, 3]
[1, 2]
[1, 2, 3]

package math.combination;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.List;/** * the T should be Comparable the T in one combination list is sort by the * Comparable T *  * @author jhren *  * @param <T> */public class ComparableCombination<T extends Comparable<? super T>> implementsCombinationable<T> {private Collection<T> elements = new ArrayList<T>();public ComparableCombination(Collection<T> elements) {this.elements.addAll(elements);}@Overridepublic List<List<T>> findCombinations(int start, int end) {if (start < 0) {throw new IllegalArgumentException("start can't be negative: "+ start);}if (end > elements.size()) {throw new IllegalArgumentException("end can't be larger than elements size: " + end + ">"+ elements.size());}if(start > end) {throw new IllegalArgumentException("start can't be larger than end: " + start + ">"+ end);}List<List<T>> result = new ArrayList<List<T>>();for (int i = start; i <= end; i++) {result.addAll(findCombinations(i));}return result;}@Overridepublic List<List<T>> findCombinations() {return findCombinations(0, elements.size());}@Overridepublic List<List<T>> findCombinations(int size) {if (size < 0) {throw new IllegalArgumentException("size can't be negative: "+ size);}if (size > elements.size()) {throw new IllegalArgumentException("size can't be larger than elements size: " + size + ">"+ elements.size());}List<List<T>> result = new ArrayList<List<T>>();if (size == 0) {result.add(new ArrayList<T>());return result;}List<List<T>> combinations = findCombinations(size - 1);for (List<T> combination : combinations) {for (T element : elements) {if (combination.contains(element)) {continue;}List<T> list = new ArrayList<T>();list.addAll(combination);if (list.contains(element))continue;list.add(element);Collections.sort(list);if (result.contains(list))continue;result.add(list);}}return result;}@Overridepublic Collection<T> getElements() {return elements;}}

第二个实现,会保持元素的输入顺序

例如输入为[3,2,1]的全组合为

[]
[3]
[2]
[1]
[3, 2]
[3, 1]
[2, 1]
[3, 2, 1]


package math.combination;import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.List;/** * the T in one combination list is sort by the input sequence * @author jhren * * @param <T> */public class CombinationSortByInput<T> implements Combinationable<T> {static private class Element<E> implements Comparable<Element<E>> {private int rank;private E e;public E getE() {return e;}private Element(E e, int rank) {this.e = e;this.rank = rank;}@Overridepublic int compareTo(Element<E> o) {return this.rank - o.rank;}}private Combinationable<Element<T>> combination = null;public CombinationSortByInput(Collection<T> elements) {Collection<Element<T>> elementsInput = convertCollection(elements);combination = new ComparableCombination<Element<T>>(elementsInput);}@Overridepublic List<List<T>> findCombinations(int start, int end) {List<List<Element<T>>> elementsOutput = combination.findCombinations(start, end);List<List<T>> output = convertListOfList(elementsOutput);return output;}@Overridepublic List<List<T>> findCombinations() {return findCombinations(0, combination.getElements().size());}@Overridepublic List<List<T>> findCombinations(int size) {return findCombinations(size,size);}private static <T> Collection<Element<T>> convertCollection(Collection<T> input) {Collection<Element<T>> elementCollectionInput = new ArrayList<Element<T>>();Iterator<T> iterator = input.iterator();int i = 0;while(iterator.hasNext()) {T t = iterator.next();Element<T> element = new Element<T>(t, i++);elementCollectionInput.add(element);}return elementCollectionInput;}private static <T> List<List<T>> convertListOfList(List<List<Element<T>>> elementsOutput) {List<List<T>> output = new ArrayList<List<T>>();for(List<Element<T>> elementList : elementsOutput) {List<T> tlist = convertList(elementList);output.add(tlist);}return output;}private static <T> List<T> convertList(Collection<Element<T>> elementList) {List<T> tlist = new ArrayList<T>();for(Element<T> element: elementList) {T t = element.getE();tlist.add(t);}return tlist;}@Overridepublic Collection<T> getElements() {return convertList(combination.getElements());}}

顺便附上TestNG unitestcode

package math.combination;import java.util.Arrays;import java.util.List;import math.combination.Combinationable;import math.combination.ComparableCombination;import org.testng.annotations.Test;import org.testng.annotations.BeforeClass;import static org.testng.AssertJUnit.assertNotNull;import static org.testng.AssertJUnit.assertEquals;import static org.testng.AssertJUnit.assertTrue;public class TestComparableCombination {private Combinationable<Integer> combination= null;@Testpublic void testGetElements() {assertNotNull(combination.getElements());assertEquals(3, combination.getElements().size());}@Testpublic void testFindCombinationsSizeZero() {List<List<Integer>> lists = combination.findCombinations(0);assertNotNull(lists);assertEquals(1, lists.size());assertNotNull(lists.get(0));assertEquals(0, lists.get(0).size());}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsSizeMinus() {combination.findCombinations(-1);}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsStartMinus() {combination.findCombinations(-1,2);}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsSizeOverflow() {combination.findCombinations(combination.getElements().size() + 1);}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsEndOverflow() {combination.findCombinations(0,combination.getElements().size() + 1);}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsStartEndWrongOrder() {combination.findCombinations(1,0);}@Testpublic void testFindCombinationsSizeTwo() {List<List<Integer>> lists = combination.findCombinations(2);assertNotNull(lists);assertEquals(3, lists.size());for(List<Integer> list: lists) {assertEquals(2, list.size());int element0 = list.get(0);int elements1 = list.get(1);assertTrue(element0 < elements1);}}@Testpublic void testFindAllCombinations1() {List<List<Integer>> lists = combination.findCombinations();assertNotNull(lists);assertEquals(8, lists.size());for(List<Integer> list : lists) {System.out.println(list);}}@Testpublic void testFindAllCombinations2() {List<List<Integer>> lists = combination.findCombinations(0, combination.getElements().size());assertNotNull(lists);assertEquals(8, lists.size());}@Test(timeOut=20000)public void testPerformance() {combination = new ComparableCombination<Integer>(Arrays.asList(3,2,1,4,5));for(int i = 0;i < 100000; i++) {combination.findCombinations();}}@BeforeClasspublic void beforeClass() {combination = new ComparableCombination<Integer>(Arrays.asList(3,2,1));}}

package math.combination;import java.util.Arrays;import java.util.List;import math.combination.CombinationSortByInput;import math.combination.Combinationable;import org.testng.annotations.Test;import org.testng.annotations.BeforeClass;import static org.testng.AssertJUnit.assertNotNull;import static org.testng.AssertJUnit.assertEquals;import static org.testng.AssertJUnit.assertTrue;public class TestCombinationSortByInput {private Combinationable<Integer> combination= null;@Testpublic void testGetElements() {assertNotNull(combination.getElements());assertEquals(3, combination.getElements().size());}@Testpublic void testFindCombinationsSizeZero() {List<List<Integer>> lists = combination.findCombinations(0);assertNotNull(lists);assertEquals(1, lists.size());assertNotNull(lists.get(0));assertEquals(0, lists.get(0).size());}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsSizeMinus() {combination.findCombinations(-1);}@Test (expectedExceptions = IllegalArgumentException.class)public void testFindCombinationsSizeOverflow() {combination.findCombinations(combination.getElements().size() + 1);}@Testpublic void testFindCombinationsSizeTwo() {List<List<Integer>> lists = combination.findCombinations(2);assertNotNull(lists);assertEquals(3, lists.size());for(List<Integer> list: lists) {assertEquals(2, list.size());int element0 = list.get(0);int elements1 = list.get(1);assertTrue(element0 > elements1);}}@Testpublic void testFindAllCombinations1() {List<List<Integer>> lists = combination.findCombinations();assertNotNull(lists);assertEquals(8, lists.size());for(List<Integer> list : lists) {System.out.println(list);}}@Testpublic void testFindAllCombinations2() {List<List<Integer>> lists = combination.findCombinations(0, combination.getElements().size());assertNotNull(lists);assertEquals(8, lists.size());}@BeforeClasspublic void beforeClass() {combination = new CombinationSortByInput<Integer>(Arrays.asList(3,2,1));}@Test(timeOut=20000)public void testPerformance() {combination = new CombinationSortByInput<Integer>(Arrays.asList(3,2,1,4,5));for(int i = 0;i < 100000; i++) {combination.findCombinations();}}}


原创粉丝点击