Шрифт:
Интервал:
Закладка:
Мы можем пойти еще дальше, если осознаем, что каждый раз, когда у нас есть каким-то образом выстроенная последовательность и необходимо что-то найти, можно использовать это решение. Итак, мы обобщили задачу поиска имен до задачи поиска чего угодно и обобщили список имен до любой выстроенной последовательности вещей. Мы преобразили наш алгоритм в общий алгоритм поиска. Теперь он подходит не только для конкретной задачи, но для любой задачи такого рода. Его можно использовать каждый раз, как только понадобится что-нибудь найти. Мы обобщили решение, которое было изобретено для решения всего одной задачи (найти наше имя), но оно подошло для целого класса проблем.
Обратите внимание: чтобы провести обобщение, необходимо скрыть часть деталей. Нам не нужно думать об особенностях имен или дисков, поэтому мы обобщили их до «элемента». Мы используем абстрагирование, чтобы провести обобщение.
Иногда мы проводим обобщение, чтобы создать очень общие алгоритмы, которые можно использовать во многих ситуациях, как показано выше. В других случаях мы понимаем, что новая задача в совершенно иной области похожа на уже решенную нами, и поэтому мы делаем однократное обобщение — переносим задачу (а значит, и решение). Например, в телефонах используется функция предиктивного набора текста. Когда вы начинаете вводить слово, телефон догадывается по набранным буквам, что за слово вы набираете. Парализованные люди, которые не могут говорить, общаются, выбирая буквы по системе моргания. Тот же самый алгоритм предиктивного набора текста можно использовать и в этой ситуации. Люди точно так же могут догадаться, что им хотят сказать, по первым буквам. Один алгоритм можно использовать для двух разных с виду проблем, как только становится очевидным их сходство при сопоставлении с образцом.
Сопоставление с образцом и обобщение используют на самых разных уровнях — от осознания, что задача аналогична уже решенной, и до понимания, что небольшие фрагменты задач одинаковы. Часто при написании программы видно, что отдельные ее части похожи на то, с чем мы уже имели дело. Предположим, нам нужно, чтобы программа каждый раз спрашивала, хотим ли мы сделать что-то еще раз (например, сыграть в игру снова после выигрыша). Если мы уже писали код для такого случая, то имеет смысл адаптировать его и интегрировать в новую программу, не продумывая необходимые команды с самого начала.
Обобщение помогает и при оценке. Предположим, что мы создали некий общий алгоритм. Его оценивают один раз, и все, что при этом узнают о нем, применимо к каждому новому случаю использования. Например, сведения об абсолютной скорости работы алгоритма и скорости его работы по сравнению с другими алгоритмами являются основанием для решения, подходит ли он для каких-либо новых задач.
Разделение крупной задачи на мелкие части, с которыми легче справиться, называется декомпозицией. Мы видели применение этого принципа, когда делали робота-мошенника и собрали целое, продумав все отдельные компоненты. Это очень действенный способ решения проблем. Именно декомпозиция позволяет писать сложные программы, состоящие из миллиона инструкций. Без нее у нас не было бы программ, позволяющих делать все то, для чего сейчас используются компьютеры.
Использование метода декомпозиции при написании программ тесно связано с абстракцией управления. Идея состоит в том, чтобы разбить программу на массу более мелких задач. Каждую из этих небольших программ написать легко. После этого становится легче написать большую объединяющую их программу, потому что не надо думать обо всех деталях. Как только части завершены, мы учитываем только то, что они делают, а не как они это делают. Чтобы облегчить процесс, каждой части присваивается имя, которое четко указывает, чтó она делает, но подробности при этом скрыты (такого рода наименования — это еще один вид абстракции). Потом при объединении маленьких программ уже не надо думать о мелких деталях.
Таким образом, декомпозиция обеспечивает еще один способ использования обобщения. Если небольшие программы написаны в достаточно общем ключе, то их используют в других больших программах. Возможно, для решения определенных подзадач пригодятся уже существующие программы, если при сопоставлении с образцом выявится необходимое соответствие. Кроме того, существуют особые приемы, позволяющие использовать декомпозицию для быстрого нахождения работающих решений. Один из вариантов — алгоритм «разделяй и властвуй». Идея заключается в том, чтобы решить задачу, найдя способ разделить ее на более мелкие, но в остальном одинаковые задачи. Чтобы решить проблему поиска по телефонному справочнику, мы можем открыть его в середине и посмотреть, находятся ли напечатанные там фамилии до или после нужной нам фамилии. После этого мы игнорируем одну из половин, так как знаем, где надо искать. У нас остается похожая, но менее масштабная проблема — поиск в половине телефонного справочника. Мы решаем эту задачу так же — открываем выбранную часть на середине и так далее, пока не найдем нужную фамилию. Это позволяет решить задачу гораздо быстрее. Такой подход — пример решения задачи с использованием рекурсии, особого вида алгоритмического мышления. На этой идее основан подход к созданию алгоритмов, в основе которого лежит деление задачи на похожие, но меньшего объема. Метод «разделяй и властвуй» выделяется в том плане, что задачу делят пополам (или на трети, четверти и т.п.), чтобы получившиеся при этом задачи были примерно одного объема, но гораздо меньшего по сравнению с общей задачей и, следовательно, легче в решении, чем изначальная.
Высокие технологии в конечном итоге создаются для людей и в помощь людям. Это значит, что вычислительное мышление главным образом связано с решением проблем людей, а не технологий. Поэтому алгоритмическое мышление должно включать понимание людей и особенно их сильных и слабых сторон. Мы видели это на многочисленных примерах — от помощи пациентам с синдромом «запертого человека» до заботы о том, чтобы медсестры не делали ошибок. Вот еще один пример, подтверждающий эту мысль. Представьте, что вы пишете алгоритм, обеспечивающий безопасность банковских операций в интернете. Можно придумать алгоритм, который потребует пароля из 1000 произвольных символов, куда нельзя вставлять существующие слова. Это, безусловно, обеспечит высокую степень безопасности! А еще это будет очень глупо. Ни один человек, за исключением пары случайных гениев, не запомнит такой пароль. Алгоритм окажется бесполезным. Решение задач с помощью вычислительного мышления должно быть связано с пониманием возможностей людей.
Как только алгоритм написан, его важно оценить. Необходимо проверить, работает ли он. В частности, надо подтвердить, что алгоритм удовлетворяет ряду требований, описывающих задачу.
Оценка подразумевает проверку соответствия вашего решения поставленной цели и его оценку по нескольким параметрам. Самый главный из них — функциональная корректность. Действительно ли ваш алгоритм работает? Это необходимо проверять всегда! Что бы ни случилось, он должен непременно давать правильный ответ. Обязательно в этом убедитесь. В противном случае человек или машина, которые будут его использовать, могут оказаться в сложной ситуации, слепо выполняя неправильные действия, и в итоге не будут знать, что делать. Мы видели это, в частности, на примере с фокусом, где надо было угадывать выбранные предметы. Даже если мы предусмотрим все возможные варианты, ничего не получится, если кто-нибудь выберет один из наших секретных предметов. Ни фокусники, ни компьютеры не должны оставаться без плана действий в подобных случаях.