stream の書式関連
参照: https://www.cs.fsu.edu/~myers/c++/notes/formatting.html
- stringstream は,str() メンバ関数で文字列になる.
stringstream ss;
ss << 100; assert(ss.str() == "100");
- 16進表記は hex.10進表記(にもどす)は dec.大文字/小文字は [no]uppercase.
stringstream ss;
ss << hex << 253 << uppercase << 254 << nouppercase << 255;
ss << dec << 100;
assert(ss.str() == "fdFEff100");
- 小数点以下の桁数は setprecision で制御
stringstream ss;
double x = 1.0 / 3.0;
ss << x << " " << setprecision(20) << x;
assert(ss.str() == "0.333333 0.33333333333333331483");
- 0詰めは setfill, 表示幅は,setw で制御
stringstream ss, ss1;
ss << setw(4) << 10 << "," << setw(4) << (int)1e8;
assert(ss.str() == " 10,100000000");
ss1 << setfill('0') << setw(4) << 10 << "," << setw(4) << (int)1e8;
assert(ss1.str() == "0010,100000000");
- ほとんどの manipulator は sticky (効果が持続) だが, setw は例外.
stringstream ss1, ss2;
ss1 << hex << 100 << " " << 200;
assert(ss1.str() == "64 c8");
ss2 << setw(4) << 5 << 6;
assert(ss2.str() == " 56");
例外
- 型宣言:
struct Exc : exception {};
- 投げる:
throw Exc();
- 受ける:
try { ... } catch(const Exc& e) { ... }
使用例
struct Exc : exception {};
auto all_non_zero = [&](string s) -> bool {
auto dfs = [&](auto f, size_t i) -> void {
if (i == s.size()) return;
if (s[i] == '0') throw Exc();
f(f, i + 1);
};
try {
dfs(dfs, 0);
return true;
}catch (const Exc& e) {
return false;
}
};
assert(all_non_zero("11111"));
assert(! all_non_zero("11101101"));
ビット処理
long long に対するもの.
- 1の数を数える –
__builtin_popcountll
assert(__builtin_popcountll(0xF) == 4);
assert(__builtin_popcountll(0x100030007000F000) == 10);
- 右端の0の数 –
__builtin_ctzll
- Count Trailing Zero であろう.
- __builtin_ctzll(x) は,x の LSB の添字に等しい.
- 引数は0ではいけない.
assert(__builtin_ctzll(0x1) == 0);
assert(__builtin_ctzll(0x8) == 3);
assert(__builtin_ctzll(1LL<<63) == 63);
- 左端の0の数 –
__builtin_clzll
- Count Leading Zero であろう.
- __builtin_clzll(x) は,63 - (x の MSB の添字) に等しい
- 引数は0ではいけない.
assert(__builtin_clzll(0x1) == 63);
assert(__builtin_clzll(1LL<<62) == 1);
vector での 重複の削除
Unix の, sort | uniq
に相当する操作
vector<int> vec({10, 2, 5, 7, 5, 2, 5});
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
assert(vec == vector<int>({2, 5, 7, 10}));
イタレータ
iterator は,「要素を指す」と考えるより「要素と要素の間を指す」 と考えた方が話が分かりやすい.
vector<int> vec({2, 4, 5, 5, 5, 6, 10, 12});
auto it1 = lower_bound(vec.begin(), vec.end(), 5);
auto it2 = upper_bound(vec.begin(), vec.end(), 5);
auto it3 = lower_bound(vec.begin(), vec.end(), 11);
auto it4 = upper_bound(vec.begin(), vec.end(), 11);
逆方向イタレータ
reverse_iterator<decltype(it)>(it)
で,
it の指している「要素間の位置」は変わらずに,方向だけが反転する.
上図で,5以下の要素を並べるコード:
stringstream ss;
vector<int> vec({2, 4, 5, 5, 5, 6, 10, 12});
auto itN = upper_bound(vec.begin(), vec.end(), 5);
for (auto itR = reverse_iterator<decltype(itN)>(itN);
itR != vec.rend(); itR++) {
ss << *itR;
}
assert(ss.str() == "55542");
set や map などに対しても,同様のことができる.
stringstream ss;
multiset<int> is({2, 4, 5, 5, 5, 6, 10, 12});
auto itN = is.upper_bound(5);
for (auto itR = reverse_iterator<decltype(itN)>(itN);
itR != is.rend(); itR++) {
ss << *itR;
}
cout << ss.str() << endl;
assert(ss.str() == "55542");
set や priority queue の比較関数
集合 (set) のテンプレートの第2引数が比較クラスになる. イタレータが降順に動いていってほしい場合,次のように書けば良い.
set<T, greater<T>> ss;
一般の比較関数 fn を書きたいときには,次のようにする.
set<T, decltype(fn)>> ss(fn);
優先度付きキューを普通に次のように書くと降順になる:
priority_queue<T> pque;
昇順にしたいときには,次のように書く:
priority_queue<T, vector<T>, greater<T>> pque;
一般の比較関数 fn を書きたいときには,次のようにする. 指定した比較関数の「大きい」順に取り出される. つまり,fn(x, y) が真の時には,yがxより先に取り出される.
priority_queue<T, vector<T>, decltype(fn)> pque(fn);
例:
using Pair = pair<int, int>;
auto comp = [&](Pair x, Pair y) -> bool {
if (x.first != y.first) return x.first < y.first;
else return x.second > y.second;
};
priority_queue<Pair, vector<Pair>, decltype(comp)> pque(comp);
pque.emplace(2, 1); pque.emplace(3, 5), pque.emplace(3, 9);
Pair p;
p = pque.top(); pque.pop(); assert(p == Pair(3, 5));
p = pque.top(); pque.pop(); assert(p == Pair(3, 9));
p = pque.top(); pque.pop(); assert(p == Pair(2, 1));