Опубликован: 27.07.2006 | Доступ: свободный | Студентов: 4408 / 1102 | Оценка: 4.28 / 4.13 | Длительность: 26:56:00
Специальности: Программист
Лекция 11:

Введение в ООП

< Лекция 10 || Лекция 11: 123456789

Примеры программ

НОД и алгоритм Евклида

При рассмотрении задач, связанных с обработкой целых чисел, часто приходится сталкиваться с понятием НОД - наибольшего общего делителя чисел. Известно много алгоритмов вычисления НОД, мы рассмотрим лишь два из них.

Задача

Напишите программу, вычисляющую НОД(a,b) - наибольший общий делитель двух введенных с клавиатуры неотрицательных целых чисел a и b, не равных нулю одновременно.

Вариант 1

Определим максимум из этих чисел и, последовательно уменьшая его, будем искать число, на которое делятся и a и b. Программа обязательно завершит свою работу, так как в самом неудачном случае, когда эти числа взаимно просты, k станет равно 1, а на 1 делятся все числа, следовательно выполнение цикла прекратится.

print "Введите первое число: "; a = gets.to_i
print "Введите второе число: "; b = gets.to_i

k = a >= b ? a : b # теперь k -  максимум 
until (a % k == 0) and (b % k == 0)
  k -= 1
end
print "НОД(#{a},#{b}) = #{k}\n"

Вариант 2 - алгоритм Евклида

Алгоритм Евклида основан на следующих свойствах НОД: для всех a и b, больших или равных 0, выполнены равенства

НОД(a, b) = НОД(a - b, b)= НОД(a, b - a); 
НОД(a, 0) = НОД(0, a) = a

Ниже приведен текст программы, реализующей алгоритм Евклида.

print "Введите первое число: "; a = gets.to_i
print "Введите второе число: "; b = gets.to_i
m, n = a, b
while  !((m == 0) || (n == 0))
  if m >= n
    m = m - n
  else
    n = n - m
  end
end

k = m == 0 ? n : m
print "НОД(#{a},#{b}) = #{k}\n"
#!/usr/bin/env ruby

# 1

print "Введите первое число: "; a = gets.to_i
print "Введите второе число: "; b = gets.to_i

k = a >= b ? a : b # теперь k -  максимум 


until (a%k == 0)&& (b%k == 0)
  k-=1
end
print "НОД(#{a},#{b}) = #{k}\n"

#2 Алгоритм Евклида

print "Введите первое число: "; a = gets.to_i
print "Введите второе число: "; b = gets.to_i
m, n = a, b
while  !((m == 0) || (n == 0))
  if m >= n
    m = m - n
  else
    n = n - m
  end
end

k = m == 0 ? n : m
print "НОД(#{a},#{b}) = #{k}\n"
Пример 1.9.

Аргументы командной строки

Как и другие языки программирования, Ruby позволяет передавать данные в программу, использую аргументы командной строки. Все, что при старте программы указывается после ее имени, интерпретатор помещает в специальный массив ARGV, работа с элементами которого нечем не отличается от работы с другими массивами. Можно, например, проверить, с правильным ли количеством аргументов командной строки была вызвана программа. Далее приводится программа, прерывающий свое выполнение, если число аргументов меньше 2:

=begin
Напишите программу подсчета суммы всех нечетных
чисел, заключенных в интервале от K до L, 
где  K и L - аргументы командной строки
=end

if ARGV.length < 2 
  puts "Слишком мало входных данных"
  exit(1)
end

s = 0
k = ARGV[0].to_i
l = ARGV[1].to_i
for i in k .. l
  s += i if i%2 != 0
end
puts "Сумма нечетных чисел в интервале " +
     "от #{k} до #{l} равна #{s}"

Для экстренного прерывания процесса выполнения программы здесь использован встроенный метод exit.

#!/usr/bin/env ruby
=begin
Напишите программу подсчета суммы всех нечетных
чисел, заключенных в интервале от K до L, 
где  K и L - аргументы командной строки
=end

if ARGV.length < 2 
  puts "Слишком мало входных данных"
  exit(1)
end

s = 0
k = ARGV[0].to_i
l = ARGV[1].to_i
for i in k .. l
  s += i if i%2 != 0
end
puts "Сумма нечетных чисел в интервале " +
     "от #{k} до #{l} равна #{s}"
Пример 1.10.

Задача

Числами Фибоначчи называется последовательность целых чисел, задаваемая соотношениями: а0 = 0, a1 = 1, an = an-1+an-2. Напишите программу, получающую в качестве аргумента командной строки целое число n, и печатающую nчисло Фибоначчи.

Вариант 1 - рекурсивная функция

В следующей программе первый элемент массива ARGV преобразовывается в целое число и передается в качестве аргумента рекурсивной функции fib.

def fib(n)
  if n<2
    n
  else
    fib(n-2)+fib(n-1)
  end
end
n = ARGV[0].to_i
puts "#{n}-е число Фибоначчи равно #{fib(n)}"

Для вычисления с помощью этой программы, размещенной в файлe fib.rb, например, 30-го числа Фибоначчи достаточно выполнить команду

ruby fib.rb 30

Данная программа использует двойную рекурсию, поэтому процесс вычисления займет достаточно заметное время.

#!/usr/bin/env ruby

=begin
Напишите программу, получающую с качестве аргумента командной строки целое
число n, и печатающую n-е  число Фибоначчи. 
=end

def fib(n)
  if n<2
    n
  else
    fib(n-2)+fib(n-1)
  end
end
t1 = Time.now
n = ARGV[0].to_i
puts "#{n}-е число Фибоначчи равно #{fib(n)}"
t2 = Time.now
puts "Время расчета около #{(t2-t1).round} сек."
Пример 1.11.

Вариант 2 - использование массива

В следующем варианте решения этой задачи каждое число Фибоначчи вычисляется лишь один раз и сразу заносится в массив. Для определения очередного элемента массива достаточно сложить два предыдущих.

n =ARGV[0].to_i
f= [0, 1]
fib = case n
      when   0
	f[0]
      when  1
	f[1]
      else
	for i in 2 .. n
	  f[i] = f[i-1] + f[i-2]
	end
	f[n]
      end

puts "#{n}-е число Фибоначчи равно #{fib}"
#!/usr/bin/env ruby

=begin
Напишите программу, получающую с качестве аргумента командной строки целое
число n, и печатающую n-е  число Фибоначчи. 
=end
t1 = Time.now
n =ARGV[0].to_i
f= [0, 1]
fib = case n
      when   0
	f[0]
      when  1
	f[1]
      else
	for i in 2 .. n
	  f[i] = f[i-1] + f[i-2]
	end
	f[n]
      end
puts "#{n}-е число Фибоначчи равно #{fib}"
t2 = Time.now
puts "Время расчета около #{(t2-t1).round} сек."
a = fib.to_s.split('")
puts "Количество цифр в #{n}-м числе Фибоначчи равно #{a.size}."
Пример 1.12.

Однако и у этой программы есть существенный недостаток - она хранит все промежуточные результаты, в то время как каждое предыдущее значение используется лишь дважды. Изменим программу так, чтобы она использовала только три переменных: вычисляемое значение и два предшествующих ему:

n =ARGV[0].to_i
if n > 1
  prev, beforePrev = 1, 0
  for i in 2 .. n
    fib  = prev + beforePrev
    prev, beforePrev = fib, prev
  end
else 
  fib = n
end
puts "#{n}-е число Фибоначчи равно #{fib}"
#!/usr/bin/env ruby

=begin
Напишите программу, получающую с качестве аргумента командной строки целое
число n, и печатающую n-е  число Фибоначчи. 
=end
t1 = Time.now
n =ARGV[0].to_i
if n > 1
  prev, beforePrev = 1, 0
  for i in 2 .. n
    fib  = prev + beforePrev
    prev, beforePrev = fib, prev
  end
else 
  fib = n
end
puts "#{n}-е число Фибоначчи равно #{fib}"
t2 = Time.now
puts "Время расчета около #{(t2-t1).round} сек."
a = fib.to_s.split("')
puts "Количество цифр в #{n}-м числе Фибоначчи равно #{a.size}."
Пример 1.13.

Включите в рассмотренные программы операторы, информирующие о продолжительности вычислений, и сравните их эффективность. Для этого найдите с помощью первой из рассмотренных программ 30, 31 и 32 числа Фибоначчи. Пользуясь второй и, тем более, третьей вы сможете вычислить достаточно большое число Фибоначчи, например, для вычисления 60000-го числа Фибоначчи, содержащего 12539 цифр на компьютере с процессором Celeron-500, программе, размещающей промежуточные результаты в массиве, потребовалось около 19 секунд, в то время как последняя программа вычислила его за 2 секунды.

< Лекция 10 || Лекция 11: 123456789
Дмитрий Фаттахов
Дмитрий Фаттахов
Виктория Бельгесова
Виктория Бельгесова

Добрый день. Как получить удостоверение о прохождении данного курса?