11/8 アルゴリズムと計算量


前回までの補足


10/25の課題について


スライドの補足

スライドに使われたプログラム

数え上げによる平方根の計算

def square(x)
  x * x
end

def sqrt1(x,delta)
  n=0
  while square(n * delta) < x
    n = n + 1
  end
  n * delta
end

二分法による平方根の計算

def good(guess,x,delta)
  (square(guess)-x).abs < delta
end

def sqrt2(x,delta)
  low=0.0; high=x; 
  mid=(low+high)/2
  while !good(mid,x,delta)
    if square(mid) < x then
      low=mid
    else
      high=mid
    end
    mid=(low+high)/2
  end
  mid
end

ニュートン法による平方根の計算

def f(r,x)
  (r + x/r) / 2
end

def sqrt3(x,delta)
  guess = x*1.0
  while !good(guess,x,delta)
    guess = f(guess,x)
  end
  guess
end

定義通りに計算するフィボナッチ数

def fib1(x)
  if x==0 || x==1 then
    1
  else 
    fib1(x-1)+fib1(x-2)
  end
end

0から計算するフィボナッチ数の計算

def fib2(x)
  i=0; fi=1; fi1=1
  while i < x
    i = i+1
    f2 = fi+fi1
    fi = fi1
    fi1 = f2
  end
  fi	
end

0から計算するフィボナッチ数の計算

def fib2(x)
  i,fi,fi1=0,1,1
  while i < x
    i,fi,fi1 = i+1,fi1,fi+fi1
end
  fi	
end

行列を用いるフィボナッチ数の計算法(3)

# 行列を用いるフィボナッチ数の計算

# ここでは行列は2次元配列で表わすことにする。

def is_even(n)
  n%2 == 0
end

# 行列a,bの積
def mat_x_mat(a, b)
  [[a[0][0]*b[0][0] + a[0][1]*b[1][0],  a[0][0]*b[0][1] + a[0][1]*b[1][1]],
   [a[1][0]*b[0][0] + a[1][1]*b[1][0],  a[1][0]*b[0][1] + a[1][1]*b[1][1]]]
end

# 単位行列
$unit = [[1,0],
         [0,1]]

# 行列の自乗
def square(m)
  mat_x_mat(m,m)
end

# 行列mのn乗
def power(m,n)
  if n==0 then
    $unit
  elsif is_even(n) then
    square(power(m, n/2))
  else
    mat_x_mat(power(m, n-1), m)
  end
end

# フィボナッチ数のQ行列
$q_matrix = [[1,1],
	     [1,0]]

def fib3(n)
  power($q_matrix, n)[0][0]
end

単純な最大公約数の計算

# 単純な最大公約数の計算

# y が xで割り切れるとき true
def divisible(y,x)
  y % x == 0
end

# nがxとyの約のときtrue
def common_divisor(n,x,y)
  divisible(x,n) && divisible(y,n)
end

# xとyの最大公約数
def gcd_simple(x,y)
  n = x
  while !common_divisor(n,x,y)
    n = n - 1
  end
  n
end

ユークリッドの互助法

def euclid(x,y)
  if x == 0 then
     y
  else
     euclid(y % x, x)
  end
end

単純整列法

# aのi番目とj番目を交換
def swap(a,i,j)
  ai = a[i]; aj = a[j]
  a[i] = aj; a[j] = ai
end

# aのi番目以降の最小の要素を見つけ、
# その添字を返す
def find_minimum(a,i)
  min_value = a[i]      # 暫定最小値
  min_index = i # その添字
  for j in (i+1)..(a.size-1)
    if a[j] < min_value then
      min_value = a[j]  # 新たな最小値
      min_index = j     # を発見した
    end # 場合
  end
  min_index     # 添字を返す
end
# 本体: 先頭から順に最小要素を移動
def sort(a)
  for i in 0..(a.size-1)
    min_index = find_minimum(a,i)
    swap(a, i, min_index)
  end
  a
end

単純整列法

# aのi番目とj番目を交換
def swap(a,i,j)
  a[i], a[j] = a[j], a[i]
end

# aのi番目以降の最小の要素を見つけ、
# その添字を返す
def find_minimum(a,i)
  # 暫定最小値とその添字
  min_value, min_index = a[i],i
  for j in (i+1)..(a.size-1)
    if a[j] < min_value then
      # 新たな最小値を発見した場合
      min_value, min_index = a[j],j
    end
  end
  min_index     # 添字を返す
end
# 本体: 先頭から順に最小要素を移動
def sort(a)
  for i in 0..(a.size-1)
    min_index = find_minimum(a,i)
    swap(a, i, min_index)
  end
  a
end

併合整列法

# 整列: 併合法

Tree = Struct.new(:left, :right)

def divide(a,i_min,i_max)
  if i_min == i_max then
    a[i_min]
  else
    mid = (i_min+i_max)/2
    Tree.new(divide(a,i_min,mid), divide(a,mid+1,i_max))
  end
end

def merge(left,right)			# leftとrightを併合した配列を作る
  merged = Array.new()			# 結果の配列を作る
  while left.size > 0 || right.size > 0	# leftかrightに要素が残っている間
    merged.push(			# 結果の配列の最後に
      if right.size == 0 then		#   右が空なら
	left.shift			#     左の先頭を
      elsif left.size == 0  then	#   左が空なら
	right.shift			#     右の先頭を
      elsif left[0] < right[0] then	#   左の先が小さければ
	left.shift			#     左の先頭を
      else				#   それ以外は
	right.shift			#     右の先頭を
      end				# 追加する
    )
  end
  merged				# 結果の配列を返す
end

def merge_tree(node_or_number)
  if node_or_number.instance_of?(Tree) then
    merge(merge_tree(node_or_number.left), 
	  merge_tree(node_or_number.right))
  else
    [node_or_number]
  end
end

def merge_sort(a)
  merge_tree(divide(a,0,a.size-1))
end

ビン整列法

# ビン整列法

$max = 1000

def count_occurences(a)			# 値の出現回数から成る配列を作る
  counts = Array.new($max, 0)		# 結果を格納する配列
  for i in 0..(a.size-1)		# aの全要素について
    counts[a[i]] = counts[a[i]]+1	# a[i]の出現回数を増やす
  end
  counts
end

def rebuild(a,counts)			# 出現回数から配列を再構成する
  i=0					# iは再構成さ出る配列の添字
  for v in 0..($max-1)			# 全ての値について小さい順に
    for k in 0..(counts[v]-1)		# 出現回数だけ
      a[i] = v				# aに書き込んでゆく
      i = i+1
    end
  end
end

def bin_sort(a)				# 配列aの整列は
  rebuild(a, count_occurences(a))	# aをaの出現回数で再構成すること
  a
end