Welcome, guest | Sign In | My Account | Store | Cart
def bell_permutations(n):
    """Return permutations of [0, 1, ..., n - 1] such that each permutation
    differs from the last by the exchange of a single pair of neighbors.
    The ``n!`` permutations are returned as an iterator. This is an
    implementation of the algorithm of Even described at
    http://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm.
    """
    assert type(n) is int and n > 0
    if n == 1:
        yield (0,)
    elif n == 2:
        yield (0, 1)
        yield (1, 0)
    elif n == 3:
        for li in [(0, 1, 2), (0, 2, 1), (2, 0, 1), (2, 1, 0), (1, 2, 0), (1, 0, 2)]:
            yield li
    else:
        m = n - 1
        op = [0] + [-1]*m
        l = list(range(n))
        while True:
            yield tuple(l)
            # find biggest element with op
            big = None, -1  # idx, value
            for i in range(n):
                if op[i] and l[i] > big[1]:
                    big = i, l[i]
            i, _ = big
            if i is None:
                break  # finish if there is no op
            # swap it with neighbor in the indicated direction
            j = i + op[i]
            l[i], l[j] = l[j], l[i]
            op[i], op[j] = op[j], op[i]
            # if it landed at the end or if the neighbor in the same
            # direction is bigger then turn off op
            if j == 0 or j == m or l[j + op[j]] > l[j]:
                op[j] = 0
            # any element bigger to the left gets +1 op
            for i in range(j):
                if l[i] > l[j]:
                    op[i] = 1
            # any element bigger to the right gets -1 op
            for i in range(j + 1, n):
                if l[i] > l[j]:
                    op[i] = -1

Diff to Previous Revision

--- revision 1 2013-12-19 15:20:53
+++ revision 2 2013-12-23 02:44:43
@@ -26,6 +26,8 @@
                 if op[i] and l[i] > big[1]:
                     big = i, l[i]
             i, _ = big
+            if i is None:
+                break  # finish if there is no op
             # swap it with neighbor in the indicated direction
             j = i + op[i]
             l[i], l[j] = l[j], l[i]
@@ -42,7 +44,3 @@
             for i in range(j + 1, n):
                 if l[i] > l[j]:
                     op[i] = -1
-            # finish when there are no ops
-            if not any(i for i in op):
-                yield tuple(l)
-                break

History