public static IntListList P (IntList L)
P(tail(L)) =
P([2,3]) =
[[2,3],[3,2]]
The question is, how do we combine the head of the list (in this case, 1)
to the result we get from finding the permutations of the tail of the list
in order to get the final answer? What we need to do is to insert the head
of the list into all the spots in each of the lists we get for P(tail(L)).
Let's say we have a method called insertNumber which does this
for us. This is how insertNumber would workinsertNumber(1,[2,3]) = [[1,2,3],[2,1,3],[2,3,1]] insertNumber(1,[3,2]) = [[1,3,2],[3,1,2],[3,2,1]]In other words, given an integer and an IntList, insertNumber returns an IntListList created by placing the integer into the IntList in each of the possible places in the IntList (i.e. at the beginning, between each element, and at the end). Assuming we have
insertNumber (more wishful thinking!), the way we can solve our permutations
problem is by creating a mapping function which applies insertNumber with
the head of our list to the result we get from finding the permutations of the tail of
the list. This is how mapInsertNumber would work
mapInsertNumber(1,[[2,3],[3,2]]) =
ILL.append(insertNumber(1,[2,3]),
insertNumber(1,[3,2]))
Since insertNumber gives us an IntListList, we put all the results of applying
insertNumber to each list in the IntListList by appending them together.
So, our code for permutations so far is the following:
// Returns the permutations of a given list of integers.
public static IntListList P (IntList L) {
if (IL.isEmpty(L)) {
// can't just return an empty IntListList or else there will be nothing to prepend on to!
return ILL.prepend(IL.empty(),ILL.empty());
} else {
// wishful thinking strategy: insert the head of the list
// into the answer we get from calculating the permutations of the tail of the list
return mapInsertNumber(IL.head(L), P(IL.tail(L)));
}
}
// Returns an IntListList from applying insertNumber of the given integer n
// to each IntList in the given IntListList L
public static IntListList mapInsertNumber (int n, IntListList L) {
if (ILL.isEmpty(L)) {
return ILL.empty();
} else {
return ILL.append(insertNumber(n, ILL.head(L)),
mapInsertNumber(n, ILL.tail(L)));
}
}
insertNumber using Wishful ThinkinginsertNumber ispublic static IntListList insertNumber (int n, IntList L)Let's use the following as our concrete example:
insertNumber(1,[2,3,4]) = [[1,2,3,4],[2,1,3,4],[2,3,1,4],[2,3,4,1]]Using wishful thinking, let's assume that we can find the result for applying
insertNumber to the tail of the list.insertNumber(1,[3,4]) = [[1,3,4],[3,1,4],[3,4,1]]What do we need to do to the answer to our smaller problem in order to get the answer to our original problem? There are two things that need to be done. We need to get the solution which starts with the integer given. It's the one we get if we add n to the beginning of L which we can do with the following bit of code:
IL.prepend(n,L)The rest of the solutions don't begin with n. What do they begin with? The head of L! In fact, all we need to do is prepend the head of L to each list we get from the result of doing
insertNumber(n,tail(L)). This is a mapping function so we will call it
mapPrepend. The way mapPrepend works is that it takes an integer
and a list of IntLists and it returns the IntListList which results from prepending the integer
to each IntList inside the given IntListList. So, mapPrepend works like so:
mapPrepend(2,[[1,3,4],[3,1,4],[3,4,1]]) =
ILL.prepend(IL.prepend(2,[1,3,4]),
ILL.prepend(IL.prepend(2,[3,1,4]),
ILL.prepend(IL.prepend(2,[3,4,1]),
ILL.empty())))
So, our code for the rest of the problem is the following:
// Returns the list of lists which result from inserting a given integer n
// into all the possible places in a given IntList L.
public static IntListList insertNumber (int n, IntList L) {
if (IL.isEmpty(L)) {
// if given an empty IntList, we want to create an IntList with n in it
// and that will be the single element in the resulting IntListList
return ILL.prepend(IL.prepend(n, IL.empty()),
ILL.empty());
} else { // implementation of strategy outlined above
return ILL.prepend(IL.prepend(n, L), // solution with n at the beginning
// solutions starting with the head of the list given
mapPrepend(IL.head(L), insertNumber(n, IL.tail(L))));
}
}
// Returns an IntListList which has the integer n prepended to each
// IntList in L.
public static IntListList mapPrepend (int n, IntListList L) {
if (ILL.isEmpty(L)) { // no lists to prepend an integer to
return L;
} else {
return ILL.prepend(IL.prepend(n, ILL.head(L)), // prepend to first list
mapPrepend(n, ILL.tail(L))); // prepend to rest of lists
}
}