Wednesday, September 4, 2013

Mergesort with Ruby

<<-DOC
  Recursive merge_sort using two-way merge using sentinel
  Credit:
  philcrissman.com/2010/07/18/how-not-to-write-sorting-algorithms-in-ruby
DOC
def merge_sort (sequence, first, last)
  if first < last
    mid = (first + last)/2
    merge_sort(sequence, first, mid);
    merge_sort(sequence, mid+1, last);

    merge(sequence, first, mid + 1, last)
  end
  sequence
end

def merge(sequence, first, mid, last)
  left  = sequence[first..mid-1]  ## power of ruby, dynamic array
  right = sequence[mid..last]     ## power of ruby. dynamic array

  left.push(Float::MAX)           ## sentinel, avoids special check
                                   # for end value on array
  right.push(Float::MAX)          ## sentinel

  i, j = 0, 0;                    ## simultaneous assigment

  (first..last).each do |n|       ## readable expression
    if left[i] <= right[j]
      sequence[n] = left[i]
      i += 1
    else
      sequence[n] = right[j]
      j += 1
    end
  end
end

## Calling with first and last enables control on how muc
## to sort.
puts merge_sort([5,-2,3,-1,4,0], 3, 5)
puts merge_sort([5,-2,3,-1,4,0], 0, 5)