# 問題解決力を鍛える!アルゴリズムとデータ構造 ## 第8章(8.5~8.7) - 任意参加 - ファシリテーター: chen ### 話す・書く順番決めルーレット in Ruby ```ruby ['hsu', 'chen', 'teruya', 'kanazawa', 'okura', 'tsujita'].shuffle.each { |v| puts ">[name=#{v}]\n\n" } ``` in JavaScript ```javascript const l = ['hsu', 'chen', 'teruya', 'kanazawa', 'okura', 'tsujita'] l[Math.floor(Math.random()*l.length)] ``` ### ファシリテーター決め方 - `%w(hsu chen teruya kanazawa okura kanno)`の順番でやっていく ### 参加者がやること - 事前に決められた章を読む - 学んだことやわからなかったことを書き込む(任意) 当日 - 最初に感想や質問を書く時間を設ける(10分) - 時間枠 60分 - 延長枠 30分 ### 勉強会時にやること 各自学びや気付き、疑問を発表していく ファシリテーターがよしなに議論を進める 終了前に勉強会を振り返る?(KPTなどで)← 60分のときに仮締め ## 各自が書き込む場所 >[name=chen] ### 8.5 配列と連結リストの比較 - 配列:i番目の要素にアクセスする必要がある時使う - 連結リスト:要素を頻繁に挿入・削除する必要がある時使う 用途が違いますよね ### 8.6 ハッシュテーブル - 挿入・削除・検索どれも処理しやすいもの - 要は、key/valueをペアしている関数 Javaでコーディングする時によくハッシュテーブル(HashMap)が使われた記憶がある... ### 8.7 まとめ この表、一目で見ると各データ構造の用途が大体わかる ![](https://i.imgur.com/5UDdBER.png) >[name=tsujita] > 8.5 - 要素xを検索する処理は、配列も連結リストもO(N)の計算量になる > 8.6 - ハッシュテーブルは要素の挿入、削除、検索がO(1)でできる なんとなく配列が便利というイメージがありましたが、ハッシュの優秀さがわかりました >[name=okura] ### 8.5 配列と連結リストの比較 基本的にコレクションの途中にデータを挿入するとき以外は配列が優位になりがちなのかな。 ### 8.6 ハッシュテーブル ここからRubyの"Hash"の名前は来ているんだけど、Matzが(ちょっと)後悔していた。 https://twitter.com/yukihiro_matz/status/1402052061592621059 ### 8.6.4 C++やPythonにおけるハッシュテーブル ここには"set"が出てくるけど、Rubyにも"Set"ライブラリはあって実装はHashを使っている。 https://docs.ruby-lang.org/ja/latest/library/set.html ### 8.6.5 連想配列 Rubyの"Hash"はこっち。 >[name=teruya] > ハッシュの衝突対策 ほぼO(1)(優秀) > 連想配列 連想配列のデータ構造として主にハッシュテーブルが用いられている、という関係性なんですね(違いをよく知らなかった) > 各データ構造の各クエリに対する計算量 やはりハッシュテーブルの優秀さが際立つ、実際はi番目の要素へのアクセスが必要になるケースが多いのだとは思いますが… 二次元配列の代わりにhash1つで賄うみたいなのも可能だったりする。 > 章末問題8.7 hashを使ったO(N)版(3秒程度) ```ruby= N = 10_000_000 K = 1_000_000 nums_array = Array.new(N) { rand(N) } nums_hash = Array.new(N) { rand(N) }.each_with_object({}) { |num, hash| hash[num] = nil } puts "Preparation Done" answer = [] nums_array.each do |num| rest = K - num if nums_hash.key?(rest) answer << [num, rest] end end p answer ``` bsearchを使ったO(NlogN)版(30秒程度) ```ruby= N = 10_000_000 K = 1_000_000 nums_array = Array.new(N) { rand(K) } nums_array2 = Array.new(N) { rand(K) } puts "Preparation Done" #O(NlogN) nums_array2.sort! answer = [] # O(N) # 全体としてO(NlogN) nums_array.each do |num_from_array| # O(logN) num_from_array2 = nums_array2.bsearch { |n| num_from_array + n >= K } next unless num_from_array2 if (num_from_array + num_from_array2) == K answer << [num_from_array, num_from_array2] end end p answer ``` ## 振り返り >[name=chen] 照屋さんのdemo、いつも楽しかったと思います 計算量が体感できて面白いですね。 >[name=tsujita] せっかくの機会なので、と思い最近AtCoderの過去問を解いてみたりしてます >[name=teruya] データ構造は実務にも活かせる知見が多くありそうですね👀 https://qiita.com/drken/items/fd4e5e3630d0f5859067 >[name=okura] 今日の内容にはなかったけど、Rubyの配列は無限に拡張されるので便利。 ## 終了後ファシリテーターがやること - 次回のファシリテーターを決める  - 照屋さん - 読む範囲を決める - 第九章全部