/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package com.espertech.esper.collection;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.NoSuchElementException;
/**
* Provides a N! (n-faculty) number of permutations for N elements.
* Example: for 3 elements provides 6 permutations exactly as follows:
* {0, 1, 2}
* {0, 2, 1}
* {1, 0, 2}
* {1, 2, 0}
* {2, 0, 1}
* {2, 1, 0}
*/
public class PermutationEnumeration implements Enumeration<int[]>
{
private final int[] factors;
private final int numElements;
private final int maxNumPermutation;
private int currentPermutation;
/**
* Ctor.
* @param numElements - number of elements in each permutation.
*/
public PermutationEnumeration(int numElements)
{
if (numElements < 1)
{
throw new IllegalArgumentException("Invalid element number of 1");
}
this.numElements = numElements;
this.factors = getFactors(numElements);
this.maxNumPermutation = faculty(numElements);
}
public boolean hasMoreElements()
{
if (currentPermutation == maxNumPermutation)
{
return false;
}
return true;
}
public int[] nextElement()
{
if (currentPermutation == maxNumPermutation)
{
throw new NoSuchElementException();
}
int[] element = getPermutation(numElements, currentPermutation, factors);
currentPermutation++;
return element;
}
/**
* Returns permutation.
* @param numElements - number of elements in each permutation
* @param permutation - number of permutation to compute, between 0 and numElements!
* @param factors - factors for each index
* @return permutation
*/
protected static int[] getPermutation(int numElements, int permutation, int[] factors)
{
/*
Example:
numElements = 4
permutation = 21
factors = {6, 2, 1, 0}
Init: out {0, 1, 2, 3}
21 / 6 == index 3 -> result {3}, out {0, 1, 2}
remainder 21 - 3 * 6 == 3
3 / 2 = second number == index 1 -> result {3, 1}, out {0, 2}
remainder 3 - 1 * 2 == 1
== index 1 -> result {3, 1, 2} out {0}
*/
int[] result = new int[numElements];
List<Integer> outList = new ArrayList<Integer>();
for (int i = 0; i < numElements; i++)
{
outList.add(i);
}
int currentVal = permutation;
for (int position = 0; position < numElements - 1; position++)
{
int factor = factors[position];
int index = currentVal / factor;
result[position] = outList.get(index);
outList.remove(index);
currentVal -= index * factor;
}
result[numElements - 1] = outList.get(0);
return result;
}
/**
* Returns factors for computing the permutation.
* @param numElements - number of factors to compute
* @return factors list
*/
protected static int[] getFactors(int numElements)
{
int[] facultyFactors = new int[numElements];
for (int i = 0; i < numElements - 1; i++)
{
facultyFactors[i] = faculty(numElements - i - 1);
}
return facultyFactors;
}
/**
* Computes faculty of N.
* @param num to compute faculty for
* @return N!
*/
protected static int faculty(int num)
{
if (num == 0)
{
return 0;
}
int fac = 1;
for (int i = 1; i <= num; i++)
{
fac *= i;
}
return fac;
}
}