#include <iostream> #include <vector> #include <array>
// 配列の分割を行う関数 template<typename Container, class PCond> int64_t partition(Container& arr, int64_t low, int64_t high, PCond& pivot) { int64_t i = low; int64_t j = high-1; int64_t bound; while (true) { // 条件に合致するものを探す while ( (pivot.IsTrue(i) == true) ) { i++; if (i >= high) break; } // 条件に合致しないものを探す while ( (pivot.IsFalse(j) == true) ) { j--; if (j == -1) break; } // 左右の走査が交差した場合に分割終了 if (i >= j) { bound = i; break; } // 条件に合致しない要素とする要素を交換 pivot.Swap(i, j); // 走査を進める i++; j--; } return bound; }
enum BoolType { True = 1, False = 0 }; using PairTypeBool = std::pair<BoolType, std::string>; using PairTypeFloat = std::pair<float, std::string>;
// データを分割する時に必要な関数をまとめたもの struct PartitionFuncBool { std::vector<PairTypeBool>& _array; int64_t _pivot; float _value; PartitionFuncBool(std::vector<PairTypeBool>& arr,int64_t pivot_index):_array(arr) { _pivot = pivot_index; _value = _array[_pivot].first; } // 要素の交換関数 void Swap(size_t i, size_t j) { // pivotが移動したので最新のindexを保存 if(i==_pivot) _pivot = j; else if(j==_pivot) _pivot = i; std::swap(_array[i], _array[j]); } // 条件判定関数 bool IsTrue(size_t i) { return _array[i].first == _value; } bool IsFalse(size_t i) { return !IsTrue(i); } };
// データを分割する時に必要な関数をまとめたもの struct PartitionFuncFloat { std::vector<PairTypeFloat>& _array; int64_t _pivot; float _value; PartitionFuncFloat(std::vector<PairTypeFloat>& arr, int64_t pivot_index) :_array(arr) { _pivot = pivot_index; _value = _array[_pivot].first; } // 要素の交換関数 void Swap(size_t i, size_t j) { // pivotが移動したので最新のindexを保存 if (i == _pivot) _pivot = j; else if (j == _pivot) _pivot = i; std::swap(_array[i], _array[j]); } // 条件判定関数 bool IsTrue(size_t i) { return _array[i].first <= _value; } bool IsFalse(size_t i) { return !IsTrue(i); } };
template<typename Container, class PCond> std::array<int64_t, 3> partition_3area(Container& arr, int64_t low, int64_t high, PCond& cond) { int64_t bound_idx = partition< Container, PCond>(arr, low, high, cond); // cond._pivot ... 移動後のpivotのindex 前半にあるはず // bound_idx ... 条件に合致しない要素の最初のindex 後半にあるはず // pivotが前半の末尾以外にある場合は、前半末尾へ移動 if(cond._pivot != bound_idx-1) cond.Swap(cond._pivot, bound_idx-1); return { low, bound_idx-1,// 移動後のpivot high }; }
void testbool() { std::vector<PairTypeBool> arr; arr.push_back(std::make_pair(True, "a")); arr.push_back(std::make_pair(False, "b")); arr.push_back(std::make_pair(False, "c")); arr.push_back(std::make_pair(True, "d")); arr.push_back(std::make_pair(True, "e")); arr.push_back(std::make_pair(True, "f")); arr.push_back(std::make_pair(False, "g")); arr.push_back(std::make_pair(True, "h")); arr.push_back(std::make_pair(False, "i")); arr.push_back(std::make_pair(True, "j")); std::cout << "分割前の配列: " << std::endl; for (size_t i = 0; i < arr.size(); i++) { std::cout << "[" << i << "] " << arr[i].first << " " << arr[i].second << std::endl; } PartitionFuncBool cond(arr, arr.size() / 2); // ピボットの値を取得 // ピボット表示 std::cout << "ピボット: " << "[" << cond._pivot << "]" << arr[cond._pivot].first << " " << arr[cond._pivot].second << std::endl; auto ret = partition_3area(arr, (size_t)0, arr.size(), cond); std::cout << "分割後の配列: " << std::endl; for (size_t i = ret[0]; i < ret[1]; i++) { std::cout << "[" << i << "] " << arr[i].first << " " << arr[i].second << std::endl; } std::cout << std::endl; std::cout << "[" << ret[1] << "] " << arr[ret[1]].first << " " << arr[ret[1]].second << std::endl; std::cout << std::endl; for (size_t i = ret[1] + 1; i < ret[2]; i++) { std::cout << "[" << i << "] " << arr[i].first << " " << arr[i].second << std::endl; } }
void testfloat() { std::vector<PairTypeFloat> arr; arr.push_back(std::make_pair(3.7 , "a")); arr.push_back(std::make_pair(2.3 , "b")); arr.push_back(std::make_pair(7.5 , "c")); arr.push_back(std::make_pair(1.2 , "d")); arr.push_back(std::make_pair(6.8 , "e")); arr.push_back(std::make_pair(5.6 , "f")); arr.push_back(std::make_pair(2.4 , "g")); arr.push_back(std::make_pair(0.9 , "h")); arr.push_back(std::make_pair(6.1 , "i")); arr.push_back(std::make_pair(5.3 , "j")); arr.push_back(std::make_pair(4.5 , "k")); arr.push_back(std::make_pair(8.2 , "l")); arr.push_back(std::make_pair(9.1 , "m")); arr.push_back(std::make_pair(1.7 , "n")); arr.push_back(std::make_pair(5.3 , "o")); arr.push_back(std::make_pair(7.7 , "p")); arr.push_back(std::make_pair(3.8 , "q")); arr.push_back(std::make_pair(4.2 , "r")); std::cout << "分割前の配列: " << std::endl; for (size_t i = 0; i < arr.size(); i++) { std::cout << "[" << i << "] " << arr[i].first << " " << arr[i].second << std::endl; } PartitionFuncFloat cond(arr, arr.size()/2); // ピボットの値を取得 // ピボット表示 std::cout << "ピボット: " << "[" << cond._pivot << "]" << arr[cond._pivot].first << " " << arr[cond._pivot].second << std::endl; auto ret = partition_3area(arr, (size_t)0, arr.size(), cond); std::cout << "分割後の配列: " << std::endl; for (size_t i = ret[0]; i < ret[1]; i++) { std::cout << "[" << i << "] " << arr[i].first << " " << arr[i].second << std::endl; } std::cout << std::endl; std::cout << "[" << ret[1] << "] " << arr[ret[1]].first << " " << arr[ret[1]].second << std::endl; std::cout << std::endl; for (size_t i = ret[1] + 1; i < ret[2]; i++) { std::cout << "[" << i << "] " << arr[i].first << " " << arr[i].second << std::endl; } }
int main() { testfloat(); std::cout << "-----------------------------------\n"; testbool(); return 0; }
分割前の配列:
[0] 3.7 a
[1] 2.3 b
[2] 7.5 c
[3] 1.2 d
[4] 6.8 e
[5] 5.6 f
[6] 2.4 g
[7] 0.9 h
[8] 6.1 i
[9] 5.3 j
[10] 4.5 k
[11] 8.2 l
[12] 9.1 m
[13] 1.7 n
[14] 5.3 o
[15] 7.7 p
[16] 3.8 q
[17] 4.2 r
ピボット: [9]5.3 j
分割後の配列:
[0] 3.7 a
[1] 2.3 b
[2] 4.2 r
[3] 1.2 d
[4] 3.8 q
[5] 5.3 o
[6] 2.4 g
[7] 0.9 h
[8] 1.7 n
[9] 4.5 k
[10] 5.3 j
[11] 8.2 l
[12] 9.1 m
[13] 6.1 i
[14] 5.6 f
[15] 7.7 p
[16] 6.8 e
[17] 7.5 c
分割前の配列:
[0] 1 a
[1] 0 b
[2] 0 c
[3] 1 d
[4] 1 e
[5] 1 f
[6] 0 g
[7] 1 h
[8] 0 i
[9] 1 j
ピボット: [5]1 f
分割後の配列:
[0] 1 a
[1] 1 j
[2] 1 h
[3] 1 d
[4] 1 e
[5] 1 f
[6] 0 g
[7] 0 c
[8] 0 i
[9] 0 b