Developer

競技プログラミング風 標準C++ライブラリ入門【第5回】
2020.11.27
Lv3

競技プログラミング風 標準C++ライブラリ入門【第5回】

競技プログラミング風 標準C++ライブラリ入門【第5回】

これまでに競技プログラミング風 標準C++ライブラリ入門 を4回にわたりお届けしたが、各方面に好評だったので、 おかわり(シーズン2)として【第5回】~【第8回】をお届けする。

標準C++ライブラリを知っていれば比較的簡単な問題をたくさん解いて、 標準C++ライブラリに親しんでいただこうというのが本連載の趣旨だ。

各問題は、「問題文」「テストコード」「ヒント」「解答例」「解説」から構成される。
まず、問題を読んで正しく理解し、テストコード部分をIDEやテキストエディタまたはweb上のコンパイラ (ideonなど)で保存・ビルド・実行し、 NGが出ないようにテストコードの「ToDo:」部分のコードを完成させてほしい。

「ヒント」「解答例」「解説」はデフォルトでは非表示になっており、中身を読みたい場合は【show】ボタンを押せば表示される。 これらをすぐに読むのではなく、ちゃんと解答を考え、使用する標準ライブラりのクラス・関数をweb検索して勉強し、 コード記述・ビルド・実行してからそれらを読むのを強く推奨する。なにごとも自分で考え、いろいろ試した上で、解答などを見るようにするのが肝要だ。 その方が解答が印象に残り問題解決方法が記憶に定着しやすいのだ。

目次

文字列変換(難易度:★☆☆☆☆)

問題

int 型引数を受け取って、それを文字列に変換したものを返す string itostr(int) を定義しなさい。

例えば、123 が引数で渡された場合は “123” を、-99 が渡された場合は “-99” を返す。
[java] #include <iostream> // 標準入出力ライブラリ
#include <string>
using namespace std; // std 名前空間使用
#define DO_TEST(exp) do_test(exp, __LINE__)
void do_test(bool b, int line) {
if( b ) return; // OK
cout << "\nNG at line " << line << "\n";
exit(1);
}
string itostr(int a) {
return ""; // ToDo: 標準関数を使い、ここを書き換えて、a の値を文字列に変換したものを返す
}
int main() {
DO_TEST( itostr(123) == "123" );
DO_TEST( itostr(-99) == "-99" );
cout << "\nGood Job!\n";
return 0;
}
[/java]

ヒント

・数値を文字列に変換するには string std::to_string(int) を使うといいぞ。

解答例
[java] string itostr(int a) {
return to_string(a); // 引数の値を文字列に変換
}
[/java]
解説

a の値を文字列に変換するには string std::to_string(a) をコールするだけだぞ。
ちなみに、引数の型は int 型だけではなく double 型などでもOKだぞ。

交換(難易度:★☆☆☆☆)

問題

string型の参照変数 str1, str2 を受け取り、その内容を交換する関数 void my_swap(string& str1, string& str2) を実装しなさい。

例えば、str1: “abc”, str2: “xyzzz” のときに、my_swap(str1, str2) をコールすると、str1: “xyzzz”, str2: “abc” となる。
[java] #include <iostream> // 標準入出力ライブラリ
#include <string>
using namespace std; // std 名前空間使用
#define DO_TEST(exp) do_test(exp, __LINE__)
void do_test(bool b, int line) {
if( b ) return; // OK
cout << "\nNG at line " << line << "\n";
exit(1);
}
void my_swap(string& str1, string& str2) {
// ToDo: 標準関数を使い、ここを書き換えて、str1 と str2 の内容を交換する
}
int main() {
string str1 = "abc", str2 = "xyzzz";
my_swap(str1, str2);
DO_TEST( str1 == "xyzzz" );
DO_TEST( str2 == "abc" );
cout << "\nGood Job!\n";
return 0;
}
[/java]

ヒント

・変数 a, b の内容を交換するには void std::swap(a, b) を使うんだぞ。

解答例
[java] void my_swap(string& str1, string& str2)
swap(str1, str2); // str1, str2 の内容を交換
}
[/java]
解説

変数 a, b の内容を交換するには void std::swap(a, b) を使うだけだ。

ちなみに、std::swap(a, b) を使わない場合は、以下のように記述する。
[java] void my_swap(string& str1, string& str2)
auto t = str1; // 一旦別の変数に退避
str1 = str2; // str1 にコピー
str2 = t; // 退避していた値を str2 にコピー
}
[/java]

複素数生成(難易度:★☆☆☆☆)

問題

double型引数で実数部 r、虚数部 i をを受け取り、complex 型オブジェクトを返す関数 complex gen_complex(double r, double i) を実装しなさい。

例えば、gen_complex(1, 2) は、実数1, 虚数2の複素数オブジェクトを返す。
[java] #include <iostream> // 標準入出力ライブラリ
#include <complex>
using namespace std; // std 名前空間使用
#define DO_TEST(exp) do_test(exp, __LINE__)
void do_test(bool b, int line) {
if( b ) return; // OK
cout << "\nNG at line " << line << "\n";
exit(1);
}
complex<double> gen_complex(double r, double i) {
return 0; // ToDo: 標準関数を使ってここを書き換え、実数r, 虚数i の複素数を返す
}
int main() {
auto c1 = gen_complex(1, 2);
DO_TEST( real(c1) == 1.0 );
DO_TEST( imag(c1) == 2.0 );
cout << "\nGood Job!\n";
return 0;
}
[/java]

ヒント

・複素数クラスの名前は complex だぞ。
・complex はテンプレートクラスなので、要素の型を指定する必要があるぞ。
・コンストラクタの引数は、実数部・虚数部の値だぞ。

解答例
[java] complex<double> gen_complex(double r, double i) {
return complex<double>(r, i); // 実数r, 虚数i の複素数を返す
}
[/java]
解説

標準C++ライブラリには complex という複素数クラスが用意されている。 このクラスはテンプレートクラスなので、complex<double> のように、実数・虚数部の型を指定する必要がある。
解答例のようにコンストラクタの引数に実数・虚数部の値を渡せば、その値の複素数オブジェクトを生成してくれる。

競技プログラミング風 標準C++ライブラリ入門 連載目次リンク

競技プログラミング風 標準C++ライブラリ入門 連載目次

筆者:津田伸秀
プロフィール:テニス・オセロ・ボードゲーム・パズル類が趣味の年齢不詳のおじさん。 自宅研究員(主席)。vi と C++が好き。迷走中・・・ ボードゲーム・パズル系アプリ開発・リリースしてます。