<stx/algorithm>
DDJ-J 1998年5月号で紹介したSTL拡張コンポーネント”STX”の改版です。
初版で定義した関数のうち、使用頻度の少ないもの、
既存のアルゴリズムで簡単に置き換えられるものを除き、新たにいくつか追加しました。
- for_each
- for_each_backward
- find_last
- find_last_if
- find_backward
- find_backward_if
- binary_find
- some
- some_if
- every
- every_if
- select_copy
- select_copy_if
- transform_if
- inject_1st
- inject_2nd
- partition_copy
- is_sorted
- lexicographical_compare_3way
for_each
template<class InputIterator1,
class InputIterator2,
class BinaryFunction>
BinaryFunction
for_each(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
BinaryFunction f)
{
while ( first1 != last1 ) {
f(*first1,*first2);
++first1;
++first2;
}
return f;
}
0 <= i < (last-first) に対し、f(*(first1+i), *(first2+i)) を行ないます。このとき f() の戻り値は棄てられます。
// sample
void f(int x, int y) {
cout << (x*y) << endl;
}
vector<int> v;
list<int> l;
for ( int i = 1; i < 10; ++i ) {
v.push_back(i);
l.push_back(i);
}
// 1*1 2*2 ... 9*9 の答を出力
stx::for_each(v.begin(), v.end(), l.begin(), l.end(), f);
for_each_backward
template<class BidirectionalIterator,
class UnaryFunction>
UnaryFunction
for_each_backward(BidirectionalIterator first,
BidirectionalIterator last,
UnaryFunction f)
{
while ( first != last ) {
--last;
f(*last);
}
return f;
}
std::for_each(first,last,f)の逆順すなわち、
f(*(last-1)); f(*(last-2)); ... f(*first);
を行ないます。
// sample
void f(int x, int y) {
cout << (x*y) << endl;
}
vector<int> v;
list<int> l;
for ( int i = 1; i < 10; ++i ) {
v.push_back(i);
l.push_back(i);
}
// 9*9 8*8 ... 1*1の答を出力
stx::for_each_backward(v.begin(), v.end(), l.begin(), l.end(), f);
find_last
template<class InputIterator,
class T>
InputIterator
find_last(InputIterator first,
InputIterator last,
const T& value)
{
InputIterator it = first;
while ( first != last ) {
if ( *first == value ) {
it = first;
}
++first;
}
return it;
}
first <= i < last に対し、*i == value となる最後のiを返します。該当する i が見つからないときは last を返します。※必ず(last – first)回の比較が行なわれます。
// sample
int array[] = { 0, 1, 2, 4, 5 };
int* p = stx::find_last(array, array+5, 4);
cout << (p-array) << endl; // p = &array[3]
find_last_if
template<class InputIterator,
class UnaryPredicate>
InputIterator
find_last_if(InputIterator first,
InputIterator last,
UnaryPredicate pred)
{
InputIterator it = first;
while ( first != last ) {
if ( pred(*first) ) {
it = first;
}
++first;
}
return it;
}
first <= i < last に対し、pred(*i) != false となる最後のiを返します。該当する i が見つからないときは last を返します。必ず (last – first) 回の比較が行なわれます。
// sample
bool gt1(int x) {
return x > 1;
}
int array[] = { 0, 1, 2, 4, 5 };
int* p = stx::find_last_if(array, array+5, gt1);
cout << (p-array) << endl; // p = &array[2]
find_backward
template<class BidirectionalIterator,
class T>
BidirectionalIterator
find_backward(BidirectionalIterator first,
BidirectionalIterator last,
const T& value)
{
BidirectionalIterator it = last;
while ( first != last ) {
--last;
if ( *last == value ) {
return last;
}
}
return it;
}
first <= i < last に対し、*i == value となる最後のiを返します。該当する i が見つからないときは last を返します。find_last()と異なり、シーケンスを逆順(last-1からfirstに向かって)検索します。
// sample
int array[] = { 0, 1, 2, 2, 5 };
int* p = stx::find_backward(array, array+5, 2);
cout << (p-array) << endl; // p = &array[3]
find_backward_if
template<class BidirectionalIterator,
class UnaryPredicate>
BidirectionalIterator
find_backward_if(BidirectionalIterator first,
BidirectionalIterator last,
UnaryPredicate pred)
{
BidirectionalIterator it = last;
while ( first != last ) {
--last;
if ( pred(*last) ) {
return last;
}
}
return it;
}
first <= i < last に対し、pred(*i) != false となる最後のiを返します。該当する i が見つからないときは last を返します。find_last()と異なり、シーケンスを逆順(last-1からfirstに向かって)検索します。
// sample
bool gt1(int x) {
return x > 1;
}
int array[] = { 0, 1, 2, 2, 5 };
int* p = stx::find_backward_if(array, array+5, gt1);
cout << (p-array) << endl; // p = &array[4]
binary_find
template<class ForwardIterator,
class T>
ForwardIterator
binary_find(ForwardIterator first,
ForwardIterator last,
const T& value)
{
ForwardIterator t = std::lower_bound(first,last,value);
return ( t == last || value < *t ) ? last : t;
}
ソートされたシーケンス[first,last)からvalueと等しい要素を探し、それを指すイテレータを返します。該当する要素が見つからないときは last を返します。バイナリサーチを行なうため、時間計算量は log(last - first) です。
// sample
int array[] = { 0, 1, 2, 2, 5 };
int* p = stx::binary_find(array, array+5, 2);
cout << (p-array) << endl; // p = &array[2]
template<class ForwardIterator,
class T,
class BinaryPredicate>
ForwardIterator
binary_find(ForwardIterator first,
ForwardIterator last,
const T& value,
BinaryPredicate pred)
{
ForwardIterator t = std::lower_bound(first,last,value,pred);
return ( t == last || pred(value,*t) ) ? last : t;
}
predに従ってソートされたシーケンス[first,last)からvalueと等しい要素を探し、それを指すイテレータを返します。該当する要素が見つからないときは last を返します。バイナリサーチを行なうため、時間計算量は log(last - first) です。
// sample
int array[] = { 5, 2, 2, 1, 0 };
int* p = stx::find_backward(array, array+5, 2, greater<int>());
cout << (p-array) << endl; // p = &array[1]
some
template<class InputIterator,
class T>
bool
some(InputIterator first,
InputIterator last,
const T& val)
{
while ( first != last ) {
if ( *first == val ) {
return true;
}
++first;
}
return false;
}
first <= i < last に対し、*i == value となる i が少なくともひとつあれば true を返します。
// sample
int array[] = { 5, 2, 2, 1, 0 };
bool t = stx::some(array, array+5, 1); // t = true;
some_if
template<class InputIterator,
class UnaryPredicate>
bool
some_if(InputIterator first,
InputIterator last,
UnaryPredicate pred)
{
while ( first != last ) {
if ( pred(*first) ) {
return true;
}
++first;
}
return false;
}
first <= i < last に対し、pred(*i) != false となる i が少なくともひとつあれば true を返します。
// sample
bool gt1(int x) {
return x > 1;
}
int array[] = { 0, 1, 0, 1, 0 };
bool t = stx:some_if(array, array+5, gt1); // t = false;
every
template<class InputIterator,
class T>
bool
every(InputIterator first,
InputIterator last,
const T& val)
{
while ( first != last ) {
if ( !(*first == val) ) {
return false;
}
++first;
}
return true;
}
first <= i < last であるすべての i に対し、*i == value であれば true を返します。
// sample
int array[] = { 2, 3, 4, 5, 6 };
bool t = stx::every(array, array+5, 3); // t = false;
every_if
template<class InputIterator,
class UnaryPredicate>
bool
every_if(InputIterator first,
InputIterator last,
UnaryPredicate pred)
{
while ( first != last ) {
if ( !pred(*first) ) {
return false;
}
++first;
}
return true;
}
first <= i < last であるすべての i に対し、pred(*i) != false であれば true を返します。
// sample
bool gt1(int x) {
return x > 1;
}
int array[] = { 2, 3, 4, 5, 6 };
bool t = stx::every(array, array+5, 3); // t = true;
select_copy
template<class InputIterator,
class OutputIterator,
class T>
OutputIterator
select_copy(InputIterator first,
InputIterator last,
OutputIterator result,
const T& value)
{
while ( first != last ) {
if ( *first == value ) {
*result = *first;
++result;
}
++first;
}
return result;
}
first <= i < last に対し、*i == value となる *i を [result,RET)にコピーします。RET は select_copy の戻り値です。
// sample
int array[] = { 5, 1, 2, 1, 0 };
vector<int> v;
stx::select_copy(array, array+5,back_inserter(V), 1); // v = { 1, 1 }
select_copy_if
template<class InputIterator,
class OutputIterator,
class UnaryPredicate>
OutputIterator
select_copy_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryPredicate pred)
{
while ( first != last ) {
if ( pred(*first) ) {
*result = *first;
++result;
}
++first;
}
return result;
}
first <= i < last に対し、pred(*i) != false となる *i を [result,RET)にコピーします。RET は select_copy の戻り値です。
// sample
bool gt1(int x) {
return x > 1;
}
int array[] = { 5, 1, 2, 1, 0 };
vector<int> v;
stx::select_copy_if(array, array+5,back_inserter(V), gt1); // v = { 5, 2 }
transform_if
template<class InputIterator,
class OutputIterator,
class UnaryFunction,
class UnaryPredicate>
OutputIterator
transform_if(InputIterator first,
InputIterator last,
OutputIterator result,
UnaryFunction fn,
UnaryPredicate pred)
{
while ( first != last ) {
if ( pred(*first) ) {
*result = fn(*first);
++result;
}
++first;
}
return result;
}
first <= i < last , pred(*i) != false となる i に対し、fn(*i)を [result,RET)にコピーします。RET は select_copy の戻り値です。
// sample
bool positive(int x) {
return x > 0;
}
int twice(int x) {
return x*2;
}
int array[] = { -2, 1, 0, 3, 2 };
vector<int> v;
stx::transform_if(array, array+5,back_inserter(V), twice, positive); // v = { 1*2, 3*2, 2*2 }
template<class InputIterator1,
class InputIterator2,
class OutputIterator,
class BinaryFunction,
class BinaryPredicate>
OutputIterator
transform_if(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
OutputIterator result,
BinaryFunction fn,
BinaryPredicate pred)
{
while ( first1 != last1 ) {
if ( pred(*first1,*first2) ) {
*result = fn(*first1,*first2);
++result;
}
++first1;
++first2;
}
return result;
}
0 <= i < (last1 - first1), pred(*(first1+i),*(first2+i)) != false となる i に対し、fn(*(first1+i),*(first2+i))を [result,RET)にコピーします。RET は select_copy の戻り値です。
// sample
bool positive(int x, int y) {
return x * y > 0;
}
int array1[] = { -2, 1, 0, 3, -2 };
int array2[] = { -2, -1, 0, 4, 2 };
vector<int> v;
stx::transform_if(array1, array1+5,
array2, back_inserter(V),
multiplies<int>(), positive); // v = { 2*-2, 3*4 }
inject_1st
template<class InputIterator,
class BinaryFunction,
class T>
T
inject_1st(InputIterator first,
InputIterator last,
BinaryFunction fn,
const T& init)
{
T result(init);
while ( first != last ) {
result = fn(result,*first);
++first;
}
return result;
}
first <= i < last に対し、x = fn(x,*i); を順に適用し、最終的に選られたxを返します。x の型は T, 初期値は init です。
// sample
int array[] = { 1, 2, 3, 4, 5 };
int n = stx::inject_1st(array, array+5, plus<int>(), 0); // n = 15
inject_2nd
template<class InputIterator,
class BinaryFunction,
class T>
T
inject_2nd(InputIterator first,
InputIterator last,
BinaryFunction fn,
const T& init)
{
T result(init);
while ( first != last ) {
result = fn(*first,result);
++first;
}
return result;
}
first <= i < last に対し、x = fn(*i,x); を順に適用し、最終的に選られたxを返します。x の型は T, 初期値は init です。
// sample
int array[] = { 1, 2, 3, 4, 5 };
int n = stx::inject_2nd(array, array+5, plus<int>(), 0); // n = 15
partition_copy
template<class InputIterator,
class OutputIterator1,
class OutputIterator2,
class UnaryPredicate>
std::pair<OutputIterator1,OutputIterator2>
partition_copy(InputIterator first,
InputIterator last,
OutputIterator1 result1,
OutputIterator2 result2,
UnaryPredicate pred)
{
while ( first != last ) {
if ( pred(*first) ) {
*result1 = *first;
++result1;
} else {
*result2 = *first;
++result2;
}
++first;
}
return std::pair<OutputIterator1,OutputIterator2>(result1,result2);
}
first < i <= last に対し、pred(*i) != false ならば [result1,RET.first)に、pred(*i) == false ならば [result2,RET.second)に *iをコピーします。RET は partition_copy() の戻り値です。
// sample
bool positive(int x) {
return x > 0;
}
int array[] = { 1, -2, 3, -4, 5 };
vector<int> v;
list<int> l;
stx::partition_copy(array, array+5,
back_inserter(v), back_insserter(l),
positive); // v = { 1, 3, 5 }, l = { -2, -4 }
is_sorted
template<class InputIterator>
bool
is_sorted(InputIterator first,
InputIterator last)
{
if ( first == last ) {
return true;
}
InputIterator next = first;
++next;
while ( next != last ) {
if ( *next < *first ) {
return false;
}
++first;
++next;
}
return true;
}
first <= i , i+1 <= last なるすべての i,i+1 に対し、*i < *(i+1) であれば true を返します。
// sample
int array[] = { 0, 1, 1, 2, 3 };
bool t = stx::is_sorted(array, array+5); // t = true;
template<class InputIterator,
class BinaryFunction>
bool
is_sorted(InputIterator first,
InputIterator last,
BinaryFunction comp)
{
if ( first == last ) {
return true;
}
InputIterator next = first;
++next;
while ( next != last ) {
if ( comp(*next,*first) ) {
return false;
}
++first;
++next;
}
return true;
}
first <= i , i+1 <= last なるすべての i,i+1 に対し、comp(*(i+1),*i) == false であれば true を返します。
// sample
int array[] = { 3, 2, 2, 1, 0 };
bool t = stx::is_sorted(array, array+5, greater<int>()); // t = true;
lexicographical_compare_3way
template <class InputIterator1,
class InputIterator2>
int
lexicographical_compare_3way(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2)
{
while (first1 != last1 && first2 != last2) {
if (*first1 < *first2) {
return -1;
}
if (*first2 < *first1) {
return 1;
}
++first1;
++first2;
}
if (first2 == last2) {
return !(first1 == last1);
} else {
return -1;
}
}
2つのシーケンス[first1,last1), [first2,last2)を辞書順に比較し、[first1,last1) < [first2,last2) ならば -1、[first1,last1) = [first2,last2) ならば 0、[first1,last1) > [first2,last2) ならば 1 を返します。
// sample string s1 = "apple"; const char* s2 = "apple"; int t = stx::lexicographical_compare_3way(s1.begin(), s1.end(), s2, s2+strlen(s2)); // t = 0
template <class InputIterator1,
class InputIterator2,
class BinaryPredicate>
int
lexicographical_compare_3way(InputIterator1 first1,
InputIterator1 last1,
InputIterator2 first2,
InputIterator2 last2,
BinaryPredicate pred)
{
while (first1 != last1 && first2 != last2) {
if ( pred(*first1,*first2) ) {
return -1;
}
if ( pred(*first2,*first1) ) {
return 1;
}
++first1;
++first2;
}
if (first2 == last2) {
return !(first1 == last1);
} else {
return -1;
}
}
2つのシーケンス[first1,last1), [first2,last2)をpredに従って辞書順に比較し、[first1,last1) < [first2,last2) ならば -1、[first1,last1) = [first2,last2) ならば 0、[first1,last1) > [first2,last2) ならば 1 を返します。
// sample
bool ignorecase_less(char x, char y) {
return toupper(x) < toupper(y);
}
string s1 = "apple";
const char* s2 = "APPLA";
int t = stx::lexicographical_compare_3way(s1.begin(), s1.end(), s2, s2+strlen(s2),
ignorecase_less); // t = -1