GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS Toufik

3 downloads 0 Views 149KB Size Report
Keywords: Gray codes, Loopless algorithms, Partitions, Plane trees ... Any partition Π can be written in the canonical sequential form π1π2 ··· πn, where i ∈ Aπi ...
GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

Toufik Mansour and Ghalib Nassar Department of Mathematics, University of Haifa, 31905 Haifa, Israel [email protected], nassar [email protected] Abstract The generation of efficient Gray codes and combinatorial algorithms that list all the members of a combinatorial object has received a lot of attention in the last few years. Knuth gave a code for the set of all partitions of [n] = {1, 2, . . . , n}. Ruskey presented a modified version of Knuth’s algorithm with distance 2. Ehrlich introduced a looplees algorithm for the set of the partitions of [n]; Ruskey and Savage generalized Ehrlich’s results and introduced two Gray codes for the set of partitions of [n]. In this paper, we give another combinatorial Gray code for the set of the partitions of [n] which differs from the aforementioned Gray codes. Also, we construct a different loopless algorithm for generating the set of all partitions of [n] which gives a constant time between successive partitions in the construction process. Keywords: Gray codes, Loopless algorithms, Partitions, Plane trees 2000 Mathematics Subject Classification: Primary 05A05, 94B25, Secondary: 05A15 1. Introduction A Gray code of a combinatorial family of objects is a listing of the objects so that the transition from an object to its successor takes only a “small change” or a small of number different letters. The definition of “small change” or small distance, depends on the particular family. For example, a Gray code for the permutations on [n] = {1, 2, . . . , n} may be defined as a list of the permutations on [n] so that successive permutations differ by an adjacent transposition (see for example [5, 18]). In this case the distance is exactly 2. A Gray code is said to be strict if successive elements differ in exactly one position and in that position the difference between the letters is either one or minus one. Several authors have been interested in Gray codes for permutations [5, 12, 18], involutions, fixed-point free involutions [22], derangements [3], permutations with a fixed number of cycles [1], and partitions of a set [4, 14]. An algorithm which generates the objects of a combinatorial family is said to be loopless if it takes no more than a constant amount of time between successive objects. The concept of loopless algorithms was firstly introduced by Ehrlich [4]. The loopless idea was implemented in different combinatorial families such as permutations [4, 8], multiset permutations [9, 10, 17, 19], and partitions of a set [4, 14]. A partition Π of the set [n] is a collection A1 , A2 , . . . , Ad of nonempty disjoint subsets of [n] such that ∪di=1 Ai = [n]. The elements of a partition are called blocks. We assume that A1 , A2 , . . . , Ad are listed in increasing order of their minimum elements, that is min A1 < min A2 < · · · < min Ad . Any partition Π can be written in the canonical sequential form π1 π2 · · · πn , where i ∈ Aπi (see, e.g. 1

2

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

[7]). From now on, we identify each partition with its canonical sequential form, see [16, page 18-19]. For example, if Π = {1, 4}, {2, 5, 7}, {3}, {6} is a partition of [7], then its canonical sequential form is π = 1231242 and in such case we write Π = π. In other words, a partition π = π1 π2 · · · πn of [n] is a word on the alphabet [n] so that (1)

1 ≤ πi ≤ max πj + 1, j∈[i−1]

for all 1 ≤ i ≤ n, and π is called a restricted growth function, see for instance [14, Page 90]. We denote the set of all partitions of [n] by Pn . For example: P1 = {1}, P2 = {11, 12} and P3 = {111, 112, 121, 122, 123}. Several authors have studied Gray codes for Pn and developed algorithms for generating Pn looplessly (see [4, 14] and references therein). More precisely, Ehrlich [4] observed that a strict Gray code for Pn is impossible for infinitely many values of n. Nevertheless, he found a loopless algorithm for generating the set of partitions Pn with the following property: successive partitions differ in one letter with the difference being 1, except if the change is in the largest letter of the partition, which can change to 1. The algorithm of Ehrlich is similar to Knuth’s algorithm. Both algorithms successively append the values 1, 2, . . . , 1 + maxj πj to partitions in Pn−1 , but in different order. Ruskey [13] presented a modification of Knuth’s algorithm in which the distance is at most 2, see Table 1. Ruskey and Savage [14] generalized Ehrlich’s results to the set of strings of non-negative integers satisfying 1 ≤ a1 ≤ k and ai ≤ 1 + max{a1 , a2 . . . , ai−1 , k − 1}. Note that the case k = 1 gives the set Pn . In particular, they showed two different Gray codes for Pn [14, Corollary 1]. Table 1 lists these gray codes for P4 together with the result of our algorithm which is discussed in Section 2. P4 in Knuth’s Modified Lex. order Gray code Knuth 1111 1111 1111 1112 1112 1112 1121 1123 1123 1122 1122 1122 1123 1121 1121 1211 1231 1221 1212 1232 1222 1213 1233 1223 1221 1234 1233 1222 1223 1234 1223 1222 1232 1231 1221 1231 1232 1211 1211 1233 1212 1212 1234 1213 1213

Ehrlich’s Ruskey & Savage Section 2 algorithm algorithms Algorithm 2 1111 1111 1111 1111 1112 1112 1112 1112 1122 1122 1122 1122 1123 1123 1123 1121 1121 1121 1121 1123 1221 1221 1221 1223 1223 1223 1222 1221 1222 1222 1223 1222 1232 1212 1233 1212 1233 1211 1234 1211 1234 1213 1231 1213 1231 1212 1232 1233 1211 1232 1212 1231 1213 1231 1213 1234 1212 1234 1211 1232

Table 1. Listing P4

Our algorithm creates a Gray code with distance 1 for Pn , see Section 2. Our technique is based on changing each time the rightmost letter πi in a partition π = π1 π2 · · · πi to the maximal unused letter in {1, 2, . . . , 1 + maxj≤i−1 πj }, where the initial value of each letter πi is 1. As we will see our Gray

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

3

code starts with the partition 11 · · · 1 ∈ Pn and ends with the partition 123223223 · · · ∈ Pn , which makes it different from the Gray codes. In Section 3 we give a loopless algorithm that generates Pn . Our algorithm is based on two steps: At first we create a plane tree whose vertices are the partitions of [n]. Then, we define a new traversal method for the plane trees, which gives a constant time between successive partitions. 2. Gray code for Pn Our main goal in this section is to give a Gray code with distance 1 for Pn . 2.1. Recursive construction. At first, we present a recursive construction of the set of the partitions of [n]. In order to do so we define the following notation. Let ℓ1 , . . . , ℓn be n lists, then ℓ1 ◦ℓ2 ◦· · ·◦ℓn = n

ℓi denotes the concatenation of these lists. Let m be an integer or integer sequence, then ℓ · m and i=1

m · ℓ, respectively, denotes the list obtained by appending ℓ to each sequence of m on the left and on the right, respectively. Lemma 1. Let n ≥ k ≥ 1 and define V1,1 = 1. Then the list Vn,k is defined by:  Vn−1,k · 1, k=1    k Vn,k = (Vn−1,k−1 · k) ◦ (Vn−1,k · i), 1 < k < n  i=1   Vn−1,k−1 · n, k=n

is the set of partitions in Pn with exactly k blocks. Moreover, the list Vn = Vn,1 ◦ · · · ◦ Vn,n is the set of all partitions in Pn . Proof. From (1) to build Vn,k either we append every partition of the list Vn−1,k with an element i to the end of it, where i = 1, 2, . . . , k, or we append every partition of the list Vn−1,k−1 with an element k to the end of it. Therefore, Vn,k is the set Pn,k ; the set of partitions of Pn with exactly k blocks. Using Sn the fact that Pn = k=1 Pn,k , we obtain that Vn,1 ◦ · · · ◦ Vn,n = Pn , which completes the proof.  The cardinality of Vn,k is given by Sn,k the Stirling number of the second kind (see for instance [15, Page 33]) and P it satisfies Sn,k = Sn−1,k−1 + kSn−1,k for 1 ≤ k ≤ n, and Sn,k = 0 for k > n or k = 0. And Bn = nk=1 Sn,k is the n-th Bell number (see for instance [15, Page 33]); the sequence of Bell  Pn−1 numbers satisfies the recurrence relation Bn = j=0 n−1 Bj , with initial condition B0 = 1. j

The following example illustrates the above lemma. For n = 0 there is only the empty partition. For n = 1 we have one partition, namely 1. For n = 2, V2,1 = (V1,1 ) · 1 = 11 and V2,2 = (V1,1 ) · 2 = 12. For n = 3, we get V3,1 = V2,1 · 1 = 111,

2

V3,2 = (V2,1 · 2) ◦ (V2,2 · i) = 112 ◦ 121 ◦ 122 = 112, 121, 122, i=1

V3,3 = V2,2 · 3 = 123. Thus the lists of the partitions of [n] for n = 2, 3 are given by V2 = V2,1 ◦ V2,2 = 11, 12 and V3 = V3,1 ◦ V3,2 ◦ V3,3 = 111, 112, 121, 122, 123, respectively. Lemma 1 defines an iterative construction for Pn . Its algorithmic version is Algorithm 1, and the induced order is the lexicographic order.

4

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

Algorithm 1 Iterative algorithm. 1: 2: 3: 4: 5: 6: 7: 8: 9:

set π[1] = π[2] = · · · = π[n] = 1, j = n while j > 0 do print π[1]π[2] · · · π[n] while π[j] = maxi≤j−1 π[i] + 1 do j =j−1 end while increase π[j] by 1 set π[j + 1] = π[j + 2] = · · · = π[n] = 1 end while

In order to explain how Algorithm 1 works, we give the following definitions. An index i of a word w = w1 w2 · · · wn on the alphabet [n] is said to be active if wi < maxj∈[i−1] wj + 1. Algorithm 1 generates first the initial partition 11 · · · 1, then it generates all the other partitions of [n] by repeating the following two steps: (1) While i = n is an active index, increase πi by 1. (2) Otherwise, find a maximal active index i > 1 (if it exists), increase πi by 1, and then set πi+1 = πi+2 = · · · = πn = 1. The C++ version of Algorithm 1 appears in Appendix A. For instance, Algorithm 1 for n = 1, 2, 3, 4 gives 1, 11, 12, 111, 112, 121, 122, 123 and 1111, 1112, 1121, 1122, 1123, 1211, 1212, 1213, 1221, 1222, 1223, 1231, 1232, 1233, 1234, respectively. Note that Algorithm 1 generates iteratively all partitions of [n], where the generating process is uncomplicated and its implementation is simple too. On the other hand, Algorithm 1 is not efficient, since • the transition from some partition to its successors takes O(n) time: if i = n is an inactive index, then Algorithm 1 decreases i until it is an active index in the partition, and then sets πj = 1, for all j = i + 1, i + 2, . . . , n. • The number of letters that changes from some partition to its successors is at least one, but sometimes n − 1 changes are required. Now our aim is to present a Gray code for Pn . In order to do that, we need the following notations and definitions. Assume that Pn is listed as a list L = π (1) , π (2) , . . . , π (Bn ) , where Bn is the n-th Bell number. For each partition π (j) ∈ L we associate the following: (j)

• stack[i] to be the vector of all possible values of πi , that is, (j)

stack[i] = [1, 2, . . . , maxk≤i−1 πk + 1]. We denote the length of the vector stack[i] by len-stack[i]. • f lag-stack[i] to be the binary vector [b1 , b2 , . . . , blen-stack[i] ], where bi is 1 if the i-th integer coordinate of the vector stack[i] has already been used, and is 0 otherwise. • nones-stack[i] to be number of ones in the binary vector f lag-stack[i]. Theorem 2. Algorithm 2 with input n generates a Gray code for Pn with distance 1.

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

5

Algorithm 2 Gary code algorithm for Pn . 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:

for i = 1 to n do set π[i] = 1 end for set stack[1][1] = 1, len-stack[1] = 1, f lag-stack[1][1] = 1 and nones-stack[1] = 1 for i = 2 to n do set stack[i][1] = 1, stack[i][2] = 2, len-stack[i] = 2, f lag-stack[i][1] = 1, f lag-stack[i][2] = 0, nones-stack[i] = 1 end for set position = 2 while position > 1 do print the vector π let position to be the maximal index i ∈ {1, 2, . . . , n} such that nones-stack[i] 6= len-stack[i] (if it does not exists set pos = 0) if pos > 0 then increase nones-stack[position] by 1 let m to be the maximal letter π[i] for all i = 1, 2, . . . , position − 1 let kpos to be the maximal index i in the set {1, . . . , len-stack[position]} such that f lag-stack[position][i] = 0 set π[position] = stack[position][kpos] and f lag-stack[position][kpos] = 1 for i = pos to n − 1 do if m < π[i] then m = π[i] end if set nones-stack[i + 1] = 1 for j = 2 to m + 1 do set stack[i + 1][j − 1] = j and f lag-stack[i + 1][j − 1] = 0 end for set stack[i + 1][m + 1] = 1, len-stack[i + 1] = m + 1 and f lag-stack[i + 1][m + 1] = 0 if π[i + 1] > 1 then set f lag-stack[i + 1][π[i + 1] − 1] = 1 else set f lag-stack[i + 1][m + 1] = 1 end if end for end if end while

Proof. The initial partition that Algorithm 2 generates is the partition 11 · · · 1 ∈ Pn . The algorithm generates the list L as follows: When the algorithm generates the partition π = π1 π2 · · · πn ∈ Pn , it finds the following parameters: • stack[i] the set of all possible letters 1, 2, . . . , maxj≤i−1 πj + 1, i = 1, 2, . . . , n. • f lag-stack[i][j] = 1 if the letter j in stack[i] has already been used and 0 otherwise. Then, the algorithm finds the maximal index i and j so that the vector f lag-stack[i][j] = 0 and sets πi as stack[i][j]. The algorithm continues until it fails to find such indices i and j.

6

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

Thus, the algorithm generates the set of all partitions of [n] starting from the partition 11 · · · 1 so that • each partition in the list is obtained from the previous one by changing exactly one letter. • the new partition π1 π2 · · · πn generated by the algorithm satisfies 1 ≤ πi ≤ maxj≤i−1 πj + 1. Hence, by (1) the resulting list L is a list for Pn such that any two consecutive partitions in L differ by exactly one letter.  Note that Algorithm 2 generates a Gray code for Pn starting with the partition 11 · · · 1 ∈ Pn and ending with the partition 123223223 · · · ∈ Pn , n ≥ 3, which differs from the known algorithms listed in Table 1. Algorithm 2, written in C++, appears in Appendix B. For example, Algorithm 2 for n = 1, 2, 3, 4 gives the lists Ln , where • • • • •

L1 = 1, L2 = 11, 12, L3 = 111, 112, 122, 121, 123, L4 = 1111, 1112, 1122, 1121, 1123, 1223, 1221, 1222, 1212, 1211, 1213, 1233, 1231, 1234, 1232. L5 = 11111, 11112, 11122, 11121, 11123, 11223, 11221, 11222, 11212, 11211, 11213, 11233, 11231, 11234, 11232, 12232, 12231, 12234, 12233, 12213, 12211, 12212, 12222, 12221, 12223, 12123, 12121, 12122, 12112, 12111, 12113, 12133, 12131, 12134, 12132, 12332, 12331, 12334, 12333, 12313, 12311, 12314, 12312, 12342, 12341, 12345, 12344, 12343, 12323, 12321, 12324, 12322.

Note that Algorithm 2 does not generate the set Pn looplessly, that is, to generate a partition from the previous one in the list, the algorithm needs O(n) time (not a constant time). Our next goal is to find a loopless algorithm for generating the set of partitions Pn .

3. Loopless algorithm In this section we generate the set of the partitions of [n] looplessly, that is, in the generation process we obtain each partition from its predecessor by making ”small changes” that are independent on n. This implies that the transition from a partition to the next one takes a constant time. In order to do so we first represent the set of partitions of [n] as a labeled plane tree. Then we use the labeled plane tree to construct a loopless algorithm for generating the set Pn . 3.1. Plane trees and partitions. A rooted tree is a tree with a distinct vertex called the root. In what follows, we always draw a rooted tree with the root on the top level. A vertex w is said to be a child or successor of a vertex v if w is on the next lower level connected to v; the vertex v is then said to be the parent of w. The degree of v is the total number of its children. A leaf is a vertex with degree 0, that is a vertex with no children. A rooted tree in which the children of each vertex are ordered is also called a plane tree. In this section we present the set Pn of partitions of [n] as the vertices of a plane tree Tn . For fixed n, we define the plane tree Tn of the set of partitions Pn as follows: • Let 11 · · · 1 ∈ Pn be the root vertex of Tn .

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

7

• Let v be the vertex π1 π2 · · · πm 11 · · · 1 at level m in Tn with πm 6= 1 (if πj = 1 for all j then we set m = 1). Then we define the children of v (from left to right) to be the vertices π1 π2 · · · πm 11 · · · 1k11 · · · 1 ∈ Pn for all k = 2, 3, . . . maxj=1,2,...,m πj + 1. In this context Tn is called the partition tree of [n]. It is obvious that the vertices of the tree Tn are exactly the partitions of [n]. For example, see Figure 1 to find the partition tree of [n] for n = 1, 2, 3, 4. 1

11

111

12

121 122

1111 112

1211

123

1221 1222

1212

1231

1121 1213

1122

1112 1123

1223 1232 1233 1234

Figure 1. Tree partitions of [n], where n = 1, 2, 3, 4 From the construction of the partition tree of [n] we can state the following result. Corollary 3. We have (i) (ii) (iii) (iv)

the the the the

number number number number

of of of of

vertices in Tn is given by Bn , leaves of Tn is given by Bn − Bn−1 , n ≥ 2,  vertices at level m of the tree Tn is given by n−1 m Bm ,  internal vertices at level m of the tree Tn is given by n−2 m Bm , n ≥ 2,

where Bn is the n-th Bell number.

Proof. From the fact that the vertices of the tree Tn are labeled by the partitions of [n], (i) holds. A leaf in the tree Tn is a vertex labeled by the partition π = π1 π2 · · · πn of [n] so that πn 6= 1. On the other hand, the number of partitions π of [n] with πn = 1 equals Bn−1 . Thus, by (i), the number of leaves in Tn is given by Bn − Bn−1 . Hence (ii) holds. A vertex at level m in the tree Tn is a vertex labeled by a partition Π = A1 , A2 , · · · , Ak of [n] with k blocks so that | ∪m j=2 Aj | = m. Hence, the number of such partitions is given by choosing n − 1 − m letters of B1 from the set {2, 3, . . . , n} (additionally, 1 ∈ A1 ), and the rest can be partitioned in all possible ways, which equals     n−1 n−1 Bm = Bm . n−1−m m Thus (iii) holds. An internal vertex at level m in the tree Tn is a vertex π such that πn = 1. Similarly to the analysis in the proof of (iii) we obtain that the number of internal vertices at level m in Tn is given by       n−1 n−1 n−2 Bm − Bm = Bm , m m−1 m which completes the proof.



8

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

Note that the partition tree that we have introduced are defined recursively. So if we use it as our data structure for generating the partitions of [n], then the generation depends on the depth of the tree, in other words, the transition from a partition to the next one depends on n. Thus, in order to get a loopless construction, we adopt a different data structure. 3.2. Modifying the partition tree. Generating the partitions of [n] by traversing the partition tree using the standard tree traversal methods creates a problem, because they are performed recursively. Therefore, that the transition from one partition to its successor takes O(n) time (non-constant time). We instead introduce a new traversal method that enables us to get rid of the O(n) cost, and thus leads to the desired loopless generation. Our method is to perform a circular traversal for the tree, level by level, from left to right starting from the tree root. The traversal of a tree level is called circular if the leftmost node in some level is next to the rightmost node in the same level. We illustrate our approach by the following examples for n = 3, 4. 111 121

1111 112 1121

1211 122

1112

123 1221

1222

1212

1223

1232

1231

1213

1233

1234

1122

1123

Figure 2. The partition tree Tn traversal starting from the tree root for n = 3, 4 Now we introduce the data structure that corresponds to the traversal of Tn presented in Figure 2. The partitions of [n] will be written to a data structure named doubly circularly linked list. A linked list is one of the fundamental dynamic data structures, and can be used to implement other data structures. It consists of a sequence of nodes, each containing arbitrary data fields and one or two references pointing to the next or the next and previous nodes, respectively. The circularly linked list is a linked list such that the first and final nodes are linked together (the tail of the linked list pointing to the head of it). This can be done for both singly and doubly linked lists. To traverse a circular linked list we begin at any node and follow the list in either direction until we return to the original node. Thus a circularly-linked list can be seen as having no beginning and no end, just like the circle. Each node of our linked list contains the following fields: • active, which denotes the active site. A site i of a word π = π1 π2 · · · πn on the alphabet [n] is said to be active if i ≤ n and πi ≤ maxj∈[i−1] πj . • max, which equals maxj∈[i−1] πj + 1. • level, which holds the tree level. • word[n], which is an array of length [n] that holds a partition π ∈ Pn . • next, prev, which are pointers to the next and previous node in the linked list, respectively.

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

9

Here are the core steps on which the algorithm is based: (1) Generate the root node, update its fields, and insert it as the head of the list. Note that at this point, the list contains only one node which is the head and also the tail of the list. (2) For each node in the list that has an active site, we generate, print and insert its children one by one orderly into the list such that the first child is next to its father in the list, the second child as next to the first one and so on. The algorithm exits from the procedure generate(node) when it completes the generation of all the children of a given node. We delete node immediately after the generation of its first child. (3) Set the next node in the list as current. If the node does not have active sites, then delete it from the list, otherwise perform step (2). Here we give the pseudo code of the algorithm: Algorithm 3 Loopless algorithm for generating Pn . 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:

define general node of the circularly linked list with the following fields active, max, level, pi[n], next and prev pointers to node create new-node set head=new-node for i = 1 to n do set head.pi[i]=1 end for set head.level=1, head.max=1, head.active=2 print head.pi create temp as a new-node while cur.level < n do if cur.active > n then delete cur set cur=cur.next else set temp=cur set cur=head procedure generate(temp) set cur=cur.next end if end while delete the list

Algorithm 3 terminates when the level of the node, which was sent as parameter to the procedure generate(node), is n, i.e., after generating the whole partition tree. Remark that when the algorithm performs step (2) (if any) for the last node of some level in the tree then the list contains exactly all the nodes of the next level of the partition tree. Algorithm 4 is the procedure which generates the nodes of the partition tree one by one and inserts them to the list. In Appendix C we give the C++ code of Algorithm 3 and Algorithm 4. Observe that after the calling of the procedure generate(node), all the partitions in the list no longer have active sites, so there are no more calls to the procedure generate(node). The generating algorithm terminates after deleting all the partitions without active sites at level n − 1 because the rest belongs

10

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

Algorithm 4 Procedure generate(node). 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43:

set flag=0 for s = temp.active to n do for t=temp.pi[active]+1 to t = temp.max + 1 do if flag=0 then create new-node set new-node=temp insert new-node to the list as the next of cur set new-node.pi[active]=t if t < temp.max then set new-node.max=temp.max else set new-node.max=t end if set new-node.level=temp.level+1, new-node.active=new-node.prev.active+1 print new-node.pi set new-node as cur delete cur.prev set flag=1 else create new-node set new-node=temp insert new-node to the list as the next of cur if t < temp.max then set new-node.max=temp.max else set new-node.max=t end if set new-node.level=temp.level+1 if cur.active=n then set new-node.active=temp.active+1, new-node.pi[temp.active]=t else set new-node.pi[prev.active]=t, new-node.active=new-node.prev.active+1 end if print new-node.pi set new-node as cur end if set t=t+1 end for if t < temp.max + 1 then set s=temp.active end if set s=s+1 end for

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

11

to level n. Table 2 shows how Algorithm 4 works for n = 4, and presents the list content after each call of the procedure generate(node) together with the inserted and the deleted partitions. Call List 1111 1211,1121,1112 1221,1212,1231 1211 1213,1121,1231 1221,1212,1231,1213 1121 1122,1123,1112 1222,1223,1212,1231 1221 1213,1122,1123 1222,1223,1232,1233 1231 1234,1213,1122,1123

Inserted 1211,1121,1112 1221,1212,1231 1213 1122,1123 1222,1223

Deleted 1211 1121 1221,1112

1232,1233,1234 1231,1212

Table 2. List contents

Algorithm 3 for n = 4 works as follows: • Lines 1-8: creating, initializing and printing the first initial partition, namely 1111. • Line 10: the algorithm terminates if the level of the current partition is 4 since all the nodes in level 4 in our example are leaves. The first partition that invokes the algorithm to terminate is 1222. • Lines 11-13: checking if the current partition has an active site. If not, then the algorithm deletes the node, otherwise the algorithm invokes the procedure generate(node). The partition 1112 leads to an execution of the deletion operation since for instance 1211 invokes the generating procedure. • Lines 5-16 in procedure generate(node): generating the first child (node) and then deleting it. For example, the partition 1211 generates the first child 1221 and then 1211 is deleted. Finally, we remark that Algorithm 3 generates the partitions of [n] independently of the partition length because to generate a new partition from current one, the algorithm changes only one letter. In other words, it generates each partition of [n] in a constant time. Also Algorithm 3 uses pointers in the construction process, because the data structure which holds the set of all partitions of [n] is generated dynamically. Acknowledgement. The authors would like to thank Vincent Vajnovszki and Silvia Heubach for reading previous version of the present paper and for a number of helpful comments. References [1] J.-Luc Baril, Gray code for permutations with a fixed number of cycles, Disc. Math. 307:13 (2007) 1559–1571. [2] D.E. Knuth, The art of computer programming, Vol. 1, Fundamental algorithms, Addison-Wesley, Reading, Mass.-London-Amsterdam, 1975. [3] J.-Luc Baril and V. Vajnovszki, Gray code for derangements, Disc. App. Math. 140 (2004) 207–221. [4] G. Ehrlich, Loopless algorithms for generating permutations, combinations, and other combinatorial configurations, J. Assoc. Comput. Mach. 20 (1973) 500–513. [5] S.M. Johson, Generating of permutations by adjacent transposition, Math. Comput. 17 (1963) 282–285. [6] J.M. Lucas, D. Roelants van Baronnaigien and F. Ruskey, On rotations and the generation of binary trees, J. Algorithms 15 (1993) 343–366.

12

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

[7] M. Klazar, On abab-free and abba-free set partitions, Europ. J. Combin. 17 (1996) 53–68. [8] C.W. Ko and F. Ruskey, Generating permutations of a bag by interchanges, Inform. Processing Lett. 41 (1992) 263–269. [9] J.F. Korsh, and P.S. LaFollette, Loopless array generation of multiset permutations, Technical Report, Department of CIS , PA, USA, 2002. [10] J.F. Korsh and S. Lipschutz, Generating multiset permutations in constant time, J. Algorithms 25 (1997) 321–335. [11] D. Roelants van Baronnaigien, A Loopless algorithm for generating binary tree sequences, Inform. Process. Lett. 39 (1991) 189–194. [12] D. Roelants van Baronaigien and F. Ruskey, Generating permutations with given ups and downs, Disc. Appl. Math. 36:1 (1992) 57–65. [13] F. Ruskey, Combinatorial generation, see http://www.cs.sunysb.edu/ algorith/implement/ruskey/implement.shtml. [14] F. Ruskey and C.D. Savage, Gray codes for set partitions and restricted growth tails, Aust. J. Combin. 10 (1994) 85–96. [15] R. Stanley, Enumerative combinatorics, Vol. 1, Cambridge University Press, Cambridge, England, 1997. [16] D. Stanton and D. White, Constructive combinatorics, Springer-Verlag (1986). [17] T. Takaoka, An O(1) time algorithm for generating multiset permutations, Lect. Notes Comp. Sci. 1741 (1999) 237–246. [18] H.F. Trotter, Algorithm 115, permutations, Comm. ACM 5 (1962) 434–435. [19] V. Vajnovszki, A loopless algorithm for generating the permutations of a multiset, Theoret. Comput. Sci. 307 (2003) 415–431. [20] V. Vajnovszki, On the loopless generation of binary tree sequences, Inform. Process. Lett. 68 (1998) 113–117. [21] V. Vajnovszki and T. Walsh, A loop-free two-close Gray-code algorithm for listing K-ary Dyck words, J. Disc. Algorithm. 4 (2006) 633–648. [22] T. Walsh, Gray codes for involutions, J. Combin. Math. Combin. Comput. 36 (2001) 95–118.

Appendix A #include #define MAXN 13 /*the maximal size*/ void main() { int pi[MAXN]; /*partition pi*/ int n=4; /*Size of the partitions*/ int i,j; /*indices*/ int max; /*contains the maximum value*/ for(i=1;i0) { /*printing the partition pi*/ for(i=1;i0) /*if the active site exists*/ { pi[j]++; for(i=j+1;iNext) print_node(Cur); else { while(Cur!=start->Prev) { print_node(Cur); Cur=Cur->Next; } print_node(Cur); } Cur=start; printf("\n"); } /******** the generating func ------******/ Node* Generate(Node *Cur,Node * Temp ) { Node *NewNode; Node *node; int i,s,t; int flag=0; for(t=Temp->Word[Temp->Active]+1;t Max+1;t++) { for(s=Temp->Active ;sNext) {

15

16

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

Cur->Next=NewNode; NewNode->Prev=Cur; NewNode->Next=Cur; Cur->Prev=NewNode; } else { NewNode = (Node *) malloc(sizeof(Node) ); NewNode->Next=Cur->Next; Cur->Next->Prev=NewNode; Cur->Next=NewNode; NewNode->Prev=Cur; } /*-----------------duplicate of the fhather ----------*/ for(i=0;iWord[i]=Temp->Word[i]; /*--------------------------end copying-----------*/ NewNode->Word[Temp->Active]= t; if(tMax) NewNode->Max=Temp->Max; else NewNode->Max=t; NewNode->Level=Temp->Level+1; NewNode->Active=Temp->Active+1; Cur=NewNode; print_node(Cur); /*----if the List have two Nodes ---------------------*/ if(Cur->Next==Cur->Prev) { free(Cur->Prev); Cur->Next=Cur; Cur->Prev=Cur; } /*--------------if there are more than two Nodes-------*/ else if(Cur->Next!=Cur->Prev) { node=Cur->Prev; node->Next->Prev=node->Prev; node->Prev->Next=node->Next; free( node); } flag=1; } else {

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

/* Henceforth insert from the second son -----*/ if(Cur==Cur->Next) { NewNode=(Node *) malloc(sizeof(Node)); Cur->Next=NewNode; NewNode->Prev=Cur; NewNode->Next=Cur; Cur->Prev=NewNode; } else if(Cur!=Cur->Next) { NewNode=(Node *) malloc(sizeof(Node)); NewNode->Next=Cur->Next; Cur->Next->Prev=NewNode; Cur->Next=NewNode; NewNode->Prev=Cur; } /*-------------Update the node fields -----*/ /*------duplicate for the father ------*/ for(i=0;iWord[i]=Temp->Word[i]; /*------------------end copying-------------***/ if(Cur->Active==n) { NewNode->Word[Temp->Active]= t; NewNode->Active=Temp->Active+1; } else { NewNode->Word[NewNode->Prev->Active]= t; NewNode->Active = NewNode->Prev->Active+1; } if(tMax) NewNode->Max=Temp->Max; else NewNode->Max=t; NewNode->Level=Temp->Level+1; print_node(NewNode); Cur=NewNode; // disp(Cur); } //else } //inernal for if(tMax+1) s=Temp->Active ; else return(Cur);

17

18

GRAY CODES, LOOPLESS ALGORITHM AND PARTITIONS

} //external for return(Cur); } //func /*----------------------free the List ------------------*/ void del(Node *start) { Node *Cur,*temp; Cur=start; if(Cur==Cur->Next) free(Cur); else { while(Cur->Next!=start) { temp=Cur; Cur=Cur->Next; free(temp); } free(Cur); } } /*-------------------------initialize a node void init(Node *Cur ,Node *Temp) { int i; for(i=0;iWord[i]=Cur->Word[i]; Temp->Max=Cur->Max; Temp->Level=Cur->Level; Temp->Active = Cur->Active; } /*---------------- Main -----------------*/ main() { Node *Head=NULL; Node * Cur,*Temp,*node; int i; for(i=0;iNext=Head; Head->Prev=Head; for(i=0;iWord[i]=1; /*--------------initialize the Node fields---------------*/ Head->Level=1; Head->Max=1; Head->Active=1; print_node(Head); Cur=Head; while(Cur->Level Active >= n) { node=Cur; node->Next->Prev=node->Prev; node->Prev->Next=node->Next; Cur=Cur->Next; free(node); } else { init(Cur,Temp); Cur=Generate(Cur,Temp); Cur=Cur->Next ; } } del(Cur) ; for(i=0;i