Different fixes

This commit is contained in:
Alexander Zaitsev
2017-08-30 20:25:15 +03:00
parent 32016b3c79
commit 7df35ffd56
4 changed files with 50 additions and 35 deletions

View File

@ -12,8 +12,16 @@ Distributed under the Boost Software License, Version 1.0.
The header file 'apply_permutation.hpp' contains two algorithms, apply_permutation and apply_reverse_permutation. Also there are range-based versions.
The algorithms transform the item sequence according to index sequence order.
The routine `apply_permutation` takes a item sequence and a order sequence. It reshuffles item sequence according to order sequence. Every value in order sequence means where the item comes from.
The routine `apply_reverse_permutation` takes a item sequence and a order sequence. It will reshuffle item sequence according to order sequence. Every value in order sequence means where the item goes to.
The routine `apply_permutation` takes a item sequence and a order sequence. It reshuffles item sequence according to order sequence. Every value in order sequence means where the item comes from. Order sequence needs to be exactly a permutation of the sequence [0, 1, ... , N], where N is the biggest index in the item sequence (zero-indexed).
The routine `apply_reverse_permutation` takes a item sequence and a order sequence. It will reshuffle item sequence according to order sequence. Every value in order sequence means where the item goes to. Order sequence needs to be exactly a permutation of the sequence [0, 1, ... , N], where N is the biggest index in the item sequence (zero-indexed).
Implementations are based on these articles:
https://blogs.msdn.microsoft.com/oldnewthing/20170102-00/?p=95095
https://blogs.msdn.microsoft.com/oldnewthing/20170103-00/?p=95105
https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115
https://blogs.msdn.microsoft.com/oldnewthing/20170109-00/?p=95145
https://blogs.msdn.microsoft.com/oldnewthing/20170110-00/?p=95155
https://blogs.msdn.microsoft.com/oldnewthing/20170111-00/?p=95165
The routines come in 2 forms; the first one takes two iterators to define the item range and one iterator to define the beginning of index range. The second form takes range to define the item sequence and range to define index sequence.
@ -21,17 +29,17 @@ The routines come in 2 forms; the first one takes two iterators to define the it
[heading interface]
There are two versions of algorithms:
1) takes three iterators.
1) takes four iterators.
2) takes two ranges.
``
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
void apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
RandomAccessIterator2 ind_begin);
RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end);
template<typename Range1, typename Range2>
void apply_permutation(Range1& item_range, Range2& ind_range);
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
void apply_reverse_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
RandomAccessIterator2 ind_begin);
RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end);
template<typename Range1, typename Range2>
void apply_reverse_permutation(Range1& item_range, Range2& ind_range);
``
@ -64,6 +72,7 @@ apply_reverse_permutation(vec, order) --> vec:{5, 4, 2, 3, 1}
[heading Complexity]
All of the variants of `apply_permutation` and `apply_reverse_permutation` run in ['O(N)] (linear) time.
More
[heading Exception Safety]
@ -76,6 +85,8 @@ All of the variants of `apply_permutation` and `apply_reverse_permutation` take
* Order sequence must be zero-indexed.
* Order sequence gets permuted.
[endsect]
[/ File apply_permutation.qbk

View File

@ -23,7 +23,7 @@ int main ( int /*argc*/, char * /*argv*/ [] )
std::cout << "apply_permutation with iterators:\n";
std::vector<int> vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0};
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
for (const auto& x : vec)
{
std::cout << x << ", ";
@ -34,7 +34,7 @@ int main ( int /*argc*/, char * /*argv*/ [] )
std::cout << "apply_reverse_permutation with iterators:\n";
std::vector<int> vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0};
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
for (const auto& x : vec)
{
std::cout << x << ", ";

View File

@ -19,8 +19,7 @@
#define BOOST_ALGORITHM_APPLY_PERMUTATION_HPP
#include <algorithm>
#include <utility>
#include <iterator>
#include <type_traits>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
@ -40,17 +39,18 @@ namespace boost { namespace algorithm
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
void
apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
RandomAccessIterator2 ind_begin)
RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end)
{
typedef typename std::iterator_traits<RandomAccessIterator1>::difference_type Diff;
using Diff = typename std::iterator_traits<RandomAccessIterator1>::difference_type;
using std::swap;
Diff size = std::distance(item_begin, item_end);
for (Diff i = 0; i < size; ++i)
for (Diff i = 0; i < size; i++)
{
Diff current = i;
auto current = i;
while (i != ind_begin[current])
{
Diff next = static_cast<Diff>(ind_begin[current]);
std::swap(item_begin[current], item_begin[next]);
auto next = ind_begin[current];
swap(item_begin[current], item_begin[next]);
ind_begin[current] = current;
current = next;
}
@ -69,18 +69,22 @@ apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_e
/// Complexity: O(N).
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
void
apply_reverse_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
RandomAccessIterator2 ind_begin)
apply_reverse_permutation(
RandomAccessIterator1 item_begin,
RandomAccessIterator1 item_end,
RandomAccessIterator2 ind_begin,
RandomAccessIterator2 ind_end)
{
typedef typename std::iterator_traits<RandomAccessIterator1>::difference_type Diff;
using Diff = typename std::iterator_traits<RandomAccessIterator2>::difference_type;
using std::swap;
Diff length = std::distance(item_begin, item_end);
for (Diff i = 0; i < length; ++i)
for (Diff i = 0; i < length; i++)
{
while (i != ind_begin[i])
{
Diff next = ind_begin[i];
std::swap(item_begin[i], item_begin[next]);
std::swap(ind_begin[i], ind_begin[next]);
swap(item_begin[i], item_begin[next]);
swap(ind_begin[i], ind_begin[next]);
}
}
}
@ -98,7 +102,7 @@ void
apply_permutation(Range1& item_range, Range2& ind_range)
{
apply_permutation(boost::begin(item_range), boost::end(item_range),
boost::begin(ind_range));
boost::begin(ind_range), boost::end(ind_range));
}
/// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range )
@ -114,7 +118,7 @@ void
apply_reverse_permutation(Range1& item_range, Range2& ind_range)
{
apply_reverse_permutation(boost::begin(item_range), boost::end(item_range),
boost::begin(ind_range));
boost::begin(ind_range), boost::end(ind_range));
}
}}

View File

@ -26,7 +26,7 @@ void test_apply_permutation()
{
std::vector<int> vec, order, result;
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//1 element
@ -36,7 +36,7 @@ void test_apply_permutation()
order.push_back(0);
result = vec;
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//2 elements, no changes
@ -46,7 +46,7 @@ void test_apply_permutation()
order.push_back(0); order.push_back(1);
result = vec;
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//2 elements, changed
@ -56,7 +56,7 @@ void test_apply_permutation()
order.push_back(1); order.push_back(0);
result.push_back(2); result.push_back(1);
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//Multiple elements, no changes
@ -66,7 +66,7 @@ void test_apply_permutation()
order.push_back(0); order.push_back(1); order.push_back(2); order.push_back(3); order.push_back(4);
result = vec;
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//Multiple elements, changed
@ -76,7 +76,7 @@ void test_apply_permutation()
order.push_back(4); order.push_back(3); order.push_back(2); order.push_back(1); order.push_back(0);
result.push_back(5); result.push_back(4); result.push_back(3); result.push_back(2); result.push_back(1);
ba::apply_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//Just test range interface
@ -97,7 +97,7 @@ void test_apply_reverse_permutation()
{
std::vector<int> vec, order, result;
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//1 element
@ -107,7 +107,7 @@ void test_apply_reverse_permutation()
order.push_back(0);
result = vec;
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//2 elements, no changes
@ -117,7 +117,7 @@ void test_apply_reverse_permutation()
order.push_back(0); order.push_back(1);
result = vec;
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//2 elements, changed
@ -127,7 +127,7 @@ void test_apply_reverse_permutation()
order.push_back(1); order.push_back(0);
result.push_back(2); result.push_back(1);
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//Multiple elements, no changes
@ -137,7 +137,7 @@ void test_apply_reverse_permutation()
order.push_back(0); order.push_back(1); order.push_back(2); order.push_back(3); order.push_back(4);
result = vec;
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//Multiple elements, changed
@ -147,7 +147,7 @@ void test_apply_reverse_permutation()
order.push_back(4); order.push_back(3); order.push_back(2); order.push_back(1); order.push_back(0);
result.push_back(5); result.push_back(4); result.push_back(3); result.push_back(2); result.push_back(1);
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin());
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
BOOST_CHECK(vec == result);
}
//Just test range interface