【C++】std::setの基本的な使い方
setはユニークな要素を格納する連想コンテナの1つです.連想コンテナとはキーと値のペアを保持するクラスを指し,setの場合はインデックスがキーとなります. setは二分木として実装されているため,キーから値をとりだすのがO(logN)と高速です. ただしvectorとは異なり要素がユニークである必要があるので,使用の際は用途に合っているか確認する必要があります. (例えばマイナンバーのように値が一意であることが保証されていればsetが適している.一方で名簿のように同姓同名の人が含まれるケースも考える場合にsetは使うべきでない)
setの使い方
基本的な使い方
- 初期化:set<ValueType> 変数名;
- 要素の追加:insert()関数を用いる
- 要素の削除:erase()関数を用いる
- 値の参照:イテレータや範囲for文を用いる
二分木で実装されているため,vectorなどで用いられる[]演算子でのアクセスはできない. - 値の検索:
- 値の一致する要素のiteratorを得るにはfind()関数を用いる
- 値の一致する要素があるかのみを確認した場合はcount()関数を用いる(返り値は0 or 1)
#include <iostream> #include <set> using namespace std; int main() { // 変数の宣言 set<int> s; // 値を挿入 s.insert(1); s.insert(2); s.insert(3); s.insert(4); s.insert(5); // 値を削除 auto c = s.erase(5); // 5は存在するのでeraseの結果1が返される c = s.erase(4); // 4は存在するのでeraseの結果1が返される c = s.erase(5); // 5は既に削除済みなので,eraseの結果0が返される // 値の参照 // iteratorを使う場合 auto iter = s.begin(); // iterの方はstd::set<ValueType>::iteratorであるが,通常autoで受ける cout << *iter << endl; // 1 cout << *(iter + 1) << endl; // 2 // 範囲for文を使う場合 for (auto x : s) { cout << *x << endl; } // 値の検索 auto find_iter = s.find(3); // O(logN)で3を探索 if (find_iter != s.end()) { cout << "Found" << endl; } else { cout << "Not found" << endl; } if (s.count(3)) { cout << "Found" << endl; } else { cout << "Not found" << endl; } }
その他
- bool empty():setの要素が空かを判定
- size=t size():setのユニークな要素の数を返す
- void clear():setの全要素を削除する
- イテレータを使ってvectorをsetに変換することができる
size_t size = s.size(); cout << "size: " << size << endl; // size: 3 s.clear(); bool isEmpty = s.empty(); // true vector<int> v{1, 2, 3, 4, 5, 3}; set<int> converted_s(v.begin(), v.end());
【C++】std::pair, tupleの基本的な使い方
2つの異なる型の値を「組」として保持するpairクラスについて使い方をまとめます. 類似のもので,より一般にN個の異なる型の値を扱うtupleクラスがあるのでこちらについても簡単に紹介します.
pairの使い方
初期化と要素へのアクセス
- make_pair()というヘルパー関数を用いて初期化
2つの値の組を設定する. - object.first, object.secondで要素へアクセス
#include <iostream> #include <string> #include <utility> using namespace std; int main() { std::pair<int, string> p = std::make_pair(1, "first"); // cout << p.first << endl; // 1 cout << p.second << endl; // "first" return 0; }
vectorと合わせた利用法
例として,名前と年齢の組を複数持つ名簿のようなものを作るケースを考えます. ここではこの名簿をvectorとpairを組み合わせることで実現します(重複がないのであれば,vectorよりもsetを使う方が適切かもしれません). 下記の例では途中でソートする処理を入れています.この場合,ソートはpairの1つ目,2つ目の要素に対して順に作用します.
#include <iostream> #include <string> #include <utility> #include <vector> using namespace std; int main() { vector<pair<string, int>> v; v.push_back(make_pair("Tom", 15)); v.push_back(make_pair("Ken", 13)); v.push_back(make_pair("Alice", 14)); v.push_back(make_pair("Alice", 16)); sort(v.begin(), v.end()); for (auto iter = v.begin(), iter != v.end(); ++iter) { cout << "Name: " << *iter.first << " Age: " << *iter.second << endl; } /* Name: Alice Age: 14 Name: Alice Age: 16 Name: Ken Age: 13 Name: Tom Age: 15 */ return 0; }
tupleの使い方
初期化と要素へのアクセス
make_tuple()というヘルパー関数を用いて初期化
pairに似ているが,pairは2つの値の組であったのに対しtupleは任意のN個の値の組を扱うことができる.std::get<i>(object)でi番目の要素へアクセス
以下の例ではtupleにx, y, z座標を格納し,それぞれの座標を表示させる例である.
#include <iostream> #include <string> #include <tuple> using namespace std; int main() { // (x, y, z)座標をtupleで定義 std::tuple<float, float, float> t = std::make_tuple(1.0, 0.0, -2.0); cout << "x: " << get<0>(p) << endl; // x: 1.0 cout << "y: " << get<1>(p) << endl; // y: 0.0 cout << "z: " << get<2>(p) << endl; // z: -2.0 return 0; }
【C++】std::vectorの基本的な使い方
動的配列vectorについて使い方のメモ. 適宜追記していく.
初期化
1次元
#include <vector> using namespace std; void initialize() { // 空のvectorとして初期化 vector<int> vec1; // 要素数(10)を指定して初期化 vector<int> vec2(10); // 要素数(10)と初期値(0)を指定して初期化 vector<int> vec3(10, 0); // データ列を指定して初期化 vector<int> vec4{1, 2, 3, 4}; }
多次元
#include <vector> using namespace std; void initialize() { // vector<vector<int>> m_vec1(10, vector<int>(5, 0)); // vector<vector<int>> m_vec2 = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, }; }
要素の参照
#include <vector> using namespace std; void ref() { vector<int> vec(10); for (int i = 0; i < 10; i++) { vec[i] = 1; // vec.at(i)でもOK } vector<vector<int>> m_vec(10, vector<int>(5, 0)); for (int i = 0; i < 10; i++) { for (int j =0; j < 5; j++) { m_vec.at(i).at(j) = i * j; // 多次元ベクトルへのアクセスはat(index)を複数回使う } } }
イテレータ
vector<int> v{1, 2, 3, 4}; auto iter = v.begin(); // vector<int>::iterator iter = v.begin(); でもOKだが,記述が面倒なので型推論のautoを通常使う cout << *iter << endl; // 1と表示 iter++; cout << *iter << endl; // 2と表示 *iter = 9; // 2番目の要素を9に変更 cout << *iter << endl; // 9と表示
イテレータを使ったLoop
vector<int> v{1, 2, 3, 4}; for (auto iter = v.begin(); iter != v.end(); ++iter) { cout << *iter << endl; }
アルゴリズム
count:値が一致する要素のカウント
vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; int n = count(v.begin(), v.end(), 5); // 5に一致する要素数を返す int i = 2, j = 7; int n_ranged = count(v.begin() + i, v.begin() + j, 5); // 3(= 2+1) ~ 8(= 7+1)の範囲で5に一致する要素数を返す
sort:要素のソート
vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; sort(v.begin(), v.end()); // {1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9}のように昇順にソートされる
reverse:順序の反転
vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; reverse(v.begin(), v.end()); // {5, 3, 5, 6, 2, 9, 5, 1, 4, 1, 3}のように逆順にソートされる // 降順にソート = 昇順ソート + 反転 vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; sort(v.begin(), v.end()); reverse(v.begin(), v.end());
find:値が動的配列に含まれるかのチェック
vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; auto iter = find(v.begin(), v.end(), 5); if (iter != v.end()) { // 見つかった場合の処理 }
要素数が多い場合
- 要素が変わらず,かつ要素が含まれるかの探索を何度も行う場合は2分探索の方が効率が良い
- sortはO(N*logN)なので毎回sortが必要になるとかえって遅くなる
- sortが1度で済む(=要素が不変な場合)は効率が良い
- findはO(N),2分探索はO(logN)
max(min)_element:最大値・最小値とその要素を見つける
#include <vector> #include <numeric> int main() { vector<int> v{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}; // *_element は,イテレーターを返すので '*' で値を取得する vector<int>::iterator min_iter = min_element(v.begin(), v.end()); vector<int>::iterator max_iter = max_element(v.begin(), v.end()); cout << "min: " << *min << ", " << "max: " << *max << endl; // distance で vec の先頭イテレーターと minIt, maxIt との距離を取得する. // インデックスを取得したいときは,vec の先頭イテレーターを指定する必要がある. // 例えば,vec.begin() + 1 とか指定すると答えは変わる. size_t minIndex = std::distance(vec.begin(), min_iter); size_t maxIndex = std::distance(vec.begin(), max_iter); return 0; } ### accumulate:要素の積算
include
include
int accumulate() {
vector
## 参考 - [http://vivi.dyndns.org/tech/cpp/vector.html:title] - [https://cpprefjp.github.io/reference/vector/vector.html:title] - [https://atcoder.jp/contests/APG4b/tasks/APG4b_t?lang=ja:title]
AWSのEC2インスタンスにRemote Desktopでつなぐ
AWSのEC2インスタンスにRemote Desktopでつなぐ
個人メモです. DockerでROSを起動するのは困難であったため,AWSでROS環境を構築する方針に切り替えます.
以下の記事を参考にすることでAWSのEC2 Ubuntu18.04インスタンスへリモートデスクトップを介してつなぐことができました.
AWS EC2でデスクトップ環境をつくる ~ Ubuntu Server 18.04 LTS GNOME編~
GUI上でのkeyboard設定も行ったのですが何故か反映されず.
ここはCloud9を使えばコーディングについては問題なくできるかな?
今度はAWSが提供するロボット開発環境であるRoboMakerで環境作成を行ってみます.
macOSにDockerをインストールし,ubuntuでROSを動かす
macOSにDockerをインストールし,ubuntuでROSを動かす
タイトルの通りです.手順をメモします.
Dockerのインストール
- Docker Desktop for Macをダウンロード.
- インストーラーを走らせる.
- Dockerのアカウントを作成する.
- LaunchpadからDockerをクリックし,Docker Desktopを起動する.
正常にインストール,起動していることをターミナルで確認.
$ docker info
ROSイメージを起動
イメージをpullする.
perceptionに関するタスクを扱いたいので,下記のtagのものを選択.$ docker pull ros:melodic-perception-bionic
コンテナを起動する. ホストと共有のディレクトリを作っておくと作業が楽になります.
$ docker run -it --name docker_ros --net='host' -v ~/Desktop/sandbox/:/sandbox/ ros:melodic-perception-bionic /bin/bash
中身を見てみると,opencv,pclなどPerceptionに必要な基本ライブラリがすでにインストールされいました.
GUIが開かない件を解決する
rvizを起動しようとしたところ,Could not connect to any X display.と怒られます.
どうやらx serverの設定がうまく出来ていないようです.
こちらのLinkに従って対応します.
- XQuartzをインストール
- XQuartzを起動し,環境設定 --> セキュリティタブの"ネットワーク・クライアントからの接続を許可"にチェックを入れる.
Indirect GLXを有効にする.
$ defaults write org.macosforge.xquartz.X11 enable_iglx -bool true
XQuartzを再起動
x serverにlocalhostを登録し,DISPLAY環境変数を指定してコンテナを起動.
$ xhost + 127.0.0.1 $ docker run -it --name docker_ros --net='host' -v ~/Desktop/sandbox/:/sandbox/ -e DISPLAY=docker.for.mac.localhost:0 -v="/tmp/.X11-unix:/tmp/.X11-unix:rw" --privileged ros:melodic-perception-bionic /bin/bash
rvizを起動するもsegmentation faultで落ちる.ムムム…
結局この問題を解決できずにmacでROSをイジるのは諦めた.
そこそこのスペックでいいからubuntuマシンを自宅に欲しいところ.
特にリモートワークが当たり前になるとねぇ.
Semantic SegmentationのためのActive Learning
Semantic SegmentationのためのActive Learning
最近興味を持っているテーマです. Googlingして目について論文をメモします.完全に個人用です.
Active Learning for Semantic Segmentation
- Cost-Effective REgion-based Active Learning for Semantic Segmentation
- unlabeled dataに対する推論結果からCost Modelを経由しAnnotationすべき領域を提案する,という流れ.
- BMVC2018.
- Suggestive Annotation: A Deep Active Learning Framework for Biomedical Image Segmentation
- Bootstrappingを用いて複数のモデルを学習し,モデル間での推論結果を比較して,Pixel-levelのUncertainty & Image-levelのSimilarityを計算.
- Uncertaintyが高い,かつRepresentativeなImageを追加アノテーションする.
- MICCAI2017
- Active Learning for Road Segmentation using Convolutional Neural Networks
- Master Thesisなので品質は?だが,背景含めて丁寧に書かれているのでありがたい.
- Bayesian SegNetを用いたUncertaintyの予測を元にAL.
- Cost-Effective ALとDeep Bayesian ALという流派がある(らしい).
- REINFORCED ACTIVE LEARNING FOR IMAGE SEGMENTATION
他にも論文はちょこちょこあるのだけれども,Deep Learningがメジャーになる前のものが多い印象.
全体的にはBlue Oceanかも?
VSCodeを使ったC++の環境構築【macOS】
VSCodeを使ったC++の環境構築【macOS】
更新日:2022/12/21 M1 Macの場合は下記を参照
【競プロ】AtCoderを始めるためのC++の基本 | そまちょブログ
Visual studio codeで競プロ環境構築[mac OS] - Qiita
更新日:2020/03/13 VSCodeの更新が盛んなので,時間がたつと記事がアテにならなくなるとのこと.
1. 下準備
-
$ brew install gcc $ which g++ >> /usr/bin/g++
VSCodeをインストールする
Download Visual Studio Code - Mac, Linux, Windows- Extensionをインストールする
- C/C++ for Visual Studio Code
兎にも角にこれ - Visual Studio Intelligence
コード補完 - Code Runner
VSCode上でのショートカット操作で外部のShell scriptを実行できる - CodeLLDB
Debugのために必要
- C/C++ for Visual Studio Code
2. コンパイルから実行まで
2.1. サンプルコードの作成
$ mkdir sample && cd sample
$ touch main.cpp
#include <iostream> using namespace std; int main(){ int year = 1986, month = 5, date = 5; cout << "hello world: " << endl << "birthday is " << year << month << date << endl; return 0; }
2.2. コンパイラPathの設定
gccをinstallすると,Mac上に2つのコンパイラ(clang, gcc)が同居する状態になる.それぞれのPathは,
- (clang) /usr/bin/g++
- (gcc) /usr/local/bin/g++-9
競技プラグラミングでは<stdc++.h>というライブラリを使うのが便利で,それはgccにのみ入っているということ. そこで,ここではgccコンパイラを使うように設定を行っていきます.
まずはg++コマンドで/usr/local/bin/g++-9が呼ばれるようにシンボリックリンクを貼ります.
$ ln -s /usr/local/bin/g++-9 /usr/local/bin/g++
$ which g++ >> /usr/local/bin/g++(/usr/bin/g++から変わりました)
ちなみに優先順位が,/usr/local/bin/g++ > /usr/bin/g++となるのは環境変数$PATHの設定によるものです.
$ echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin
2.3. Code Runnerの設定
VSCode上からC++のコンパイルを行うためにCode Runnerの設定を行います.
Extension --> Code Runner --> 設定(歯車マーク) --> Extension Setting --> Code-runner:Executor Map --> Edit in settings.json
でsettings.jsonを開きます.
{
"code-runner.runInTerminal": true,
"workbench.sideBar.location": "left",
"editor.suggestSelection": "first",
"vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
"runner.languageMap": {
"cpp": "/Users/ユーザー名/vsc_run/cpp.sh"
}
}
重要なのは"runner.languageMap"の部分で,使用言語毎に走らせるshell scriptのPathを設定します.
vsc_run/cpp.shはまだ存在しないので,これから作成します.
2.3. Shell scriptの作成
cpp.shを作ります.
$ mkdir ~/vsc_run
$ emacs cpp.sh
cpp.shの一例
#!/bin/sh file = $1 objfile = `echo $f | sed 's/\.[^\.]*$//'` g++ -g -o $objfile $file ./$objfile
main.cppをコンパイルしてmainという実行ファイルを作成する,という内容です.
VSCodeのCode Runnerによってこのshell scriptが呼ばれ,コンパイルおよび実行がされます.
2.4. 動作確認
それではVSCodeから実行します.デフォルトではcontrol + option + nで実行されます.(押しにくい) VSCode画面下部のターミナルに,
hello world:
birthday is 198655
と表示されれば成功です.歳がバレますね.
2.5. stdc++.hを使えるようにする
競プロで便利だと言われるstdc++.hをincludeできるように設定していきます.
先ほどのサンプルでincludeした
まず,stdc++.hの在処を見つけましょう.
$ cd /usr/local/
$ find . -name "stdc++.h"
./Cellar/gcc/9.2.0_1/include/c++/9.2.0/x86_64-apple-darwin18/bits/stdc++.h
このファイルをコンパイラが認識できる/usr/local/下に配置します.
$ mkdir /usr/local/include/bits
$ cp ./Cellar/gcc/9.2.0/include/c++/9.2.0/x86_64-apple-darwin18/bits/stdc++.h /usr/local/include/bits/
ここまで作業すれば,#include <bits/stdc++.h>でコンパイルが通るようになります.
2.6. C/C++ Intellisenseの設定
コンパイルは通るものの,未だ#include <bits/stdc++.h>に赤破線が出たり,コードの補完が効かない状態にあるそうです.
これを正常に動作させるために,Intellisense機能に/usr/local/include/をpathとして登録し,stdc++.hが認識できるようにします.
Command+Shift+Pでコマンドパレットを開き,"C/Cpp: Edit configurations"を選択する.
jsonファイルのなかの"includePath"の部分に,/usr/local/include/**を追加してpathを登録します.
"compilerPath"も2.2.で設定した/usr/local/bin/g++になっているか確認しましょう.
"configurations": [
{
"name": "Mac",
"includePath": [
"${workspaceFolder}/**",
"/usr/local/include/**"
],
"defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/local/bin/g++",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "gcc-x64"
}
],
"version": 4
}
3. デバッグ
デバッグできる環境作成のためにtasks.json,およびlaunch.jsonの設定を行います.
3.1. tasks.jsonの設定
Command+Shift+Pでコマンドパレットを開き,taskと入力し,選択肢から"Tasks: Configure Default Build Task"を選択します.
いくつか選択肢が出てくるので,今回使用するコンパイラに合わせて"C/Cpp: g++ build active file"を選択します.(少々うろ覚え)
以下にtasks.jsonの例を示します.環境変数fileDirname, fileBasenameNoExtensionを使ってあげると,いちいちファイル毎に引数を設定する必要がなくなり楽です.
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "g++ build active file",
"command": "/usr/local/bin/g++",
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "/usr/local/bin"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
3.2. launch.jsonの設定
次にデバッグ設定のlaunch.jsonを作成します.
Command+Shift+Pでコマンドパレットを開き,debugと入力し,選択肢から"Debug: Open launch.json"を選択します.
環境の選択は"C++(GDB/LLDB)"を選択.(うろ覚え)
LLDBをデバッガとして使うため,"type"を"lldb"に設定します.
"externalConsole"をtrueに設定することで,競技プログラミングで出てくるような外部入力用コンソールが立ち上がるようになります.
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "lldb", // cppdbgから変更
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "lldb"
}
]
}
3.3. デバッグしてみる
確認したい箇所にブレークポイントを貼り,画面左の方にある虫さんマークを選択します.
debugの情報表示画面が出てきたら,F5でdebugを開始しましょう.
しかしここでハマりました.
冒頭で書いたCtrl+option+nでbuildすると何か違うモードに入ってしまうようで,ブレークポイントを設定しても止まってくれませんでした.
Shift+command+bで再buildしてあげると正常にdebugを行う事ができました.
そう考えると今回の件ではCodeRunnerを使うメリットはあまりなかったということになりますね.
まとめ
めでたくbuild & debug環境をmacのVSCode上で構築する事が出来ました.
これで競技プログラミング含め,Cppの勉強が捗ると思います.