Closed7

AtCoder C++入門の覚え書き #3-1 キャスト、size_t、printf+string, map, 演算子オーバーロード etc

こどはざこどはざ

型のキャスト

キャストのやり方。

int a = 2;
double b = 0.01;
b = (double) a;

暗黙のキャスト

int a = 2;
double b = 0.01;

cout << a + b << endl;
cout << (double) a + b << endl; //上と同じ意味

doubleやfloatをint型に変換すると 小数点以下は切り捨てられる

cout << (int) 3.99 << endl; // 3
こどはざこどはざ

文字列変換のための関数

stoi("7");     // int
stoll("8");    // int64_t
stod("3.14");  // double
stof("3.14");  // float
こどはざこどはざ

size_t 型

配列長を取る size_t 型は unsigned long なので、数値を加工する際に負になるとオーバーフローしてしまう。

無限に近いループ

vector<int> arr = {}; // 長さゼロの配列
for (int i = 0; i <= arr.size() -1; i++ ) { // arr.size() -1 がオーバーフローする
    cout << i; 
}

// (int) にキャストすれば意図した動作になる
for (int i = -1; i <= (int) arr.size() - 1; i++ ) {
    cout << i; // 1回だけ出力される
}
こどはざこどはざ

printf() scanf()

printf()

cout を使わなくてもフォーマット指定で printf() で出力できる。
ただし、 stringを出力する際には注意s.c_str() を実行する必要がある。

string str = "hoge";
printf("string: %s", str.c_str());

scanf()

scanf() を使えばフォーマット指定で入力を取れる。

int i;
scanf("i = %d", &i);

scanf() で string を読むのは一筋縄ではいかない。

char c[100];
int i;
scanf("s = %4s, i = %d", &c, &i); // "s = hoge, i = 7"
printf("s = %s, i = %d", c, i);

ちなみに char[]string への暗黙キャストはちゃんと行われるのでそこは安心。
vector<char> から string への変換は、stringのコンストラクタを使う。

vector<char> c = { 'a', 'b', 'c' };
string s(c.begin(), c.end()); // "abc"
こどはざこどはざ

pair, tuple, tie, ignore

  • 2組の決まった型を組み合わせて使えるのが pair<type, type>
  • 任意数の決まったかたを組み合わせられるのが tuple<type, type, (...)>
  • tie() で任意の個別の変数にpair, tuple型の値をアサインできる
  • tie(ignore) で任意番目の値の代入を無視できる
pair<string, int> p("hoge", 7);
tuple<string, int, bool> t("fuga", 2, false);

// pair, tupleの値を使う
cout << p.first << endl;       // p.first, p.second が使える
cout << get<0>(t) << endl; // get<定数>(t) で任意番目の値にアクセスする。変数は使えない

// tie() で pair や tuple 型の値を個別の変数に格納できる。
string ps;
int pi;
tie(ps, pi) = p;

string ts;
int ti;
bool tb;
tie(ts, ti, tb) = t;

// tie() 中に ignore を入れて値セットの一部の代入を無視できる
tie(ignore, ti, ignore)  = t; // ti = get<1>(t)

make_pair() と make_tuple()

make_pair() make_tuple() を使ってそれぞれの型のデータを作れる。

pair<string, int> p;
p = make_pair("hoge", 2);

tuple<string, int, bool> t;
t = make_tuple("fuga", 3, true);
こどはざこどはざ

map, setはkeyごとにソートされているため、データの挿入と削除に O(log N) かかる。
ソートする必要がなければ unordered_mapunordered_set を代わりに使うことを検討する(平均 O(1) で動作)

map

map<string, string> m;
string key = "hoge";
m[key] = "fuga"; // 値の追加
m.erase(key); // 値の削除
m.at(k); // 値へのアクセス
m.count(k); // 存在確認
m.size(); // データ数を取得

// 値へのアクセス補足
cout << m.at("no-data") << endl; // 値がない場合エラー
cout << m["no-data"] << endl; // 値がない場合初期値が追加される。m.size()の値が1増える

queue, priority_queue

queueのメソッドはJSの配列と似ているが、細かく違うので気をつける。
特に pop() は要素を削除するだけで値は返さない 点に注意。
最前列の値を取りたければ front() でアクセスすること(priority_queueの場合は top() )

queue<int> q;
q.push(3);
q.push(2);

while (!q.empty()) {
  cout << q.front() << endl;
  p.pop()
}

queueとpriority_queueの違いは以下。

  • 先頭要素の取得方法 q.front() pq.top()
  • priority_queueはソートが入るので pop() push() の計算量が O(log N)

その他

  • stack, deque(queue+stack)などがある
  • unordered_set, unordered_mapの値の追加削除は平均 O(1)
  • *lower_bound(begin, end, i) *upper_bound(begin, end, i) 覚える
こどはざこどはざ

演算子オーバーロード

なかなか使い所がイメージできないので後で必要なときに学ぶことにする。

このスクラップは2023/10/11にクローズされました