Improve this recursive code please!
Steven Taschuk
staschuk at telusplanet.net
Fri May 9 17:00:33 EDT 2003
Quoth waxmop:
> Hi - I wrote a program that gets two arguments: numbricks, and numbins.
> The program calculates every possible way to distribute all the bricks
> into the bins, using a recursive function.
[...]
On further reflection I realized that no recursion is necessary in
the first place:
def arrangements(bricks, bins):
"""Iterate over arrangements of so many bricks in so many bins."""
if bricks < 0:
raise ValueError('bricks == %r < 0' % bricks)
if bins <= 0:
raise ValueError('bins == %r <= 0' % bins)
built = [0]*bins
built[0] = bricks
while True:
yield tuple(built)
# Change (..., m, ...bunch of 0s..., n) (where m > 0)
# into (..., m-1, n+1, ...bunch of 0s...)
for i in range(bins-2, -1, -1):
if built[i]: # built[i] == m
break
else:
break
built[i] -= 1
# following three-step waltz needed lest i+1 == bins-1
n = built[-1]
built[-1] = 0
built[i+1] = n + 1
Admittedly this is more cryptic than a recursive solution. But it
does have all the other desired properties: it considers each bin
distinct but all bricks the same; it produces results in sorted
order; it holds only one result in memory at a time, avoiding a
combinatoric explosion of memory consumption; and, as an added
benefit, it doesn't recurse at all. (In a sense, the list of bins
itself serves as the stack.)
It also happens to be easily translated into C, which in this case
produces a considerable performance improvement. (Among (bricks,
bins) values in [1,8]^2, from 4x to 12x faster on my machine, with
indications that the disparity would be greater for greater
values.)
--
Steven Taschuk "The world will end if you get this wrong."
staschuk at telusplanet.net -- "Typesetting Mathematics -- User's Guide",
Brian Kernighan and Lorrinda Cherry
More information about the Python-list
mailing list