LoginSignup
0
1

More than 1 year has passed since last update.

簡単なアルゴリズム問題を解いた【探索、ソート】

Last updated at Posted at 2021-04-20

はじめに

キタミ式の基本情報技術者試験の勉強してたらアルゴリズムの説明が出てきたので、久しぶりにコーディングしてみた

一つのメソッドで完結させる、なるべく簡潔なコードにする、フラグ変数やインデックス変数を使わない、などの縛りを設けてます

※仕様は殆ど上記の本の内容だけに従ってます

※ハッシュ法、ヒープソートはわけわかめだったのでやってません
 似たような書き方されてるコードがあれば教えてください

探索

線形探索法

def linear_search(ary, find)
  ary.each { |x| return true if x == find }
  false
end

二分探索法

def binary_search(ary_should_sort, find)
  ary = ary_should_sort.sort

  loop do
    return false if ary.size == 1

    middle = ary[ary.size / 2]
    return true if middle == find

    half = ary.each_slice(ary.size / 2).to_a
    half[1].concat(half[2]) if half[2] != nil

    ary = middle > find ? half[0] : half[1]
  end
end

ソート

基本交換法(バブルソート)

def bubble_sort(copied_ary)
  ary = copied_ary.dup

  (ary.size).times do
    (ary.size - 1).times do |i|
      ary[i], ary[i + 1] = ary[i + 1], ary[i] if ary[i] > ary[i + 1]
    end
  end

  ary
end

終了判定(ary.each_cons(2).all? { |a, b| a <= b })があんまりよくない気がするけど本に何も書いてないのでセーフ
↑偶然バブルソートは配列の要素数回ループすると知ったので書き換えました

基本選択法(選択ソート)

def selection_sort(copied_ary)
  ary = copied_ary.dup

  (ary.size - 1).times do |i|
    min_index              = ary[i..].index(ary[i..].min) + i
    ary[i], ary[min_index] = ary[min_index], ary[i]
  end

  ary
end

基本挿入法(挿入ソート)

def insertion_sort(copied_ary)
  ary = copied_ary.dup

  divided_ary  = ary.chunk_while { |a, b| a <= b }.to_a
  sorted_ary   = divided_ary.max_by(&:size)
  unsorted_ary = (divided_ary - [sorted_ary]).flatten

  return sorted_ary if unsorted_ary == []

  unsorted_ary.each do |e_un|
    index = sorted_ary.size
    sorted_ary.reverse_each do |e|
      break unless e > e_un
      index -= 1
    end

    sorted_ary.insert(index, e_un)
  end

  sorted_ary
end

シェルソート

def shell_sort(copied_ary)
  ary = copied_ary.dup

  h = 1
  h = h * 3 + 1 until h > ary.size / 9

  while h != 0
    sliced_ary = ary.each_slice(h).to_a

    taken_ary = sliced_ary[0].zip(*sliced_ary[1..])
    taken_ary.map!(&:compact).delete_if(&:empty?).map! { |x| insertion_sort(x) }

    ary = taken_ary[0].zip(*taken_ary[1..]).map(&:compact).flatten
    h = (h - 1) / 3
  end

  ary
end

これだけ仕様を調べてから書きました(参考
我ながらいい感じのコードだと思います

クイックソート

def quick_sort(ary)
  return ary if ary.size == 1 || ary.all? { |x| x == ary[0] }

  middle = (ary.min + ary.max).fdiv(2)
  smaller, bigger = ary.partition { |x| x < middle }

  return quick_sort(smaller) + quick_sort(bigger)
end

初めて書いた再帰的プログラムです
短く纏められる再帰凄い(小並感)

おわり

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1