---
# System prepended metadata

title: 問題解決力を鍛える！アルゴリズムとデータ構造

---

# 問題解決力を鍛える！アルゴリズムとデータ構造 

## 第10.5章~

- 任意参加
- ファシリテーター:  tsujita

### 話す・書く順番決めルーレット

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=tsujita]

- ヒープの部分で高校数学の数列を思い出しました・・・


>[name=teruya] 

https://atcoder.jp/contests/past202004-open/tasks/past202004_f
```ruby=
# 最大が最上位の親になる 優先度付きキュー PQ
# 最小が最上位の親にする時は、コメントアウト箇所を変更
# 更新機能
class PriorityQueue
  attr_accessor :data, :size

  def initialize(array = [])
    @data = []
    array.each { |a| push(a) }
  end

  def push(element)
    current = @data.size
    @data[up_heap(current, element)] = element
  end

  def pop
    ret = @data.first
    x = @data.last
    @data[down_heap(0, x)] = x
    @data.pop
    ret
  end

  def update(current, element)
    index = up_heap(current, element)
    index = down_heap(current, element) if index == current
    @data[index] = element
  end

  def size
    @data.size
  end

  def front
    @data.first
  end

  def empty?
    @data.empty?
  end

  def parent(num)
    (num - 1) / 2
  end

  def left_child_index(num)
    2 * num + 1
  end

  def right_child_index(num)
    2 * num + 2
  end

  def have_parent?(index)
    index > 0
  end

  def have_child?(index)
    left_child_index(index) < @data.size
  end

  private

    def up_heap(current, element)
      while have_parent?(current)
        p_index = parent(current)
        break if @data[p_index] >= element
        # break if @data[p_index] <= element
        @data[current] = @data[p_index]
        current = p_index
      end
      current
    end

    def down_heap(current, element)
      while have_child?(current)
        a_index = left_child_index(current)
        b_index = right_child_index(current)
        a_index = b_index if @data[b_index] && @data[b_index] > @data[a_index]
        break if @data[a_index] <= element
        # a_index = b_index if @data[b_index] && @data[b_index] < @data[a_index]
        # break if @data[a_index] >= element
        @data[current] = @data[a_index]
        current = a_index
      end
      current
    end
end

n = gets.to_i
# 初期値がarrayのhash
tasks = Hash.new { |hash, key| hash[key] = [] }
n.times do
  day, point = gets.split.map(&:to_i)
  tasks[day] << point
end
# pp tasks
# {1=>[3], 2=>[2, 4]}

pq = PriorityQueue.new
sum = 0
(1..n).each do |i|
  tasks[i].each { |point| pq.push(point) }
  sum += pq.pop
  puts sum
end
```

>[name=okura]

### 10.5 木

よく見かけるのは根付き木な気がする。

### 10.6 順序木と二分木

順序木という概念は初めて知った。二分木はよく聞く。強平衡二分木の性質が良いので、なんとかしてデータ構造をそれにしたい（そのためには多少コストをかけてもよい）という感じなのだろうと思った。

### 10.7 ヒープ

ヒープはスタックと対になる感じで「Rubyのしくみ」とかで見かけたことがある。

ヒープはRubyだと何が使われるんだろうと思って調べたけど、あんまり出てこない。
https://github.com/florian/rb_heap

### 10.8 二分探索木

Gemとかはなさそうだけど、自前で割と簡単に書けるのかな。

### おまけ

`RubyVM::AbstractSyntaxTree`に追加したメソッド。

```ruby=
def traverse(*types, &block)
  if block_given?
    children.each do |node|
      yield(node) if node.respond_to?(:type) && (types.empty? || types.include?(node.type))
      node.traverse(*types, &block) if node.respond_to?(:traverse)
    end
  else
    to_enum(:traverse, *types)
  end
end

def parent_of?(other)
  children.map(&:node_id).include?(other.node_id)
end
```


>[name=chen]

- ヒープは、アルゴリズムとして大体理解できるけど、どこで使われるのがよく分かりないんですね...
- code 10.5 ヒープの実装例、jsで書きました。

```javascript=
const heap = []
let size = heap.length

function heap_push(x){
　heap.push(x)
  let i = size - 1
  while(i > 0) {
  	let p = (i - 1) / 2
    if(heap[p] >= x) break
    heap[i] = heap[p]
    i = p
  }
  heap[i] = x
}

function get_top(){
　if(heap.length > 0) return heap[0]
  else return -1
}

function heap_pop(){
　let size = heap.length
　if(heap.length === 0) return
　let x = heap[heap.length - 1]
　heap.pop()
　let i = 0
  while( i * 2 + 1 < size){
　　let child_1 = i*2 + 1
　　let child_2 = i*2 + 2
　　if(child_2 < heap.length 
    	&& heap[child_2] > heap(child_1))
    {
    	child_1 = child_2
    }
    if(heap[child_1] <= x) break
    i = child_1
  }
  heap[i] = x
} 


heap_push(5)
heap_push(6)
heap_push(1)

console.log("heap : " + heap)
console.log("top : " + get_top())
heap_pop()
console.log("heap : " + heap)
console.log("top : " + get_top())

heap_push(11)

console.log("heap : " + heap)
console.log("top : " + get_top())

// "heap : 5,6,1"
// "top : 5"
// "heap : 5,1"
// "top : 5"
// "heap : 5,1,11"
// "top : 5"

```

## 振り返り
>[name=tsujita]

せっかく勉強しているので仕事でアルゴリズムを活かしていきたい・・

> [name=teruya]

優先度付きキューでないと対応不可能な課題は少ないと思いますね🧐


>[name=okura]

"heap"

> 積み重ね，堆積（たいせき），山（積み）


> [name=chen]

ヒープの利用できる場合
https://ylb.jp/2006b/proc/heap/
> プログラムが使うメモリ領域として、プログラムの機械語が置かれている領域(プログラム領域、またはテキスト領域)のほかに、静的領域とスタック領域があることはすでに学びました。 この章では、もう1つのメモリ領域であるヒープ領域(heap)について学びます。 ヒープを使うと「必要になった時に必要なぶんだけメモリを確保する」ことができます。


うんん...大学卒業から今まで全く使ったことがないっすね...:thinking_face:



## 終了後ファシリテーターがやること
- 次回のファシリテーターを決める
    - hsuさんに確認する
- 読む範囲を決める
    - 第11章
   