C++ の配列の要素のシフト
- 
          
            C++ で配列の要素をずらすには std::rotateアルゴリズムを使用する
- 
          
            カスタムラッパー関数 std::rotateを使って C++ の配列の要素をシフトさせる
- 
          
            std::rotate_copyアルゴリズムを用いて、C++ の配列内の要素をシフトする
 
この記事では、C++ で配列の要素をずらす方法をいくつか紹介します。
C++ で配列の要素をずらすには std::rotate アルゴリズムを使用する
    
関数 std::rotate は C++ アルゴリズムライブラリの一部であり、<algorithm> ヘッダを用いてインポートすることができます。このアルゴリズムは、配列の要素を左側に回転させます。イテレータ型の 3つのパラメータを受け取り、2 番目のパラメータは、新しく構築された範囲の最初の要素となる必要のある要素を指定します。一方、1 番目と 3 番目の要素は、開始位置と終了位置を指定する元の範囲指定子です。
また、rbegin/rend イテレータを用いて要素を右側に移動させるには、std::rotate を利用することができることに注意してください。次の例では、この関数は 10 個の整数を持つ std::vector オブジェクト上で呼び出され、両方向の操作を示しています。
#include <algorithm>
#include <array>
#include <iostream>
#include <vector>
using std::array;
using std::cout;
using std::endl;
using std::rotate;
using std::vector;
template <typename T>
void printElements(T &v) {
  cout << "[ ";
  for (const auto &item : v) {
    cout << item << ", ";
  }
  cout << "\b\b ]" << endl;
}
int main() {
  vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  printElements(vec);
  rotate(vec.begin(), vec.begin() + 3, vec.end());
  printElements(vec);
  rotate(vec.rbegin(), vec.rbegin() + 3, vec.rend());
  exit(EXIT_SUCCESS);
}
出力:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
[ 4, 5, 6, 7, 8, 9, 10, 1, 2, 3 ]
カスタムラッパー関数 std::rotate を使って C++ の配列の要素をシフトさせる
あるいは、std::rotate アルゴリズムをカプセル化するためのラッパー関数を実装して、ユーザに回転させる配列オブジェクトとシフトさせる位置の数を表す整数の 2つの引数だけを渡すように要求することもできます。また、渡された整数の符号を回転操作が処理される方向として表すこともできます。
このカスタム関数では、右回転を意味する正の整数と左回転を意味する負の整数を任意に選択しました。
この rotateArrayElements 関数テンプレートは、C++ 標準ライブラリコンテナを用いて構築された固定配列オブジェクトと動的配列オブジェクトの両方で利用できることに注意してください。
#include <algorithm>
#include <array>
#include <iostream>
#include <vector>
using std::array;
using std::cout;
using std::endl;
using std::rotate;
using std::vector;
template <typename T>
void printElements(T &v) {
  cout << "[ ";
  for (const auto &item : v) {
    cout << item << ", ";
  }
  cout << "\b\b ]" << endl;
}
template <typename T>
int rotateArrayElements(T &v, int dir) {
  if (dir > 0) {
    rotate(v.rbegin(), v.rbegin() + dir, v.rend());
    return 0;
  } else if (dir < 0) {
    rotate(v.begin(), v.begin() + abs(dir), v.end());
    return 0;
  } else {
    return 1;
  }
}
int main() {
  array<int, 10> arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  rotateArrayElements(arr, 3);
  printElements(arr);
  rotateArrayElements(vec, -3);
  printElements(vec);
  exit(EXIT_SUCCESS);
}
出力:
[ 8, 9, 10, 1, 2, 3, 4, 5, 6, 7 ]
[ 4, 5, 6, 7, 8, 9, 10, 1, 2, 3 ]
std::rotate_copy アルゴリズムを用いて、C++ の配列内の要素をシフトする
std::rotate_copy アルゴリズムは std::rotate と同じ操作を実装していますが、前者は回転させた配列の要素を関数パラメータを追加して指定した別の範囲にコピーします。
まず、新しい範囲を宣言する必要があります。この場合は std::vector 型が選択され、コンストラクタは元の vector のサイズを受け取ります。
そして、std::rotate_copy 関数を std::rotate で指定したのと同じパラメータを指定して呼び出すことができます。
次の例では、配列要素の左回転のみを示していることに注意してください。
#include <algorithm>
#include <array>
#include <iostream>
#include <vector>
using std::array;
using std::cout;
using std::endl;
using std::rotate;
using std::rotate_copy;
using std::vector;
template <typename T>
void printElements(T &v) {
  cout << "[ ";
  for (const auto &item : v) {
    cout << item << ", ";
  }
  cout << "\b\b ]" << endl;
}
int main() {
  vector<int> vec1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  printElements(vec1);
  vector<int> vec2(vec1.size());
  rotate_copy(vec1.begin(), vec1.begin() + 3, vec1.end(), vec2.begin());
  printElements(vec2);
  exit(EXIT_SUCCESS);
}
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
[ 4, 5, 6, 7, 8, 9, 10, 1, 2, 3 ]
