『競プロのための標準 C++』を読みながら取ったメモ
こちらの書籍を読みながら知らなかった項目を実装しながらメモ.
01 string
- string型で宣言した変数は初期化しなければカラ.サイズは0.
string 変数名(n,char型)
でchar型の文字をn回繰り返した文字列で初期化できる.- stoiでstring型からint型に変換できるが,文字列が
"1101"
などの二進数文字列の場合,stoi(string, nullptr, 基数)
でパースして整数変換できる. - .push_back(char型) で末尾に1文字追加,.pop_back()で末尾の1文字削除
- 文字列の基本の順番は
0 < 9 < A < Z < a < z
(参考:ASCIIコード表)で,辞書形式の順番になる.
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(0); string s; cout << s << endl; cout << s.size() << endl; //output // // 0 string s5(5, 'a'); cout << s5 << endl; cout << s5.size() << endl; //output // aaaaa // 5 s = "1101"; int ss = stoi(s, nullptr, 2); cout << ss << endl; //output // 13 s = "test"; s.push_back('a'); cout << s << endl; s.pop_back(); cout << s << endl; //output // testa // test vector<string> sv; sv.push_back("Ca"); sv.push_back("ab"); sv.push_back("Ab"); sv.push_back("cA"); sort(sv.begin(), sv.end()); for (size_t i = 0; i < sv.size(); i++) { cout << sv[i] << endl; } //output // Ab // Ca // ab // cA return 0; }
02 vector
- 初期化
- .empty()で空チェック
- string型同様,.push_back(), .pop_back()で末尾の追加・削除
vector<bool>
のみ,.flip() で true/false の反転ができる- (vector関連ではないが,cout << boolalpha でbool型の出力を0/1ではなくtrue/falseで表示できる)
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(0); vector<int> nums(5, 100); cout << nums.size() << endl; for (size_t i = 0; i < nums.size(); i++) { cout << nums[i] << endl; } //output // 5 // 100 // 100 // 100 // 100 // 100 vector<int> nums_test1(3); cout << nums_test1.size() << endl; for (size_t i = 0; i < nums_test1.size(); i++) { cout << nums_test1[i] << endl; } vector<string> nums_test2(2); cout << nums_test2.size() << endl; for (size_t i = 0; i < nums_test2.size(); i++) { cout << nums_test2[i] << endl; } //output // 3 // 0 // 0 // 0 // 2 // // vector<int> empty1(3, 1); cout << empty1.empty() << endl; vector<int> empty2; cout << empty2.empty() << endl; //output // 0(false) // 1(true) vector<int> pushpopback {5, 10, 3}; pushpopback.push_back(100); for (size_t i = 0; i < pushpopback.size(); i++) { cout << pushpopback[i] << endl; } //output // 5 // 10 // 3 // 100 pushpopback.pop_back(); for (size_t i = 0; i < pushpopback.size(); i++) { cout << pushpopback[i] << endl; } //output // 5 // 10 // 3 vector<bool> booleans_test = {false, true, false}; booleans_test.flip(); for (size_t i = 0; i < booleans_test.size(); i++) { cout << boolalpha << booleans_test[i] << endl; } //output // true // false // true return 0; }
03 numeric
accumurate(イテレータ最初, イテレータ最後, 初期値, binary_op)
で初期値に対して配列の累積和を計算- 上記で binary_op を指定した場合はその計算を行いながら処理する(例えば string(), multiplies
() など) iota(イテレータ最初, イテレータ最後, 初期値)
で初期値から1ずつ増やした値を各要素にセットする.- 上記で初期値を 'a' にセットすれば a から順にアルファベットをセットした配列を作れる(ただし,vectorのTypeはcharで定義すること)
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(0); vector<int> vec = {1, 2, 3, 4, 5}; int s = accumulate(vec.begin(), vec.end(), 0); cout << s << endl; s = accumulate(vec.begin(), vec.end(), 100); cout << s << endl; //output // 15 // 115 vector<string> vec2 = {"apple", "orange", "peach"}; string s2 = accumulate(vec2.begin(), vec2.end(), string()); cout << s2 << endl; s2 = accumulate(vec2.begin(), vec2.end(), string("header_")); cout << s2 << endl; //output // appleorangepeach // header_appleorangepeach s = accumulate(vec.begin(), vec.end(), 1, multiplies<>()); cout << s << endl; //output // 120 iota(vec.begin(), vec.end(), 11); for (size_t i = 0; i < vec.size(); i++) { cout << vec[i] << endl; } //output // 11 // 12 // 13 // 14 // 15 vector<char> vec_char(26); iota(vec_char.begin(), vec_char.end(), 'a'); for (size_t i = 0; i < vec_char.size(); i++) { cout << vec_char[i] << endl; } //output // a // b // ................. // z return 0; }
04 unordered_set
そもそも unordered_set を知らなかったのでググった.
主な set との違いを unordered_set - cpprefjp C++日本語リファレンス より引用.
unordered_set は、同一キーの要素を複数格納できず、格納順が規定されていないコンテナである。
コンテナ内の各要素は、キーのハッシュ値に基づきハッシュテーブルに格納されるため、決められた順序で並んでいるわけではない。
- set は二分探索木で実装されているが,unordered_set はハッシュ値に基づくため,要素の順が規定されていない
- vector からもイテレータを指定することで unordered_set に変換可能
- 格納順が異なっても格納内容が一致すれば各コンテナの比較
==
で true となる(逆に格納内容が一致しなければ false) .count(Key)
で指定した要素の個数(重複を許さないので 0 or 1)を取得可能.insert(Value)
で要素追加できる- 既に同じ要素が存在する場合は
insert(Value).second
で戻り値(bool)が false となる
- 既に同じ要素が存在する場合は
- erase(Key),.clear() なども vector 同様に使える
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(0); unordered_set<string> uos_colors = {"orange", "pink", "red", "green", "blue", "red"}; cout << uos_colors.size() << endl; for (auto itr = uos_colors.begin(); itr != uos_colors.end(); itr++) { cout << *itr << endl; } //output // 5 // blue // green // red // pink // orange set<string> s_colors = {"orange", "pink", "red", "green", "blue", "red"}; cout << s_colors.size() << endl; for (auto itr = s_colors.begin(); itr != s_colors.end(); itr++) { cout << *itr << endl; } //output // 5 // blue // green // orange // pink // red vector<string> v_colors = {"orange", "pink", "red", "green", "blue", "red"}; unordered_set<string> from_vector (v_colors.begin(), v_colors.end()); cout << from_vector.size() << endl; for (auto itr = from_vector.begin(); itr != from_vector.end(); itr++) { cout << *itr << endl; } //output // 5 // blue // green // red // pink // orange unordered_set<string> uos_colors2 = {"red", "orange", "blue", "blue", "green", "pink"}; cout << "--" << endl; for (auto itr = uos_colors2.begin(); itr != uos_colors2.end(); itr++) { cout << *itr << endl; } //output // pink // green // blue // orange // red unordered_set<string> uos_colors3 = {"red", "orange", "green", "pink"}; cout << "--" << endl; for (auto itr = uos_colors3.begin(); itr != uos_colors3.end(); itr++) { cout << *itr << endl; } //output // green // orange // pink // red cout << boolalpha << (uos_colors == uos_colors2) << endl; cout << boolalpha << (uos_colors == uos_colors3) << endl; //output // true // false cout << uos_colors.count("red") << endl; cout << uos_colors.count("white") << endl; //output // 1 // 0 uos_colors.insert("gray"); cout << "--" << endl; for (auto itr = uos_colors.begin(); itr != uos_colors.end(); itr++) { cout << *itr << endl; } //output // gray // blue // green // red // pink // orange uos_colors.erase("gray"); cout << "--" << endl; for (auto itr = uos_colors.begin(); itr != uos_colors.end(); itr++) { cout << *itr << endl; } //output // blue // green // red // pink // orange uos_colors.clear(); cout << uos_colors.size() << endl; //output // 0 return 0; }
05 algorithm
ほとんど知らなかった項目なので,今後自分が使いそうな項目のみメモ.
- 3つ以上の数値の最大値・最小値はリスト{...} を使って
min({...})
のように書ける min_element(itrFirst, itrLast)
で配列の最小値のイテレータを取得でき,*をつけるとその値を取得できるdistance(itrFirst, min_element())
で最小値の位置を取得できるminmax(変数 or リスト)
で与えられた値の最小値,最大値の pair を取得でき,最小値は pair.first, 最大値は pair.second で取得できるfill(itrFirst, itrLast, value)
で配列を value で埋めるremove(itrFirst, itrLast, value)
で配列中から value を削除して,削除した要素を埋めて並び直し(削除して余った領域は無効領域として残る),有効範囲のイテレータを返す- 上記の無効領域を削除するのが .erase で,
.erase(remove(), itr.Last)
で削除 remove_if(itrFirst, itrLast, unaryPred)
で上記の条件付き削除が可能reverse(itrFirst, itrLast)
で要素を逆順にするrotate(itrFirst, itrMId, itrLast)
で,itrMid で指定した要素が先頭で itrLast まで続き,そのあとから残りの要素が itrFirst 続くように並び替えるunique(itrFirst, itrLast)
で隣り合った要素が同じにならないように要素を削除して,削除した要素を埋めて並び直し(削除して余った領域は remove 同様無効領域とする),有効範囲のイテレータを返す- remove と同様,unique で返ってきたイテレータを
erase(unique(), itr.Last)
とすることで,無効領域を削除できる- sort 後,unique → erase とすれば重複要素の削除ができる(setでもできるが)
sort(itrFirst, itrLast, greater<>{})
で要素が大きい順に並べる(指定しない場合は小さい順)nth_element(itrFirst, itrNth, itrLast)
で,itrNth 番目の要素の値が,配列全体のうち N 番目に小さい値となるようにソートする(ただし,itrNth の前後は順不定)lower_bound(itrFirst, itrLast, value)
でソート済みの配列に対して value を挿入しようとする際,ソート状態を維持できかつ最も左の位置を取得し,その位置を示すイテレータを返す- 実際に何番目となるかは
distance(itrFirst, lowe_bound())
で取得 - lower_bound は最も左となる位置だが,upper_bound は最も右側となる位置
equal_range(itrFirst, itrLast, value)
で lower_bound と upper_bound 両方の結果を pair で取得できる- ソート済みの2つの配列について,
- 和集合(少なくともどちらか1つの配列に存在する要素集合)は
set_union(itrFirst1, itrLast1, itrFirst2, itrLast2, itrOut)
で取得可能 - 積集合(両方の配列に存在する要素集合)は
set_intersection(itrFirst1, itrLast1, itrFirst2, itrLast2, itrOut)
で取得可能 - 差集合(前者の集合から後者に存在する要素を取り除いた集合) は
set_difference(itrFirst1, itrLast1, itrFirst2, itrLast2, itrOut)
で取得可能 - 対称差集合(2つの配列のどちらかにしか存在しない要素集合)は
set_symmetric_difference(itrFirst1, itrLast1, itrFirst2, itrLast2, itrOut)
で取得可能 - 和集合のように重複した要素を削除することなく,マージした集合を得るのは
merge(itrFirst1, itrLast1, itrFirst2, itrLast2, itrOut)
で取得可能- いずれの場合も計算結果を itrOut で示したイテレータに格納できる(例:空の配列に
back_inserter(配列名)
で格納できる)
- いずれの場合も計算結果を itrOut で示したイテレータに格納できる(例:空の配列に
- 和集合(少なくともどちらか1つの配列に存在する要素集合)は
next_permutation(itrFirst, itrLast)
で辞書順に次の順列を取得できる- ソート済みの配列に対して do-while 文ですべての順列を列挙できる
- next_permutationがイマイチよくわからなかったのでまとめてみた - Qiita が実装についてとてもわかりやすかった
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout << "--" << endl; int a = 30, b = 40, c = 10; cout << min({a, b, c}) << endl; //output // 10 cout << "--" << endl; vector<int> data = {100, -3, 0, 10, 40, 1}; cout << *min_element(data.begin(), data.end()) << endl; cout << distance(data.begin(), min_element(data.begin(), data.end())) << endl; //output // -3 // 1 cout << "--" << endl; auto p = minmax({a, b, c}); cout << p.first << " " << p.second << endl; //output // 10 40 cout << "--" << endl; fill(data.begin(), data.end(), 0); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // 0 // 0 // 0 // 0 // 0 // 0 cout << "--" << endl; data = {100, -3, 0, 10, 40, 1}; auto itrRemove = remove(data.begin(), data.end(), 0); data.erase(itrRemove, data.end()); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // 100 // -3 // 10 // 40 // 1 cout << "--" << endl; auto itrRemove2 = remove_if(data.begin(), data.end(), [](int n){return (n%2==0);}); data.erase(itrRemove2, data.end()); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // -3 // 1 cout << "--" << endl; data = {100, -3, 0, 10, 40, 1}; reverse(data.begin(), data.end()); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // 1 // 40 // 10 // 0 // -3 // 100 cout << "--" << endl; data = {100, -3, 0, 10, 40, 1}; rotate(data.begin(), data.begin() + 2, data.end()); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // 0 // 10 // 40 // 1 // 100 // -3 cout << "--" << endl; data = {1, 1, 0, 10, 10, 3, 4, 5, 5}; auto itrUnique = unique(data.begin(), data.end()); data.erase(itrUnique, data.end()); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // 1 // 0 // 10 // 3 // 4 // 5 cout << "--" << endl; sort(data.begin(), data.end(), greater<>{}); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // 10 // 5 // 4 // 3 // 1 // 0 cout << "--" << endl; data = {100, -3, 0, 10, 40, 1}; nth_element(data.begin(), data.begin()+2, data.end()); cout << data[2] << endl; //output // 1 cout << "--" << endl; data = {100, -3, 0, 10, 40, 1}; sort(data.begin(), data.end()); for (size_t i = 0; i < data.size(); i++) { cout << data[i] << endl; } //output // -3 // 0 // 1 // 10 // 40 // 100 cout << "--" << endl; auto itr = lower_bound(data.begin(), data.end(), -1); cout << *itr << endl; cout << distance(data.begin(), itr) << endl; //output // 0 // 1 cout << "--" << endl; itr = lower_bound(data.begin(), data.end(), 0); cout << *itr << endl; cout << distance(data.begin(), itr) << endl; //output // 0 // 1 cout << "--" << endl; itr = upper_bound(data.begin(), data.end(), 0); cout << *itr << endl; cout << distance(data.begin(), itr) << endl; //output // 1 // 2 cout << "--" << endl; auto itr_equal = equal_range(data.begin(), data.end(), 0); cout << *itr_equal.first << endl; cout << distance(data.begin(), itr_equal.first) << endl; cout << *itr_equal.second << endl; cout << distance(data.begin(), itr_equal.second) << endl; //output // 0 // 1 // 1 // 2 cout << "--" << endl; vector<int> vec1 = {0, 2, 5, 9}; vector<int> vec2 = {2, 3, 4, 5}; vector<int> vec3; set_union(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec3)); for (size_t i = 0; i < vec3.size(); i++) { cout << vec3[i] << endl; } //output // 0 // 2 // 3 // 4 // 5 // 9 vec3.clear(); cout << "--" << endl; set_intersection(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec3)); for (size_t i = 0; i < vec3.size(); i++) { cout << vec3[i] << endl; } //output // 2 // 5 vec3.clear(); cout << "--" << endl; set_difference(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec3)); for (size_t i = 0; i < vec3.size(); i++) { cout << vec3[i] << endl; } //output // 0 // 9 vec3.clear(); cout << "--" << endl; set_symmetric_difference(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec3)); for (size_t i = 0; i < vec3.size(); i++) { cout << vec3[i] << endl; } //output // 0 // 3 // 4 // 9 vec3.clear(); cout << "--" << endl; merge(vec1.begin(), vec1.end(), vec2.begin(), vec2.end(), back_inserter(vec3)); for (size_t i = 0; i < vec3.size(); i++) { cout << vec3[i] << endl; } //output // 0 // 2 // 2 // 3 // 4 // 5 // 5 // 9 cout << "--" << endl; data = {1, 2, 3, 4}; do { for (size_t i = 0; i < data.size(); i++) { cout << data[i] << " "; } cout << endl; } while (next_permutation(data.begin(), data.end())); //output // 1 2 3 4 // 1 2 4 3 // 1 3 2 4 // 1 3 4 2 // 1 4 2 3 // 1 4 3 2 // 2 1 3 4 // 2 1 4 3 // 2 3 1 4 // 2 3 4 1 // 2 4 1 3 // 2 4 3 1 // 3 1 2 4 // 3 1 4 2 // 3 2 1 4 // 3 2 4 1 // 3 4 1 2 // 3 4 2 1 // 4 1 2 3 // 4 1 3 2 // 4 2 1 3 // 4 2 3 1 // 4 3 1 2 // 4 3 2 1 return 0; }
06 tuple
省略
07 ios, iomanip
省略