第2回 C++(標準ライブラリの紹介)
標準ライブラリ(STL)でよく使う機能について紹介します。
ただし書き
- 以降では聞いたこともないものがたくさん出てきますが、もちろん全て覚える必要はありません
- stringとvector、ソートは頻出ですが、それ以外のものは簡単な問題では使わなくていいことが多いです
- 「こんなのがある」ということを覚えてもらい、必要なときにリファレンスを見ながら使えるようになれば十分です
文字列を扱う。
string str;
空の文字列を宣言
str[i]
i番目の文字を参照
str = str2
文字列の代入
str + str2
文字列の連結
str.size()
文字列の長さ
str == str2
文字列の比較
str <= str2
str > str2
文字列の辞書順比較
str.find(str2)
文字列の検索(str
の中にstr2
が見つかればその位置を示す数値を、見つからなければ-1を返す)
str.rfind(str2)
文字列を後ろから検索
str.substr(i, len)
i番目からlen
文字分の部分文字列を取得
動的配列を作る。
動的配列とはサイズが決まっていない配列のこと。要素を追加すれば(push_back()
を使えば)自動的にサイズが大きくなる。
主な関数:
vector<int> vec;
int型の配列を宣言+空の配列を生成
vector<int> vec(n);
int型の配列を宣言。要素数はn
vector<int> vec(n, i);
int型の配列を宣言。要素数はn
で、要素の値はすべてi
vec[i]
i番目の要素を参照
vec = vec2
配列の代入(vec2
の中身が全てvec
にコピーされる)
vec.size()
配列の要素数
vec.push_back(some_number)
配列の末尾に要素を追加
vec.insert(it, sume_number)
イテレータが示す位置の直前に要素を追加
vec.erase(it)
イテレータが示す位置の要素を削除
vec.begin()
配列の先頭を示すイテレータを返す
vec.end()
配列の終端を示すイテレータを返す
イテレータ
コンテナ(vectorや後述のmapなど)の中身を統一的に扱うための機能。
上記のinsertやeraseのほか、後述のアルゴリズム系の処理で使われる。
vectorのイテレータは配列のポインタとほぼ同等に扱うことができる(ポインタがイテレータの一種として扱えるように設計されている)。
コンテナ(主にvectorと普通の配列)を操作する簡単なアルゴリズム集。
色々なデータ構造で使えるようにしているため、イテレータを使っている。
主な関数:
sort(begin, end)
イテレータが示す範囲をソートする
lower_bound(begin, end, value)
upper_bound(begin, end, value)
イテレータが示す範囲で2分探索
- 二分探索はソート済みの配列から効率よく値を検索するアルゴリズムのこと
- 戻り値はイテレータとなる
next_permutation(begin, end)
イテレータが示す範囲の次の順列を生成する
find(begin, end, value)
値の検索。値がvalue
になる最初の要素のイテレータを返す
count(begin, end, count)
値の個数を数える
min(a,b)
max(a,b)
最大最小
min_element(begin, end)
max_element(begin, end)
イテレータが示す範囲で最小値/最大値となる要素のイテレータを返す
swap(a, b)
値の入れ替え
next_permutationの例:
出力:
[ 0 1 2 3 ]
[ 0 1 3 2 ]
[ 0 2 1 3 ]
[ 0 2 3 1 ]
...8個省略...
[ 3 1 0 2 ]
[ 3 1 2 0 ]
[ 3 2 0 1 ]
[ 3 2 1 0 ]
参考ページ:競技プログラミングで使えそうなSTLまとめ (Competitive Programming Advent Calendar) - プログラミング関係のメモとか
pair
2つの要素をペアにする。
自分で構造体を作れば同じことができるが、pairを使うと構造体を自作する必要がないので便利。
pair<char, double> p;
文字と実数のペアを保持するペアを宣言
make_pair(a, b)
aとbのペアを作成
pair<char, double>(s,d)
sとdのペアを作成。ほぼmake_pair
と同じだが、typedef
を使うとこちらのがタイプ数が少なくなる
p.first
1つ目の要素にアクセス
p.second
2つめの要素にアクセス
p < p2
p >= p2
p == p2
pair同士の比較
- 1つ目の要素の要素と2つ目の要素を順に大小比較する
二分探索木を使った連想配列を作る。
連想配列は、添字に自然数以外のものでも使える配列のこと。
後の講習会で解説するメモ化再帰を実装するときに使われることがある。
map<int, double> p;
数値をキーとして実数を保持するmapを宣言+空のmapを作成
map[key]
キーに該当する要素にアクセス
サンプルコード:
サンプルコードの出力:
5
44は見つかりません
2が見つかりました
key: -888, value: 5000
key: 2, value: 7
key: 100000000, value: 3
その他の標準ライブラリ
以下のヘッダも使うと便利なことあるから覚えておくといいです
C++の文法について
C++の文法で重要そうな部分を
ローカル変数宣言の位置
C言語では「ローカル変数宣言はブロックの先頭にまとめておかないといけない」と習ったかもしれませんが、
C++では関数の途中で宣言しても大丈夫です。(というか最近のC言語(C99)でもOKなはず)
参照渡し
int&
のように変数宣言の型の後ろに&
をつけると、その変数は参照渡しとなる。
参照渡しを使うと、ポインタを使ったときと同じような効果を得ることができる。
参照渡しを使う利点は以下の通り。
- ポインタと同様に関数から呼び出し元の変数の値を書き換えられる
- ポインタと違い普通の変数と同じように扱える(
*
演算子によるアドレスの解決が不要)
- 変数の不要なコピーをしなくて済む
- 上記のコードでは要素数1万のvectorを関数に渡しているが、これを値渡しすると関数呼び出しの度に1万個の要素をコピーすることになる。コピーが必要な場合もあるが、多くの場合無駄である
structの関数定義
C++のstructは、関数を持てる。また、typedefなしでも型名だけでアクセスできる。
細かいことを書くと、C++のstructはデフォルトの可視範囲がpublicなclassと等価。
operator?
という関数を定義する(?
は何か演算子)と、そのstructに対する演算子の効果を変えることができる。
これを演算子オーバーロードという。
演算子オーバーロードは比較可能なクラスを使うときに使用される。
演習
AIZU ONLINE JUDGEの問題1173「世界の天秤」
余談:定期オンラインコンテストについて
ICPCは1年に一度行うプログラミングコンテストですが、他にもコンテストやオンライン判定システムは色々あります。
アルゴリズム関係のもののうち、代表的なもの(というか僕が知っているもの)は次の通り。
定期コンテスト
年一回
オンラインジャッジ
TopCoder部というページでTopCoder SRMなどの参加方法やコンテストの日程を確認できます。
結構頻繁にコンテストがあるので、暇なときに参加してみましょう。