ヒープのsiftdownリファクタリング

MyHeapのsiftdownでコードの重複と分岐の分かりづらさが気になったので書き換えてみた。

  def siftdown(n)
    if n * 2 > @n then return
    elsif n * 2 == @n then
      if @q[n] >  @q[n * 2] then
        @q[n], @q[n * 2] = @q[n * 2], @q[n]
      end
    elsif n * 2 + 1 <= @n then
      left = n * 2
      right = n * 2 + 1
      if (@q[left] < @q[right]) &&
          (@q[n] > @q[left]) then
        @q[n], @q[left] = @q[left], @q[n]
        siftdown(left)
      end
      if (@q[right] < @q[left]) &&
          (@q[n] > @q[right]) then
        @q[n], @q[right] = @q[right], @q[n]
        siftdown(right)
      end
    end
  end
  def siftdown(n)
    left = n * 2
    right = left + 1

    case
    when @n < left then return

    when @n == left then
      if @q[n] >  @q[left] then
        @q[n], @q[left] = @q[left], @q[n]
      end

    when @n >= right then
      [left, right].permutation.each do |a, b|
        if (@q[a] < @q[b]) &&
            (@q[n] > @q[a]) then
          @q[n], @q[a] = @q[a], @q[n]
          siftdown(a)
        end
      end
    end
  end

すっきりしたとは言え、[left, right].permutationのところが、かなり意味が分かりづらくなった気がする。かといって、[ [left, right], [right, left] ]はないだろう……。

それと、a, b = b, aみたいな多重代入って長くなると見にくくなって、swap(a, b)みたいな書き方ができたほうがすっきりするようにも思える。