Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Операторы циклов, их виды, особенности и области применения (ИСТОРИЯ ПОЯВЛЕНИЯ И РАЗВИТИЯ)

Содержание:

ВВЕДЕНИЕ

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

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

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

Для достижения цели необходимо решить ряд задач:

  1. Проследить историю развития циклов, как изменился подход по сравнению с современностью;
  2. Изучить и систематизировать информацию о том, каких видов бывают циклы, какие операторы для них используются и в каких задачах они применяются;
  3. Рассмотреть на практике как выбор вида цикла влияет на решение одной и той же задачи.

1 ИСТОРИЯ ПОЯВЛЕНИЯ И РАЗВИТИЯ

1. 1СТРУКТУРЫ ЦИКЛ

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

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

use16 ;Генерировать 16-битный код

org 100h ;Программа начинается с адреса 100h

mov ah,02h ;Для вызова функции DOS 02h - вывод символа

mov dl,'A' ;Первый выводимый символ

mov cx,26 ;Счётчик повторений цикла

myloop:

int 21h ;Обращение к функции DOS

inc dl ;Следующий символ

loop myloop ;Команда цикла

mov ah,09h ;Функция DOS 09h - вывод строки

mov dx,press ;В DX адрес строки

int 21h ;Обращение к функции DOS

mov ah,08h ;Функция DOS 08h - ввод символа без эха

int 21h ;Обращение к функции DOS

mov ax,4C00h ;\

int 21h ;/ Завершение программы

Данная программа выводит все буквы английского алфавита, ASCII коды этих символов идут друг за другом, поэтому можно делать это в цикле, просто прибавляя постоянное значение к регистру, в котором содержится код символа. Командой цикля является loop, она отправляет выполнение команды на метку в коде myloop, до тех пор, пока в регистре cx не обнулится счётчик цикла.

Надо сказать, что такая конструкция не единственный вариант организации цикла. В низкоуровневых языках программирования рчень распространена практика создавать циклы с помощью операторов безусловного перехода goto, в языке ассемблера это команда jmp или jump. Операторы безусловного перехода состоят из двух частей, самого оператора и метки в коде, куда отправляет оператор перехода.

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

Оператор безусловного перехода долго вызвал много критики и споров, считается, что код с goto сложно форматировать, он мешает чёткой структуре программы и создаёт так называемый спагетти-код, а некоторые способы его применения создают проблемы с логикой программы. Доводы против были настолько серьёзными, что в структурном программировании теперь считается, что использование данного оператора крайне нежелательно. Это несомненно повлияло на некотрые современные языки программирования, например в Java и Ruby данный оператор запрещён.

Тем не менее, goto до сих пор, хоть и редко, используется в современных программах, например, встречается в ядре Linux и в некоторых Android-приложениях.

Приведём небольшой пример использования безусловного перехода в языке ассемблера при организации цикла

mov cx,N

CYCL:

jcxz Exit

<тело цикла>

dec cx

jmp CYCL

EXIT:   

. . .

С развитием языков программирования развивались и конструкции, используемые при написании программ. Программы становились объёмнее, кода становилось несравнимо больше, появилось сначала функциональное программирование, затем и объектно-ориентированное, но цикл продолжает оставаться одной из самых используемых структур при решении задач программирования. Конечно же, и синтаксически, и структурно выглядит он в современной трактовке уже иначе.

АЛГОРИТМИЧЕСКАЯ СТРУКТУРА ЦИКЛ

Цикл  ̶ разновидность управляющей конструкции в высокоуровневых языках программирования, предназначенная для организации многократного исполнения набора инструкций. Также циклом может называться любая многократно исполняемая последовательность инструкций, организованная любым способом.

В алгоритмическую структуру цикл входит серия команд, выполняемая многократно, такая последовательность команд называется телом цикла, и условие выхода из цикла или условие окончания цикла – логическое выражение, от принимаемого значения которого зависит,  будет в очередной раз выполняться тело цикло или цикл завершится. Единичное выполнение тела цикла называют итерацией.

 Переменная, которая хранит текущий номер итерации, называется счётчиком итераций цикла, или просто счётчиком цикла. Счётчик не обязательный элемент цикла, кроме того, счётчик может быть не один, так как условие выхода из цикла может зависеть от нескольких изменяемых в цикле переменных, и может даже определяться какими-либо внешними условиями (например, истечением определённого времени), в таком случае счётчика может вообще не быть.

Исполнение любого цикла включает первоначальную инициализацию переменных цикла, проверку условия выхода, исполнение тела цикла и обновление переменной цикла на каждой итерации. Кроме того, большинство языков программирования предоставляет средства для досрочного управления циклом, например, операторы завершения цикла, то есть выхода из цикла независимо от истинности условия выхода (в языке Си — break) и операторы пропуска итерации (в языке Си —continue).

2.1 ВИДЫ ЦИКЛОВ

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

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

В случае использования счётчика цикла, (которые так и называются цикл со счётчиком), выделяют циклы с инкрементным счётчиком, если заданный счётчик увеличивается с каждой итерацией, и циклы с декрементным счётчиком, если счётчик с каждой итерацией уменьшается. Правила для изменения счётчика в большинстве языков можно задать при определении цикла, условием же окончания цикла определяется достижение счётчиком некого граничного значения. В большинстве языков программирования цикл со счётчиком является циклом с предусловием.

Кроме того циклы бывают вложенными несчётное количество раз, то есть в одном цикле может присутствовать сколько угодно внутренних циклов, а внутренние циклы в свою очередь могут содержать сколько угодно других внутренних циклов. Необязательно циклы будут все одного вида, скорее наоборот.

Рассмотрим каждый вид циклов поподробнее.

2.2 БЕЗУСЛОВНЫЕ ЦИКЛЫ

Основной особенностью данного вида цикла считается отсутствие условия выхода в оформлении самого цикла, но если выхода из цикла не предусмотрено вообще, цикл будет выполняться бесконечно, что приведёт к зависанию программы. Соответственно выход всё равно должен быть предусмотрен в теле цикла с помощью специальных команд.

Блок-схему цикла можно изобразить следующим образом

Условие

True

Тело цикла

Выход из цикла

Дальнейший код программы

Рисунок 1. Блок-схема безусловного цикла.

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

Приведём пример описанного вида цикла на языке программирования C++

int i=0; // счётчик метров

int j=0; // счётчик дней

while (true){

i=i+2; j++; //улитка проползает в день вверх по столбу 2 метра

if(i>=10){break;} //если столб длиной 10 метров закончился, выходим

i--; //за ночь улитка сползает на метр вниз

}

После окончания цикла переменная j содержит ответ на задачу, за сколько дней улитка доберётся до вершины столба, если за день она проползает 2 метра, а за ночь сползает вниз на 1 метр.

2.3 ЦИКЛЫ С ПРЕДУСЛОВИЕМ

Основной особенностью цикла, исходя из названия, является то, что выражение для условия выхода из цикла вычисляется перед телом цикла. Если выражение принимает значение ИСТИНА, то итерация выполняется, если ЛОЖЬ, то цикл завершается, таким образом, возможны ситуации, когда цикл не пройдёт ни одной итерации, именно это является основным условием выбора данного вида цикла при построении алгоритма.

В большинстве языков программирования оператором для такого вида цикла служит while. На языке Pascal цикл с предусловием выглядит следующим образом:

while <условие> do

begin

<тело цикла>

end;

На языке C++ синтаксис использования оператора цикла с предусловием имеет похожий вид:

while (<условие>){

<тело цикла>

}

Блок схема цикла с предусловием приведена на Рисунке 2.

Условие

True

Тело цикла

Дальнейший код программы

False

Рисунок 2. Блок-схема цикла с предусловием.

Такой вид цикла очень удобно использовать для проверки каких-либо условий, которые могут быть уже выполнены к началу цикла. Приведём пример на языке C++. Решим задачу поиска наибольшего общего делителя для двух чисел по схеме Евклида.

int m,n; // вводимое пользователем числа

std::cout << ”Введите m”;

std::cin >> m; // пользователь вводит значение m

std::cout << ”Введите n”;

std::cin >> n; // пользователь вводит значение n

while(m!=n){ // пока n неравно m

if(m>n){m=m-n;}

else{n=n-m;}

}

std::cout << ”Наибольший общий делитель равен ”<<m;

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

2.4 ЦИКЛЫ С ПОСТУСЛОВИЕМ

Цикл с постусловием отличается от остальных видов тем, что проверка условия выхода из цикла производится в конце тела цикла и исходя из вычисленного значения выражения условия происходит либо выход из цикла, либо следующая итерация.

Что примечательно, в трактовке условия цикла с постусловием в разных языках есть различия. В Паскале и языках, произошедших от него, условие такого цикла трактуется как условие выхода ( цикл завершается, когда условие истинно, в русской терминологии такие циклы называют ещё «цикл до» ), а в Си и его потомках — как условие продолжения ( цикл завершается, когда условие ложно, такие циклы иногда называют «цикл пока»).

На языке Pascal цикл с постусловием выглядит следующим образом:

repeat

<тело цикла>

until <условие выхода>

На языке C++ используется уже знакомый нам оператор while:

do{

<тело цикла>

} while (<условие подолжения цикла>)

На рисунке приведена блок схема цикла с постусловием в трактовке языка С++

True

Тело цикла

Дальнейший код программы

False

Условие

Рисунок 3. Блок-схема цикла с постусловием.

Как хорошо видно из блок-схемы, такой цикл выполнится всегда хотя бы раз, даже если условие выхода сразу истинное.

Приведём пример использования цикла с постусловием на языке C++

int i=0; // вводимое пользователем значение

do{

std::cout << ” Введите целое число от 1 до 10”;

std::cin >> i;

}while ((i<1) || (i>10)) // пока i меньше 1 или больше 10, алгоритм

// будет просить ввести значение ещё раз

От пользователя требуется ввести целое число в диапазоне от 1 до 10 включительно. Для первоначального ведения данных должна пройти хотя бы одна итерация, если пользователь ввёл значение правильно сразу, то тело цикла выполнится один раз, в обратном случае цикл будет продолжаться, пока в переменной не окажется требуемого значения. Окончание цикла говорит о том, что в переменной i содержится значение, которое больше 0 или меньше 11.

2.5 ЦИКЛЫ СО СЧЁТЧИКОМ

Такой вид счётчика используется для цикла с конечным числом итераций. Где специальная переменная, которая называется счётчиком, принимает заданное значение, изменяется с определённым шагом каждую итерацию и при достижении заданного граничного значения является условием выхода из цикла. Во всех языках программирования для цикла со счётчиком используется оператор for. Поэтому данный вид цикла по другому называют «цикл для», имея в виду что он выполняется дл переменной счётчика.

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

В языке Pascal задаётся только начальное значение счётчика и граничное, шаг равен 1, изменить это можно, только если менять сам счётчик внутри цикла, но это очень непредсказуемо, потому то разные трансляторы могут по разному собрать программу и результат будет не тот который ожидался. Вот как выглядит код цикла со счётчиком на языке Pascal

for i:=1 to 10 do

begin

<тело цикла>

end;

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

for (int i=10; --i; 0) {

<тело цикла>

}

Построим блок схему цикла со счётчиком

True

Тело цикла

Дальнейший код программы

False

i <= <конечное значение>

i = <начальное значение>

i = i+1

Начало цикла

Рисунок 4. Блок-схема для цикла со счётчиком

Приведём пример решения задачи на вычисление последовательности из 10 чисел Фибоначчи на языке C++ ( поледовательность Фибоначчи – широко известная последовательность, каждый член которой, начиная с третьего, образуется путём сложения предыдущих двух членов последовательности, первый элемент равен 1, второй элемент равен 2)

int a[10]; // задаём массив, где будет храниться последовательность

a[0]=1; // инициируем первое число Фибоначчи

std::cout<<”a[1]=”<< a[0];

a[1]=2; // инициируем второе число Фибоначчи

std::cout<<”a[1]=”<< a[1];

for (int i=2; i++; i<10) // пока счётчик не дойдёт до 9 будут

{ // вычисляться наши числа

a[i]= a[i-1] + a[i-2]; // каждое число равно сумме двух предыдущих

std::cout<<”a[“<<i+1<<”]=”<< a[i];

}

Посчитанные числа сразу выводятся на экран. В силу того что индексация массивов в языке C++ начинается с 0, при выводе на экран индекс элемента массива нужно увеличить, чтобы он соответствовал индексу последовательности, именно поэтому счётчик цикла изменяется с 0 до 9, а не с 1 до 10 как это должно казаться на первый взгляд.

ВЫБОР И ПРИМЕНЕНИЯ ЦИКЛОВ

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

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

Рассмотрим задачу, обход матрицы размерностью n на n по спирали, таким образом, как показано на рисунке

image262.png

Рисунок 5. Схема обхода матрицы

Обход начинается всегда с левого верхнего угла и идёт по часовой стрелке, постепенно сужаясь к центру.

Для краткости положим, что у нас уже есть массив a, размерностью n на n, и он уже заполнен некими числами, нам остаётся только вывести их в заданном порядке. Так как решать задачу мы будем на языке C++ , необходимо помнить что нумерация массивов в этом языке начинается с 0, поэтому элемент матрицы A11 будет содержаться в переменной a[0][0].

Решим эту задачу двумя способами, через использование циклов со счётчиками и с использованием циклов с предусловиями.

int k, m, e;

k=0;

m=0;

for ( e=1; e++; e<2n)

{

if ((e%4)==1){

for ( i=k; i++; i<(n-k) )

{

std::cout<<a[k][i];

}

k++;

}

if ((e%4)==2)

{

for ( i=m+1; i++; i<(n-m) )

{

std::cout<<a[i][n-m-1];

}

m++;

}

if ((e%4)==3)

{

for ( i=n-k-1; i--; i>=k )

{

std::cout<<a[n-k][i];

}

k++;

}

if ((e%4)==0)

{

for ( i=n-m-1; i--; i>=m )

{

std::cout<<a[i][m-1];

}

m++;

}

}

При обходе матрицы по заданным правилам, есть 4 вида цикла: увеличивается второй индекс при неизменном первом, затем увеличивается первый индекс при неизменном втором, затем уменьшается второй индекс и после этого уменьшается первый. Так получается один виток спирали, в 4 шага. Всего шагов для обхода матрицы требуется 2*n-1. Таким образом, мы создали цикл со счётчиком от 1 до 2*n-1, чтобы обойти всю матрицу. Но теперь нам надо определить в каждом шаге, каким именно из 4-ёх вариантов двигаться, для этого нам поможет остаток от деления переменной цикла e. Заведём дополнительно счётчики отступа k и m. Первый отвечает за отступ по горизонтали, второй за отступ по вертикали. Будем их увеличивать по мере углубления витков. Решение этой задачи с помощью циклов со счётчиками на первый взгляд удачнее всего, но давайте попробуем решить эту задачу с помощью цикла while.

int i, j, k, l, x, y, z, e;

k = n;

x = 0;

y = 1;

e = 1;

i = 0;

j = 0;

while (e<2*n)

{

k = k- abs(x);

l = 0;

while (l<k)

{

i = i + x;

j = j + y;

std::cout<<a[i][j];

}

z=x;

x=y;

y=z*(-1);

}

В данном случае мы заметили определённые закономерности в изменении индексов при обходе матрицы по спирали, и выразили их математически: индекс элемента матрицы меняется поочерёдно с одинаковым шагом 1) 0 и 1; 2) 1 и 0; 3) 0 и -1; 4) -1 и 0. И если первому элементу присвоить второй, а второму первый умноженный на -1 (в случае 0 останется также 0), то можно эти шаги циклично менять. Далее нашли зависимость от того, сколько раз нужно сделать итераций в каждом шаге и теперь можно составить цикл, в котором будет, как и в прошлом, 2*n-1 шагов.

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

ЗАКЛЮЧЕНИЕ

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

Для достижения цели нами был поставлен ряд задач, а именно:

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

Мы рассмотрели историю развития языков программирования от машинных кодов до современных процедурных и объекно-ориентированных языков программирования. Выяснили, как изменился подход к использованию цикла, и что в старом подходе уже утратило свою актуальность.

  1. Систематизировать информацию о видах циклов и сферах их применений

В ходе работы мы выделили 4 вида циклов. Рассмотрели, какие особенности есть у каждого, и в каких задачах их лучше применять. Ознакомились с синтаксисом в различных языках и попробовали применить на практике исходя из их сферы применения.

  1. Посмотреть на практике как тот или иной вид цикла будет влиять на решение одной и той же задачи в программировании.

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

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

СПИСОК ЛИТЕРАТУРЫ

  1. Культин Н.Б.: С/С++ в задачах и примерах. - СПб: БХВ-Петербург, 2011
  2. Вирт Н. Алгоритмы и структуры данных. - М.: Мир, 1989.
  3. Гуда А.Н.: Информатика и программирование. - М.: Дашков и К, 2010
  4. Зубов В.С. Программирование на языке Turbo Pascal (версии 6.0 и 7.0). - М.: Информационно-издательский дом "Филинъ", 1997.
  5. Боровский, А.Н. Практическое программирование на C++. / А.Н. Боровский. - СПб.: BHV, 2012.
  6. Материалы сайта https://ru.wikipedia.org.