Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
STLの型の使い分け(ダイジェスト版) @ Sapporo.cpp 第7回勉強会 (2014.10.18)
Next
Download to read offline and view in fullscreen.

5

Share

Download to read offline

C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)

Download to read offline

Ohotech 特盛 #10(2014.8.30)にて
http://ohotech.connpass.com/event/7517/

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

C++のSTLのコンテナ型を概観する @ Ohotech 特盛 #10(2014.8.30)

  1. 1. Ohotech 特盛 #10(2014.8.30) C++のSTLの コンテナ型を概観する H.Hiro @ Sapporo.cpp Twitter: @h_hiro_ http://hhiro.net/about/
  2. 2. 自己紹介
  3. 3. H.Hiro ●情報系の研究員 やってます (2014年3月まで大学院生でした) ●趣味でもプログラム書いてます ●C++とかRubyとか他にも何でも
  4. 4. IT系勉強会で北見に来るのは 2年ぶりです
  5. 5. 最近の勉強会発表 "コンピュータに「最長しりとり」「最短距離でのJR線全線乗り尽くし」を 解いてもらった方法" @ FuraIT #3 (2014.8.23) http://www.slideshare.net/maraigue/graph-andlgpk
  6. 6. よろしく お願いします
  7. 7. はじめに
  8. 8. 今回知って もらえればと 思っていること
  9. 9. 1. 汎用的なデータ構造は C++だと"STL"として 提供されるということ
  10. 10. 2. どんなデータ構造を どんな場合に使えば よいかの感覚
  11. 11. 3. "STL怖い"なんて 言わなくてよいように なること
  12. 12. では始めます
  13. 13. おしながき
  14. 14. 1)STLとは 2)「データ構造」を考える理由 3)STLのコンテナ型と それぞれの特徴 4)STLを使うと便利なこと
  15. 15. STLとは
  16. 16. STLとは ●Standard Template Libraryの略 ●汎用的、かつ型に依存しない データ構造や処理(アルゴリズム) を提供する
  17. 17. STLとは ●Standard Template Libraryの略 ●汎用的、かつ型に依存しない データ構造や処理(アルゴリズム) を提供する
  18. 18. Template(テンプレート)とは ●コンパイル時に有効になる クラスや関数に対するパラメータ ●型によらない機能を提供するのが 代表的な用法 template <class TYPE> TYPE max(const TYPE & v1, const TYPE & v2){ return(v1 > v2 ? v1 : v2); } max(1.0, 3.0); // TYPEはfloatとみなされる max(1, 5); // TYPEはintとみなされる max<int>(1, 5); // 型を明示してもよい
  19. 19. STLの例 #include <iostream> #include <vector> #include <algorithm> int main(void){ // 「intのvector」「doubleのvector」を作る // (あとで説明しますが、可変長配列です) std::vector<int> hoge = {3, 1, 4}; std::vector<double> piyo = {5.6, 1.2, 3.4}; // int/doubleの型によらず、同じ記法でソート(並べ替え)できる std::sort(hoge.begin(), hoge.end()); std::sort(piyo.begin(), piyo.end()); }
  20. 20. ●汎用的に利用されるデータ構造や アルゴリズムを自前で作るのは ミス・バグの原因にもなる ●STLが提供する機能の特性を 理解したうえで、先人の力を借りよう ●複数人で開発するときとかは特に。 (標準ライブラリなので何かと便利!)
  21. 21. 「データ構造」を 考える理由
  22. 22. そもそも データ構造って 何なのか
  23. 23. たとえば
  24. 24. RPGを例に考えてみると ●パーティーの編成 (例えば「4人まで」とする) ●現在プレイヤーが持っている アイテムの一覧 ●マップ上の地形
  25. 25. パーティーの編成 (例えば「4人まで」とする) →配列があればよい  サイズも固定でよい 職業:勇者、HP:120、… 職業:魔法使い、HP:95、… 職業:格闘家、HP:135、… 職業:僧侶、HP:110、…
  26. 26. 現在プレイヤーが持っている アイテムの一覧 →「どのアイテムを何個持って いるか」という表 では表をどう作る? 構造体の配列にする ほかの方法もある アイテム名個数 薬草10 魔法石2 お守り3 : :
  27. 27. マップ上の地形 →表があればよい (マス目状の配置であれば) →線の一覧を格納する (マップが自由に描ける場合) 3Dだともっと面倒
  28. 28. いろんな データ構造を 考えないと ならない
  29. 29. しかも 面倒なことに
  30. 30. 適切なデータ構造を 選ばないと 処理が遅くなったり メモリを過剰に 消費したりする
  31. 31. データ構造 自体はSTLが 面倒見て くれるけど
  32. 32. どのデータ構造 で作るかは プログラマーが 判断する
  33. 33. この先では STLの型について そういった話を していきます
  34. 34. STLの コンテナ型一覧 (Part 1)
  35. 35. コンテナ型 =(複数の)要素を 保持する型
  36. 36. コンテナ型(1): vector 可変長配列 (あとで要素数を変えられる) vector<int> hoge = {3, 1, 4}; hoge.push_back(7); hoge.pop_front(); 3 1 4 3 1 4 7 1 4 7
  37. 37. std::vector<int> hoge; // ↑int型の要素を // 格納するvector std::vector<std::string> piyo; // ↑string型(文字列型)の要素を // 格納するvector
  38. 38. 補足 vector<int> hoge = {3, 1, 4}; ↑こういう書き方は、  配列ではもともとできましたが、  vector(やその他のクラス)で使うには  比較的新しいコンパイラが必要です。 (現時点での最新のC++規格  「C++11」で新規に規格化)
  39. 39. コードはこんな感じ #include <iostream> #include <vector> // vectorを使うために int main(void){ std::vector<int> hoge(3); // 要素数3のvector // ここでは数値を使ってループしている // 「イテレータ」を使う方法もある(あとで説明します) for(size_t i = 0; i < hoge.size(); ++i){ hoge[i] = i * i; } // (以下略) }
  40. 40. vectorの特性(1) ●k番目の要素を取得(ランダムアクセス) →即座に完了。  vectorはメモリ上に等間隔で要素を  並べて保持しているので(配列と同じ)  メモリ上のその場所にアクセスするだけ。 3 1 4 7
  41. 41. vectorの特性(2) ●要素を1つ挿入する →大きく時間がかかる場合がある。 →もともと配列にあった要素をずらさないと  ならない。 3 1 4 2番目に「5」を追加 3 5 1 4
  42. 42. vectorの特性(2) ●要素を1つ挿入する →大きく時間がかかる場合がある。 →もともと配列にあった要素をずらさないと  ならない。 →場合によっては、要素のメモリ上の  置き場所をまるごとずらす必要がある。 3 1 4 1 5 9 2 ↑二つのvectorが隣接したメモリ領域に格納されている。 ここで、「3 1 4」のほうを長くしようとすると?
  43. 43. vectorの特性(3) ●要素を1つ削除する →挿入と同じ理屈で、  大きく時間がかかる場合がある。 3 5 1 4 「5」を削除→「1」「4」はずらす 3 1 4
  44. 44. vectorの特性(4) ●メモリの消費量 →少ない。  変数を格納する領域+ポインタ変数2つ  (領域の起点&領域のサイズ) 3 1 4 7
  45. 45. ここまでのまとめ: vectorの利点 ●ランダムアクセスは速い ●メモリもそこまで食わない vectorの欠点 ●挿入・削除は遅い (最悪でvectorのサイズに比例)
  46. 46. vectorの欠点 ●挿入・削除は遅い (最悪でvectorのサイズに比例) ↑これに対処してみる。
  47. 47. コンテナ型(2): list 双方向連結リスト 要素の値 3 次の要素 前の要素 要素の値 1 次の要素 前の要素 要素の値 4 次の要素 前の要素 C++11ではforward_list (一方向連結リスト)もある
  48. 48. listの特性(1) ●要素を1つ挿入する・削除する →ポインタを付け替えるだけでよいので  高速(ただし、挿入/削除する要素の  ありかが事前にわかっている場合) 3 1 4 5
  49. 49. listの特性(1) ●要素を1つ挿入する・削除する →ポインタを付け替えるだけでよいので  高速(ただし、挿入/削除する要素の  ありかが事前にわかっている場合) 3 1 4 5
  50. 50. listの特性(2) ●k番目の要素を取得(ランダムアクセス) →k回ポインタを辿る必要がある。  vectorに比べると非常に遅い 要素の値 3 次の要素 前の要素 要素の値 1 次の要素 前の要素 要素の値 4 次の要素 前の要素
  51. 51. listの特性(3) ●メモリの消費量 →vectorに比べると多い。  格納する1要素につき、ポインタ変数  2つぶんの領域が追加で必要になる。  (forward_listの場合は1つ) 要素の値 3 次の要素 前の要素 要素の値 1 次の要素 前の要素 要素の値 4 次の要素 前の要素
  52. 52. ここまでをまとめると ●vector:「k番目の要素を取得」という操作 (ランダムアクセス)が多いときに有利 ●list:要素の挿入・削除が多いときに有利
  53. 53. さて
  54. 54. もう一つ 別の需要を 考えてみます
  55. 55. 検索
  56. 56. 検索問題 std::vector<int> hoge = {3, 1, 4}; hogeの中に「2」があるか調べるには?
  57. 57. 検索問題 std::vector<int> hoge = {3, 1, 4}; hogeの中に「2」があるか調べるには? →先頭から順に見る。  hogeの要素数が増えると当然遅くなる。 →std::list<int>だったとしても同じ。
  58. 58. vectorだろうが listだろうが 検索は 時間がかかる
  59. 59. でも 安心してください
  60. 60. 検索時間の削減を 優先した コンテナ型もある
  61. 61. コンテナ型(3): set ●集合(要素を重複なく格納) ●「ある要素が存在するか否か」を 比較的高速に判定可能 std::set<int> hoge = {3, 1, 4}; std::set<int>::iterator it = hoge.find(6);
  62. 62. コンテナ型(3): set ●multiset(要素を重複ありで格納) もある ●C++11では、unordered_set・ unordered_multiset (内部実装が異なる)もある set:二分木 unordered_set:ハッシュテーブル
  63. 63. setの特性(1) ●ある要素が存在するか調べる →setなら logn に比例する程度の時間。  (n: すでに入っている要素数) →unordered_setなら、nにほぼ依存しない  時間で済む上、setよりも省メモリ。  ただしC++11対応環境が必要。
  64. 64. setの特性(2) ●検索が高速になるように、 要素は内部で勝手に並び替えられている。 ●なので、順番を維持したいときは 別途対策を考える必要がある。 ●setは要素の大小順、unordered_setは ハッシュ関数(詳細略)の値の順で並ぶ
  65. 65. ここまでをまとめると 型 計算時間 (n:格納された要素数) 任意の 順序での 要素格納 ランダム アクセス 要素の 挿入・削除 要素の検索 vector 速い O(1)時間 遅い O(n)時間 遅い O(n)時間 可能 list forward_list 遅い O(n)時間 速い O(1)時間 遅い O(n)時間 可能 set unordered_set など できない (そもそも、 自由に並べ られない) 速い O(1)~O(logn) 時間 速い O(1)~O(logn) 時間 不能
  66. 66. ここまで説明したもの vector, list, forward_list#, set, multiset, unordered_set#, unordered_multiset# #:C++11で新規導入
  67. 67. まだいろいろ あるので 手短に説明します
  68. 68. コンテナ型(4): deque ●固定サイズの配列を可変個繋いでいる ●先頭か末尾であれば挿入・削除が高速 (それ以外はvectorと同じで低速) ●listよりメモリを使わないので、挿入・削除が 先頭か末尾中心であるときに有効 ●ランダムアクセスも可能 3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4 6 2 6 4 3 3 8
  69. 69. コンテナ型(5): priority_queue ●入れた要素を大きさの順にしか取り出せない ●その代わり、取り出しは高速で 要素の挿入も比較的高速
  70. 70. コンテナ型(6): array 普通の固定長配列(a[10]など)に便利な 機能を追加したもの。C++11で新規導入 コンテナ型(7): bitset 固定長のビット列。いわゆる「フラグ」 可変長の場合はvector<bool>を使うなどの 対応が必要
  71. 71. コンテナ型(8): stack 「スタック」。割愛します コンテナ型(9): queue 「キュー」。割愛します
  72. 72. ここまで説明したもの vector, list, forward_list#, set, multiset, unordered_set#, unordered_multiset#, deque, priority_queue, array#, bitset, stack, queue #:C++11で新規導入
  73. 73. 現時点での まとめ
  74. 74. ここまで出てきた コンテナ型の 使い分け
  75. 75. 状況おすすめ 要素数が少ない vector ランダムアクセスする機会が多い 計算時間よりもメモリ消費を抑えたいvector/deque 要素の挿入・削除を する機会が多い 先頭・末尾が中心deque 途中にもlist/forward_list 要素の検索をする 機会が多い 重複した要素の 格納は不要 set/unordered_set 重複した要素の 格納も必要 multiset/ unordered_multiset ※priority_queue, array, bitset, stack, queueは割愛
  76. 76. ここで 一旦休憩 質問ありましたらどうぞ
  77. 77. STLの コンテナ型一覧 (Part 2)
  78. 78. Part 2は そんなに長く ないです
  79. 79. Part 2で やること
  80. 80. 連想配列
  81. 81. 連想配列 ふつうの配列と違って 好きな型の値で要素を参照できる Rubyだと「ハッシュ」とか、Pythonだと「辞書」とか呼ばれる std::map<std::string, int> attendee = {{"Kitami", 8}, {"Sapporo", 5}}; std::cout << attendee["Sapporo"] << std::endl; std::cout << attendee["Kitami"] << std::endl; ++attendee["Kitami"]; std::cout << attendee["Sapporo"] << std::endl; std::cout << attendee["Kitami"] << std::endl;
  82. 82. std::map<int, double> hoge; // ↑int型の値を指定して // double型の値を設定/取得する std::map<std::string, int> piyo; // ↑string型(文字列型)の値を // 指定して // int型の値を設定/取得する
  83. 83. さっきまでとの違い 当然だが、型を2つ指定する必要 std::vector<int> hoge; // ↑指定する型はintだけ std::map<std::string, int> piyo; // ↑指定する型はstringとint
  84. 84. STLの連想配列型 ●map ●unordered_map ●multimap ●unordered_multimap
  85. 85. 使い分け ●"unordered"の有無 →実装の違い(setと同様) C++11前提でよいならunordered優先で ●"multi"の有無 →重複を許すか否か(setと同様)
  86. 86. ここまで説明したもの vector, list, forward_list#, set, multiset, unordered_set#, unordered_multiset#, deque, priority_queue, array#, bitset, stack, queue, map, multimap, unordered_map#, unordered_multimap# #:C++11で新規導入
  87. 87. STLの コンテナ型は これで全部 (おそらく)
  88. 88. では、もっと 活用してみよう
  89. 89. STLを使うと 便利なこと
  90. 90. 再掲 // 「intのvector」「doubleのvector」を作る std::vector<int> hoge = {3, 1, 4}; std::vector<double> piyo = {5.6, 1.2, 3.4}; // intでもdoubleでも同じ記法でソート(並べ替え)できる std::sort(hoge.begin(), hoge.end()); std::sort(piyo.begin(), piyo.end()); 型が違っても同じコードが使える
  91. 91. それだけじゃない // 「intのvector」「intのdeque」を作る std::vector<int> hoge = {3, 1, 4}; std::deque<int> piyo = {3, 1, 4}; // vectorでもlistでも同じ記法でソート(並べ替え)できる std::sort(hoge.begin(), hoge.end()); std::sort(piyo.begin(), piyo.end()); コンテナ型の方が違っていてもよい!
  92. 92. STLには、このような コンテナ型を問わない APIが大量に用意されている ↓ コードの使い回しが容易 型の切り替えが容易
  93. 93. イテレータ ●「要素の列挙」を抽象化したもの ●例えば「次の要素を得る」ことは vectorなら「ポインタをインクリメント」 listなら「別途格納された次のポインタへ」 ●このおかげで様々な汎用性が得られている 3 1 4 7
  94. 94. イテレータ ●「要素の列挙」を抽象化したもの ●例えば「次の要素を得る」ことは vectorなら「ポインタをインクリメント」 listなら「別途格納された次のポインタへ」 ●このおかげで様々な汎用性が得られている 要素の値 3 次の要素 前の要素 要素の値 1 次の要素 前の要素 要素の値 4 次の要素 前の要素
  95. 95. イテレータ 要素を単純に列挙するコード std::vector<int> hoge = {3, 1, 4}; for(std::vector<int>::iterator it = hoge.begin(); it != hoge.end(); ++it){ // イテレータはポインタ同様、*で値に変換できる std::cout << *it << std::endl; } ※補足:hoge.end()は「最終要素の次」、  すなわち「ダミーの無効な要素」を表す
  96. 96. イテレータ 要素を単純に列挙するコード std::list<int> hoge = {3, 1, 4}; for(std::list<int>::iterator it = hoge.begin(); it != hoge.end(); ++it){ // イテレータはポインタ同様、*で値に変換できる std::cout << *it << std::endl; } vectorでもlistでもコードはほぼ同じ!
  97. 97. アルゴリズム ●#include <algorithm>すると いろんなアルゴリズムが利用可能に ●検索、並び替え、コピーなど ●パラメータとしてイテレータを渡すことが多い std::vector<int> hoge = {3, 1, 4}; // 偶数である最初の要素を返す std::vector<int>::iterator search_result = std::find_if(hoge.begin(), hoge.end(), [](int x){ return x % 2 == 0; });
  98. 98. おわりに
  99. 99. STLの便利なところ ●基本的なデータ構造なら 自分でわざわざ作らなくてよい ●アルゴリズムも然り ●標準ライブラリなので環境依存も小さい ●新しめのコンパイラ(C++11対応)を 使うとさらに便利に
  100. 100. STLの注意点 ●データ構造の選択はプログラマーの判断 ●今回割愛した話 ●イテレータを1つ進めるのが速い型、遅い型 (※unorderedでないset、mapは遅い) ●イテレータを外部に保存してよい型、 保存に注意を要する型 (※注意を要する型 =vector、deque、unordered_*)
  101. 101. Ohotech 特盛 #10(2014.8.30) C++のSTLの コンテナ型を概観する 終わり
  • npc001

    Aug. 14, 2020
  • DaikiShintani

    Mar. 10, 2019
  • ssuser97a00f

    May. 7, 2015
  • matsud224

    May. 3, 2015
  • keisukegoto92

    Oct. 14, 2014

Ohotech 特盛 #10(2014.8.30)にて http://ohotech.connpass.com/event/7517/

Views

Total views

3,553

On Slideshare

0

From embeds

0

Number of embeds

558

Actions

Downloads

22

Shares

0

Comments

0

Likes

5

×