1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.iterators;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.NoSuchElementException;
27 import java.util.Objects;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class PermutationIterator<E> implements Iterator<List<E>> {
46
47
48
49
50 private final int[] keys;
51
52
53
54
55 private final Map<Integer, E> objectMap;
56
57
58
59
60
61
62
63
64 private final boolean[] direction;
65
66
67
68
69
70 private List<E> nextPermutation;
71
72
73
74
75
76
77 public PermutationIterator(final Collection<? extends E> collection) {
78 Objects.requireNonNull(collection, "collection");
79 keys = new int[collection.size()];
80 direction = new boolean[collection.size()];
81 Arrays.fill(direction, false);
82 int value = 1;
83 objectMap = new HashMap<>();
84 for (final E e : collection) {
85 objectMap.put(Integer.valueOf(value), e);
86 keys[value - 1] = value;
87 value++;
88 }
89 nextPermutation = new ArrayList<>(collection);
90 }
91
92
93
94
95
96 @Override
97 public boolean hasNext() {
98 return nextPermutation != null;
99 }
100
101
102
103
104
105
106 @Override
107 public List<E> next() {
108 if (!hasNext()) {
109 throw new NoSuchElementException();
110 }
111
112
113 int indexOfLargestMobileInteger = -1;
114 int largestKey = -1;
115 for (int i = 0; i < keys.length; i++) {
116 if (direction[i] && i < keys.length - 1 && keys[i] > keys[i + 1] ||
117 !direction[i] && i > 0 && keys[i] > keys[i - 1]) {
118 if (keys[i] > largestKey) {
119 largestKey = keys[i];
120 indexOfLargestMobileInteger = i;
121 }
122 }
123 }
124 if (largestKey == -1) {
125 final List<E> toReturn = nextPermutation;
126 nextPermutation = null;
127 return toReturn;
128 }
129
130
131 final int offset = direction[indexOfLargestMobileInteger] ? 1 : -1;
132 final int tmpKey = keys[indexOfLargestMobileInteger];
133 keys[indexOfLargestMobileInteger] = keys[indexOfLargestMobileInteger + offset];
134 keys[indexOfLargestMobileInteger + offset] = tmpKey;
135 final boolean tmpDirection = direction[indexOfLargestMobileInteger];
136 direction[indexOfLargestMobileInteger] = direction[indexOfLargestMobileInteger + offset];
137 direction[indexOfLargestMobileInteger + offset] = tmpDirection;
138
139
140 final List<E> nextP = new ArrayList<>();
141 for (int i = 0; i < keys.length; i++) {
142 if (keys[i] > largestKey) {
143 direction[i] = !direction[i];
144 }
145 nextP.add(objectMap.get(Integer.valueOf(keys[i])));
146 }
147 final List<E> result = nextPermutation;
148 nextPermutation = nextP;
149 return result;
150 }
151
152 @Override
153 public void remove() {
154 throw new UnsupportedOperationException("remove() is not supported");
155 }
156
157 }