Hi Roy,
The method above (at least in the way i have coded it) will soon run out of memory. I tried 10 elements and it threw OutOfMemory exception).I am new to Java and not very familiar with the way it deals with memory and how objects are passed around in procedures. I am sure someone with experience in Java could do much better than the code above (hence more efficient). However going recursively will still eat lots of memory. Starting a new function before another one finishes fills the stack memory.
Another way would be to generate combinations for fixed maximum number of elements and then chopping off elements from the end one by one to form the new shorter combinations as they are needed. This would certainly reduce the need for memory. Certainly but not necessarily noticeably. For big numbers of elements is negligent. E.g. 10 factorial is negligable in comparison to 13 factorial.
So one starts thinking of a iterative solution.
1. As a first step
Need to realise that the problem is also solved by finding a way to swap elements of the array to form all possible unique placements of the elements (thats what combinations are so nothing new here

).
2. In attempt to find all possible unique element placements in iterative manner consider:
- Let N be the number of elements
- Start by generating N unique combinations
One way to do this is to rotate the array of elements N-1 times + 1 time the array as it is
- Take each of the N unique combinations and perform the same swap to all of them
Basically... if you decide to swap Element[1] with Element[5] in the first combination than we must do the same swap on all the other starting unique combinations. This restriction guaranties that the combinations formed after the swapping will also be unique.
The whole concept is based ont the following statement, with which i believe you will agree.
Changing all unique things in the same exact way, guaranties they will still be unique
It is important to change them all in the exact way otherwise if one or more are left untouched the changed ones could become same as those untouched.
As long as the same swap is applied to all unique combinations. The resulting combinations will remain unique in between them. Must emphasise here that this is not to say that the resulting combinations are unique compared to the all previously generated ones. Consider for example swapping elements once and then back again to as they were.
The trick is to realise (if you havent yet) that if the swap sequences are "never reversed" than the new unique combinations will be unique even when compared to the starting ones. "Never reversed" in the sense that in the end the swap sequence does not lead to an array with element positions that were found before via swapping.
"Changing all unique things in the same exact same unique ways, guaranties that they will be unique even to what they were before"
So to cut it short:
Code:
function CombineFixed(Elements)
begin
N := Elements.NumberOfElements;
StartCombinations[0]:=Elements;
for i:=0 to N-1 do
StartCombinations[i]:=rotate(Elements);
for i:=0 to N-1 do
begin
NewUniqueCombinations:=swapCombine(StartCombinations[i]);
Combinations.AddElements(NewUniqueCombinations);
end;
end;
function swapCombine(StartCombination)
begin
N := StartCombinations.NumberOfElements;
// To make sure swap sequences are never reversed
// first swap all Elements in combination with their
// immediate neighbour to the right (because its the right way).
//
// And when all such possible immediate swaps are finished
// do the same but this time swapping with the neigbour one
// after the one to the right (again because right is the right way.)
//
// And when all such possible immediate swaps are finished do
// the same but this time swapping with the neigbour one after the
// one after the one to the right (thats the right way)
//
// ...
//
// And so on until you reach and perform swapps with the neighbours
// which are N-2 steps away to the right.
for Distance:=1 to N-2 do
begin
// Perform all possible swaps with elements in the given distance (to the right)
// Swaps are tried starting from the left most to element up to the one that is
// Distance elements away from the left boundary
for i:=0 to N-Distance do
begin
swap(SwapCombinations[i],SwapCombinations[i+distance]);
NewCombination=SWapCombinations[i];
Combinations.Add(NewCombination);
end;
end;
return Combinations;
end;
Oh well so much talk ... I could be wrong because i havent tested the above code. However two things kind of convinced me that this is a good way to find unique combinations.
1. The laws of preservation of uniqueness
Please dont take these seriously general, however i must say they were very useful due to the finite nature of the problem.
2. The swapCombine method will generate exactly
(N-1)*(N-2)*(N-3) ...*3*2 unique combinations.
And remember swapCombine is called N time (one for each starting unique combination) this means in the end the whole algorithm will generate N factorial unique combinations. And this is the maximum number of unique combinations you could get with N Elements.
Of course in order to achieve exactly what was required in the begining (combinations of all different lengths) an extra step is required. The chopping off:
Code:
function ChopOff(FixedSizeCombinations)
begin
//GEt number of elements in one combination
N := FixedSizeCombinations[0].NumberOfElements;
for i:=0 to N-1 do
begin
//Get a shorter combination by getting only elements up to the i-th position
ShorterCombination=FixedSizeCombinations[0].SubElements(0,i);
VariableLengthCombinations.Add(ShorterCombination);
end;
result:=VariableLengthCombinations;
end;
Hope this helps a little more ...
PS> For all that it matters the swaps could go the Left way (the one we left) which could very well be the right way.
"It is in our collective behaviour that we are most mysterious" Lewis Thomas