Читаем Грокаем алгоритмы полностью

В исходном наделе можно разместить два участка 640 × 640, и еще останется место. Тут-то и наступает момент истины. Нераспределенный остаток — это тоже надел земли, который нужно разделить. Так почему бы не применить к нему тот же алгоритм?

Итак, мы начали с надела 1680 × 640, который необходимо разделить на участки. Но теперь разделить нужно меньший сегмент — 640 × 400. Если вы найдете самый большой участок, подходящий для этого размера, это будет самый большой участок, подходящий для всей фермы. Мы только что сократили задачу с размера 1680 × 640 до 640 × 400!


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

«Если вы найдете самый большой участок, подходящий для этого размера, это будет самый большой участок, подходящий для всей фермы». Если истинность этого утверждения для вас неочевидна, не огорчайтесь. Она действительно не очевидна. К сожалению, доказательство получится слишком длинным, чтобы его можно было бы привести в книге, поэтому вам придется просто поверить мне на слово. Если вас интересует доказательство, поищите «алгоритм Евклида». Хорошее объяснение содержится на сайте Khan Academy: https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/the-euclidean-algorithm.

Применим тот же алгоритм снова. Если начать с участка 640 × 400, то размеры самого большого квадрата, который можно создать, составляют 400 × 400 м.

Остается меньший сегмент с размерами 400 × 240 м.

Отсекая поделенную часть, мы приходим к еще меньшему размеру сегмента, 240 × 160 м.

После очередного отсечения получается еще меньший сегмент.

Эге, да мы пришли к базовому случаю: 160 кратно 80. Если разбить этот сегмент на квадраты, ничего лишнего не останется!

Итак, для исходного надела земли самый большой размер участка будет равен 80 × 80 м.

Вспомните, как работает стратегия «разделяй и властвуй»:

1. Определите простейший случай как базовый.

2. Придумайте, как свести задачу к базовому случаю.

«Разделяй и властвуй» — не простой алгоритм, который можно применить для решения задачи. Скорее, это подход к решению задачи. Рассмотрим еще один пример.

Имеется массив чисел.

Нужно просуммировать все числа и вернуть сумму. Сделать это в цикле совсем не сложно:

def sum(arr):

  total = 0

  for x in arr:

    total += x

  return total

print sum([1, 2, 3, 4])

Но как сделать то же самое c использованием рекурсивной функции?

Шаг 1: определить базовый случай. Как выглядит самый простой массив, который вы можете получить? Подумайте, как должен выглядеть простейший случай, и продолжайте читать. Если у вас будет массив с 0 или 1 элементом, он суммируется достаточно просто.

Итак, с базовым случаем мы определились.

Шаг 2: каждый рекурсивный вызов должен приближать вас к пустому массиву. Как уменьшить размер задачи? Один из возможных способов:

В любом случае результат равен 12. Но во второй версии функции sum передается меньший массив. А это означает, что вы сократили размер своей задачи!

Функция sum может работать по следующей схеме:

А вот как это выглядит в действии.

Вспомните, что при рекурсии сохраняется состояние.


совет

Когда вы пишете рекурсивную функцию, в которой задействован массив, базовым случаем часто оказывается пустой массив или массив из одного элемента. Если вы не знаете, с чего начать, — начните с этого.


Пара слов о функциональном программировании

Зачем применять рекурсию, если задача легко решается с циклом? Вполне резонный вопрос. Что ж, пора познакомиться с функциональным программированием!

В языках функционального программирования, таких как Haskell, циклов нет, поэтому для написания подобных функций приходится применять рекурсию. Если вы хорошо понимаете рекурсию, вам будет проще изучать функциональные языки. Например, вот как выглядит функция sum на языке Haskell:

sum [] = 0      Базовый случай

sum (x:xs) = x + (sum xs)    Рекурсивный случай

На первый взгляд кажется, что одна функция имеет два определения. Первое определение выполняется для базового случая, а второе — для рекурсивного случая. Функцию также можно записать на Haskell с использованием команды if:

sum arr = if arr == []

            then 0

            else (head arr) + (sum (tail arr))

Но первое определение проще читается. Так как рекурсия широко применяется в языке Haskell, в него включены всевозможные удобства для ее использования. Если вам нравится рекурсия или вы хотите изучить новый язык — присмотритесь к Haskell.


Упражнения

4.1 Напишите код для функции sum (см. выше).

4.2 Напишите рекурсивную функцию для подсчета элементов в списке.

4.3 Найдите наибольшее число в списке.

4.4 Помните бинарный поиск из главы 1? Он тоже относится к классу алгоритмов «разделяй и властвуй». Сможете ли вы определить базовый и рекурсивный случай для бинарного поиска?


Быстрая сортировка

Перейти на страницу:

Все книги серии Библиотека программиста

Программист-фанатик
Программист-фанатик

В этой книге вы не найдете описания конкретных технологий, алгоритмов и языков программирования — ценность ее не в этом. Она представляет собой сборник практических советов и рекомендаций, касающихся ситуаций, с которыми порой сталкивается любой разработчик: отсутствие мотивации, выбор приоритетов, психология программирования, отношения с руководством и коллегами и многие другие. Подобные знания обычно приходят лишь в результате многолетнего опыта реальной работы. По большому счету перед вами — ярко и увлекательно написанное руководство, которое поможет быстро сделать карьеру в индустрии разработки ПО любому, кто поставил себе такую цель. Конечно, опытные программисты могут найти некоторые идеи автора достаточно очевидными, но и для таких найдутся темы, которые позволят пересмотреть устоявшиеся взгляды и выйти на новый уровень мастерства. Для тех же, кто только в самом начале своего пути как разработчика, чтение данной книги, несомненно, откроет широчайшие перспективы. Издательство выражает благодарность Шувалову А. В. и Курышеву А. И. за помощь в работе над книгой.

Чед Фаулер

Программирование, программы, базы данных / Программирование / Книги по IT

Похожие книги

Язык программирования C++. Пятое издание
Язык программирования C++. Пятое издание

Лучшее руководство по программированию и справочник по языку, полностью пересмотренное и обновленное под стандарт С++11!Р'С‹ держите в руках новое издание популярного и исчерпывающего бестселлера по языку программирования С++, которое было полностью пересмотрено и обновлено под стандарт С++11. Оно поможет вам быстро изучить язык и использовать его весьма эффективными и передовыми способами. Р' соответствии с самыми передовыми и современными методиками изложения материала авторы демонстрируют использование базового языка и его стандартной библиотеки для разработки эффективного, читабельного и мощного кода.С самого начала этой книги читатель знакомится со стандартной библиотекой С++, ее самыми популярными функциями и средствами, что позволяет сразу же приступить к написанию полезных программ, еще не овладев всеми нюансами языка. Большинство примеров из книги было пересмотрено так, чтобы использовать новые средства языка и продемонстрировать РёС… наилучшие СЃРїРѕСЃРѕР±С‹ применения. Эта книга — не только проверенное руководство для новичков в С++, она содержит также авторитетное обсуждение базовых концепций и методик языка С++ и является ценным ресурсом для опытных программистов, особенно желающих побыстрей узнать об усовершенствованиях С++11.Стенли Р'. Липпман работал старшим консультантом в Jet Propulsion Laboratory, архитектором РіСЂСѓРїРїС‹ Visual С++ корпорации Microsoft, техническим сотрудником Bell Laboratories и главным инженером- программистом по анимации в кинокомпаниях Disney, DreamWorks, Pixar и PDI.Р–РѕР·и Лажойе, работающий ныне в кинокомпании Pixar, был членом канадской РіСЂСѓРїРїС‹ разработчиков компилятора C/C++ корпорации IBM, а также возглавлял рабочую группу базового языка С++ в составе международной организации по стандартизации ANSI/ISO.Барбара Э. Му имеет почти тридцатилетний опыт программирования. На протяжении пятнадцати лет она работала в компании AT&T, сотрудничая с Бьярне Страуструпом, автором языка С++, и несколько лет руководила РіСЂСѓРїРїРѕР№ разработчиков С++.• Узнайте, как использовать новые средства языка С++11 и стандартной библиотеки для быстрого создания надежных программ, а также ознакомьтесь с высокоуровневым программированием• Учитесь на примерах, в которых показаны передовые стили программирования и методики проектирования• Р

Барбара Э. Му , Жози Лажойе , Стенли Б. Липпман

Программирование, программы, базы данных