In this project our goal is to create methods that will list all solutions to our four counting problems, given parameters n (the number of items to be chosen from, which will be the set {1,...,n}) and k (the number of items to be chosen). Remember the types of sequences we are counting in each case:
Sequence
objects.
Perm
objects.
Set
objects.
Multiset
objects.
We will thus have a class Sequence
and classes Perm
, Set
, and Multiset
extending
Sequence
. Here is something like the API for Sequence
:
public class Sequence {
public int n; // elements will be in {1,...,n}
public int k; // number of elements
public int [] values = new int[k]; // the elements
public Sequence(int n, int k)
{// constructor, gives first sequence, all 1's
for (int i=0; i<k; i++) values[i] = 1;}
public String toString() {
if (k == 0) return "";
else {
String w = Integer.toString(values[0]);
for (int i=1; i<k; i++)
w += (" " + Integer.toString(values[i]));}
return w;}
public boolean isFirst()
{// returns whether this is the first sequence of its type
for (int i=0; i<k; i++)
if (values[i] != 1) return false;
return true;}
public void iterate ()
{// changes this sequence to next one in order
// you write code
// last sequence iterates to first one
}
public Sequence next ()
{// returns sequence after this one in order
// you write code
}
public static void printAll(int n, int k)
{// prints all sequences with of length k and range n
Sequence s = new Sequence(n,k);
do {
System.out.println(s.toString);
s.iterate();}
while (!s.isFirst());}
We then have to write the three classes extending Sequence
,
and overwrite:
isFirst
, to test for the first object
iterate
and next
, to give the next object of
the new class
listAll
, to use the right constructor
That's a start. The other idea we discussed on Friday 1 February was whether
we could make a recursive sequence lister, to avoid the difficulty in
particular of coding the Perm.iterate
method. The idea is that
to list all Perm
objects with parameters n and k, we let a variable
i loop from 1 through n, and for each i we list length-k perms starting with
i and continuing with a translated version of all perms with parameters n-1
and k-1. For example, let n=4, k=3, and i=2. There are six perms of length
3 starting with 2, which are 213, 214, 231, 234, 241, and 243. If we take the
six perms of length 2 with elements from {1,2,3}, we get 12, 13, 21, 23, 31, and
32. We make each of the length-3 perms by putting a 2 first and then
translating the two elements of the length-2 perm, with 2's becoming 3's and
3's becoming 4's.
The problem with implementing this is that our sequence lister must have an interface allowing it to accept the output of another version of itself. I think the easiest way to do this is to have the lister be an iterator object, which we can initialize and iterate as needed -- then the length-k iterator can contain a length-(k-1) iterator within it.
Here's the promised additional detail on the alternate implementation.
Let's define a PermIterator
class:
public class PermIterator
{// lists all Perms of range n and length k
int n; // entries range from 1 to n
int k; // range of entries
PermIterator sub; // PermIterator variable for recursive call
int i; // index for looping through value of (virtual) current[0]
public PermIterator (int newN, int newK)
{// sets up sub if required
n = newN;
k = newK;
if (k > 0) {
i = 1;
sub = new PermIterator(n-1; k-1);}}
public void reset()
{// sets current to [1,2,...,k], i to 1, resets sub if it exists
// code missing
}
public boolean hasNext()
{// returns whether another Perm is available in the list
if (i < n) return false;
if (k == 0) return false;
return sub.hasNext();}
public Perm next()
{// returns next Perm in canonical ordering
Perm out = new Perm(n,k);
if (sub.hasNext())
{// return i followed by translation of sub.next()
// code missing...
}
else {
if (i < n) i++;
else i = 1;}}}
Last modified 19 February 2008