Splitting an STL list? - c++

I have a circular linked list that looks something like this:
4 -> 3 -> 2 -> 5 -> 0 -> 1 -> beginning
I want to split this list into two segments, reverse one of the segments, and then rejoin the list. Something like this:
Split, an O(1) operation
4 ** 3 -> 2 -> 5 ** 0 -> 1 -> beginning
Reverse, an O(n) operation
0 ** 3 -> 2 -> 5 ** 4 -> 1 -> beginning
Rejoin, an O(1) operation
0 -> 3 -> 2 -> 5 -> 4 -> 1 -> beginning
The STL does not appear to have a circular linked list, but I'm hoping I can get away with representing the list as a (forward) list. This, requires:
* A way to split the lists into sublists
* A way to merge the lists together
Merging the sublists together should be easy using std::list::splice, and it should be an O(1) operation. Yay!
However, I can't find a good O(1) way to split the lists into sublists. One approach is to use iterators, but I don't think that works in my case because the sublist goes off the end of the list and resumes at the beginning of the list.
Is there an efficient way to implement this algorithm using the STL? Or should I just give up and write my own circular linked list library?
Thanks!

I am not sure how helpful this is, but here it is:
template<typename I>
void inner(I b, I e)
{
std::reverse(b, e); // l = {4 5 2 3 0 1}
}
template<typename L, typename I>
void outer(L& l, I b, I e)
{
l.splice(l.begin(), l, e, l.end()); // l = {0 1 4 3 2 5}
std::reverse(l.begin(), b); // l = {4 1 0 3 2 5}
}
int main ()
{
std::list<int> t, l{4, 3, 2, 5, 0, 1};
std::cout << l << std::endl;
auto b = l.begin(), e = l.begin();
std::advance(b, 1);
std::advance(e, 4);
bool in = true;
in ? inner(b, e) : outer(l, b, e);
std::cout << l << std::endl;
}
There are two options:
reverse the inner part of the list (3 2 5)
reverse the outer part (0 1 -> 4)
and you might want to reverse the shorter one, but you'll have to count for this, which is linear-time. I have written two separate functions inner,outer for these two tasks.
inner is very simple (nothing but a wrapper) and working as expected. However, outer is leaving the list in a state that is equivalent to the expected modulo some rotation (circular shift). If you are modelling a circular list, this should be fine. But if you want the output exactly as in your example, you'll have to count again, to find the right point where to rotate. I would avoid this, as it is linear-time.
Note that no splitting is actually needed, because reversal is in-place. Also, operation
l.splice(l.begin(), l, e, l.end());
is constant-time.
Check live example.

Related

C++ Priority Queue - ordering intervals

Given initially a time interval. Every time, we pick the largest interval and split that into two halves. If there is a tie, then we pick the interval with the lowest starting point.
for example - [0,9]
first split - P1 [0,4] and P2 [4,9]
For second split :
dist(P1) = 3 => if pick P1, new intervals would be [0,2] and [2,4].
dist(P2) = 4 => if pick P2, new intervals are [4, 6] and [6,9]
In both the cases, we have to create sub interval of distance 1. So, it's a tie. and, we pick P1 as P1 < P2.
[0,2], [2, 4], [4, 9]
Third Split:
[0,2], [2, 4], [4,6], [6,9]
Fourth Split:
There is a tie, s0, picked [0,2]
[0,1], [1,2], [2,4], [4,6], [6, 9]
Fifth Split:
[0,1], [1,2], [2,3], [3,4], [4,6], [6,9]
a possible candidate to be on the top : [4,6]
But, I always get [1,2] on top.
#include <iostream>
#include <queue>
using namespace std;
int main()
{
auto dist{ [](const auto & p) {
return p.second - p.first - 1;
} };
auto comp{
[&dist](const auto & p1, const auto & p2) {
if (abs(dist(p1) - dist(p2)) <= 1) {
return p1.first > p2.first;
}
return dist(p1) < dist(p2);
}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(comp)> maxQ{comp};
maxQ.push({ 0, 9 }); // initial interval
for (int i{ 0 }; i < 5; ++i) {
auto ii{ maxQ.top() };
maxQ.pop();
int mid = (ii.first + ii.second) / 2;
maxQ.push({ ii.first, mid });
maxQ.push({ mid, ii.second });
}
while (!maxQ.empty()) {
auto& ii{ maxQ.top() };
cout << ii.first << " : " << ii.second << endl;
maxQ.pop();
}
}
I'm getting the following output :
1 : 2
6 : 9
0 : 1
2 : 3
3 : 4
4 : 6
IMO, 1 : 2 interval shouldn't be on top. Could someone help me here, why is it so.
It turns out that this issue has more to do with how priority queues comparators are designed, refer to The reason of using `std::greater` for creating min heap via `priority_queue`
The gist of it is that when two nodes are compared, if the comparator returns true, p1 will fall below p2. So a basic ">" comparator, will have smaller nodes at the top, and bigger nodes at the bottom.
To visualize the issue, I ran through it in a debugger, this is the moment at which the (1,2) is being put above (6,9). This is the current state of the priority queue:
2 : 4
6 : 9
4 : 6
0 : 1
1 : 2
We see that (2,4) is in front (6,9), which is expected since our comparison function says that (2,4) < (6,9) as explained above.
Then, the code goes to pop the top of the priority queue, meaning replaces (2,4) with the new biggest interval. How priority queues in C++ do this, is they swap the first element and last elements of the heap, and then reduce the size of it by 1 (so we lose the original first element).
So after the swap and size reduction, our heap looks like this:
1 : 2
6 : 9
4 : 6
0 : 1
Then, since the previously deemed smallest element is now at the top of the queue, we need to find its rightful spot.
So (1,2) is going to look at its children, (6,9) and (4,6), and see which is more important.
With our comparison operator, (4,6) is the more important node.
It then compares, (1,2) with the most important of the previous two nodes, (4,6), to see if it needs to perform a swap to make the queue valid.
It then finds that (1,2) is more important because 1 < 4. Thus, (1,2) stays in its spot and we're left with:
1 : 2
6 : 9
4 : 6
0 : 1
We can plainly see that [1,2] is ordered before [4,6], by plugging it into your comparator:
comp([1,2], [4,6])
if (abs(dist([1,2]) - dist([4,6])) <= 1) { // abs(0 - 1) <= 1 or 1 <= 1
return 1 > 4; // false
}
return dist([1,2]) < dist([4,6]); // not reached
Only you can correct the comparator to achieve whatever your goal is here, but the existing code is wrong if you want [1,2] to be ordered after [4,6].
At a guess, though, based on your description, you might try:
if (abs(dist(p1)) == abs(dist(p2)))
But I'd go to some lengths to ensure that your ordering is strict weak as it must be for the container. Sprinkling some more abs around may help.
Overall this is quite a complex comparator that's not easy to understand at a glance.
I think It is because the ordering of intervals is not strict.
e.g. P1(0,1), P2(4,6) and P3(6,9)
P1 should come before P2.
P2 should come before P3.
P3 should come before P1.
That's crazy. How could I set a strict pair ordering here?

Adjusting index in a vector in C++

I am writing a code in which the values of vector indexes are displayed as per the sorted order of the elements they hold:
For example:
values -> 3 2 4 1 5
indices -> 1 2 3 4 5 //yeah I know C++ indexing starts with 0. Well, while printing, I will add 1
result -> 4 2 1 3 5 //Bear with me. I know its confusing. I will clarify below
Now, the result has been obtained by sorting the elements and printing their earlier indices.
Like:
values(sorted) -> 1 2 3 4 5
indices(before sorting) -> 4 2 1 3 5
Now, there are many ways to do it with some suggesting to store the previous values and search and print the previous index, while others suggesting to create a new vector and copy the previous indices in it and then sorting them and.... (Well I didn't read further, 'cause that's definitely not how I was gonna proceed)
I tried a different approach while trying to not use a second vector.
So here's the approach:
while (!vec_students.empty()) {
std::vector<int>::iterator iterator = std::min_element(vec_students.begin(), vec_students.end());
std::cout << std::distance(vec_students.begin(), iterator) + 1 << " ";
vec_students.erase(iterator);
}
Now in this approach, the problem I am facing is that once I use erase, the index of all elements decreases by a certain incrementing value. So this was the solution I thought of:
while (!vec_students.empty()) {
static int i = 0; //yeah I know standard static variables are initialised to 1.
std::vector<int>::iterator iterator = std::min_element(vec_students.begin(), vec_students.end());
std::cout << std::distance(vec_students.begin(), iterator) + i << " ";
vec_students.erase(iterator);
i++;
}
Now the thought goes like this:
Initial Solution:
vector: 2 3 1
expected output: 3 1 2 (For explanation refer above)
first index = indexof(min(2,3,1)) -> 2 (while printing add 1) -> 3
second index = indexof(min(2,3)) -> 0 (while printing....) -> 1
third index = indexof(min(3)) -> 0 (while...) -> 1
Then I realized that the vector size decreases which means, indices will decrease (by 1 in this case)
so I added the extra i thingy.
Solution working:
vector: 2 3 1 i = 0
first index = indexof(min(2,3,1)) -> 3 -> add i -> 3 -> increment i -> i = 1
second index = indexof(min(2,3)) -> 0 -> add i -> 1 -> increment i -> i = 2
third index = indexof(min(3)) -> 0 -> add i -> 2 -> increment i -> i = 3
and the program ends.
But in the above case, instead of 3 1 2 I am getting 3 2 3 (first value right, rest incremented by 1)
What is wrong with my logic?
the index of all elements decreases by a certain incrementing value.
Not all, just the ones that come after the one you removed. Here's one way to do it without making another vector:
#include <algorithm>
#include <iostream>
#include <limits>
#include <vector>
int main() {
std::vector<int> v{3, 2, 4, 1, 5};
auto const* beg = v.data();
auto sz = v.size();
while (sz--) {
auto const min = std::min_element(v.begin(), v.end());
std::cout << &*min - beg << ' ';
*min = std::numeric_limits<int>::max();
}
}
This won't work properly if you have INT_MAX in your vector. In any case, making a second vector could yield better solutions. An example:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v{3, 2, 4, 1, 5};
std::vector<int const*> addresses;
addresses.reserve(v.size());
std::transform(v.cbegin(), v.cend(), std::back_inserter(addresses),
[](auto const& elm) { return &elm; });
std::sort(addresses.begin(), addresses.end(),
[](int const* const ptr1, int const* const ptr2) {
return *ptr1 < *ptr2;
});
for (auto* p : addresses) {
std::cout << p - v.data() << ' ';
}
}
You think you should add indices because the vector is shrink.
Well, not really, only those after the removed element should be effected.
example.
[2,1,3] => [2,3]
index of 2 remains at 0,
while index of 3 becomes 1 from 2

Efficient way to reverse three consecutive subranges [A,B,C] -> [C,B,A]

I've got an array [A,B,C] consisting of three consecutive sub-arrays A, B and C. I'd like to reverse the larger array into [C,B,A]. My current attempt involves thee calls to std::rotate, as shown below. I wonder if there is a more straightforward/efficient way to achieve this, preferably using an std algorithm.
Step 1: "swap" sub-array B,C
[A,B,C] -> [A|B,C] -> [A,C,B]
Step 2: "swap" sub-array A,C
[A,C,B] -> [A,C|B] -> [C,A,B]
Step 3: "swap" sub-array A,B
[C,A,B] -> [C|A,B] -> [C,B,A]
Edit
For example given the array [1,2,3|4,5,6|7,8,9] I would like to "reverse" it into [7,8,9|4,5,6|1,2,3]
Sample implementation. Please note that the sizes of the "ranges" are merely illustrative.
Reverse the whole array then reverse each subarray.
[1,2,3|4,5,6|7,8,9]
[9,8,7|6,5,4|3,2,1]
[7,8,9|4,5,6|1,2,3]
This will take two linear passes and is extremely CPU cache friendly.
Here's a version with Ranges V3:
array<int, 9> arr = {{1,2,3,4,5,6,7,8,9}};
auto v = view::chunk(arr, 3) | view::reverse | view::join;
array<int, 9> reversed;
ranges::copy(v, reversed.begin());
for(int n : arr) cout << n << ' '; cout << '\n';
for(int n : reversed) cout << n << ' '; cout << '\n';
Prints:
1 2 3 4 5 6 7 8 9
7 8 9 4 5 6 1 2 3
Can't say much about performance, but it didn't compile quickly for me.

Making the number of key occurances equal using CUDA / Thrust

Is there an efficient way to take a sorted key/value array pair and ensure that each key has an equal number of elements using the CUDA Thrust library?
For instance, assume we have the following pair of arrays:
ID: 1 2 2 3 3 3
VN: 6 7 8 5 7 8
If we want to have two of each key appear, this would be the result:
ID: 2 2 3 3
VN: 7 8 5 7
The actual arrays will be much larger, containing millions of elements or more. I'm able to do this using nested for-loops easily, but I'm interested in knowing whether or not there's a more efficient way to convert the arrays using a GPU. Thrust seems as though it may be useful, but I don't see any obvious functions to use.
Thank you for your help!
Caveat: If this is the only operation you plan to do on the GPU, I would not recommend it. The cost to copy the data to/from the GPU will likely outweigh any possible efficiency/performance benefit from using the GPU.
EDIT: based on the comments that the sequence threshold is likely to be much longer than 2, I'll suggest an alternate method (method 2) that should be more efficient than a for-loop or brute-force method (method 1).
In general I would place this problem in a category called stream compaction. Stream compaction generally refers to taking a sequence of data and reducing it to a smaller sequence of data.
If we look in the thrust stream compaction area, an algorithm that could be made to work for this problem is thrust::copy_if() (in particular, for convenience, the version that takes a stencil array).
method 1:
To think about this problem in parallel, we must ask ourselves under what condition should a given element be copied from the input to the output? If we can formalize this logic, we can construct a thrust functor which we can pass to thrust::copy_if to instruct it as to which elements to copy.
For a given element, for the sequence length = 2 case, we can construct a complete logic if we know:
the element
the element one place to the right
the element one place to the left
the element two places to the left
Based on the above, we will need to come up with "special case" logic for those elements for which any of the items 2,3, or 4 above are undefined.
Ignoring the special cases, if we know the above 4 items, then we can construct the necessary logic as follows:
If the element to my left is the same as me, but the element two places to the left is different, then I belong in the output
If the element to my left is different than me, but the element to my right is the same as me, I belong in the output
Otherwise, I don't belong in the output
I'll leave it to you to construct the necessary logic for the special cases. (Or reverse-engineer it from the code I've provided).
method 2:
For long sequences, method 1 or a for-loop variant of the logic in method 1 will generate at least 1 read of the data set per element of the sequence length. For a long sequence (e.g. 2000) this will be inefficient. Therefore another possible approach would be as follows:
Generate an exclusive_scan_by_key in both forward and reverse directions, using the ID values as the key, and a thrust::constant_iterator (value=1) as the values for the scan. For the given data set, that creates intermediate results like this:
ID: 1 2 2 3 3 3
VN: 6 7 8 5 7 8
FS: 0 0 1 0 1 2
RS: 0 1 0 2 1 0
where FS and RS are the results of the forward and reverse scan-by-key. We generate the reverse scan (RS) using .rbegin() and .rend() reverse iterators. Note that this has to be done both for the reverse scan input and output, in order to generate the RS sequence as above.
The logic for our thrust::copy_if functor then becomes fairly simple. For a given element, if the sum of the RS and FS value for that element is greater than or equal to the desired minimum sequence length (-1 to account for exclusive scan operation) and the FS value is less than the desired minimum sequence length, then that element belongs in the output.
Here's a fully worked example of both methods, using the given data, for sequence length 2:
$ cat t1095.cu
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/zip_iterator.h>
#include <iostream>
#include <thrust/scan.h>
#include <thrust/iterator/constant_iterator.h>
struct copy_func
{
int *d;
int dsize, r, l, m, l2;
copy_func(int *_d, int _dsize) : d(_d),dsize(_dsize) {};
__host__ __device__
bool operator()(int idx)
{
m = d[idx];
// handle typical case
// this logic could be replaced by a for-loop for sequences of arbitrary length
if ((idx > 1) && (idx < dsize-1)){
r = d[idx+1];
l = d[idx-1];
l2 = d[idx-2];
if ((r == m) && (m != l)) return true;
if ((l == m) && (m != l2)) return true;
return false;}
// handle special cases
if (idx == 0){
r = d[idx+1];
return (r == m);}
if (idx == 1){
r = d[idx+1];
l = d[idx-1];
if (l == m) return true;
else if (r == m) return true;
return false;}
if (idx == dsize-1){
l = d[idx-1];
l2 = d[idx-2];
if ((m == l) && (m != l2)) return true;
return false;}
// could put assert(0) here, should never get here
return false;
}
};
struct copy_func2
{
int thresh;
copy_func2(int _thresh) : thresh(_thresh) {};
template <typename T>
__host__ __device__
bool operator()(T t){
return (((thrust::get<0>(t) + thrust::get<1>(t))>=(thresh-1)) && (thrust::get<0>(t) < thresh));
}
};
int main(){
const int length_threshold = 2;
int ID[] = {1,2,2,3,3,3};
int VN[] = {6,7,8,5,7,8};
int dsize = sizeof(ID)/sizeof(int);
// we assume dsize > 3
thrust::device_vector<int> id(ID, ID+dsize);
thrust::device_vector<int> vn(VN, VN+dsize);
thrust::device_vector<int> res_id(dsize);
thrust::device_vector<int> res_vn(dsize);
thrust::counting_iterator<int> idx(0);
//method 1: sequence length threshold of 2
int rsize = thrust::copy_if(thrust::make_zip_iterator(thrust::make_tuple(id.begin(), vn.begin())), thrust::make_zip_iterator(thrust::make_tuple(id.end(), vn.end())), idx, thrust::make_zip_iterator(thrust::make_tuple(res_id.begin(), res_vn.begin())), copy_func(thrust::raw_pointer_cast(id.data()), dsize)) - thrust::make_zip_iterator(thrust::make_tuple(res_id.begin(), res_vn.begin()));
std::cout << "ID: ";
thrust::copy_n(res_id.begin(), rsize, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl << "VN: ";
thrust::copy_n(res_vn.begin(), rsize, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
//method 2: for arbitrary sequence length threshold
thrust::device_vector<int> res_fs(dsize);
thrust::device_vector<int> res_rs(dsize);
thrust::exclusive_scan_by_key(id.begin(), id.end(), thrust::constant_iterator<int>(1), res_fs.begin());
thrust::exclusive_scan_by_key(id.rbegin(), id.rend(), thrust::constant_iterator<int>(1), res_rs.begin());
rsize = thrust::copy_if(thrust::make_zip_iterator(thrust::make_tuple(id.begin(), vn.begin())), thrust::make_zip_iterator(thrust::make_tuple(id.end(), vn.end())), thrust::make_zip_iterator(thrust::make_tuple(res_fs.begin(), res_rs.rbegin())), thrust::make_zip_iterator(thrust::make_tuple(res_id.begin(), res_vn.begin())), copy_func2(length_threshold)) - thrust::make_zip_iterator(thrust::make_tuple(res_id.begin(), res_vn.begin()));
std::cout << "ID: ";
thrust::copy_n(res_id.begin(), rsize, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl << "VN: ";
thrust::copy_n(res_vn.begin(), rsize, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
$ nvcc -o t1095 t1095.cu
$ ./t1095
ID: 2 2 3 3
VN: 7 8 5 7
ID: 2 2 3 3
VN: 7 8 5 7
Notes:
the copy_func implements the test logic for a given element for method 1. It receives the index of that element (via the stencil) as well as a pointer to the ID data on the device, and the size of the data, via functor initialization parameters. The variables r, m, l, and l2 refer to the element to my right, myself, the element to my left, and the element two places to my left, respectively.
we are passing a pointer to the ID data to the functor. This allows the functor to retrieve the (up to) 4 necessary elements for the test logic. This avoids a messy construction of a thrust::zip_iterator to provide all these values. Note that the reads of these elements in the functor should coalesce nicely, and therefore be fairly efficient, and also benefit from the cache.
I don't claim that this is defect-free. I think I got the test logic right, but it's possible I didn't. You should verify the logical correctness of that portion of the code, at least. My purpose is not to give you a black-box piece of code, but to demonstrate how to think your way through the problem.
This approach may get cumbersome for key sequences longer than 2. In that case I would suggest method 2. (If you already have a sequential for-loop that implements the necessary logic, you may be able to drop a modified version of that into the method 1 functor for longer key sequences. Such a for-loop should probably still benefit from coalesced access and adjacent accesses from the cache.)

Generating all permutations excluding cyclic rotations

So I need an algorithm to generate all permutations of a list of numbers excluding cyclic rotations (e.g. [1,2,3] == [2,3,1] == [3,1,2]).
When there is at least 1 unique number in the sequence it is fairly straight forward, take out that unique number, generate all permutations of the remaining numbers (but with a small modification to the 'standard' permutations algorithm) and add the unique number to the front.
For generating the permutations I've found that it's necessary to change the permutations code to:
def permutations(done, options)
permuts = []
seen = []
for each o in options
if o not in seen
seen.add(o)
permuts += permutations(done+o, options.remove(o))
return permuts
Only using each unique number in options once means that you don't get 322 twice.
This algorithm still outputs rotations when there are no unique elements, e.g. for [1,1,2,2] it would output [1,1,2,2], [1,2,2,1] and [1,2,1,2] and the first two are cyclic rotations.
So is there an efficient algorithm that would allow me to generate all the permutations without having to go through afterwards to remove cyclic rotations?
If not, what would be the most efficient way to remove cyclic rotations?
NOTE: this is not using Python, but rather C++.
For the case of permutations where all numbers are distinct, this is simple. Say the numbers are 1,2,...,n, then generate all permutations of 1,2,...,n-1 and stick n at the front. This gives all permutations of the full set modulo cyclic rotations. For example, with n=4, you would do
4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1
This ensures that some cyclic rotation of each permutation of 1,2,3,4 appears exactly once in the list.
For the general case where you want permutations of a multiset (repeated entries allowed), you can use a similar trick. Remove all instances of the largest letter n (similar to ignoring the 4 in the above example) and generate all permutations of the remaining multiset. The next step is to put the ns back into the permutations in canonical ways (similar to putting the 4 at the beginning in the above example).
This is really just a case of finding all Lyndon words to generate necklaces
Think about testing each of the permutations you output, looking for a cyclic rotation that's "lexically" earlier than the one you've got. If there is one, don't return it - it will have been enumerated somewhere else.
Choosing a "unique" first element, if one exists, helps you optimize. You know if you fix the first element, and it's unique, then you can't possibly have duplicated it with a rotation. On the other hand, if there's no such unique element, just choose the one that occurs the least. That way you only need to check for cyclic rotations that have that first element. (Example, when you generate [1,2,2,1] - you only need to check [1,1,2,2], not [2,2,1,1] or [2,1,1,2]).
OK, pseudocode... clearly O(n!), and I'm convinced there's no smarter way, since the case "all symbols different" obviously has to return (n-1)! elements.
// generate all permutations with count[0] 0's, count[1] 1's...
def permutations(count[])
if(count[] all zero)
return just the empty permutation;
else
perms = [];
for all i with count[i] not zero
r = permutations(copy of count[] with element i decreased);
perms += i prefixed on every element of r
return perms;
// generate all noncyclic permutations with count[0] 0's, count[1] 1's...
def noncyclic(count[])
choose f to be the index with smallest count[f];
perms = permutations(copy of count[] with element f decreased);
if (count[f] is 1)
return perms;
else
noncyclic = [];
for each perm in perms
val = perm as a value in base(count.length);
for each occurence of f in perm
test = perm rotated so that f is first
tval = test as a value in base(count.length);
if (tval < val) continue to next perm;
if not skipped add perm to noncyclic;
return noncyclic;
// return all noncyclic perms of the given symbols
def main(symbols[])
dictionary = array of all distinct items in symbols;
count = array of counts, count[i] = count of dictionary[i] in symbols
nc = noncyclic(count);
return (elements of nc translated back to symbols with the dictionary)
This solution is going to involve a bit of itertools.permutations usage, set(), and some good ol' fashioned set difference. Bear in mind, the runtime for finding a permutation will still be O(n!). My solution won't do it in-line, either, but there may be a much more elegant solution that allows you to do so (and doesn't involve itertools.permutations). For this purpose, this is the straightforward way to accomplish the task.
Step 1: Algorithm for generating cycles, using the first element given. For a list [1, 1, 2, 2], this will give us [1, 1, 2, 2], [1, 2, 2, 1], [2, 1, 1, 2], [2, 2, 1, 1].
def rotations(li):
count = 0
while count < len(li):
yield tuple(li)
li = li[1:] + [li[0]]
count += 1
Step 2: Importing itertools.permutations to give us the permutations in the first place, then setting up its results into a set.
from itertools import permutations
perm = set(permutations([1, 1, 2, 2]))
Step 3: Using the generator to give us our own set, with the cycles (something we want to rid ourselves of).
cycles = set(((i for i in rotations([1, 1, 2, 2]))))
Step 4: Apply set difference to each and the cycles are removed.
perm = perm.difference(cycles)
Hopefully this will help you out. I'm open to suggestions and/or corrections.
First I'll show the containers and algorithms we'll be using:
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
#include <iterator>
using std::vector;
using std::set;
using std::sort;
using std::next_permutation;
using std::copy;
using std::ostream_iterator;
using std::cout;
Next our vector which will represent the Permutation:
typedef vector<unsigned int> Permutation;
We need a comparison object to check whether a permutation is a rotation:
struct CompareCyclicPermutationsEqual
{
bool operator()(const Permutation& lhs, const Permutation& rhs);
};
And typedef a set which uses the cyclic comparison object:
typedef set<Permutation, CompareCyclicPermutationsEqual> Permutations;
Then the main function is quite simple:
int main()
{
Permutation permutation = {1, 2, 1, 2};
sort(permutation.begin(). permutation.end());
Permutations permutations;
do {
permutations.insert(permutation);
} while(next_permutation(numbers.begin(), numbers.end()))
copy(permutations.begin(), permutations.end(),
ostream_iterator<Permutation>(cout, "\n");
return 0;
}
Output:
1, 1, 2, 2,
1, 2, 1, 2,
I haven't implemented CompareCyclicPermutationsEqual yet. Also you'd need to implement ostream& operator<<(ostream& os, const Permutation& permutation).