Информатика
Именная карта банка для детей
с крутым дизайном, +200 бонусов
Закажи свою собственную карту банка и получи бонусы
План урока:
С повторяющимися действиями мы сталкиваемся и в обычной жизни и при решении задач. Проход стрелок часов каждую минуту, секунду, час, смена дня и ночи, ежедневные сборы в школу, еженедельная смена уроков, ежегодные поездки на море – примеров циклов повторения миллиарды. Несмотря на разнообразие происходящих процессов, большинство из них можно описать простыми конструкциями. Делая что-то раз за разом, мы не задумываемся, что ученые уже написали алгоритмы с повторением или циклы универсальными способами.
Циклы, их виды
Многие операции, действия выполняются однотипно много раз. Этот процесс повторения называют циклом, а повторяемая последовательность – телом цикла. Процедуру с повторяющимися этапами называют циклической.
Каждое повторение действий в алгоритмах – итерация.
Выделяют 3 основных вида повторяющихся структур:
Описывать подобные процессы удобно схематично или при помощи команд.
Цикл с предусловием
Описание цикла с условием двумя способами:
Особенность этой конструкции – существуют такие условия, когда команды не будут выполнены ни разу.
Циклический алгоритм, примеры:
алг забор
нц пока есть кирпичи и раствор цемента
если высота забора 1 алгоритм
Как научить преодолевать трудности, а заодно и писать циклы
Несмотря на то, что речь пойдет об одной из базовых тем, данная статья написана для опытных специалистов. Цель — показать какие заблуждения бывают у новичков в программировании. Для практикующих разработчиков эти проблемы уже давно решены, позабыты или вообще не замечены. Статья может пригодиться, если вдруг вам придется помогать с этой темой кому-нибудь. В статье проводятся параллели с материалом из различных книг по программированию авторства Шилдта, Страуструпа, Окулова.
Тема про циклы выбрана потому, что на ней отсеивается довольно много людей при освоении программирования.
Данная методика рассчитана на слабых студентов. Как правило, сильные на этой теме не застревают и особенных методик для них придумывать не нужно. Второстепенная цель статьи — перевести эту методику из класса «работает на всех студентах, но только у одного преподавателя» в класс «работает у всех студентов, всех преподавателей». На абсолютную оригинальность не претендую. Если вы уже применяете похожую методику для обучения этой теме, напишите, пожалуйста, чем ваш вариант отличается. Если решите применить, расскажите по итогам, как все прошло. Если похожая методика описана в какой-нибудь книжке, напишите, пожалуйста, название.
Данную методику я отрабатывал 4 года, занимаясь индивидуально со студентами разного уровня подготовки. Всего около полусотни студентов и двух тысяч часов занятий. Поначалу на этой теме студенты навечно застревали и уходили. После каждого студента методика и материалы корректировались. Последний год студенты уже не застревают на этой теме, так что я решил поделиться наработками.
Зачем столько букв? Циклы это же элементарно!
Как я уже писал выше, для практикующих разработчиков и для сильных студентов, сложность концепции циклов может быть недооценена. Например можно устроить долгую лекцию, увидеть кивающие головы и умные глаза. Но при попытке решить какую-нибудь задачу, начинается ступор и необъяснимые проблемы. После лекции у студентов наверняка сложилось лишь частичное понимание. Ситуация усугубляется тем, что студенты не могут сами озвучить, в чем именно их заблуждение.
Однажды я осознал, что студенты воспринимают мои примеры как иероглифы. То есть как неделимые куски текста, в которых нужно дописать какую-то «магическую» букву и оно заработает.
Иногда я замечал, что студенты думают, что для решения конкретной задачи нужна какая-то еще конструкция, которую я просто еще не рассказал. Хотя для решения требовалось лишь немного модифицировать пример.
Поэтому я пришел к идее о том, что основное внимание нужно обращать не на синтаксис выражений, а на идею о рефакторинге повторяющегося кода с помощью циклов. Как только ученики осваивают эту идею, то любой синтаксис подтягивается путем небольших упражнений.
Кому и зачем я преподаю
Поскольку вступительных экзаменов нет, то на занятиях могут быть как сильные, так и очень слабые студенты. Более подробно о моих студентах можно почитать в статье Портрет слушателей вечерних курсов
Я стремился к тому, чтобы программирование осваивали все, кто этого хочет.
Мои занятия проходят индивидуально и студент платит свои деньги за каждое. Казалось бы, студенты будут оптимизировать затраты и требовать минимум. Однако люди ходят на очные занятия с живым преподавателем не за самими знаниями, а за уверенностью в том что они успели усвоить, за ощущением прогресса и за одобрением от эксперта (преподавателя). Если студенты не будут чувствовать прогресса в своем обучении, они будут уходить. В целом можно построить занятия так, чтобы студенты ощущали прогресс в увеличении количества знакомых конструкций. То есть сначала подробно изучаем while, потом изучаем for, потом do while и вот у нас готов курс на тысячу и одну ночь, в котором два месяца изучаются одни только циклы, а на выходе — студент, который под диктовку написал стандартную библиотеку. Однако для того, чтобы решать практические задачи, нужно не только знание материала, но и самостоятельность в его применении и в поиске новой информации. Поэтому для очных курсов считаю правильным принцип — научить минимуму и поощрять самостоятельное изучение нюансов и смежных тем. В теме про циклы, минимумом я считаю конструкцию while. На ней можно понять принцип. Зная принцип можно освоить и for и do-while самостоятельно.
Чтобы добиться освоения материала слабыми студентами, описать синтаксис недостаточно. Нужно давать побольше простых, но разнообразных заданий и расписывать примеры более подробно. В конечном итоге скорость освоения ограничивается способностью студента к преобразованию выражений и поиску закономерностей. Для сообразительных студентов, большинство заданий будут скучными. При занятиях с ними, можно не настаивать на решении 100% задач. Мой материал можно посмотреть на моем гитхабе. Правда репозиторий больше похож на гримуар чернокнижника — никто, кроме меня, не поймет что где находится, а если провалить проверку, то можно сойти с ума
Методика ориентирована на практику
Теория объясняется на примере решения задачи. На занятиях по основам программирования, где изучаются ветвления и циклы, просто не получится устроить полезную лекцию по одной теме на целый час. 15-20 минут хватает, чтобы объяснить концепцию. Основные сложности появляются при выполнении практических заданий.
Начинающие преподаватели могут вывалить операторы, ветвления, циклы и массивы за одну лекцию. Вот только студенты у них столкнутся с проблемой усвоения этой информации.
Нужно ведь не только рассказать материал, но и убедиться, что слушатели его поняли.
Факт усвоения темы определяется по тому, как студент справляется с самостоятельной работой.
Если студенту удалось решить задачу по теме без помощи преподавателя, значит тема усвоена. Чтобы обеспечить самостоятельную проверку, у каждой задачи описывается таблица с тестовыми сценариями. У задач есть ярко выраженный порядок. Пропускать задачи не рекомендуется. Если текущая задача слишком сложная, то к следующей переходить бесполезно. Она ещё сложнее. Чтобы студент мог осилить текущую сложную задачу, ему объясняется несколько приемов на примере первой задачи. Собственно, все содержание темы сводится к приемам преодоления трудностей. Циклы это, скорее, побочный эффект.
Первая задача всегда пример. Вторая отличается незначительно и выполняется «самостоятельно» сразу же после первой под присмотром преподавателя. Все последующие задачи направлены на то, чтобы обратить внимание на разные мелочи, которые могут вызывать заблуждения.
Объяснение примера представляет собой диалог, в котором у студента нужно вызывать back propagation и кросс-валидацию чтобы убедиться в усвоении порции материала.
Буду банален и заявлю, что первый пример по теме — очень важен. При наличии материала для обширной самостоятельной работы, упущения первого примера можно поправить. Если кроме примера больше ничего нет, то студент скорее всего не освоит тему.
While или for?
Один из спорных вопросов — выбор конструкции для примера: while или for. Однажды мой знакомый практикующий разработчик без опыта преподавания целый час убеждал меня, что цикл for — самый простой для понимания. Аргументы сводились к «в нем все понятно и по местам разложено». Однако первопричина затруднений настоящих новичков в самой идее цикла, а не в его написании. Если человек не поймет эту идею, то у него будут затруднения с синтаксисом. Как только идея осознана, то проблемы оформления кода исчезают сами.
В моих материалах тема циклов следует за темой про ветвления. Внешнее сходство if и while позволяет провести прямую аналогию: «когда условие в заголовке истинно, то выполняется тело». Особенность цикла лишь в том, что тело выполняется много раз.
Второй мой аргумент в том, что while требует меньше оформления, чем for. Меньше оформления — меньше глупых ошибок с пропущенными запятыми и скобочками. У новичков еще не настолько развита внимательность и дотошность, чтобы автоматически избегать синтаксических ошибок.
Третий аргумент — во многих хороших книгах while объясняется первым.
Если студенту удается легко преобразовывать выражения, то можно рассказать о for мимоходом. Студент дальше сам выберет что ему больше нравится. Если же преобразования вызывают затруднения, то лучше не рассеивать внимание. Пускай сначала студент решит все с помощью while. Когда тема циклов освоена, можно переписать решения, чтобы отработать преобразование while в for.
Циклы с постусловием — довольно редкий зверь. На него я время не трачу вообще. Если студент освоил идеи выявления закономерностей и преобразования выражений, то сможет разобраться без моей помощи.
При демонстрации первого примера сильным студентам, обращаю внимание на то, что в первом примере важно зафиксировать не только решение, но и всю цепочку действий, которые привели к результату. Ленивые студенты могут пренебречь писаниной и перенести себе только конечный алгоритм. Их нужно убедить в том, что однажды и для них попадется сложная задача. Для ее решения, понадобится идти по шагам как в этом примере. Именно поэтому важно зафиксировать все этапы. В следующих задачах можно будет оставить только финальный вариант решения.
Основная идея автоматизации в том, что мы поручаем компьютеру выполнять рутинную работу за человека. Один из базовых приемов — написание циклов. Он применяется когда в программе подряд пишется несколько одинаковых повторяющихся действий.
Явное лучше неявного
Ура, работает!
Ура, работает!
Ура, работает!
Ура, работает!
Ура, работает!
Ура, работает!
Ура, работает!
Ура, работает!
Такой вариант плох тем, что в выводе не видно значения счетчика. Это проблема для начинающих. Не стоит ее недооценивать. Поначалу эта задача была первой, а задача про вывод ряда чисел по возрастанию — второй. Приходилось вводить дополнительные термины «цикл N раз» и «цикл от A до B», которые по сути одно и то же. Чтобы не плодить лишних сущностей, я решил показывать только пример с выводом ряда чисел. Немногим удается без подготовки научиться держать в голове счетчик и моделировать поведение программы в голове. Некоторые студенты впервые сталкиваются с моделированием «в уме» именно на теме про циклы.
После некоторой практики, задачу на повторение одинакового текста я даю на самостоятельное решение. Если давать сначала видимый счетчик, а потом невидимый, то у студентов возникает меньше проблем. Иногда достаточно подсказки «не пиши счетчик на экран».
Как объясняется у других?
В большинстве учебных материалов в интернете, синтаксис цикла дается в составе «лекции». Например на developer.mozilla.org (в настоящий момент) вместе с циклом while описываются еще несколько конструкций. При этом даются исключительно сами конструкции в виде шаблонов. Результат их запуска описывается словами, а иллюстрация отсутствует. На мой взгляд, такая подача темы умножает на ноль полезность таких материалов. Ученик может переписать код и запустить его сам, но эталон для сравнения все равно нужен. Как понять, что пример переписан правильно, если не с чем сравнить результат?
Когда дается только шаблон, без примера, студенту становится еще сложнее. Как понять, что фрагменты кода расставлены в шаблоне правильно? Можно попробовать написать как-нибудь, а потом запустить. Но если нет эталона для сравнения результата, то запуск тоже не поможет.
В курсе по C++ на интуите синтаксис цикла закопан в третьей странице лекции 4 по теме «операторы». При объяснении синтаксиса циклов делают особый упор на термин «оператор». Термин подается в виде набора фактов вроде «символ; это оператор», «<> это составной оператор», «тело цикла должно быть оператором». Мне такой подход не нравится тем, что он как бы прячет важные взаимосвязи за одним термином. Разбор исходного кода программы на термы на таком уровне нужен разработчикам компиляторов для реализации спецификации языка, но никак не студентам в первом приближении. Новички в программировании редко обладают достаточной дотошностью, чтобы настолько внимательно относиться к терминам. Редкий человек запоминает и понимает новые слова с первого раза. Практически никто не может правильно применить термин, который только что узнал. Поэтому у студентов возникает куча ошибок вроде «написал while(a такт 10
такт 9
такт 8
такт 7
такт 6
такт 5
такт 4
такт 3
такт 2
такт 1
Подход с описанием шаблона, примера программы и результата работы этой программы используется также в книге «Javascript для детей» и в курсе js на w3schools.com. Формат веб-страницы даже позволяет сделать этот пример интерактивным.
В книге Страуструпа «Принципы и практика с использованием C++» 2016 г. автор пошел еще дальше. Первым делом объясняется какой результат должен получиться, а уже после этого — показывают текст программы. Причем в качестве примера берут не просто случайную программу, а дают экскурс в историю. Это помогает обратить внимание на нее «Смотри, это не просто какой то бесполезный текст. Ты видишь что то значимое».
В качестве примера итерации рассмотрим первую программу, выполненную на машине с хранимой программой (EDSAC). Она была написана Дэвидом Уилером (David Wheeler) в компьютерной лаборатории Кэмбриджского университета (Cambridge University, England) 6 мая 1949 года. Эта программа вычисляет и распечатывает простой список квадратов.
0 0
1 1
2 4
3 9
4 16
.
98 9604
99 9801
Здесь в каждой строке содержится число, за которым следуют знак табуляции (‘\t’) и квадрат этого числа. Версия этой программы на языке C++ выглядит так:
Любопытно, что шаблон синтаксиса в этой книге не описывается. Страуструп в руководстве инструктора (перевод) делает упор на то, что уважает интеллект своих студентов. Возможно умение выявить шаблон в нескольких примерах и считается проявлением такого интеллекта.
Как объясняю я сам
На этой задаче мы знакомимся с приемами решения сложных задач. Первоначальное решение нужно сделать примитивно и просто. Ну а затем можно подумать, как улучшить это решение.
Введение
Глава 1
Глава 2
Глава 3
Глава 4
Глава 5
Глава 6
Глава 7
Заключение
По моим наблюдениям, подход «шаблон-пример-результат» в разных комбинациях все равно приводит к тому, что студенты воспринимают цикл как иероглиф. Это проявлялось в том, что они не понимали зачем там писать условие, как выбирать между i++ и i— и прочие вроде бы очевидные вещи. Для избежания этих заблуждений, подход к рассказу о циклах должен подчёркивать смысл повторения одинаковых действий и только потом — оформление их с помощью конструкции. Поэтому прежде чем давать синтаксис цикла, нужно решить задачу «в лоб». Примитивное решение задачи про оглавление выглядит так:
Как его можно улучшить?
Заменить однообразные действия на цикл.
Какие действия тут повторяются подряд без изменений?
В этом фрагменте таких нет. Впрочем команды по выводу слова «Глава» с номером очень похожи друг на друга.
Поэтому следующий этап — поиск разницы между фрагментами. Это только в этой задаче все очевидно, потом повторяться будут не одиночные команды, а блоки кода по 5 строк и более. Искать придется не просто в списке команд, а конструкциях ветвления или цикла.
В примере разница между командами в числе после слова «Глава».
Как только разница найдена, нужно понять закономерность изменения. Отличающийся фрагмент это число? Оно постоянно увеличивается или уменьшается? Как меняется значение числа между двумя командами рядом?
В примере число после слова «Глава» увеличивается с шагом 1. Разница найдена, закономерность выявлена. Теперь можно заменить различающийся фрагмент на переменную.
Объявлять такую переменную нужно перед первым из повторяющихся фрагментов. Такую переменную обычно называют I или j или как-то более развернуто. Её начальное значение должно быть равно первому выводимому на экран значению. В примере первое значение это 1.
Какое начальное значение нужно взять для вывода ряда чисел «100, 101, 102, 103, 104, 105»?
В этом ряду первое число 100.
После каждой команды вывода нужно увеличить значение этой переменной на 1. Эта единица — шаг изменения.
Какой шаг будет в ряду чисел «100, 102, 104, 106»?
В этом ряду шаг 2.
После замены различающегося фрагмента на переменную, код будет выглядеть так:
После применения приема «выразить закономерность переменной» в коде получается несколько групп одинаковых действий, которые идут подряд. Теперь повторяющиеся действия можно заменить на цикл.
Далее вводится новые термины, чтобы студент не оказался в ситуации «все понимаю, но сказать не могу»:
— счётчик — всегда переменная, которая нужна для отслеживания количества шагов цикла. Обычно целое число, которое сравнивается с ограничением.
— шаг счётчика — описание закономерности изменения счётчика.
— ограничение — число или переменная, с которой сравнивается счётчик, чтобы алгоритм был конечным. Значение счётчика меняется так, чтобы приближаться к ограничению.
— тело цикла — набор команд, которые будут повторяться. Когда говорится «команда написана внутри цикла», то имеют в виду именно тело.
— итерация цикла — однократное выполнение тела цикла.
— условие цикла — логическое выражение, от которого зависит, будет ли выполняться ещё одна итерация. (Тут возможна путаница с конструкциями ветвления)
Нужно быть готовым к тому, что первое время студенты будут применять термины не по назначению. Это относится как к сильным, так и к слабым. Налаживание общего языка это целое искусство. Сейчас напишу кратко: нужно ставить задачу «выдели фрагмент кода с » и самому правильно использовать эти термины в разговоре.
После преобразования с циклом получается фрагмент:
Главное заблуждение
Одно популярное заблуждение студентов в том, что они помещают внутри конструкции цикла такие действия, которые нужно делать всего один раз. Например вот так:
Ученики постоянно натыкаются на эту проблему, как в начале, так и в более сложных задачах.
Коронная подсказка в этом случае:
Сколько раз нужно повторять написание команды: один раз или много?
Команды вывода слов «Введение» и «Заключение», а также объявление и инициализация переменной i не похожи на другие повторяющиеся действия. Они выполняются всего по одному разу, значит их нужно писать за пределами тела цикла.
В коде должны остаться все три этапа решения, чтобы потом ссылаться на них в случае затруднений. Первые два варианта достаточно закомментировать, чтобы они не мешали.
Внимание студента нужно обратить на следующие факты:
— В условии цикла обычно сравнивается счётчик и ограничение. Счётчик может меняться в теле цикла, а ограничение — нет. Чтобы нарушить это правило, нужно сформулировать веские причины.
— Команды для вывода слов «Введение» и «Заключение» находятся за пределами тела цикла. Нам их нужно выполнить 1 раз. «Введение» — до повторения действий, «Заключение» — после.
В процессе закрепления этой темы, освоения следующих, а также разбирательств с затруднениями даже сильным студентам полезно задавать вопрос: «А вот это действие сколько раз нужно выполнять? Один или много?».
Развитие дополнительных навыков
Чтобы понять, насколько быстро можно двигаться, нужно дать прочитать условия этих задач и спросить: «чем они отличаются от примера?», «Что нужно изменить в примере, чтобы решить их?». Если студент осмысленно отвечает, тогда пусть решит хотя бы одну на занятии, а остальные — дома самостоятельно. Если решение будет успешно, то можно начать объяснение про условия внутри циклов.
Если с самостоятельным решением затруднения, то нужно все отрабатывать на занятии. Чтобы решение задачи не напоминало рисование совы, я рекомендую сначала решить задачу не универсально. То есть так, чтобы решение проходило первый тест и не использовало конструкцию цикла. Ну а потом уже применять преобразования, чтобы добиться универсальности решения.
Циклы и ветвления
На мой взгляд, полезно дать тему «циклы внутри ветвлений» отдельно. Так, чтобы потом было видно разницу между многократной проверкой условия и однократной.
Задачи для закрепления будут про вывод чисел от А до В, которые вводятся пользователем:
— всегда по возрастанию.
— по возрастанию или по убыванию в зависимости от значений А и В.
К теме «ветвления внутри циклов» нужно переходить только после того, как студент освоил приемы: «замена закономерности на переменную» и » замена повторяющихся действий на цикл».
Главная причина применения ветвлений внутри циклов — аномалии в закономерности. В середине она нарушается в зависимости от исходных данных.
Тем студентам, которые способны искать решение путем комбинирования простых приемов, достаточно сказать «ветвления можно писать внутри циклов» и дать задачу «для примера» полностью на самостоятельное решение.
Задача для примера:
Пользователь вводит число Х. Вывести в столбик числа от 0 до 9 и поставить знак ‘+’ напротив того числа, которое равно Х.
Типы циклов в языках программирования: for, foreach, while и do while
Авторизуйтесь
Типы циклов в языках программирования: for, foreach, while и do while
В программировании различные типы циклов применяются для того, чтобы повторить некоторое действие нужное количество раз. Например отсортировать элементы массива или найти факториал числа. Цикл состоит из условия и тела цикла. Код, находящийся в теле, выполняется, когда условие равно true. Каждое повторение цикла называется итерацией.
Типы циклов
Цикл For
i — это переменная-счётчик, которая сначала равна нулю. До тех пор, пока она меньше 10, выполняется тело цикла, затем счетчик увеличивается на единицу. For — цикл с предусловием. Это значит, что сначала проверяется условие, и если оно true, то тело выполняется. В скобках объявляется тип переменной счётчика и её начальное значение. Затем указывается условие конца цикла и способ, которым изменяется значение счётчика.
Цикл Foreach (или совместный цикл)
Тело этого цикла выполнится для каждого элемента коллекции. В переменной element будет доступен по очереди каждый элемент массива array.
Цикл While
Относится к тому же типу циклов, что и For, — цикл с предусловием. С его помощью можно создать безусловный цикл, например while(1) — бесконечный цикл. Чтобы его закончить, нужно использовать служебное слово break.
Цикл Do While
Do While относится к типу циклов с постусловием. Однако здесь код выполнится как минимум один раз, даже если условие false.
Вложенные циклы
Циклы можно помещать внутрь друг друга. Это удобно для перебора многомерных коллекций. Код в примере выше выведет в консоль значение каждого элемента из двумерного массива array.
Операторы циклов
Break
Оператор break используется для досрочного выхода из цикла. Когда программа встречает break, цикл немедленно завершается и начинает выполняться код, следующий за циклом.
Continue
Оператор Continue даёт циклу команду выйти из текущей итерации и перейти к следующей.
Этот код выведет в консоль все нечетные числа из диапазона от 0 до 10:
Цикл (программирование)
Цикл — разновидность управляющей конструкции в высокоуровневых языках программирования, предназначенная для организации многократного исполнения набора инструкций. Также циклом может называться любая многократно исполняемая последовательность инструкций, организованная любым способом (например, с помощью условного перехода).
Содержание
Определения
Последовательность инструкций, предназначенная для многократного исполнения, называется телом цикла. Единичное выполнение тела цикла называется итерацией. Выражение определяющее, будет в очередной раз выполняться итерация, или цикл завершится, называется условием выхода или условием окончания цикла (либо условием продолжения в зависимости от того, как интерпретируется его истинность — как признак необходимости завершения или продолжения цикла). Переменная, хранящая текущий номер итерации, называется счётчиком итераций цикла или просто счётчиком цикла. Цикл не обязательно содержит счётчик, счётчик не обязан быть один — условие выхода из цикла может зависеть от нескольких изменяемых в цикле переменных, а может определяться внешними условиями (например, наступлением определённого времени), в последнем случае счётчик может вообще не понадобиться.
Исполнение любого цикла включает первоначальную инициализацию переменных цикла, проверку условия выхода, исполнение тела цикла и обновление переменной цикла на каждой итерации. Кроме того большинство языков программирования предоставляют средства для досрочного завершения цикла, то есть выхода из цикла независимо от истинности условия выхода.
Виды циклов
Безусловные циклы
Иногда в программах используются циклы, выход из которых не предусмотрен логикой программы. Такие циклы называются безусловными, или бесконечными. Специальных синтаксических средств для создания бесконечных циклов, ввиду их нетипичности, языки программирования не предусматривают, поэтому такие циклы создаются с помощью конструкций, предназначенных для создания обычных (или условных) циклов. Для обеспечения бесконечного повторения проверка условия в таком цикле либо отсутствует (если позволяет синтаксис, как, например, в цикле LOOP…END LOOP языка Ада), либо заменяется константным значением (while true do … в Паскале).
Цикл с предусловием
Цикл с предусловием — цикл, который выполняется пока истинно некоторое условие, указанное перед его началом. Это условие проверяется до выполнения тела цикла, поэтому тело может быть не выполнено ни разу (если условие с самого начала ложно). В большинстве процедурных языков программирования реализуется оператором while, отсюда его второе название — while-цикл. На языке Pascal цикл с предусловием имеет следующий вид:
Цикл с постусловием
Цикл с постусловием — цикл, в котором условие проверяется после выполнения тела цикла. Отсюда следует, что тело всегда выполняется хотя бы один раз. В языке Паскаль этот цикл реализует оператор repeat..until; в Си — do…while.
Pascal:
В трактовке условия цикла с постусловием в разных языках есть различия. В Паскале и языках, произошедших от него, условие такого цикла трактуется как условие выхода (цикл завершается, когда условие истинно, в русской терминологии такие циклы называют ещё «цикл до»), а в Си и его потомках — как условие продолжения (цикл завершается, когда условие ложно, такие циклы иногда называют «цикл пока»)…..
Цикл с выходом из середины
Цикл с выходом из середины — наиболее общая форма условного цикла. Синтаксически такой цикл оформляется с помощью трёх конструкций: начала цикла, конца цикла и команды выхода из цикла. Конструкция начала маркирует точку программы, в которой начинается тело цикла, конструкция конца — точку, где тело заканчивается. Внутри тела должна присутствовать команда выхода из цикла, при выполнении которой цикл заканчивается и управление передаётся на оператор, следующий за конструкцией конца цикла. Естественно, чтобы цикл выполнился более одного раза, команда выхода должна вызываться не безусловно, а только при выполнении условия выхода из цикла.
Принципиальным отличием такого вида цикла от рассмотренных выше является то, что часть тела цикла, расположенная после начала цикла и до команды выхода, выполняется всегда (даже если условие выхода из цикла истинно при первой итерации), а часть тела цикла, находящаяся после команды выхода, не выполняется при последней итерации.
Легко видеть, что с помощью цикла с выходом из середины можно легко смоделировать и цикл с предусловием (разместив команду выхода в начале тела цикла), и цикл с постусловием (разместив команду выхода в конце тела цикла).
Часть языков программирования содержат специальные конструкции для организации цикла с выходом из середины. Так, в языке Ада для этого используется конструкция LOOP…END LOOP и команда выхода EXIT или EXIT WHEN:
Здесь внутри цикла может быть любое количество команд выхода обоих типов. Сами команды выхода принципиально не различаются, обычно EXIT WHEN применяют, когда проверяется только условие выхода, а просто EXIT — когда выход из цикла производится в одном из вариантов сложного условного оператора.
В тех языках, где подобных конструкций не предусмотрено, цикл с выходом из середины может быть смоделирован с помощью любого условного цикла и оператора досрочного выхода из цикла (такого, как break в Си), либо оператора безусловного перехода goto.
Цикл cо счётчиком
Цикл со счётчиком — цикл, в котором некоторая переменная изменяет своё значение от заданного начального значения до конечного значения с некоторым шагом, и для каждого значения этой переменной тело цикла выполняется один раз. В большинстве процедурных языков программирования реализуется оператором for, в котором указывается счётчик (так называемая «переменная цикла»), требуемое количество проходов (или граничное значение счётчика) и, возможно, шаг, с которым изменяется счётчик. Например, в языке Оберон-2 такой цикл имеет вид:
(здесь v — счётчик, b — начальное значение счётчика, e — граничное значение счётчика, s — шаг).
Неоднозначен вопрос о значении переменной по завершении цикла, в котором эта переменная использовалась как счётчик. Например, если в программе на языке Паскаль встретится конструкция вида:
возникает вопрос: какое значение будет в итоге присвоено переменной k: 9, 10, 100, может быть, какое-то другое? А если цикл завершится досрочно? Ответы зависят от того, увеличивается ли значение счётчика после последней итерации и не изменяет ли транслятор это значение дополнительно. Ещё один вопрос: что будет, если внутри цикла счётчику будет явно присвоено новое значение? Различные языки программирования решают данные вопросы по-разному. В некоторых поведение счётчика чётко регламентировано. В других, например, в том же Паскале, стандарт языка не определяет ни конечного значения счётчика, ни последствий его явного изменения в цикле, но не рекомендует изменять счётчик явно и использовать его по завершении цикла без повторной инициализации. Программа на Паскале, игнорирующая эту рекомендацию, может давать разные результаты при выполнении на разных системах и использовании разных трансляторов.
Радикально решён вопрос в языке Ада: счётчик считается описанным в заголовке цикла, и вне его просто не существует. Даже если имя счётчика в программе уже используется, внутри цикла в качестве счётчика используется отдельная переменная. Счётчику запрещено явно присваивать какие бы то ни было значения, он может меняться только внутренним механизмом оператора цикла. В результате конструкция
внешне аналогичная вышеприведённому циклу на Паскале, трактуется однозначно: переменной k будет присвоено значение 100, поскольку переменная i, используемая вне данного цикла, не имеет никакого отношения к счётчику i, который создаётся и изменяется внутри цикла. Считается, что подобное обособление счётчика наиболее удобно и безопасно: не требуется отдельное описание для него и минимальна вероятность случайных ошибок, связанных со случайным разрушением внешних по отношению к циклу переменных. Если программисту требуется включить в готовый код цикл со счётчиком, то он может не проверять, существует ли переменная с именем, которое он выбрал в качестве счётчика, не добавлять описание нового счётчика в заголовок соответствующей процедуры, не пытаться использовать один из имеющихся, но в данный момент «свободных» счётчиков. Он просто пишет цикл с переменной-счётчиком, имя которой ему удобно, и может быть уверен, что никакой коллизии имён не произойдёт.
Цикл со счётчиком всегда можно записать как условный цикл, перед началом которого счётчику присваивается начальное значение, а условием выхода является достижение счётчиком конечного значения; к телу цикла при этом добавляется оператор изменения счётчика на заданный шаг. Однако специальные операторы цикла со счётчиком могут эффективнее транслироваться, так как формализованный вид такого цикла позволяет использовать специальные процессорные команды организации циклов.
В некоторых языках, например, Си и других, произошедших от него, цикл for, несмотря на синтаксическую форму цикла со счётчиком, в действительности является циклом с предусловием. То есть в Си конструкция цикла:
фактически представляет собой другую форму записи конструкции:
То есть в конструкции for сначала пишется произвольное предложение инициализации цикла, затем — условие продолжения и, наконец, выполняемая после каждого тела цикла некоторая операция (это не обязательно должно быть изменение счётчика; это может быть правка указателя или какая-нибудь совершенно посторонняя операция). Для языков такого вида вышеописанная проблема решается очень просто: переменная-счётчик ведёт себя совершенно предсказуемо и по завершении цикла сохраняет своё последнее значение.
Вложенные циклы
Существует возможность организовать цикл внутри тела другого цикла. Такой цикл будет называться вложенным циклом. Вложенный цикл по отношению к циклу в тело которого он вложен будет именоваться внутренним циклом, и наоборот цикл в теле которого существует вложенный цикл будет именоваться внешним по отношению к вложенному. Внутри вложенного цикла в свою очередь может быть вложен еще один цикл, образуя следующий уровень вложенности и так далее. Количество уровней вложенности как правило не ограничивается.
Полное число исполнений тела внутреннего цикла не превышает произведения числа итераций внутреннего и всех внешних циклов. Например взяв три вложенных друг в друга цикла, каждый по 10 итераций, получим 10 исполнений тела для внешнего цикла, 100 для цикла второго уровня и 1000 в самом внутреннем цикле.
Одна из проблем, связанных с вложенными циклами — организация досрочного выхода из них. Во многих языках программирования есть оператор досрочного завершения цикла (break в Си, exit в Турбо Паскале, last в Perl и т. п.), но он, как правило, обеспечивает выход только из цикла того уровня, откуда вызван. Вызов его из вложенного цикла приведёт к завершению только этого внутреннего цикла, объемлющий же цикл продолжит выполняться. Проблема может показаться надуманной, но она действительно иногда возникает при программировании сложной обработки данных, когда алгоритм требует немедленного прерывания в определённых условиях, наличие которых можно проверить только в глубоко вложенном цикле.
Решений проблемы выхода из вложенных циклов несколько.
Совместный цикл
Ещё одним вариантом цикла является цикл, задающий выполнение некоторой операции для объектов из заданного множества, без явного указания порядка перечисления этих объектов. Такие циклы называются совместными (а также циклами по коллекции, циклами просмотра) и представляют собой формальную запись инструкции вида: «Выполнить операцию X для всех элементов, входящих в множество M». Совместный цикл, теоретически, никак не определяет, в каком порядке операция будет применяться к элементам множества, хотя конкретные языки программирования, разумеется, могут задавать конкретный порядок перебора элементов. Произвольность даёт возможность оптимизации исполнения цикла за счёт организации доступа не в заданном программистом, а в наиболее выгодном порядке. При наличии возможности параллельного выполнения нескольких операций возможно даже распараллеливание выполнения совместного цикла, когда одна и та же операция одновременно выполняется на разных вычислительных модулях для разных объектов, при том что логически программа остаётся последовательной.
Совместные циклы имеются в некоторых языках программирования (C#, Java, JavaScript, Perl, Python, PHP, LISP, Tcl и др.) — они позволяют выполнять цикл по всем элементам заданной коллекции объектов. В определении такого цикла требуется указать только коллекцию объектов и переменную, которой в теле цикла будет присвоено значение обрабатываемого в данный момент объекта (или ссылка на него). В различных языках программирования синтаксис оператора различен: