Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlinと探索アルゴリズムでスマートに 木構造データをさばく / Handle Tree Data with Kotlin and BFS

15c2fcbb0358a6c4910fb043e2b1f71e?s=47 YuitoSato
September 22, 2021

Kotlinと探索アルゴリズムでスマートに 木構造データをさばく / Handle Tree Data with Kotlin and BFS

https://server-sider-kotlin.connpass.com/event/224077/

こちらのイベントの資料です。
Kotlinと探索アルゴリズムをつかって木構造のデータをKotlinのコレクションクラスのようにスマートに扱う実装について紹介しています。

15c2fcbb0358a6c4910fb043e2b1f71e?s=128

YuitoSato

September 22, 2021
Tweet

Transcript

  1. @ 2021 Loglass Inc. 1 木構造のデータって意外と多くない? Kotlinと探索アルゴリズムでスマートに 木構造データをさばく 2021/9/22 株式会社ログラス

    佐藤有斗
  2. @ 2021 Loglass Inc. 2 • 佐藤 有斗(ゆいと) • 株式会社ログラス

    • TypeScriptとKotlinとScalaの民 • 好きなゲーム: スマブラ、原神 # 自己紹介
  3. @ 2021 Loglass Inc. 3 # 株式会社ログラスについて • 創業2年目のシードスタートアップ •

    プランニング・クラウド • Kotlin × Spring Boot 次世代型プランニング・クラウド「Loglass」を開発するログラス、 ICCサミット 「カタパルト・グランプリ」で優勝 https://prtimes.jp/main/html/rd/p/000000036.000052025.html
  4. @ 2021 Loglass Inc. 4 木構造のデータってよく使いますか?

  5. @ 2021 Loglass Inc. 5 # 木構造のデータってこんなの(以下ツリーと呼びます) 1 11 13

    12 111 112 1121
  6. @ 2021 Loglass Inc. 6 # 世の中にツリーはとても多い ディレクトリ 部署 家系図

    法人 タスク
  7. @ 2021 Loglass Inc. 7 # Loglassにもたくさん出てくるツリー

  8. @ 2021 Loglass Inc. 8 # よくあるケース: ツリーを他のツリーに変換したい 1 11

    13 12 111 112 1121 10 110 130 120 1110 1120 11210 10倍!
  9. @ 2021 Loglass Inc. 9 再帰関数を書くか、、、

  10. @ 2021 Loglass Inc. 10 再帰関数を書くか、、、

  11. @ 2021 Loglass Inc. 11 再帰関数を書くか、、、

  12. @ 2021 Loglass Inc. 12 読みづらい😇

  13. @ 2021 Loglass Inc. 13 # 普段使いにはつらい再帰関数 • そもそも処理が追いづらい ◦

    土日の趣味プログラミング以外で出会いたくない
  14. @ 2021 Loglass Inc. 14 mapみたいな関数があればな〜〜〜〜〜〜〜

  15. @ 2021 Loglass Inc. 15 例えば: listOf(1,2,3).map { it *

    10 }
  16. @ 2021 Loglass Inc. 16 tree.map { it * 10

    } な感じで書きたいな〜
  17. @ 2021 Loglass Inc. 17 よし、作ろう

  18. @ 2021 Loglass Inc. 18 1. 木構造を抽象化する 2. mapのインターフェースを考える 3.

    mapの実装をする # Tree.mapを作るまでのステップ
  19. @ 2021 Loglass Inc. 19 1. 木構造を抽象化する 2. mapのインターフェースを考える 3.

    mapの実装をする # Tree.mapを作るまでのステップ
  20. @ 2021 Loglass Inc. 20 # 1. 木構造を抽象化する • ジェネリクスを使って木構造の中のデータは何でもとれるようにする

  21. @ 2021 Loglass Inc. 21 # 1. 木構造を抽象化する • これでどんなデータでも木構造にできる!

    あ い え う Tree<String> True False False Tree<Boolean> Hoge1 Hoge2 Hoge3 Tree<Hoge>
  22. @ 2021 Loglass Inc. 22 1. 木構造を抽象化する 2. mapのインターフェースを考える 3.

    mapの実装をする # Tree.mapを作るまでのステップ
  23. @ 2021 Loglass Inc. 23 # 2. mapのインターフェースを考える tree.map {

    it * 10 } な感じで書きたいな〜
  24. @ 2021 Loglass Inc. 24 # 2. mapのインターフェースを考える tree.map {

    data -> data * 10 } ちょっと整形
  25. @ 2021 Loglass Inc. 25 # 2. mapのインターフェースを考える tree.map {

    data -> data * 10 } ここは (Int) -> Int
  26. @ 2021 Loglass Inc. 26 # 2. mapのインターフェースを考える tree.map {

    data -> data * 10 } つまり (Treeの中身) -> 変換したい型の関数
  27. @ 2021 Loglass Inc. 27 # 2. mapのインターフェースを考える tree.map {

    data -> data * 10 } つまり (T) -> S の関数
  28. @ 2021 Loglass Inc. 28 # 2. mapのインターフェースを考える 1 2

    4 3 Tree<T = Int> あ い え う Tree<S = String> f: (T) => S • つまりこう
  29. @ 2021 Loglass Inc. 29 1. 木構造を抽象化する 2. mapのインターフェースを考える 3.

    mapの実装をする # Tree.mapを作るまでのステップ
  30. @ 2021 Loglass Inc. 30 # 3. mapの実装をする

  31. @ 2021 Loglass Inc. 31 # 3. mapの実装をする 自分自身に関数を適用 さっきの

    「1 -> “あ”」の関数
  32. @ 2021 Loglass Inc. 32 # 3. mapの実装をする 子供全員に再帰関数を 適用する

  33. @ 2021 Loglass Inc. 33 できた!

  34. @ 2021 Loglass Inc. 34 全体像

  35. @ 2021 Loglass Inc. 35 FIN

  36. @ 2021 Loglass Inc. 36 ではない

  37. @ 2021 Loglass Inc. 37

  38. @ 2021 Loglass Inc. 38 10000階層のツリー

  39. @ 2021 Loglass Inc. 39

  40. @ 2021 Loglass Inc. 40 スタックオーバーフロー!!!

  41. @ 2021 Loglass Inc. 41 # ⚠ここからは尺の関係上ざっくり説明します • 全てを理解しようとしないでください •

    あ〜こんなやり方あるんだな〜で大丈夫です 👍 • コードはこちらです ◦ https://github.com/YuitoSato/kotlin-sandbox/blob/master/src/main/kotlin/tree/Tre e.kt
  42. @ 2021 Loglass Inc. 42 # 再帰関数におけるスタックオーバーフローとは • 子の計算を全て終えないと親の関数が終わらない ◦

    計算時の関数内ローカル変数をスタックに保持するが、そこがパンクする
  43. @ 2021 Loglass Inc. 43 # では世の中の全ての再帰関数はスタックオーバーフローを起こすの? • 言語によってはNo •

    一部の言語には末尾再帰最適化というものが実装されている
  44. @ 2021 Loglass Inc. 44 # 末尾再帰最適化 (tail call optimization)

    とは~ ざっくり説明 • 一部のプログラムではビルド時に 末尾呼び出しの再帰関数を単なる While文に最適化してい る
  45. @ 2021 Loglass Inc. 45 # これは末尾再帰

  46. @ 2021 Loglass Inc. 46 # これは末尾再帰ではない 最後に評価される関数は Treeのコンストラクタ

  47. @ 2021 Loglass Inc. 47 別のやり方でやろう

  48. @ 2021 Loglass Inc. 48 最適化が使えないので自力Whileをする

  49. @ 2021 Loglass Inc. 49 # map処理のおさらい 1 2 4

    3 5 6
  50. @ 2021 Loglass Inc. 50 # map処理のおさらい あ 2 4

    3 5 6
  51. @ 2021 Loglass Inc. 51 # map処理のおさらい あ い 4

    3 5 6
  52. @ 2021 Loglass Inc. 52 # map処理のおさらい あ い 4

    う 5 6
  53. @ 2021 Loglass Inc. 53 # map処理のおさらい あ い え

    う 5 6
  54. @ 2021 Loglass Inc. 54 # map処理のおさらい あ い え

    う お 6
  55. @ 2021 Loglass Inc. 55 幅優先探索だ!💡

  56. @ 2021 Loglass Inc. 56 # 幅優先探索にはキュー(先に入れたものが先に出る)を使う 1 2 4

    3 5 6 処理待ちノードを入れるキュー 優先処理 1
  57. @ 2021 Loglass Inc. 57 # 幅優先探索にはキュー(先に入れたものが先に出る)を使う あ 2 4

    3 5 6 処理待ちノードを入れるキュー 優先処理 2 3 4 1
  58. @ 2021 Loglass Inc. 58 # 幅優先探索にはキュー(先に入れたものが先に出る)を使う あ い 4

    3 5 6 処理待ちノードを入れるキュー 優先処理 3 4 5 6 2
  59. @ 2021 Loglass Inc. 59 # こう実装してみます

  60. @ 2021 Loglass Inc. 60 # こう実装してみます キューと最終的に返す ツリーの初期化。

  61. @ 2021 Loglass Inc. 61 # こう実装してみます キューから取り出して 関数を適用

  62. @ 2021 Loglass Inc. 62 # こう実装してみます 処理したノードを 最終的なツリーに足す

  63. @ 2021 Loglass Inc. 63 # こう実装してみます 次に処理されるノード(子 供)をキューにいれる

  64. @ 2021 Loglass Inc. 64 # こう実装してみます 最後にリターン

  65. @ 2021 Loglass Inc. 65 # イメージ: ① キューと空のツリーを用意する 1

    2 4 3 5 6
  66. @ 2021 Loglass Inc. 66 # イメージ: ② キューに積む 1

    2 4 3 5 6 1
  67. @ 2021 Loglass Inc. 67 # イメージ: ③ キューの先頭に関数を適用する 1

    2 4 3 5 6 あ
  68. @ 2021 Loglass Inc. 68 # イメージ: ④ キューの先頭を最終的なツリーに追加する 1

    2 4 3 5 6 あ
  69. @ 2021 Loglass Inc. 69 # イメージ: ④ 子供を全てキューに積む 1

    2 4 3 5 6 あ 2 3 4
  70. @ 2021 Loglass Inc. 70 # イメージ: ①~④を繰り返す 1 2

    4 3 5 6 あ い え う お か
  71. @ 2021 Loglass Inc. 71 できた!(強引)

  72. @ 2021 Loglass Inc. 72 今回のコードはこちらに全てあります。 https://github.com/YuitoSato/kotlin-sandbox/blo b/master/src/main/kotlin/tree/Tree.kt

  73. @ 2021 Loglass Inc. 73 # まとめ → 世の中にツリーは多い →

    ツリーのデータ変換は再帰関数が多くてつらい → map関数を作って再帰処理を隠蔽する → と思ったらスタックオーバーフローしてしまった → スタックオーバーフローを回避するために幅優先探索で実装する → ハッピー!
  74. @ 2021 Loglass Inc. 74 ハッピー!(強引)

  75. @ 2021 Loglass Inc. 75 # 余談: Q. スタックオーバーフローってどれくらいで起きるの? 🤔

    A. 手元のマシンで試したら10000階層くらいで発生した(※JVM内で格納しているスタックの量 に寄ります)
  76. @ 2021 Loglass Inc. 76 # 余談: Q. Loglassってそんな階層の深いツリーを扱うの? 🤔

    A. 扱いません
  77. @ 2021 Loglass Inc. 77 # 余談: Q. え、じゃあ幅優先探索の実装とか、必要、、? A.

    要りません
  78. @ 2021 Loglass Inc. 78 結論: ほぼほぼ再帰処理実装でOK(オチです)

  79. @ 2021 Loglass Inc. 79 ありがとうございました! Kotlinで複雑なデータ構造に 立ち向かいたい人Welcomeです!