Условный оператор. Полная и неполная развилка. Переключатель
На практике решение большинства задач не удается описать с помощью программ линейной структуры. При этом после проверки некоторого условия выполняется та или иная последовательность операторов, однако происходит нарушение естественного порядка выполнения операторов. Для этих целей используют управляющие операторы. Условный оператор используется для реализации разветвлений в программе, которые происходят при выполнении некоторого условия и имеет следующую структуру
if ( выражение ) серия1; else серия2;
Если выражение, выступающее в качестве условия, принимает значение 0, то выполняются операторы, расположенные после else (серия2), если отлично от нуля, — операторы, после if. При записи логического выражения следует избегать знака = = (равно) для действительных переменных (double), так как они представляются неточно, а поэтому может не произойти совпадений значений выражений, стоящих слева и справа от знака равно. Для устранения указанного недостатка следует требовать выполнения условия с заданной точностью, т.е. вместо отношения X = = Y рекомендуется, например,
fabs(X - Y) < 1E-8.
Поскольку развилка может быть неполной, то возможна и неполная форма записи условного оператора:
if ( логическое выражение ) серия;
Условный оператор реализует разветвление вычислительного процесса по двум направлениям, одно из которых осуществляется при выполнении условия, другое — в противном случае. Для реализации разветвлений более чем по двум направлениям необходимо использовать несколько условных операторов. Рассмотрим примеры.
Задача 1. Даны действительные числа x, y. Если x и y отрицательны, то каждое значение заменить модулем; если отрицательно только одно из них, то оба значения увеличить на 0,5; если оба значения неотрицательны и ни одно из них не принадлежит отрезку [0,5; 2,0], то оба значения уменьшить в 10 раз; в остальных случаях x и y оставить без изменения.
Разработаем алгоритм решения задачи, после чего напишем программу. Алгоритм запишем словесно:
- ввести значения x, y;
- если x<0 и y<0, найти их Классы и перейти к п. 5, иначе перейти к следующему пункту;
- если x<0 или y<0, увеличить каждую величину на 0,5 и перейти к п. 5,иначе перейти к следующему пункту;
- если ни x, ни y не принадлежат отрезку [0,5; 2,0], уменьшить их в 10 раз;
- вывести значения x и y;
- конец.
function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} } Листинг решения
// программа условие1 #include <iostream.h> #include <math.h> void main() { double x,y; cout << "'Введите два действительных числа "; cin >> x >> y; if((x<0)&&(y<0)) { x = fabs(x); y = fabs(y); } else { if((x<0)||(y<0)) { x += 0.5; y += 0.5; } else { if(!(((x>=0.5)&&(x<=2.0))||((y>=0.5)&&(y<=2.0)))) { x /= 10.0; y /= 10.0; } } } cout << "Результат: "; cout.width(6); cout << x << " " << y; } |
Задача 2. Дано действительное число a. Вычислить f(a), если
function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} } Листинг решения
// программа условие2 #include <iostream.h> #include <math.h> void main() { double a,f; cout << "Введите действительное число: "; cin >> a; if(a <= 0) f = 0; else if(a <= 1) f = a*a-a; else f = a*a - sin(3.14*a*a); cout.width(6); cout << "Значение функции F(x) при x = " << a << " равно " << f; } |
Кроме условного оператора в качестве управляющей структуры довольно часто используется переключатель switch. Эта структура позволяет переходить на одну из ветвей в зависимости от значения заданного выражения (селектора выбора). Ее особенность состоит в том, что выбор решения здесь осуществляется не в зависимости от истинности или ложности условия, а является вычислимым. Переключатель позволяет заменить несколько операторов развилки (в силу этого его ещё называют оператором множественного ветвления).
В конструкции switch вычисляется выражение K и выбирается ветвь, значение метки которой совпадает со значением K. После выполнения выбранной ветви происходит выход из конструкции switch по метке break. Если в последовательности нет метки со значением, равным K, то управление передается по метке default, если он присутствует, если же его нет, то следующему за переключателем оператору.
Запись переключателя:
switch (K)
{
case константа1: опрераторы1; break;
case константа2: опрераторы2; break;
...
default: опрераторы_default
}
Любая из указанных серий операторов может состоять как из единственного оператора, так и нескольких (в этом случае, как обычно, операторы, относящиеся к одной метке, должны быть заключены в операторные скобки {...}).
Задача 1. В старояпонском календаре был принят двенадцатилетний цикл. Годы внутри цикла носили названия животных: крысы, коровы, тигра, зайца, дракона, змеи, лошади, овцы, обезьяны, петуха, собаки и свиньи. Написать программу, которая позволяет ввести номер года и печатает его название по старояпонскому календарю. Справка: 1996 г. — год крысы — начало очередного цикла.
Поскольку цикл является двенадцатилетним, поставим название года в соответствие остатку от деления номера этого года на 12. function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} }
Листинг решения
// программа горосокоп #include <iostream.h> void main() { int year; cout << "введите год: "; cin >> year; switch (year%12) { case 0: cout << "Год Обезьяны"; break; case 1: cout << "Год Петуха"; break; case 2: cout << "Год Собаки"; break; case 3: cout << "Год Свиньи"; break; case 4: cout << "Год Крысы"; break; case 5: cout << "Год Коровы"; break; case 6: cout << "Год Тигра"; break; case 7: cout << "Год Зайца"; break; case 8: cout << "Год Дракона"; break; case 9: cout << "Год Змеи"; break; case 10: cout << "Год Лошади"; break; case 11: cout << "Год Овцы"; break; } } |
Задача 2. Найти наибольшее из двух действительных чисел, используя переключатель. function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} }
Листинг решения
// программа максмум #include <iostream.h> void main() { int x,y,max; cout << "Введите два неравных числа"; cin >> x >> y; switсh (x>y) { case 1: max = x; case 0: max = y; } cout << "Максимальное из них есть " << max; } |
Контрольные вопросы и задания
- Когда возникает необходимость в организации развилки?
- Какая развилка называется полной? неполной?
- Выражение какого типа может выступать в качестве условия при организации развилки? Какие значения принимают такие выражения?
- Могут ли в полной развилке не выполниться операторы ни по одной из ветвей? выполниться по обеим ветвям?
- Записать примеры 1-3 по теме "переключатель" с помощью условного оператора. Сколько развилок понадобилось в каждом из случаев?
- В каком случае целесообразно использовать переключатель?
- Используя переключатель, решить задачу: "Определить знак заданного целого числа".
Циклы
Командой повторения или циклом называется такая форма организации действий, при которой одна и та же последовательность действий повторяется до тех пор, пока сохраняется значение некоторого логического выражения. При изменении значения логического выражения на противоположное повторения прекращаются (цикл завершается).
Для организации цикла необходимо выполнить следующие действия:
- перед началом цикла задать начальное значение параметра;
- внутри цикла изменять параметр цикла с помощью оператора присваивания;
- проверять условие повторения или окончания цикла;
- управлять циклом, т.е. переходить к его началу, если он не закончен, или выходить из цикла в противном случае.
Различают циклы с известным числом повторений (цикл с параметром) и итерационные (с пред- и постусловием).
В цикле с известным числом повторений параметр изменяется в заданном диапазоне.
Если в цикле изменяется простая переменная, то она является параметром цикла; если в цикле изменяется переменная с индексом, то индекс этой переменной является параметром цикла.
Для организации цикла с известным числом повторений в C++ используется оператор for.
Структура цикла, организованного с помощью этого оператора, имеет вид:
for (выражение_1; выражение_2; выражение_3) тело_цикла
Здесь выражение_1 — инициализирующее; выражение_2 - аналог логического завершения (пока не равно нулю); выражение_3 - изменяет параметры цикла. Каждое выражение может состоять из нескольких операторов разделенных оператором запятой.
Все операторы "выражения" могут быть пропущены, но при этом внутри цикла должен иметься их аналог. Например конструкция
for(;;)
означает бесконечный цикл.
Задача 1. Дано натуральное n, действительное x. Вычислить
Разработаем алгоритм решения задачи:
- ввести данные - количество слагаемых n и число x;
- присвоить переменной, в которой будем хранить степени sin x, значение 1; S := 0;
- присвоить параметру цикла значение 1;
- если значение параметра цикла меньше n, перейти к следующему пункту, иначе к п. 9;
- вычислить очередную степень sin x;
- добавить вычисленное значение к сумме;
- увеличить параметр цикла на 1;
- перейти к п.4;
- вывести на печать сумму S;
- конец.
function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} } Листинг решения
// Программа вычисления суммы степеней sin x} #include <iostream.h> #include <math.h> void main() { float S, X, Pr; int N; cout << "Введите число слагаемых и x: "; cin >> N >> X; Pr = 1; S = 0; for(int i=1; i<=N; i++) { Pr *= sin(X); S += Pr; } cout.width(4); cout << "Сумма равна " << S; } |
Для организации цикла с неизвестным количеством повторений используются цикл с предусловием и цикл с постусловием
while (выражение) <тело цикла>;
do <тело цикла> while (выражение);
Для оператора цикла с предусловием проверяется значение логического выражения, если оно имеет значение отличное от нуля, то операторы, входящие в цикл, выполняются, в противном случае осуществляется выполнение оператора, следующего за циклом.
Цикл с постусловием выполняется хотя бы один раз. Затем проверяется значение логического выражения, если оно отлично от нуля, то операторы, входящие в цикл, выполняются, в противном случае осуществляется выход из цикла.
Входить в цикл можно только через его начало, т.е. нельзя входить внутрь цикла с помощью управляющего оператора, т.к. в этом случае параметр цикла не определен.
Задача 2. Найти наименьший номер члена последовательности, для которого выполняется условие |an-an-1| < e, где an=arctg an-1+1, a1=0. Вывести на экран этот номер и все элементы ai (i = 1, 2, ..., n).
Поскольку по ходу решения задачи необходимо знать an и an-1, будем запоминать их соответственно в переменных ANew и AOld.
function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} } Листинг решения
// программа последовательность #include <iostream.h> #include <math.h> void main() { int N; float Eps, AOld, ANew; AOld = 0; ANew = atan(AOld) + 1; N = 2; cout << AOld << " " << ANew; while(fabs(ANew - AOld) >= Eps) { AOld = ANew; ANew = atan(AOld) + 1; cout << " " << ANew; N++; } cout << "Искомый номер " << N; } |
Внутрь одного цикла может входить один или несколько других. При этом охватывающий цикл называется внешним, а вложенные циклы — внутренними. Правила организации как внешнего, так и внутренних циклов такие же, как и простого цикла.
Задача 3. На интервале [2; n] найти натуральное число с максимальной суммой делителей.
Предлагаемая задача может быть отнесена к классу «задачи целочисленной арифметики», где аргументы, результаты и промежуточные величины относятся к целому типу. Следует заметить, что в такого рода задачах довольно часто используются операции деления нацело и деления с остатком; наиболее типичной подзадачей является определение количества цифр в записи числа.
Алгоритм решения задачи:
- ввести число n;
- переменной для хранения максимальной суммы делителей присвоить значение 1 (это сумма делителей числа 1);
- запомнить число с максимальной суммой делителей;
- параметру цикла I присвоить значение 2;
- если I больше n, перейти к п. 13, иначе - к следующему пункту;
- переменной для хранения очередной суммы делителей присвоить значение 0;
- параметру цикла K присвоить значение 1;
- если K больше I/2, перейти к п. 11, иначе - к следующему пункту;
- если I делится на K без остатка, добавить K к текущей сумме делителей;
- увеличить K на 1 и перейти к п. 8;
- сравнить текущую сумму делителей с максимальной, если максимальная меньше, запомнить новое значение и число, соответствующее этой сумме;
- увеличить I на 1 и перейти к п. 5;
- вывести число с максимальной суммой делителей и эту сумму;
- конец.
function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} } Листинг решения
// программа максимальная сумма делителей #include <iostream.h> #include <math.h> void main() { int N, Sum_Max, Sum, Ch; cout << "Введите число N: "; cin >> N; Sum_Max = 1; /*Максимальная сумма делителей*/ Ch = 1; /*Число с максимальной суммой делителей*/ for( int i = 2; i<= N; i++) /*Это цикл по количеству чисел*/ { Sum = 0; for (int k= 1; k<= i/2 + 1; k++) /*В этом цикле находим сумму делителей*/ if(i % k == 0) /*Если i нацело делится на k, то k - делитель i*/ Sum += k; Sum += i; if (Sum > Sum_Max) { Sum_Max = Sum; Ch = i; } } cout << "Максимальную сумму делителей " << Sum_Max << " имеет число " << Ch; } |
Задача 4. Дано натуральное число n. Получить все простые делители этого числа.
function changeProof(proofobj) { if (proofobj.style.display=='none') {proofobj.style.display='inline'} else {proofobj.style.display='none'} } Листинг решения
// Программа отыскания простых делителей данного числа #include <iostream.h> #include <math.h> void main() { int N, I, Vsp, Log_Per, Priznak; cout << "Введите натуральное число: "; cin >> N; Priznak = 1; /*Признак того, не является ли введенное число простым*/ /*Пока параметр цикла не превысил квадратного корня из данного числа, продолжаем поиск простых делителей*/ for(I = 2; I<= floor(sqrt(N)); I++) if (N % I == 0) { Priznak = 0; /*Введенное число не является простым*/ Log_Per = 0; /*Логическая переменная, принимающая значение True, если нашлись делители I, отличные от 1 и I*/ Vsp = 2; do { if (I % Vsp == 0) Log_Per = 1; Vsp++; } while ((Vsp < I) && (Log_Per!=1)); if ((Log_Per!=1)||(i==2)) cout << I; /*Если число I простое, печатаем его*/ } if (Priznak) cout << N; } |
Предлагаем читателю самостоятельно разобраться с представленным решением.
Контрольные вопросы и задания
- Назовите отличия итерационных циклов и цикла с параметром.
- Какова структура оператора цикла с параметром? Как выполняется цикл с парметром?
- Какого типа должны быть пареметр цикла, его начальное и конечное значения в цикле с параметром в языке Pascal?
- Могут ли параметр цикла, его начальное и конечное значения в цикле с параметром в языке C++ быть разных типов? Обоснуйте ответ.
- Может ли один цикл быть вложен внутрь другого? Если да, то какова глубина этой вложенности?
- Какова структура циклов с пред- и постусловием? как выполняются эти циклы?
- Каково минимальное и максимальное количество исполнений циклов с пред- и постусловием? С чем это связано?
- Сколько раз исполнится фрагмент программы?
for (i = 1; i <= -1; i++) k = k * i;
- Сколько раз исполнится фрагмент программы?
for (i = -1; i <= 1 ; i++) k = k * i;
- Сколько раз исполнится фрагмент программы?
for (i = 1; i <= -1; i--) k = k * i;
- Сколько раз исполнится фрагмент программы?
M = 123; While (M != 0) M = M % 10;