Цикли

Оператори за цикли

1.Въведение

Да се разгледа следната задача:

Задача 1: Да се състави програма, която въвежда цяло число x и извежда на екрана първите три цели числа, по-големи от x.

Примерен вход: x=21                                    Примерен изход:  22

23

24

#include<iostream.h>

int main()
{
	int x;
	cout<<"x=";
	cin>>x;
	cout<<x+1<<endl;
	cout<<x+2<<endl;
	cout<<x+3<<endl;
	return 0;
}

При вход от клавиатурата 21 програмата ще изведе числата 22, 23 и 24.

Представете си как ще се реши задачата, ако нейното условие изискваше изход не на 3, а на 100 числа? Ами на 1000?

Не е логично да използваме горния начин, тъй като това означава да изпишем най-малко 100 реда код (съответно 1000 реда код). Разглеждайки подробно решението, забелязваме, че има зависимост между операторите, извеждащи числата. Тази зависимост може да се представи като цикличен алгоритъм.

Алгоритъм, в който дадена група от действия се изпълнява необходимият брой пъти, докато е изпълнено дадено условие, се нарича цикличен (цикъл).

 

Цикълът съдържа четири основни съставни части:

  • Инициализация – задава се начална стойност на някои променливи, участващи в цикъла;
  • Тяло на цикъла – съдържа действията, които се повтарят многократно;
  • Актуализация – обновяване стойностите на участващите величини и подготовка за следващото изпълнение на цикъла;
  • Условие за край на цикъла – гарантира прекратяване изпълнението на цикъла.

Едно изпълнение на тялото на цикъла се нарича итерация.

 

В зависимост от това дали броят на повторенията на тялото на цикъла е предварително известен или не, цикличните процеси се делят на два основни вида:

  • индуктивни (броят на повторенията е известен предварително);
  • итеративни (броят на повторенията не е известен предварително).

За създаване на циклични алгоритми в езика С++ се използват три оператора. При използването им от съществено значение е кои действия ще се повтарят и до кога ще се повтарят те.

 2. Оператор за броячен цикъл for

Синтаксис:

for(<инициализация>;<условие>;<корекция>) <оператор>;

където:

<инициализация> задава началната стойност на една или няколко променливи;

<условие> е логически израз;

<корекция> е един или няколко оператора, които обикновено влияят на <условие>;

<оператор> е произволен допустим за езика С++ оператор, който се нарича тяло на цикъла. Допустимо е тялото на цикъла да бъде изградено от два и повече оператори, като в този случай те се ограждат в операторни скоби.

{
    <оператор_1>;
    <оператор_2>;
    …
    <оператор_N>;
}

Семантика:

  1. Изпълнението на оператора започва с частта <инициализация>.
  2. Изчислява се стойността на <условие>.
  3. Ако тази стойност е false, цикълът прекратява своето действие. Ако стойността е true, се изпълнява <оператор> (тялото на цикъла).
  4. Изпълняват се операторите в частта <корекция> и се преминава към стъпка 2.

Ще решим Задача 1 чрез цикъл for, но не конкретно за първите 3 числа, по-големи от x, а за произволен брой такива. Колко да бъдат те ще се зададе чрез променлива n в програмата.

Примерен вход: x=15                                   Примерен изход: 16

                              n=6                             17

18

19

20

21

Решение:

#include<iostream.h>

int main()
{
	int x,n;
	cout<<"x=";
	cin>>x;
	cout<<"n=";
	cin>>n;
	for(int i=1;i<=n;i++) cout<<x+i<<endl;
	return 0;
}

Цикълът for oсновно се използва за индуктивни циклични процеси, а променливата i от горния пример се нарича управляваща променлива на цикъла. Тя служи предимно за задаване броя на повторенията на цикъла. В много от задачите обаче тази променлива участва и в тялото му. Един пример за това е следната задача:

 

Задача 2: Да се състави програма, която въвежда от клавиатурата естествено число n и извежда всички естествени числа, по-малки от n и кратни на 5.

 

Примерен вход: n=14                                    Примерен изход:  5

10

Решение:

#include<iostream.h>

int main()
{
	unsigned int n;
	cout<<"n=";
	cin>>n;
	for(int i=1;i<=n;i++) if(i%5==0) cout<<i<<endl;
	return 0;
}

 

По-ефективно решение може да се направи, като се знае, че първото естествено число, което се дели на 5 без остатък, е 5, а всяко следващо е с 5 по-голямо от предишното. Опитайте се да решите самостоятелно задачата по този начин.

 

Задача 3: Да се състави програма, която въвежда от клавиатурата петцифрено естествено число k и го извежда в обратен ред на цифрите му.

Примерен вход: k=78213                            Примерен изход:  31287

 

За решението на задачата ще ползваме следния алгоритъм:

1). Последната цифра на k се отделя като остатък при деление на k с 10 и се извежда на екрана.

2). Посредством целочислено деление на k с 10 се получава нова стойност за k, която има една цифра по-малко.

3). Предните две действия се повтарят 5 пъти, колкото са цифрите на числото.

Решение:

//Program_3a.cpp;

#include<iostream.h>

int main()
{

	unsigned long int k;
	cout<<"k=";
	cin>>k;
	for(int i=1;i<=5;i++)
	{
		cout<<k%10;     //Извежда последната цифра
		k=k/10;    //Премахва последната(изведена вече)цифра
	}

	return 0;
}

 3. Цикъл с предусловие

Синтаксис:

while(<условие>) <оператор>;

където:

<условие> е логически израз (най-често израз за сравнение), чийто резултат е от логически тип. Нарича се условие за край на цикъла.

<оператор> (тяло на цикъла) е произволен допустим за езика С++ оператор. В случай че в тялото на цикъла е необходимо да бъдат използвани два или повече оператора, се използва конструкцията блок:

{
    <оператор_1>;
    <оператор_2>;
    …
    <оператор_N>;
}

Семантика:

  1. Изчислява се стойността на логическия израз <условие>.
  2. Ако тази стойност е false цикълът прекратява своето действие. Ако стойността е true, се изпълнява тялото на цикъла и се преминава към стъпка 1.

 

Проверката на условието се извършва преди тялото на цикъла, което означава, че тялото може да не се изпълни нито веднъж. В тялото на цикъла трябва да има оператори, които водят до промяна стойността на логическия израз <условие>, за да не се получи зацикляне.

Ако трябва да се реши Задача 3 за число с произволен брой цифри, процесът вече е итеративен, т.е. не се знае броят на повторенията. Поради тази причина по-удобен за ползване e операторът за цикъл с предусловие. За решаване на задачата ще използваме алгоритъм, подобен на вече описания.

1). Последната цифра на k се отделя като остатък при деление на k с 10 и се извежда на екрана.

2). Посредством целочислено деление на k с 10 се получава нова стойност за k, която има една цифра по-малко.

3). Предните две действия се повтарят, докато k получи стойност нула. Това е условието за край на цикъла.

Защо тялото на този цикъл ще се изпълни толкова пъти, колкото са цифрите на числото?

Примерен вход: k=845                                 Примерен изход:  548

Примерен вход: k=392721                         Примерен изход:  127293

 

Кодът на задачата изглежда по следния начин:

Решение:

//Program_3b.cpp;

#include<iostream.h>

int main()
{
	unsigned long int k;
	cout<<"k=";
	cin>>k;

	while(k!=0)
	{
		cout<<k%10;  //Извежда последната цифра
		k=k/10;      //Премахва последната цифра
	}
	return 0;
}

4. Цикъл със следусловие

Синтаксис:

do
<оператор>;
while(<условие>);

където:

<условие> е логически израз (най-често израз за сравнение), чийто резултат е от логически тип. Нарича се условие за край на цикъла.

<оператор> (тяло на цикъла) – произволен допустим за езика С++ оператор. В случай, че в тялото на цикъла е необходимо да бъдат използвани два или повече оператора, те се ограждат в операторни скоби:

{
    <оператор_1>;
    <оператор_2>;
    …
    <оператор_N>;
}

Семантика:

  1. Изпълнява се тялото на цикъла – <оператор>.
  2. Изчислява се стойността на логическия израз – <условие>.
  3. Ако тази стойност е false, цикълът прекратява своето действие. Ако стойността е true, се преминава към стъпка 1.

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

Задача 4: Да се напише програма, която въвежда от клавиатурата естествено число n и цифра p. Ако в записа на числото n се съдържа цифра p, да се изведе на монитора “да”, в противен случай – “не”.

Примерен вход: n=72715                            Примерен изход: не

                              p=6

Примерен вход: n=59213                            Примерен изход: да

                              p=2

Решение:

#include<iostream.h>

int main()
{
	unsigned long int n,p,k;
	cout<<"n=";
	cin>>n;
	cout<<"p=";
	cin>>p;

	do
	{
		k=n%10; //Намира последната цифра
		n=n/10; //Премахва последната цифра
	}
	while((k!=p)&&(n!=0));

	if(k==p)cout<<"да"<<endl;
	else cout<<"не"<<endl;

	return 0;
}

 5. Основни алгоритми, реализиращи се с циклични оператори

  • Проверка за коректност на входни данни

В много от задачите се налага да се въвеждат данни, които отговарят на предварително зададени условия. Следната задача показва коректно съставено условие за проверка дали въведено число е в даден интервал. За реализацията на задачата е подходящо да се ползва цикъл while.

Задача 5: От клавиатурата се въвежда естествено число n в интервала 5<=n<=50. Ако числото не е в този интервал да се изисква ново въвеждане. При коректно зададен вход за n да се изчисли и изведе квадрата му.

Решение:

//Program_5.cpp;
#include<iostream.h>

int main()
{
	int n;
	cout<<„n=";
	cin>>n;
	while((n<5)||(n>50))
	{
		cout<<„Некоректни данни! Въведи отново n!"<<endl;
		cout<<„n=";
		cin>>n;
	}

	cout<<n*n<<endl;
	return 0;
}

Опитайте се да направите проверка за коректност на входни данни като използвате цикъл do … while.

  • Намиране на максимален и минимален елемент в редица от числа

За намиране на максимален и минимален елемент може да се разгледат два случaя. В първия броят на числата в редицата е предварително известен, а във втория – броят на числата от редицата не е известен. За решението е удобно да се декларират три променливи с имена max, min и chislo. Първата да служи за съхранение на максималния елемент, втората – за минималния, а променливата chislo – за въвеждане на числата от редицата.

Задача 6: Да се напише програма, която въвежда от клавиатурата естествено число n и след него n на брой реални числа. Да се изведат максималното и минималното от тях.

Примерен вход: 5                                                       Примерен изход: Min=-45

                              -6 -2 -45 -7 -1.3                   Max=-1.3

Решение:

#include<iostream.h>

int main()
{
	int n;
	cin>>n;
	double max,min,chislo;
	cin>>chislo;
	min=chislo;      // min и max се инициализират
	max=chislo;      // с първата въведена стойност

	for(int i=1;i<=n-1;i++)
	{
		cin>>chislo;
		if(chislo>max) max=chislo;
		if(chislo<min) min=chislo;
	}
	cout<<"Min="<<min<<endl;
	cout<<"Max="<<max<<endl;

	return 0;
}

 

Задача 7: Да се напише програма, която въвежда последователно от клавиатурата реални числа до момента, в който се въведе числото нула. Да се изведат на монитора минималното и максималното от въведените числа, без да се включва нулата.

Примерен вход: 5.1

6

2.2

8.4

2

–3

0

Примерен изход: Min=-3

                              Max=8.4

Решение:

#include<iostream.h>

int main()
{

      	double max,min,chislo;

      	cin>>chislo;
  		min=chislo;      // min и max се инициализират

		max=chislo;      // с първата въведена стойност

      	while(chislo!=0)
      	{

          	if(max<chislo) max=chislo;
         	if(min>chislo) min=chislo;
        	cin>>chislo;
    	 }

      	cout<<"Min="<<min<<endl;
     	cout<<"Max="<<max<<endl;
      	return 0;
}
  • Намиране на сумата и произведението на редица от числа

За намиране сума на n на брой числа се използва следният алгоритъм:

  • Декларира се променлива sum, в която ще се натрупва сумата.
  • Променливата sum се инициализира с нула.
  • Въвежда се поредното число и стойността му се добавя към тази на sum.
  • Стъпка 3 се извършва n пъти, колкото е броят на числата.
  • Извежда се стойността на променливата sum, която е натрупаната сума.

Този алгоритъм може да се използва и за намиране на произведението на числа. Променливата, в която ще се натрупва произведението, трябва да се инициализира с 1. Защо?

 

Задача 8: Да се състави програма, която въвежда от клавиатурата естествено число n и след него n на брой реални числа. Да се изведе сумата и произведението им.

За решението на задачата е удобно да се декларират три променливи с имена sum, pr и chislo. Първата служи за натрупване на сумата, а втората – за натрупване на произведението на числата. Променливата chislo служи за въвеждане на числата от редицата. Променливата sum се инициализира със стойност нула, а променливата pr – със стойност 1.

Примерен вход: 4                                           Примерен изход: Sum=16.7

                              1.2                                                                          Pr=26.5

                              -3

                              15

-0.5

 

Решение:

#include<iostream.h>

int main()
{
       double sum,pr,chislo;
       sum=0; //Инициализиране на променивата за сума
       pr=1;  //Инициализиране на променивата за произведение
       int n;
       cin>>n;

       for(int i=1;i<=n;i++)
       {
            cin>>chislo;
            sum=sum+chislo;//Натрупване на сумата
      		pr=pr*chislo;//Натрупване на произведението
       }

       cout<<"Sum="<<sum<<endl;
       cout<<"Pr="<<pr<<endl;
       return 0;
}

 6. Оператор break

Задача 9: Да се напише програма, която въвежда от клавиатурата реално число k и след него n на брой реални числа. Ако числото k се среща сред въведените след него n числа, на екрана да изведе съобщение “да”, в противен случай – “не”.

Тъй като броят на повторенията е известен предварително, е удобно да се използва операторът за цикъл for. При реализацията на алгоритъма в момента, в който се въведе число, равно на търсеното число k, цикълът може да се прекъсне, защото продължаването му става излишно. В такъв случай се използва операторът за прекъсване на цикъл – break.

Оператор break прекратява изпълнението на оператор за цикъл, който го съдържа.

За решението на задачата ще използваме допълнителна променлива, наречена флаг. Такава променлива (flag) се използва често в програмирането. Тя служи да маркира промяната на някакво условие, като променя своята стойност от 0 на 1 и обратно.

Решение:

#include<iostream.h>

int main()
{
	int k;
	cin>>k;
	int n,flag=0;
	double chislo;
	for(int i=1;i<=n;i++)
	{
		cin>>chislo;
		if(chislo==k)
		{
			flag=1;   /*Ако числото е равно на въведеното
          			   flag присвоява стойност 1*/
			break;    //Прекъсва изпълнението на цикъла
		}
	}

	if(flag==1)cout<<"да"<<endl;
	else cout<<"не"<<endl;
	return 0;
}

 7. Вложени цикли

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

  • Управляващите променливи на двата цикъла са различни и не трябва да се актуализират едновременно.
  • Вътрешният цикъл трябва да се съдържа изцяло в тялото на външния цикъл.
  • От тялото на вътрешен цикъл управлението може да се предаде на оператор от тялото на външния цикъл, но обратното не е възможно.
  • Външният и вътрешният цикъл могат да са както от един и същи вид, така и от различни видове.
  • Променливите, декларирани в тялото на вътрешния цикъл, не се “виждат” извън него. Те могат да се ползват само в този цикъл.

 

Задачa 10: Да се напише програма, която въвежда от клавиатурата естествени числа, по-големи или равни на 3, като въвеждането продължава до въвеждане на числото нула. Програмата трябва да изведе броя на простите числа измежду въведените.

Примерен вход: 4 11 13 12 0

Примерен изход: Брой прости числа:2

В решението на задачата се използват три променливи – chislo, br и flag. В chislo се записва всяко поредно число. Променливата br се ползва за брояч – в началото има стойност нула, а при всяко намиране на просто число се увеличава с единица (br++). Променливата flag служи за маркиране на намерените прости числа.

Решението е реализирано с два вложени цикъла – във външния (do…while) се въвеждат числата, а във вътрешния (for) се проверява дали текущото число е просто.

Решение:

#include<iostream.h>

int main()
{
	unsigned int chislo,br=0,flag;
	do
	{
		flag=1;
		cin>>chislo;    
		//Следва проверка дали числото е просто
		for(int i=2;i<=chislo/2;i++)
		if(chislo%i==0)
   		{
			flag=0;
			break; /*При първото срещане на делител прекъсва
			цикъла for и променя стойността на флага.*/
   		}
		//Ако флагът не се е променил, значи числото е просто
		if(flag==1) br++;
	}while (chislo!=0);
	cout<<"Брой прости числа:"<<br<<endl;
	return 0;

}