View Javadoc
1   package com.github.davidmoten.rx.internal.operators;
2   
3   import java.util.Iterator;
4   import java.util.List;
5   
6   public final class Permutations {
7   
8       private Permutations() {
9           // prevent instantiation
10      }
11  
12      public static <T> Iterable<Swap<T>> iterable(final List<T> list) {
13          return new Iterable<Swap<T>>() {
14              @Override
15              public Iterator<Swap<T>> iterator() {
16                  return new PermutationsSwapIterator<T>(list);
17              }
18          };
19      }
20  
21      public static <T> Iterator<Swap<T>> iterator(List<T> list) {
22          return new PermutationsSwapIterator<T>(list);
23      }
24  
25      private static class PermutationsSwapIterator<T> implements Iterator<Swap<T>> {
26  
27          /**
28           * After
29           * http://www.cut-the-knot.org/Curriculum/Combinatorics/JohnsonTrotter.
30           * shtml
31           * 
32           */
33          private final T[] values;
34          private final DirectedReference[] references;
35  
36          @SuppressWarnings("unchecked")
37          public PermutationsSwapIterator(List<T> list) {
38              this.values = (T[]) list.toArray();
39              this.references = new DirectedReference[list.size()];
40              for (int i = 0; i < this.references.length; i++) {
41                  this.references[i] = new DirectedReference(-1, i);
42              }
43          }
44  
45          private boolean isMobile(int index) {
46              if (index == 0 && references[index].direction == -1) {
47                  return false;
48              } else if (index == references.length - 1 && references[index].direction == 1) {
49                  return false;
50              } else if (references[index
51                      + references[index].direction].reference > references[index].reference) {
52                  return false;
53              } else {
54                  return true;
55              }
56          }
57  
58          @Override
59          public boolean hasNext() {
60              for (int i = 0; i < references.length; i++) {
61                  if (isMobile(i)) {
62                      return true;
63                  }
64              }
65              return false;
66          }
67  
68          @Override
69          public Swap<T> next() {
70              // find the largest mobile reference "chosen"
71              int chosen = Integer.MIN_VALUE;
72              int chosenIndex = -1;
73              for (int i = 0; i < references.length; i++) {
74                  if (isMobile(i) && references[i].reference > chosen) {
75                      chosen = references[i].reference;
76                      chosenIndex = i;
77                  }
78              }
79  
80              // swaps it in the indicated direction
81              int neighbourIndex = chosenIndex + references[chosenIndex].direction;
82              Swap<T> swap = new Swap<T>(values[references[chosenIndex].reference],
83                      values[references[neighbourIndex].reference]);
84  
85              DirectedReference tmp = references[chosenIndex];
86              references[chosenIndex] = references[neighbourIndex];
87              references[neighbourIndex] = tmp;
88  
89              // reverse the direction of all references larger than "chosen"
90              for (int i = 0; i < references.length; i++) {
91                  if (references[i].reference > chosen) {
92                      references[i].reverse();
93                  }
94              }
95  
96              return swap;
97          }
98  
99          @Override
100         public void remove() {
101             throw new UnsupportedOperationException("cannot remove from permutations");
102         }
103 
104     }
105 
106     public static class Swap<T> {
107         private final T left;
108         private final T right;
109 
110         Swap(T left, T right) {
111             this.left = left;
112             this.right = right;
113         }
114 
115         public T left() {
116             return left;
117         }
118 
119         public T right() {
120             return right;
121         }
122 
123         @Override
124         public String toString() {
125             return "Swap [left=" + left + ", right=" + right + "]";
126         }
127 
128     }
129 
130     private static class DirectedReference {
131         private final int reference;
132         private int direction;
133 
134         DirectedReference(int direction, int reference) {
135             this.direction = direction;
136             this.reference = reference;
137         }
138 
139         public void reverse() {
140             this.direction = -this.direction;
141         }
142 
143         @Override
144         public String toString() {
145             String val = String.valueOf(reference);
146             String result = direction == -1 ? "<" + val : val + ">";
147             return result + String.valueOf(reference);
148         }
149     }
150 
151 }