Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование с нуля - это совсем просто! 55) Рекурсивное приближение к финалу


Информационный Канал Subscribe.Ru

 
Школа программирования

Программирование с нуля - это совсем просто!

55) Рекурсивное приближение к финалу.

Забыл в прошлый раз про оператор выбора написать, для Си++.

Вот так он выглядит:

  switch( условие ) {

     case вариант: ...
            break;

     case вариант: ...
            break;

     default: ...
           break;

     }

Например:

   switch( x+5 ) {

   case 1: x = 1;
          break;

   case 2: x = 2;
          break;

   default: x = 0;
         break;

   }

default - необязательный раздел, вызывается, если не найден ни один подходящий вариант.

Здесь важное отличие от варианта Паскаля - наличие оператора break, указывающего на окончание кода обработкио определенного варианта. В Паскале всегда выполняются операторы только из одного условия, а вот в Си могут быть выпонены и последующие. Например:

   switch( x+5 ) {

   case 1: x = 1;
       // убрали отсюда break!

   case 2: x = 2;
          break;

   default: x = 0;
         break;

   }

Тогда, если значение x+5 будет равно 1, то выберется первый вариант, x=1, но затем выполнение команд продолжится до ближайшего break в пределах текущего switch! То есть далее встретится и выполнится x=2, и только потом break остановит работу switch-оператора, и управление будет передано какому-то следующему за ним оператору. Это нередкая ошибка си-программистов, пропуск break.


Теперь обещанная рекурсия. Это метод управления работой программы, основанный на вызове некоторой функцией самой себя. Классический пример из этой области - факториал. Факториалом числа N называют произведение 1*2*3*...*N. Например, факториал числа шесть будет равен 1*2*3*4*5*6. Мы уже программировали эту функцию с помощью цикла, а теперь запрограммируем с помощью рекурсии. ДЛя этого нам нужно определить два условия: как вести себя рекурсивной функции на произвольном значении N, и когда ей остановиться себя вызывать.

Вот как можно факториал определить:

Функция факториал-числа( N ) равна:

N * факториал-числа( N-1 ) если N > 1

или

1

если N <= 1.

Что это означает? Например, функция факториал-числа 3 чему равна? Смотрим по нашему описанию.

Она равна 3 (N=3), умноженному на факториал-числа( 3-1 = 2 ). Так как N=3 у нас больше 1.

факториал-числа 2 чему равна?

Она равна 2 (N), умноженному на факториал-числа( 2-1 = 1 ). Так как N=2 у нас больше 1.

Наконец факториал-числа 1 чему равен? Вот он уже равен 1, и рекурсивного дальнейшего вызова уже не происходит. То есть возвращаемся по цепочке вызовов вверх:

F(3) = 3 * F(3-1) // спуск вниз - рекурсивный вызов самой себя
F(2) = 2 * F(2-1) // спуск вниз - рекурсивный вызов самой себя
F(1) = 1 // спуск закончен
F(2) = 2 * 1 = 2 // возвращаемся обратно с уже рассчитанными значениями
F(3) = 3 * 2 = 6 // возвращаемся обратно с уже рассчитанными значениями

Вот как это мы запрограммируем:

  function F( N : Integer ): Integer;
   begin
   if N > 1
      then Result := N * F( N-1 )
      else Result := 1
   end;

Правда, красиво? И никаких циклов. Вообще всю цепочку расчетов делает программа. Правда, не все языки допускают рекурсию, но Паскаль и Си - да.

47-е задание будет на рекурсию. Запрограммируйте с ее помощью алгоритм нахождения наименьшего общего делителя чисел. У чисел 10 и 55 это будет 5 - наименьший (но больший единицы) делитель, на который делятся оба числа без остатка.

Вот такая формула:

NOD(n,m) = NOD(m,r), где n > m, а r - остаток от деления n на m (операция mod в Паскале, % в Си).

Если m = 0, то NOD(n,0) = n. А если n = 0, то NOD(0,m) = m.

Например, NOD(55,10) = NOD(10,5), r = 5 (55 mod 10 = 5).

Может, кто-нибудь кроме Тани попробует сделать рекурсию на лямзиках? Это действительно сложно.

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


До последних заданий добираются уже считанные единицы, но это нормально, раз кто-то добирается. Уже сейчас можно сказать, что базовый курс практически одновременно и успешно закончат (если не передумают :) Лена, Екатерина, два Алексея, и еще наверное несколько человек, кто начал позже, но стремительно нагоняет :)

То есть им уже можно искать работу от 1000 долларов :) Только базы данных немного подучить (за неделю можно), и все.

Камень-ножницы-бумага.

Здесь: russianenterprisesolutions.com/sbo/download/lena42.zip

лучшее решение Лены - кстати, рекомендую всем, просто поиграть даже интересно, с таким дизайном!

Здесь: russianenterprisesolutions.com/sbo/download/alex.rar - классическое, Алексея.

Здесь - russianenterprisesolutions.com/sbo/download/knb.zip- вариант Екатерины - на Си++.

Они от 2 до 20 килобайтов.


* Сделал прогу.Не знаю как остановить таймер.

Остановить - просто свойство Enabled таймера перевести обратно в false.

* Прочитал Вашу статью по поводу использования MediaPlayerв Delphi.
Как правильно настроить кодеки, чтобы медиаплейер проигрывал MP3.
Какие кодект для этого необходимы.
И как проверить программно может ли медиаплейер воспроизвести данный файл.

Кодеки смотрим, на Панели управления - Звуки и аудио - Оборудование - Audio Codecs. Жмем Свойства, выбираем закладку Свойства. Обычно это что-то типа l3codec (Fraunhofer MPEG), может быть и явно какой-нибудь с mp3/mpeg-буквами в названии. Если нету такого, то ищем mp3-кодек здесь: http://websound.ru/ - Софт - Енкодеры.

Чтобы проверить, можно ли воспроизвести некоторый файл, такой код, шаблон можно использовать. Комментировать не буду, просто готовый код:

   // проверка на доступность mp3-движка

   WavPlayer.DeviceType := dtAutoSelect; // пусть плеер попробует найти
  mp3-кодек сам

   ... // указываем путь к файлу, например
   WavPlayer.FileName = 'xxx.mp3' ;

   try
      WavPlayer.Open;
   except
     // здесь обработка возможной ошибки:
     // текст ошибки будет в WavPlayer.ErrorMessage

      WavPlayer.DeviceType := dtWaveAudio; // явно указываем, что
  будем
  использовать стандартный wav-файл, который в Windows всегда
  поддерживается

      WavPlayer.FileName = 'xxx.wav' ;
      WavPlayer.Open;
   end;

Код

   try

...

   except

...

   end;

работает так - выполняется часть от try до except, если возникает ошибка во время ее выполнения, так называемая исключительная ситуация (например, деление на ноль или сбой при работе с файлами), что требует вмешательства Windows, то вызывается часть от except до end. Если ошибок нету, то эта часть не выполняется!

Таким образом пробуем запустить плеер с mp3-файлом, и если возникла ошибка, то явно указываем, что будем использовать wav-формат.


(c) 2004-2005 Сергей Бобровский bobrovsky@russianenterprisesolutions.com

Школа программирования с нуля
Все предыдущие выпуски базового курса тут:
http://russianenterprisesolutions.com/sbo/

 

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.prognull
Отписаться

В избранное