Programiranje Mat Inf Gim 1 Mak

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 346

ЃОРЃИ ЈОВАНЧЕВСКИ

МИЛЕ ЈОВАНОВ
ЕМИЛ СТАНКОВ

ПРОГРАМИРАЊЕ

ЗА I ГОДИНА
МАТЕМАТИЧКО – ИНФОРМАТИЧКА
ГИМНАЗИЈА

Скопје, 2022
Ѓорѓи Јованчевски
Миле Јованов
Емил Станков

ПРОГРАМИРАЊЕ

УЧЕБНИК ЗА I ГОДИНА
Математичко-информатичка гимназија

Скопје, 2022
ПРОГРАМИРАЊЕ
УЧЕБНИК ЗА I ГОДИНА
Математичко-информатичка гимназија

Автори:
Ѓорѓи Јованчевски,
Миле Јованов,
Емил Станков,
Рецензенти:
Дејан Спасов
Билјана Пејовска
Викторија Доказа
Јазична редакција:
Виолета Јанушева
Јованка Јованчевска
Стручна редакција:
Џеваир Беќири

Уредник:
Елена Стефановска
Тамара Јовановиќ Нешовска

Графичко и Техничко уредување:


Владанка Колева, Евгенија Павлова – АРС СТУДИО
Место и година на издавање: Скопје,2022

Издавач:
Министерство за образование и наука на Република Северна Македонија, ул.„Св.
Кирил и Методиј“ бр.54, 1000 Скопје.Со одлука број 26-304/1 од 08.07.2022 година на
Националната комисија за учебници, се одобрува употребата на овој учебник.

CIP:
Содржина

СОДРЖИНА

Вовед

1. ОСНОВИ НА ПРОГРАМИРАЊЕ 1
1.1 Алгоритми 3
Алгоритамски чекори 4
Вежби 5
1.2 Програми 5
Вежби 6
1.3 Претставување на алгоритмите 7
Структурирани алгоритми 9
Вежби 12
1.4 Програмирање 12
1.5 Програмски јазици 14
Виши програмски јазици 16
Вежби 21
1.6 Интегрирана околина за програмирање 22
Интегрирана околина за програмирање Code::Blicks 23
Вежби 27
1.7 Алгоритамски контролни структури 31
Редоследна контролна структура 31
1.8 Јазикот С++ 32
Елементи на јазикот С++ 33
Вежби 36
1.9 Податоци и променливи 37
Вежби 40
1.10 Типови податоци 41
Целоброен тип податоци 41
Знаковен тип податоци 43
Реален тип податоци 43
Логички тип податоци 45
1.11 Читање и печатење на податоци 46
Вежби 51
Резиме 54

i
ПРОГРАМИРАЊЕ

2. ОСНОВНИ КОНТРОЛНИ СТРУКТУРИ 55


2.1 Споредбени и логички изрази 57
Логички операции и изрази 57
Вежби 58
2.2 Алгоритамска контролни структури за избор од две
можности 58
Вежби 60
2.3 Контролни наредби за избор од две можности 61
Контролна наредба за избор if 61
Контролна наредба за избор if-else 62
Условен оператор 67
Вежби 68
2.4 Алгоритамска контролна структура за избор од повеќе
можности 69
Вежби 70
2.5 Контролна наредба за избор switch 71
Вежби 73
2.6 Алгоритамска контролнa структурa за повторување со излез на
почетокот од циклусот 75
Вежби 77
2.7 Контролна наредба за повторување while 78
Оператори за инкрементирање и за декрементирање 78
Вежби 82
2.8 Алгоритамска контролнa структурa за повторување со излез на
крајот од циклусот 84
2.9 Контролна наредба do-while 85
Вежби 87
2.10 Алгоритамска контролнa структурa за повторување со броење на
циклусите 88
Вежби 92
2.11 Контролна наредба for 93
Вежби 98
Резиме 101

3. ОСНОВНА СЛОЖЕНОСТ НА АЛГОРИТМИ 103


Вежби 113
Резиме 114

4. ПОТПРОГРАМИ - ФУНКЦИИ 115


4.1 Подалгоритми 117
4.2 Функциски подалгоритми и потпрограми 119
ii
Содржина

Функциски подалгоритми 119


Функции со повратна вредност 122
Вежби 126
4.3 Процедурални подалгоритми и потпрограми 128
Процедурални подалгоритми 128
Функции без повратна вредност 132
Референтни параметри 134
Вежби 138
4.4 Глобални, локални и статички променливи 139
4.5 Библиотечни функции 145
Математички функции 146
Функција за генерирање случајни броеви 150
Функции за работа со знаци 151
Вежби 152
Резиме 152

5. НИЗИ 155
5.1 Еднодимензионални низи 156
Решени задачи 164
Наредба for базирана на опсег 169
Вежби 170
Прашања 154
5.2 Сортирање на низа и класен шаблон vector 172
Вежби 175
5.3 Текстуални низи 176
Решени задачи 183
Шаблонот string 185
Вежби 187
5.4 Дводимензионални низи 188
Решени задачи 194
Вежби 198
Резиме 199

6. ДАТОТЕКИ 201
Влезни датотеки 204
Излезни датотеки 205
Влезно-излезни датотеки 206
Решени задачи 209
Вежби 218
Резиме 220

iii
ПРОГРАМИРАЊЕ

7. ПРЕТСТАВУВАЊЕ НА ПОДАТОЦИТЕ ВО КОМПЈУТЕРОТ 221


7.1 Бројни системи 222
Вежби 2227
7.2 Претставување на податоците во компјутерот 227
7.2.1 Претставување на знаците 228
7.2.2 Претставување на сликите 230
7.2.3 Претставување на звукот 231
7.2.4 Претставување на броевите 231
Вежби 236
7.3 Операции со бинарни броеви 236
Вежби 240
Резиме 241

8. КЛАСИ И ОБЈЕКТИ 243


8.1 Дефинирање класи и декларирање објекти 250
8.2 Директен пристап до членови на класата 258
Вежби 259
Резиме 260

9. ДИНАМИЧКИ СТРУКТУРИ НА ПОДАТОЦИ 261


9.1 Листи 263
9.2 Линеарни секвенцијални листи 263
9.2.1 Куп 264
9.2.2 Ред 268
Вежби 274
9.3 Стандардна библиотека на шаблони на С++ 272
Вежби 273
9.4 Контејнери 273
Вежби 274
9.5 Итератори 275
Вежби 276
9.6 Класен шаблон array 276
9.7 Класен шаблон vector 279
Вежби 280
9.8 Пар и мапа 282
Вежби 283
9.9 Контејнери адаптери 284
Вежби 285
9.10 Алгоритми од стандардната библиотека на шаблони на С++ 285
Вежби 289
Резиме 290

iv
Содржина

10. АЛГОРИТМИ КАЈ НИЗИ И ГРАФОВИ 291


10.1 Барање податоци 292
10.1.1 Секвенцијално барање 292
10.1.2 Барање со чекор 293
10.1.3 Бинарно барање 297
Вежби 302 0
10.2 Сортирање податоци 300
10.2.1 Сортирање со споредување на елементите 302
10.2.2 Сортирање со наоѓање на најмалиот (или најголемиот)
елемент 303
10.2.3 Сортирање со вметнување 305
10.2.3.1 Сортирање со линеарно вметнување 305
10.2.3.2 Сортирање со бинарно вметнување 308
10.2.4 Сортирање со меурче 310
10.2.5 Сортирање со кофи 313
Вежби 315
10.3 Графови 316
10.3.1 Темиња, ребра и типови на графови 316
10.3.2 Претставување на граф 318
10.3.3 Пребарување низ граф прво по длабочина 320
10.3.4 Пребарување низ граф прво по широчина 324
Вежби 327
Резиме 328

ДОДАТОК 331
А Основни типови податоци во С++ 331
Б Знаци ASCII 332

ЛИТЕРАТУРА 333

v
ПРОГРАМИРАЊЕ

vi
Вовед

Вовед
Овој учебник претставува почетен курс за изучување на програмира-
њето. Тој во целост ја следи и ја покрива Наставната програма за предметот
Програмирање од прва година за Математичко-информатичката гимназија и е
плод на богатото долгогодишно искуство на авторите во пренесување на веш-
тините за програмирање.
Учебникот ги опфаќа основите на алгоритамското изразување на про-
блемите преку посебен псевдојазик, како и кодирањето во програмскиот јазик
С++.
Изучувањето на програмирањето го започнуваме со запознавање со ал-
горитмите, програмите и текстуалното и графичкото претставување на алго-
ритмите.
За кодирање на алгоритмите во јазик што го разбира компјутерот, на-
правени се т.н. програмски јазици. Програмските јазици се состојат од конечно
множество наредби. Да се научат наредбите на кој било програмски јазик не е
воопшто тешко, тешко е да се смисли постапка (алгоритам) за решавање на
конкретен проблем. Затоа, е воведен псевдојазик на македонски со кој попри-
родно се изразуваат алгоритмите и основните алгоритамски контролни струк-
тури.
Во првата глава ученикот се запознава со програмскиот јазик С++, прво
со неговите основни елементи, како: променливите, типовите податоци, на-
редбите за читање и за печатење и структурата на програма во јазикот С++.
Во втората глава се објаснети основните алгоритамски контролни (уп-
равувачки) структури за контрола и управување со текот на извршување на ал-
горитмите: контролните структури за избор и контролните структури за пов-
торување. Тие се доволни за да се изрази секој алгоритам. Нивната имплемен-
тација е објаснета и илустрирана преку соодветните наредби во програмскиот
јазик С++.
Во третата глава е дадено објаснување за сложеноста на алгоритмите
и за видовите на сложеност и е потенцирано дека сè уште има проблеми за кои
нема ефикасни алгоритми.
Четвртата глава се однесува на расчленување на задачите (проблеми-
те) на подзадачи, кои се изразени со подалгоритмите и со потпрограмите –
функциите во програмскиот јазик С++.
Во петтата глава се ученикот се запознава со првите сложени струк-
тури на податоци, и тоа: еднодимензионалните низи, текстуалните низи, пове-
ќедимензионалните низи, како и нивната имплементација во програмскиот јазик
С++. Преку запознавање со низите, ученикот ќе се стекне со знаења кои ќе му
овозможат решавање на посложени алгоритамски проблеми.

vii
ПРОГРАМИРАЊЕ

Шестата глава не се однесува на програмирањето, туку е запознавање


на учениците со претставувањето на податоците во компјутерот за да стек-
нат претстава за начинот на кој може компјутерот да обработува разни ви-
дови податоци: броеви, текст, слика и звук.
Во седмата глава се изучува како се користат текстуалните датотеки
во програмирањето, а осмата глава претставува воведување на учениците во
објектно ориентираното програмирање.
Во деветтата и во десеттата глава ученикот се воведува во динамич-
ките структури на податоци кои се користат во програмирањето, во нивното
претставување, како и во алгоритмите за работа со нив.
Сметаме дека изложениот материјал е доволен за секој почетник во
програмирањето, а неговото совладување не е тешко бидејќи настојувавме да
го изложиме на лесен и достапен начин, со многу примери и решени задачи.
Вашите забелешки и сугестии ќе бидат добредојдени во натамошното
надградување на учебникот.

Авторите

Забелешка: Во соработка со лекторот, авторите се обидоа да изразат


на македонски јазик некои информатички термини, но и термини од програм-
скиот јазик С++. Тие, можеби, ќе звучат невообичаено за некои читатели, но
сметаме дека е крајно време да се поработи на проблемот на употребата на
информатичките термини во македонскиот јазик.
Конкретно, поради специфичноста на овој програмски јазик, но и на ја-
зикот што се употребува во информатиката кај нас, воопшто, одредени тер-
мини само се транскрибираат на македонски јазик. Во учебникот се почитува
мислењето на авторите дека некои поими, поради нивната многузначност, во
овој програмски јазик треба да се напишат во форма која не соодветствува со
правилата за нивната употреба во македонскиот јазик.

viii
1. Основи на програмирање

1. ОСНОВИ НА ПРОГРАМИРАЊЕ
Во оваа глава ќе се запознаете со следното:

 Алгоритми, алгоритамски чекори, општи и детални алгоритми.


 Програма, програмски јазик и програмирање.
 Претставување на алгоритмите со псевдојазик и со блок-дијаграм
(стандардно, структурно, со UML-јазик).
 Фази на решавање задача со помош на компјутер.
 Програмски јазици, историски развој, видови, генерации, поделба.
 Преведувачи и интерпретатори.
 Елементи на интегрирани околини за програмирање.
 Интегрираната околина за програмирање Code::Blocks.
 Алгоритамски контролни структури, редоследна контролна структура.
 Елементи на јазикот С++. Изглед и објаснување на програма во С++.
 Величини, податоци, константи и променливи.
 Типови на податоци (целоброен, знаковен, реален, логички, наброив).
 Конверзија на типот, преименување на типот.
 Читање и печатење податоци, излезни секвенци.

Клучни зборови

bool Машински ориентирани јазици


char Модул
Code::Blocsks Модуларно програмирање
double Назабување
endl Наредба
float Неозначен број
int Објектно ориентирани јазици
include Објектно ориентирано програмирање
iostream Означен број
long Оператор
short Општ алгоритам
typedef Поврзувач
Unified Modeling Language Подзадача
Алгоритам Почеток
Алгоритамски чекор Преведувач

1
ПРОГРАМИРАЊЕ

Апликативна програма Преименување на типот


Апстрактни типови Приоритет на оператори
Асемблери Проблемски ориентирани јазици
Асембли Програма
Бит Програмер
Блок-дијаграм Програмирање
Величина Програмирање одгоре надолу
Виш програмски јазик Програмски јазик
Декларативни јазици Променлива
Детален алгоритам Процедурални јазици
Дибагер Псевдојазик
Знаковен тип Реален тип
И Резервирани зборови
Идентификатори Секвенца
Изворна програма Селекција
Извршна програма Семантика
ИИЛИ Симболи (мнемоници)
ИЛИ Симболички јазик
Императивни јазици Синтакса
Интерпретатори Системски програми
Исказ Скрипти
Итерација Скриптни јазици
Кодирање Софтвер
Коментар Спецификатор
Комплемент Стандардно графичко претставување
Константа Структурирани алгоритми
Корисничка програма Структурирано програмирање
крај Тип
Логички јазици Уредувач
Логички тип Функциски јазици
Машинска инструкција Целоброен тип
Машински јазик FALSE
Машински независни јазици TRUE

2
1. Основи на програмирање

1.1 Aлгоритми
Секој човек точно знае што треба да направи кога треба да си ја подготви
чантата за следниот ден, да се јави некому на телефон или да се сретне некаде со
пријателите. Но не е толку лесно да се инсталира кабелска телевизија, да се
пресмета волуменот на делот во машината за перење каде што се става облеката
или на делот за замрзнување во домашниот ладилник.
Човечките активности, во голем дел, можe да се извршат како редослед
од определен број одделни помали елементарни активности (активности за кои
не е потребно објаснување за да бидат извршени). За некои активности, тој ре-
дослед е сложен и тежок за паметење, па извршувањето не е воопшто лесно.
За да може еден изведувач да изврши дадена активност, тој треба да го
познава точниот редослед на елементарните активности што треба да се ис-
полнат. За таа цел, изведувачот треба да добие листа со инструкции за тоа какви
активности да преземе и по кој редослед. Таа листа со инструкции може да се
нарече алгоритам (англ. algorithm). Можеме да кажеме дека:
алгоритам е постапка од конечен број строго дефинирани дејства
(активности, операции) и точно зададен редослед за нивно извршување.
Поимот алгоритам ќе го објасниме подетално на примерот за наоѓање на
најголемиот број од три дадени броја. Можеме да ја примениме следнава пос-
тапка: ќе споредиме кои било два броја и поголемиот од нив ќе го споредиме со
третиот број. Поголемиот број при второто споредување е најголемиот од трите
броја.
Очигледно е дека постапката се состои од само две точно дефинирани
дејства (операции):
 Споредување на кои било два броја и одредување на поголемиот.
 Споредување на поголемиот број од првото споредување со третиот број
и одредување на поголемиот од нив.
За да се примени оваа постапка врз кои било три броја, потребно е тие да
бидат претходно зададени. Резултатот од постапката е најголемиот број. Тоа зна-
чи дека решавањето на некоја задача се состои во одредување на излезните
резултати со примена на одредена постапка – алгоритам врз влезните податоци.
Затоа, може да се рече дека:
алгоритам претставува постапка која се состои од конечно множество
точно дефинирани дејства (операции), применети врз влезните податоци по
строго пропишан редослед, со кои се доаѓа до излезни резултати.
Зборот алгоритам е земен од латинскиот јазик и претставува латински
превод на презимето Al‒Khwarizmi на арапскиот математичар од IX век Abu
Ja’far Muhammad ibn Musa al‒Khwarizmi, кој прв ги формулирал правилата за
извршување на четирите основни аритметички операции со арапски цифри.

3
ПРОГРАМИРАЊЕ

Алгоритамски чекори

Дејствата од кои се состои еден алгоритам се нарекуваат алгоритамски


чекори (англ. algorithms steps). Во зависност од тоа дали чекорите се поопшти
или подетални, алгоритамот може да биде општ или детален.
На пример, општиот алгоритам за задачата од претходната точка (одре-
дување на најголемиот од трите дадени броја), можеме да го запишеме како на
слика 1.1.1.
чекор 1: Задавање на трите броја.
чекор 2: Споредување на кои било два броја и наоѓање на поголемиот од нив.
чекор 3: Споредување на поголемиот број најден во чекор 2 со третиот број и
наоѓање на поголемиот од нив.
чекор 4: Печатење на резултатот.
Слика 1.1.1
Ако ги означиме броевите со a, b и c, поголемиот од a и b со p, а поголе-
миот од p и c со n, тогаш може да напишеме подетален алгоритам, како на слика
1.1.2.
чекор 1: Задавање на броевите a, b и c.
чекор 2: Ако a е поголем од b, тогаш p = a, инаку p = b.
чекор 3: Ако p е поголем од c, тогаш n = p, инаку n = c.
чекор 4: Печатење на n.
Слика 1.1.2
Рековме дека во секој алгоритам има влезни податоци и излезни ре-
зултати. Излезните резултати се добиваат со „трансформација“ на влезните пода-
тоци при извршувањето на алгоритамот чекор по чекор. Притоа, трансформа-
цијата не се врши секогаш директно, туку со посредство на меѓурезултати. Така,
во горниот алгоритам меѓурезултат е p, влезни податоци се a, b и c, а излезен
резултат е n.
За да ја провериме исправноста на алгоритамот, се врши тестирање врз
произволни влезни податоци. На пример, да го тестираме алгоритамот за брое-
вите: a = 37, b = 12, c = 44.
чекор 1: a = 37, b = 12, c = 44.
чекор 2: a (= 37) е поголем од b (= 12), тогаш p = а (= 37).
чекор 3: p (= 37) не е поголем од c (= 44), затоа n = c (= 44).
чекор 4: печати n (= 44).
Постојат повеќе начини за претставување на алгоритмите. Подоцна ќе
разгледаме три од нив:
 Текстуално претставување.
 Графичко претставување.
 Претставување преку програмски јазик.

4
1. Основи на програмирање

Вежби

Вежба 1.1.1
Опишете алгоритам за разговор на мобилен телефон кога каните
некого на роденденска забава. Претпоставете дека тој што го барате за-
должително ќе Ви се јави.

Вежба 1.1.2
Опишете ги сите познати алгоритми за копирање датотеки со
помош на Windows Explorer.

Вежба 1.1.3
Замислете дека дома имате интелигентен робот кој ги изведува
следните активности (со соодветната команда): „Земи лонец“, „Внима-
телно стави го над ринглата од шпоретот“, „Наполни го со вода“ „Земи
јајце од фрижидерот“, „Вклучи го шпоретот“, „Исклучи го шпоретот“,
„Почекај водата да зоврие“ и „Почекај точно 9 минути“.
Обидете се да напишете упатство (алгоритам) со кое роботот ќе
успее „тврдо“ да Ви свари 4 јајца на шпорет со една рингла. За да бидат
тврдо сварени јајцата, потребно е да се варат 9 минути од зовривањето на
водата.

1.2 Програми
Компјутерот не е способен за никаква самостојна работа. За да може ком-
пјутерот да изврши каква било работа, потребно е да му се зададат соодветни
наредби со кои се активира и се извршува некоја програма (англ. program). Ако
програмата е правилно напишана, компјутерот ќе ја изврши и ќе ги даде соод-
ветните резултати.
Целокупната работа на компјутерот се одвива под контрола на посебни
т.н. системски програми (англ. system programs), кои може да се поделат во три
групи:
 Оперативни системи (англ. operating systems).
 Контролни програми (англ. control programs).
 Услужни програми (англ. utility programs).
Програмите кои извршуваат одредени работи за корисниците се нареку-
ваат апликативни програми (англ. application programs) или кориснички про-
грами (англ. user programs).
Сите апликативни програми кои ги имаме на нашиот компјутер решаваат
одредени задачи, односно со нив извршуваме одредена работа. На пример, поз-
нати апликативни програми се програмите од пакетот Мајкрософт офис (англ.

5
ПРОГРАМИРАЊЕ

Microsoft Office): Мајкрософт ворд (англ. МS Word), Мајкрософт ексел (англ. MS


Excel), Мајкрософт пауерпоинт (англ. MS PowerPoint) итн.
Сите програми кои може да ги извршува компјутерот, со едно име се на-
речени софтвер (англ. software). На слика 1.2.1 е дадена една можна поделба на
софтверот.

Слика 1.2.1
Целокупниот софтвер е напишан со т.н. програми (англ. programs). Една
програма претставува текст кој компјутерот може да го разбере и изврши. Про-
грамите се пишуваат во некој програмски јазик (англ. programming language), кој
служи за комуникација меѓу човекот и компјутерот. Програмите се пишуваат со
наредби кои компјутерот треба да ги „разбере“ и, понатаму, да ги изврши оние
дејства кои се „искажани“ со тие наредби.
Сите апликативни програми кои ги имаме на нашиот компјутер решаваат
одредени задачи.
За некој да напише програма за решавање на одредена задача со помош
на компјутер, потребно е да знае да програмира.
Процесот на пишување програма е наречен програмирање (англ. pro-
gramming), а луѓето што ги пишуваат програмите (програмираат) се нарекуваат
програмери (англ. programmers).
Програмите може да се уредуваат (пишуваат и менуваат) со некој уреду-
вач на текст, да се паметат како датотеки и да се извршуваат.

Вежби

Вежба 1.2.1
Дајте пример за 3 програми кои се на Вашиот компјутер. Обидете
се да ги ставите во соодветната категорија од второто ниво на слика 1.3.
6
1. Основи на програмирање

Вежба 1.2.2
Обидете се да дадете пример за програма за секоја од наведените
програми од третото ниво на слика 1.3.

1.3 Претставување на алгоритмите

Рековме дека алгоритмите може да се претстават на три начини: тексту-


ално, графички и преку програмски јазик.
Текстуалното претставување на алгоритмите се врши со чекори, како што
е покажано во потточката 1.1 Алгоритми. Притоа, може да се користи и т.н.
псевдојазик за опишување на алгоритмите.
Ние ќе го користиме псевдојазикот (со зборови од македонскиот јазик),
кој се состои од зборовите: алгоритам, подалгоритам, почеток, крај, ако, то-
гаш, инаку, случај, додека, извршувај, повторувај, до, за, чекор, зголемувај,
намалувај, читај, печати, продолжи, прекин, излез, скок, врати.
Овие зборови ќе ги пишуваме зацрнето (задебелено) за да потенцираме
дека тие се зборови резервирани од псевдојазикот.
Пример за текстуално претставување на ал- алгоритам Најголем
горитам со ваков псевдојазик е даден на слика почеток
1.3.1, каде што е претставен алгоритамот за наоѓа- читај a, b, c;
ње на најголемиот од три броја од слика 1.1.2. Во ако a > b
него, со стрелка p  a се изразува дејството со кое тогаш
на променливата p ѝ се доделува вредноста на про- pa
менливата a. инаку
pb
Графичкото претставување на алгоритмите
крај_ако {a > b}
се врши со т.н. блок-дијаграм (англ. flowchart). Во
ако p > c
блок-дијаграмот се користат посебни графички тогаш
симболи (блокови) за одредени дејства (операции) np
дадени на слика 1.3.2. Ваквото претставување се инаку
нарекува стандардно графичко претставување. nc
Графичкото претставување на алгоритмите крај_ако {p > c}
има свои предности и свои недостатоци. Преднос- печати n;
та е во поголемата прегледност на текот на дејства- крај {Најголем}
та во алгоритамот бидејќи човекот полесно перци-
Слика 1.3.1
пира слика од текст. Од друга страна, блок-дија-
грамот за поголем алгоритам може да зафаќа повеќе страници и алгоритамот да
биде непрегледен.

7
ПРОГРАМИРАЊЕ

po~etok

Слика 1.3.2 a, b, c
Алгоритамот за одредување на најголемиот
од трите дадени броја претставен графички со блок- ne
a>b
da
дијаграмот од слика 1.3.1 е даден на слика 1.3.3.
Претставувањето на алгортимите може да
биде и директно преку програмски јазик. Притоа, p b p a
алгоритамот го „изразуваме“, т. е. кодираме (англ.
code) со наредбите од некој програмски јазик. Така
кодираниот алгоритам со наредби од некој програм-
ne da
ски јазик се нарекува изворна програма (англ. sour- p>c
ce program). За да може да се изврши изворната про-
грама, таа мора да се преведе во извршна програ-
n c np
ма (англ. executive program).
На пример, разгледаниот алгоритам за наоѓа-
ње на најголемиот број од 3 дадени броја, кодиран
во програмскиот јазик C++ е даден на слика 1.3.4.
n

kraj

Слика 1.3.3
8
1. Основи на програмирање

Слика 1.3.4
По извршување на програмата, излезот е:

Структурирани алгоритми

Алгоритмите за посложените задачи може да бидат многу долги и не-


прегледни. Затоа и програмите што ќе се напишат според тие алгоритми може да
бидат тешко разбирливи. Тоа е посебно важно кога ќе се јави потреба од некоја
измена или надополнување во нив. За полесно снаоѓање во големите програми,
денес тие се пишуваат со техника за програмирање позната под името структу-
рирано програмирање (англ. structured programming).
Името структурирано програмирање е добиено според користењето на
т.н. алгоритамски контролни структури (англ. algorithm control structures), пре-
ку кои се управува (се контролира) со текот на извршување на алгоритмите. По-
некогаш, скратено се користи и терминот структурирано програмирање.
9
ПРОГРАМИРАЊЕ

Во структурираното програмирање се користат две техники за прог-


рамирање:
 Програмирање одгоре надолу (англ. top-down programming).
 Модуларно програмирање (англ. modular programming).
Програмирањето одгоре надолу се врши со разделување (расчленување)
на задачата на помали и поедноставни задачи т.н. подзадачи. Ако е потребно, и
тие подзадачи понатаму се разделуваат на уште поедноставни подзадачи сè до-
дека не се добијат задачи што лесно се програмираат.
Секоја подзадача од така расчленетата задача може да се
разгледува како посебна целина, независна од другите. За секоја
може посебно да се напише алгоритам, а потоа и да се испрогра-
мира како посебен програмски дел. Таквите делови (целини) од
програмата се нарекуваат модули (англ. modules).
Секој модул има само една влезна точка (почеток) и са-
мо една излезна точка (крај), слика 1.3.5. Сите модули во про-
грамата се подредени секвенцијално (еден по друг) и не може
ниту еден од нив да се прескокне. Функцијата што ја извршува
еден модул не смее да се повторува во друг модул, односно не
смее да има преклопување на модулите. Исто така, еден модул
може да се состои од повеќе други модули, а може да биде и дел
од поголем модул.
Модуларното програмирање е посебно корисно при из-
мена на програмите или при поправка на грешки. Ако треба да
се измени програмата или да се поправи некоја грешка во неа,
тогаш се менува само модулот во кој се јавила грешката, а не Слика 1.3.5
целата програма.
Графичкото претставување на алгоритмите читај a, b, c
при структурираното програмирање се разликува
од графичкото претставување при неструктурира- ако a > b
ното програмирање, кое се нарекува стандардно тогаш
претставување. pa
Структурираните алгоритми се претста- инаку
вуваат со правоаголни блокови. Секој правоагол- pb
ник изразува посебна целина (модул) со свој поче-
ток и крај. Ако некој модул се дели на поедностав- ако p > c
ни делови, тоа се претставува со помали правоагол- тогаш
ници во поголемиот. На пример, алгоритамот за на- np
оѓање на најголемиот од три дадени броја, претста- инаку
вен стандардно на слика 1.3.3, структурирано е nc
претставен на слика 1.3.6.
печати n
Слика 1.3.6
10
1. Основи на програмирање

За унифицирано претставување на разните дијаграми, кон крајот на 90-


тите години од минатиот век е создаден графички јазик наречен Unified Modeling
Language – UML.
Ние ќе го користиме UML-јазикот за графичко претставување на алгорит-
мите.
UML има голем број графички симболи, а ние во оваа книга ќе ги корис-
тиме следните:

Почеток

Крај

Активност

Избор (разгранување)

Спојување

Дијаграмот за наоѓање на најголемиот


од три броја (слика 1.3.3, слика 1.3.6) изразен
со UML-јазик, ќе биде како на слика 1.3.7.

Слика 1.3.7

11
ПРОГРАМИРАЊЕ

Вежби

Вежба 1.3.1
а) Наведете неколку можни дефиниции за алгоритам.
б) Кои се можните чекори за одредување на средната вредност на
три броја?

Вежба 1.3.2
Да се претстави текстуално и графички алгоритам за утврдување
дали природниот број n е парен или непарен.

Вежба 1.3.3*
Да се претстави текстуално и графички алгоритам за утврдување
дали три броја a, b и c може да бидат страни на триаголник.

Вежба 1.3.4*
Да се подредат три броја a, b и c по големина, од најмал до најго-
лем.

1.4 Програмирање

За да може некој да напише програма за решавање на одредена задача со


помош на компјутер, потребно е да знае да програмира.
Програмирањето е процес на пишување програма.
Луѓето што програмираат се нарекуваат програмери.
Меѓутоа, за да се реши некоја задача со помош на компјутер, не е доволно
само да знаеме да програмираме и да напишеме програма. Програмирањето е
само еден дел од тој процес, кој се состои од неколку фази:
 Поставување на задачата.
 Дефинирање на алгоритам (постапка) за решавање на задачата.
 Пишување на програмата.
 Тестирање на програмата.

I фаза: Поставување на задачата

При поставување на задачата, треба точно да се дефинираат и да се пре-


цизираат условите под кои таа ќе се решава. Затоа, прво треба правилно да се
разбере задачата. Тоа се прави со анализа на нејзината природа, а ако е потребно
и со навлегување во стручната област на која ѝ припаѓа.
За да го дообјасниме погоре кажаното, ќе поставиме неколку задачи и ќе
ги анализираме.

12
1. Основи на програмирање

1. Да се најде збирот на првите 10 природни броја.


2. Да се реши систем од две линеарни равенки со две непознати.
3. Да се направи список на артиклите во една продавница по количина и по
вредност и да се пресмета вкупната вредност на стоката.
4. Од 16 дрвца од кибрит двајца играчи А и Б земаат наизменично по 1, 2, 3
или 4 дрвца. Победува оној кој последен ќе земе дрвце. Дали може еден
од нив постојано да победува?
За првата задача, секој ќе рече дека не е тешка – штом знам да собирам,
знам и да напишам програма.
За втората задача, треба да се знае некоја метода за решавање на систем
од две линеарни равенки со две непознати, какви што се: методата на замена или
методата на спротивни коефициенти.
За третата задача, треба да се знае:
 Името на секој артикл.
 Количината на секој артикл.
 Единечната цена по килограм, по литар или по пакување.
За четвртата задача, нема да ставаме дрвца во компјутерот, туку од бројот
16 наизменично ќе одземаме по онолку дрвца колку што ќе каже секој играч - 1,
2, 3 или 4. Суштината на задачата е да се осмисли по колку дрвца да се земаат,
знаејќи колку зеле противниците и уште колку останале за да се доземат послед-
ните и да се победи.

II фаза: Дефинирање алгоритамот за решавање на задачата

По извршената анализа на задачата, потребно е да се дефинира (нај-


де/смисли) или да се избере (ако знаеме повеќе) алгоритамот за нејзиното реша-
вање. Најчесто постапката произлегува од извршената анализа на задачата и од
консултираната стручна литература во која се содржани одредени релации, фор-
мули и методи за нејзиното решавање. Притоа, треба да се води сметка постапка-
та да биде применлива за извршување на компјутер. Во неа јасно треба да се на-
ведат сите операции што треба да ги изврши компјутерот за да даде точни резул-
тати. Секоја операција треба да биде еднозначно дефинирана, а и редоследот на
операциите треба да биде точно зададен. Се разбира, целата постапка треба да
биде конечна, односно да завршува по конечен број операции, т. е. по конечно
време на извршување. Вака дефинираната постапка за решавање на некоја зада-
ча, како што беше и претходно споменато, се нарекува алгоритам.
Да напоменеме дека за решавање на иста задача може да се напишат по-
веќе различни алгоритми.

13
ПРОГРАМИРАЊЕ

III фаза: Пишување на програмата

Пишувањето на програма претставува запишување (изразување, кодира-


ње) на алгоритамот со елементите на некој програмски јазик (англ. progra-
mming language). За програмските јазици ќе зборуваме во следната потточка.

IV фаза: Тестирање на програмата

Во четвртата фаза се врши тестирање на програмата за да се провери дали


дава точни резултати. Тестирањето се врши најчесто со вредности чии решенија
ги знаеме или можеме (на некој начин) да ги провериме.

1.5 Програмски јазици

Луѓето меѓусебно се разбираат и комуницираат со помош на јазикот.


Така, без разлика дали е претставен со знаци, со симболи или со говор, јазикот
претставува основно средство за комуникација.
Јазиците може да бидат:
 Природни.
 Вештачки.
За комуникација меѓу себе, луѓето ги користат природните јазици, како на
пример, македонскиот, англискиот, рускиот итн. За комуникација помеѓу луѓето
и машините (или помеѓу две машини), се користат вештачките јазици.
Посебен вид вештачки јазици се програмските јазици, кои се развиени за
комуникација меѓу човекот и компјутерот. Со програмските јазици се изразува
постапката (алгоритамот) за решавање на некоја задача запишана во текстуална
форма наречена програма (англ. program). Компјутерот мора да ги „разбира“
програмите и да ги извршува оние дејства кои се „искажани“ со нив.
Од појавата на компјутерите до денес се развиени голем број програмски
јазици. Тие се делат на три групи:
 Машински јазик.
 Симболички јазици.
 Виши програмски јазици.

Машински јазик*1

Машинскиот јазик (англ. machine language) е јазикот на компјутерот. Тој е


единствениот јазик што секој компјутер го разбира и на кој компјутерите не-
посредно работат. Се состои од одреден број машински инструкции (англ. ma-

1
Ознаката * значи дека оваа потточка е корисна, но не е неопходна за понатамошно раз-
бирање на материјалот. Ознаката ќе ја користиме и во дриги поднаслови.
14
1. Основи на програмирање

chine instructions), кои се изразуваат само со нули и единици, т. е. само со бинар-


ни цифри, слика 1.5.1.
Меѓутоа, записот со бинарни броеви е многу голем и непрегледен. Пора-
ди тоа, машинските програми (на хартија) најчесто се запишуваат во хексадеци-
малниот броен систем, слика 1.5.1.

Mашински инструкции

Бинарен запис Хексадецимален запис

101110001101011000010110 B8D616
1000111011011000 8ED8
101000000000000000000000 A00000
00000010000001100000000100000000 02060100
101110110001000010000000 BB1080
1000100000000111 8807
1011010001001100 B44C
1100110100100001 CD21
Слика 1.5.1
*
Симболички јазици

Симболичкиот јазик (англ. assembly language) е на повисоко ниво од ма-


шинскиот. Кај првите компјутери, програмите се пишувале само на машински
јазик. Со текот на времето, за полесно и за побрзо претставување на решението
на поставената задача, програмерите почнале да се служат со кратки едноставни
зборови наречени симболи или мнемоници2 за означување на машинските ин-
струкции. Така се изградиле симболичките јазици. Името го добиле токму пора-
ди тоа што со нив машинските инструкции и податоци се изразуваат на симбо-
лички начин.
На пример, машинската програма од слика 1.5.1 има симболички запис
како на слика 1.5.2.
Симболичките јазици се поразбирли- 16D7 : 0000 MOV AX,16D6
ви од машинскиот јазик. На пример, од слика 16D7 : 0003 MOV DS, AX
1.5.2 се гледа дека MOV е кратенка за помес- 16D7 : 0005 MOV AL, [0000]
тување (англ. move), ADD значи додавање, т. 16D7 : 0008 ADD AL, [0001]
16D7 : 000C MOV BX, 8010
е. собирање (англ. add) итн.
16D7 : 000F MOV [BX], AL
Но симболичките јазици се неразбир- 16D7 : 0011 MOV AH, 4C
ливи за компјутерот, што значи дека програ- 16D7 : 0013 INT 21
мата напишана на симболички јазик не може
непосредно да се извршува во компјутерот. Слика 1.5.2

2
Мнемоника е техника за паметење.
15
ПРОГРАМИРАЊЕ

Затоа, се изработени посебни системски програми наречени преведувачи (англ.


compilers), кои програмата од симболички јазик ја преведуваат во програма на
машински јазик.
Симболичките јазици се машински ориентирани јазици бидејќи секој
компјутер или секое семејство компјутери има свој сопствен симболички јазик,
што зависи од процесорот на компјутерот.
Симболичките јазици најчесто се познати под името асембли (англ.
аssembly), а нивните преведувачи се нарекуваат асемблери (англ. assemblers).

Виши програмски јазици

Вишите програмски јазици (англ. high-level languages) се јазиците на кои


се мисли кога зборуваме за програмирањето. Нивниот развој започнува од 50-
тите години на XX век кога компјутерите со својата универзалност почнале да
навлегуваат во многу области на човековото работење. Кај произведувачите и ко-
рисниците на компјутери се наметнало прашањето: „Како компјутерите да се
доближат до човекот за да може да ги користат и луѓе кои не ја познаваат техни-
ката за машинското и симболичкото програмирање?“
Основната идеја во решавањето на овој проблем била програмите да се
пишуваат на јазик сличен со човечкиот природен јазик. За многу кратко време,
вишите програмски јазици биле општоприфатени и користени од голем број ко-
рисници.
Брзото прифаќање и масовното користење на овие јазици се должи на
следниве факти:
 Програмирањето значително е олеснето поради блискоста на овие
јазици со природниот писмен начин на изразување на човекот и со тер-
минологијата од областа во која припаѓа задачата.
 Овозможуваат брзо и ефикасно запишување на алгоритмите.
 Не бараат познавање на техничките својства на компјутерот и не се
зависни од компјутерот на кој се извршува програмата, односно иста
програма може да се извршува на различни компјутери.
 Брзо и лесно се учат.
 Овозможуваат размена на програми и на искуства меѓу корисниците.
Сите наведени факти се базираат на структурата на вишите програмски
јазици, која видно се разликува од структурата на машинскиот и на симболич-
ките јазици.
Иако вишите програмски јазици се вештачки јазици, тие се изградени на
сличен начин како и природните. Имено, секој од тие јазици си има своја азбука
составена од букви, цифри и специјални знаци: интерпункциски, знаци за арит-
метичките операции, за споредување и друго3.

3
Кај програмските јазици најчесто се користи англиската азбука.
16
1. Основи на програмирање

Со комбинирање на знаците од абецедата, се формираат елементарните


конструкции на јазикот – зборовите, кои го сочинуваат речникот на јазикот. На
пример: read, do, while, new, OPEN, MULTIPLY, STOP, if итн.
Зборовите имаат одредено значење, но во програмите не може да фигу-
рираат како самостојни елементи кои директно ќе влијаат врз работата на ком-
пјутерот, туку се комбинираат во јазични конструкции наречени реченици или
наредби или искази (англ. statements). Наредбите имаат точно дефинирано зна-
чење и може во програмата да стојат како самостојни целини, т. е. да предизви-
каат одредена акција во компјутерот.
Еве неколку примери за наредби:
if (ti > jas) System.out.println("Cestitam. Ti pobedi. ");
throw new UserDefinedException("Kreiran e UserDefinedException! ");
MULTIPLY BROJ1 BY BROJ2 GIVING PROIZVOD.
Важно е да потенцираме (како и кај природните јазици) дека секоја низа
(комбинација) знаци од абецедата не претставува збор од јазикот, односно дека
секоја конструкција од зборови не претставува наредба. Според ова, и вишите
програмски јазици, како и природните, си имаат своја граматика која ги содржи
правилата за градење зборови и наредби.
Секој јазик содржи одредено множество резервирани зборови (англ.
reserved words). Програмерите можат да користат и други зборови, различни од
резервираните, кои се формирани по одредени правила. Тие се нарекуваат иден-
тификатори (англ. identifiers).
Постојат строги правила по кои се конструираат наредбите, кои се наре-
чени синтаксички правила или само синтакса (англ. syntax) на јазикот. Со тие
правила се проверува исправноста на секоја наредба во програмата.
Секоја наредба во програмата мора да има точно дефинирано значење и
да предизвика точно дефинирани дејства. Значењето (смислата) на наредбите е
наречено семантика (англ. semantics) на јазикот.
Програмите напишани на вишите програмски јазици не може директно да
се извршуваат на компјутерот. За таа цел, се потребни посебни системски прог-
рами што ќе извршат нивно преведување на машински јазик наречени преведу-
вачи. Секој програмски јазик има свој преведувач.
Програмата напишана на виш програмски јазик се нарекува изворна про-
грама (англ. source program), а преведената машинска програма се нарекува из-
вршна програма (англ. executive program).
Преведувањето шематски е претставено на следнава слика.

Слика 1.5.3 а

17
ПРОГРАМИРАЊЕ

Извршната програма обично се запаметува како датотека на некоја над-


ворешна меморија, за оттаму да се повикува и да се извршува по потреба. Но
понекогаш таа само се меморира во внатрешната меморија и се извршува ди-
ректно оттаму.
Понекогаш, наместо да се преведе целата програма и да се креира нејзина
извршна верзија, се користи таканаречено директно извршување на изворните
програми. Тоа се прави со посебен вид преведувачи наречени интерпретатори
(англ. interpreters).
Интерпретаторите не прават датотека во машинска форма на изворната
програма, туку секвенцијално ги интерпретираат и ги извршуваат нејзините
наредби.
Шемата на интерпретирањето на програмата е дадена на слика 1.5.3 б.

Слика 1.5.3 б
Вишите програмски јазици не зависат од машината на која ќе се извршува
некоја програма напишана со нив и затоа се нарекуваат машински независни
јазици. Затоа, при градбата на вишите програмски јазици, не се води сметка за
типот на компјутерот на кој ќе се извршуваат програмите напишани со нив, туку
се води сметка за типот на проблемот што се решава. Велиме дека тие се ориен-
тирани кон решавањето на одреден тип проблеми (економски, технички, статис-
тички итн.) и затоа, се нарекуваат проблемски ориентирани јазици.
Развојот на вишите програмски јазици започнал во 50-тите години од ми-
натиот век. Досега се развиени над 3 000 програмски јазици.
Во табела 1.5.1 е дадено хронолошки појавувањето на некои поважни
програмски јазици.
Година Јазик
1945 Машински
јазик
1950 Симболички
јазик
1955 Fortran

18
1. Основи на програмирање

1960 Algol Cobol Lisp


1965 Basic Simula PL/I
1970 Pascal Prolog Logo
1975 Cobol Scheme ML
1980 C Ada Eiffel
1985 Objective-C SQL Perl
1990 C++ Visual Basic Python
1995 Delphi HTML Ruby
Java JavaScript PHP
2000 C# Scala R
2007 Go Clojure
2010 Swift Google Dart Julia
Hack Rust Pixie
2012 TypeScript
2016 Kotlin
Табела 1.5.1
Денес, модерните програмски јазици развиени по 2010 година се наме-
нети за програмирање на веб-апликации кои работат на интернет, а кои ги инте-
грираат добрите карактеристики на неколку јазици. Тие се т.н. скриптни јазици
(англ. scripting languages). Со нив се изработуваат посебни програми – скрипти
(англ. scripts) кои се извршуваат на веб-страниците, но при извршување на други
програми. Скриптите не се преведуваат, туку се интерпретираат. Скриптните ја-
зици се дизајнирани за интеграција и комуникација со другите програмски јази-
ци, како: HTML, Java или C++.
Најпознати скриптни јазици се: JavaScript, PHP, Python, VBScript итн.
На слика 1.5.5 а, б, в, г, д и ѓ се наведени едноставни програми за
решавање на задачата во која треба да се најде збирот на првите 10 природни
броеви напишани во Јава (англ. Java), Це++ (англ. C++), Паскал (англ. Pascal),
Фортран (англ. FORTRAN), Руби (англ. Rubby) и Пајтон (англ. Python).
Пишувањето на програмите се врши во некој уредувач на текст, а потоа
тие се запишуваат (чуваат) на некоја надворешна меморија како датотека под не-
кое име. Таквата програма не може да се изврши бидејќи е потребно претходно
да се преведе.
Изворните програми најчесто имаат наставка по името која е кратенка од
програмскиот јазик. Наставката е одделена од името со точка: .pas, .bas, .for, .cpp,
.java итн. На пример: zbir.pas, prva.bas, mojaPrograma.cpp, podredi.java итн.
Извршните програми кои се добиваат по преведување на изворните про-
грами имаат наставка: .exe, .com, .bat, .bin итн. На пример: zbir.exe, prva.com итн.

19
ПРОГРАМИРАЊЕ

#include <iostream> public class JavaPrimer {


using name space std; public static void
main(String[] args) {
void main(){ int n, suma;
int n, suma; suma = 0;
suma = 0; n = 1;
n = 1; while(n <= 10) {
while(n <= 10) { suma = suma + n;
suma = suma + n; n = n + 1;
n = n + 1; }
} System.out.println(suma);
cout << suma << endl; }
} }
Слика 1.5.5 а: Слика 1.5.5 б:
Програма во Це++ Програма во Јава
PROGRAM Suma; SUMA = 0
VAR N, Suma: integer; N = 1
BEGIN WHILE N <= 10
Suma := 0; SUMA = SUMA + N
N := 1; N = N + 1
WHILE N <= 10 DO ENDWHILE
BEGIN WRITE(*,30)SUMA
Suma := Suma + N; 30 FORMAT(I10)
N := N + 1; STOP
END; Слика 1.5.5 г:
WriteLn(Suma); Програма во Фортран
END.
Слика 1.5.5 в:
Програма во Паскал
suma = 0 suma = 0
n = 1 n = 1
while n <= 10 while n <= 10:
suma = suma + n suma = suma + n
n = n + 1 n = n + 1
end print suma
puts suma Слика 1.5.5 ѓ:
Слика 1.5.5 д: Програма во Пајтон
Програма во Руби
Слика 1.5.5 а, б, в, г, д, ѓ

20
1. Основи на програмирање

Вежби

Вежба 1.5.1
Одговорете на следните прашања:
1. Објаснете ги фазите за решавање на некоја задача со помош на
компјутер.
2. Што треба да знаете за да можете да пишувате програми?
3. За кои програмски јазици сте слушнале?
4. Објаснете што е програмирање, а што програма.
5. Како се делат програмските јазици?
6. *Каков јазик е машинскиот јазик? Зошто не се програмира во него?
7. *Во кој броен систем се запишуваат машинските програми на
хартија?
8. *Дали е поедноставен машинскиот јазик или симболичките јазици?
9. *Како се нарекуваат системските програми што имаат задача да ги
преведуваат програмите од симболички на машински јазик?
10. На кои факти се должи масовното користење на вишите програмски
јазици?
11. Има ли разлика меѓу азбуката на природен и на програмски јазик?
12. Дали зборовите во вишите програмски јазици имаат значење?
13. Од што се состои речникот на еден виш програмски јазик?
14. Може ли една програмска наредба да се состои само од еден збор?
15. Како се нарекува програмата напишана на виш програмски јазик, а
како програмата преведена на машински јазик? Кои наставки ги
имаат соодветните датотеки?
16. Зошто велиме дека вишите програмски јазици се машински
независни јазици?
17. Наведете неколку виши програмски јазици.

21
ПРОГРАМИРАЊЕ

1.6 Интегрирана околина за програмирање

Елементи на интегрираните околини за програмирање

Според кажаното во претходните делови на оваа глава, за да можеме да


почнеме со програмирање, ние мора барем делумно да се запознаеме со елемен-
тите од некој виш програмски јазик. Потоа, во некој уредувач на текст ја пишу-
ваме програмата. За да може да видиме дали програмата што сме ја напишале го
прави тоа што се очекува, ние неа треба да ја преведеме во машински јазик (со
помош на преведувач). Потоа, добиената извршна програма треба да ја извршиме
и дури тогаш да видиме што прави нашата програма.
За да му се олесни работата на програмерот, сите програми кои ни ги о-
возможуваат горенаведените функции (пишување, уредување, преведување и
извршување на програма) се составуваат (интегрираат) во една т.н. интегрирана
околина за развој (програмирање) (англ. Integrated Development Environment –
IDE). Значи, секоја околина за програмирање е составена од множество програми
кои соодветствуваат на различни етапи при решавање на една задача со програ-
мирање.

Уредувач на текст

Уредувачот на текст наречен текст-уредувач (англ. text editor) е програма


која овозможува внесување на текст од тастатурата директно во изворната
програма, како и за извршување на основните операции за обработка на тексто-
вите. Таа дава можност за зачувување на програмите и отворање на зачуваните
програми за повторна обработка.

Преведувач

Преведувачот е програма која ја преведува корисничката програма од


јазикот за програмирање во кој е напишана, во јазик на компјутерот. Таа, исто
така, е дизајнирана за да проверува постоење на грешки во програмите.

Дибагер

За жал, преведувачите можат да откријат грешки во програмата, поради


неправилно користење на програмскиот јазик. Друг тип грешки кои често се слу-
чуваат, особено од програмерите почетници, се логичките грешки, т. е. програ-
мата не го прави тоа за кое е наменета иако работи исправно. Тие грешки се
откриваат многу тешко и затоа треба да се провери начинот на кој се извршуваат
програмите со претходно подготвени влезни податоци, за кои резултатот е поз-
нат. Таквите влезни податоци се нарекуваат тест-примери. Дибагер (англ. de-
22
1. Основи на програмирање

bugger) е програмата од интегрираната околина која помага при барање на логич-


ките грешки. Таа дозволува да го следиме извршувањето на програмата на тест-
примерите чекор по чекор и, на тој начин, да ги откриеме логичките грешки. За
време на тој процес, дибагерот може да покажува и некои меѓурезултати кои доз-
волуваат да се определат местото и видот на грешката.

Поврзувач

Понекогаш една програма е премногу голема за да се напише како една


датотека. Освен тоа, различните делови може да се пишуваат од различни
програмери. Понекогаш делови од дадена програма може да бидат искористени
и во друга програма. Во таков случај, овие делови треба да бидат оформени како
самостојни датотеки. Имајќи предвид дека една програма може да вклучува
неколку различни делови, неопходно е некој одделните преведени делови да ги
обедини во една извршна програма. Тоа е улогата на поврзувачот. Друга улога на
поврзувачот е да ги „поврзе“ со програмата сите библиотеки со стандардните
функции кои се користат (повикуваат) во програмата.
Интегрираната околина за програмирање вообичаено изгледа како пове-
ќето програми со кои работиме. Таа има основен прозорец со работна област,
лента за менијата и други вообичаени елементи: копчиња за затворање и промена
на големината на прозорецот, копчиња за минимизирање итн. Во работната об-
ласт се отвораат прозорците на одделните програми. Во лентата за менија се
наоѓаат менијата (листи од наредби), со кои се повикуваат функциите на околи-
ната: мени за уредување, мени за преведување, спојување и извршување на про-
грами, мени за тестирање итн.

Интегрирана околина за програмирање Code::Blocks

Како да ја најдеме и инсталираме интегрираната околина


Code::Blocks?

Интегрираната околина за програмирање Code::Blocks е бесплатна и мо-


же да се најде на интернет на адресата:
https://www.codeblocks.org/downloads/binaries/.
По кликањето на овој линк, се отвора страница на која има понудено
преземање на Code::Blocks за кориснички оперативен систем. За почетниците,
кои користат оперативен систем Windows, се препорачува да ја симнат верзијата
која вклучува MinGW setup. Во времето на пишување на оваа книга, тоа е линкот
codeblocks-20.03mingw-setup.exe кој е наменет за корисниците на сите оператив-
ни системи Windows. По притискање на изворот Sourceforge.net, се отвора нова
страницата, која по истекот на 5 секунди сама нуди опција да се зачува датотека-
та на локација избрана од корисникот. По зачувувањето на датотеката, треба да
23
ПРОГРАМИРАЊЕ

се следат инструкциите за инсталирање. Корисниците на Linux, исто така, имаат


опција за современа стабилна верзија од програмата, но, за жал, за корисниците
на Mac OS Х достапни се само постари верзии на програмата.

Стартување

При инсталацијата на Code::Blocks во менито Programs од основното


мени Start, се создава група програми со име CodeBlocks. За да се стартува око-
лината за програмирање, треба да се избере CodeBlocks од оваа група.

Главен прозорец

Во главниот прозорец на CodeBlocks има алатки за зачувување, преба-


рување, преведување и извршување на програми, алатки за дибагирање итн.
Работниот прозорец изгледа како на слика 1.6.1. Негови основни елементи се
следните:

Слика 1.6.1 Главен прозорец на Code::Blocks


24
1. Основи на програмирање

а) Лента со менија
Лентата со менија се наоѓа во најгорниот дел на прозорецот, веднаш под
неговиот наслов. Во неа се наоѓаат менијата File, Edit, View, Search, Project, Bu-
ild, Debug, wxSmith, Tools, Plugging, Settings и Help. Секое мени содржи наредби
за околината и/или други менија. Значењето на повеќето од нив ќе биде разгледа-
но понатаму.

б) Ленти со алатки
Лентите со алатки (копчиња за стартување на најчесто користените ко-
манди на околината) се наоѓаат непосредно под лентата со паѓачки менија.
Алатките во околината за програмирање Code::Blocks се поделени во групи, во
зависност од нивното значење. Покажувањето и криењето на различните групи
алатки се реализира слично како во програмите на Microsoft Office, со избирање
на опцијата View -> Toolbars. Секоја група има свое име и ако пред името го има
знакот за штиклирање (), групата се гледа на екранот, а ако го нема тој знак,
таа не се гледа. Секоја алатка соодветствува на некои од командите на менито.

в) Работна површина
Во работната површина може да се наоѓаат потпрозорците на програмите
на околината. Најважните од нив се:
 Прозорецот за уредувачот на текст. Во него може да има неколку стра-
ници, во зависност од тоа во колку програми работи програмерот во даде-
ниот момент. Името на програмата е напишано на натписот, кој се наоѓа
во горниот дел на страницата (види слика 1.6.1.). Натписот на страницата
која е активна во моментот е различен од натписите на другите страници.
 Прозорецот за соопштенија. Во овој прозорец може да се отвори една од
повеќето страници. Во него се прикажуваат информации за преведување-
то, за поврзувањето, за стартувањето итн. Ако за време на преведувањето
бидат откриени грешки, тогаш тие се покажуваат во страницата Build
messages на овој прозорец.
 Прозорецот за организација на работата на програмата.
Прозорците може да се затвораат, да се зголемуваат или намалуваат итн.

Уредувач на текст

а) Внесување и обработка на текст


Уредувачот на текст ги има сите стандардни алатки за внесување и уре-
дување на текст. При уредувањето на текстот, можеме да ги користиме речиси
истите наредби кои ги има во уредувачите на текст во програмите за канцела-
риско работење, како Microsoft Office Word, OpenOffice Writer и други. Исто та-
ка, важат истите наредби за движење на покажувачот од глувчето.

25
ПРОГРАМИРАЊЕ

Дополнително, движењето на покажувачот од глувчето може да се врши


и преку менито Search. Наредбата Goto Function… (Ctrl + Alt + G) е наменета за
работа со големи програми, кои имаат неколку програмски делови (функции). Со
нејзина помош, покажувачот од глувчето се поставува на почетокот на некоја
функција во програмата чие име сме го задале како аргумент. Наредбата Goto
Line… (Ctrl + G) го поставува покажувачот од глувчето на почетокот на наведе-
ната линија итн.

б) Селектирање, копирање и преместување на текст


И овие операции се реализираат како во останатите уредувачи на текст,
најчесто преку менито Edit.

в) Барање и заменување

Во многу случаи може да има потреба од барање на одреден текст низ


програмата, а по наоѓањето, и негово заменување со друг. Тоа се реализира со
помош на наредбите во менито Search (Find, Replace итн.).

Преведување и извршување на програмите

Mенито Build содржи наредби за преведување и извршување на програ-


ми. Преведувањето на програмата од тековната страница на тековниот прозорец,
која има наставка .cpp, се врши со командата Build -> Build, која се задава и со
копчињата Ctrl + F9. Како резултат од преведувањето, во папката во која се наоѓа
датотеката со изворната програма, се креира соодветна извршна програма со нас-
тавка .exe. Извршната програма се стартува на некои од стандардните начини на
оперативниот систем. Преведувањето и извршувањето на програмата може да се
извршат и со една наредба, т. е. со наредбата Build -> Build and Run, која се зада-
ва и со притискање на копчето F9.
За да ја изврши програмата, оперативниот систем отвора текстуален про-
зорец, во кој се внесуваат влезните податоци и се прикажуваат резултатите од
извршувањето на програмата.

Следење на извршувањето на програмата

Следењето на извршувањето на програмата е многу важна постапка за


проучувањето на даден алгоритам, но и за барање на логички грешки во програ-
мата. Интегрираната околина Code::Blocks дава можност за такво следење. За
оваа цел, може да се посочат редови во текстот (контролни точки) во кои сакаме
да запре извршувањето на програмата, како и променливи чија содржина сакаме
да ја набљудуваме. Кога започнуваме со извршување на програмата во режим на
следење, таа работи нормално додека не стигне до контролната точка, а потоа
26
1. Основи на програмирање

запира. Во тој момент, програмерите можат да ја разгледаат содржината на из-


браните променливи за набљудување. Потоа, продолжува извршувањето на
програмата и програмерот може да ги следи вредностите на набљудуваните про-
менливи и да проверува дали одговараат на очекуваните вредности. Исто така,
програмерот може да остави програмата да се извршува регуларно до следната
контролна точка. Сите команди поврзани со следењето на програмата при извр-
шување се во менито Debug.
Поставување на контролна точка се прави кога ќе се постави покажува-
чот од глувчето во избраната линија и кога ќе се зададе наредбата Debug ->
Toggle Breakpoint, која се задава и со притискање на копчето F5. Ќе забележите
дека лево од линијата се поставува црвена точка. Со кликање со глувчето на цр-
вената точка, таа се отстранува. Со наредбата Debug -> Start, започнува следење-
то на програмата. Таа се извршува правилно сè до контролната точка каде што
запира, поставувајќи една жолта стрелка во линијата. Оттаму следењето на про-
грамата продолжува преку останатите наредби од менито, и тоа:
 Debug – Next Step, се извршува само една наредба, по што жолтата стрел-
ка преминува во следната линија.
 Continue, се извршува програмата до следната контролна точка или до
крајот ако не се сретне контролна точка.
 Step into, се користи само за наредби во кои се повикува функција и по-
требно е следење на повиканата функција.
Следењето се прекинува со наредбата Debug -> Stop Debugger.
Во секој момент програмерите можат да користат специјален начин за
задавање на (привремена) контролна точка со наредбата Debug -> Run to Cursor.
Пред да се искористи наредбата, треба покажувачот да се постави на почетокот
на наредбата од каде што сакаме да продолжи следењето на програмата. Програ-
мата ќе запре веднаш откако ќе се извршат наредбите до линијата со означената
наредба. При следното следење на извршувањето на програмата, оваа линија
нема да е контролна точка, освен ако не го поставиме покажувачот од глувчето
повторно во неа и не ја зададеме командата Debug -> Run to Cursor. Понатаму,
следењето на извршувањето на програмата може да продолжи по вообичаениот
начин.

Вежби

Вежба 1.6.1

Стартувајте го CodeBlocks. Од менијата изберете креирање на нов про-


ект: File > New > Project > Empty Project > Go.

27
ПРОГРАМИРАЊЕ

Во следниот прозорец внесете „Project Title“, „Folder“, „Project filename“


и „Resulting file Name“. На пример, за наслов на проектот внесете PrvProekt.

Одберете GNU GCC Compiler и означете ги следните две опции за да


креирате конфигурации „debug“ и „release“.

28
1. Основи на програмирање

Додадете изворна датотека во проектот: File > New > File > C/C++ Source
и изберете C++ како програмски јазик. Потоа внесете го името на датотеката со
полната патека (на пример Vezhba1 – во соодветната папка каде што е проектот)
и не заборавајте да го вклучите „Add file to active project“.
За секој проект, треба да се постават следните опции:
„Project > Build Options... > Compiler Flags“.

Со ова креиравте еден проект кој во себе, засега, содржи една празна
датотека, која е спремна во неа да ја напишете Вашата прва програма.

29
ПРОГРАМИРАЊЕ

Вежба 1.6.2

a) Во отворената датотека од Вежба 1.6.1. внесете го текстот на следна-


ва програма:

#include <iostream>
using namespace std;
int main() {
cout << "Ova e primer za programa";
cout << "koja e napishana vo C++.";
cout << "So nea go probuvam CodeBlocks dali raboti!\n";
return 0;
}

б) Зачувајте ја програмата со наредбата File/Save, под името Vezba1.cpp.


в) Преведете ја програмата Vezba1.cpp (со проверка за грешки при пре-
ведување без да ја стартувате) со притискање на копчињата Ctrl + F9.
г) Ако при внесувањето на програмата Vezba1.cpp, сте пропуштиле
нешто во однос на дадениот текст од погоре, отстранете ги грешките
и зачувајте ги промените со притискање на копчињата Ctrl + S. Потоа,
извршете ја програмата со притискање на копчето F9.

Вежба 1.6.3

а) Креирајте нов проект и повторно поставете ја претходната програма.


Извршете ја.
б) Намерно направете некоја грешка во програмата. На пример, наместо
cout, напишете cot во една од наредбите. Обидете се сега да ја
извршите. Што се случува? Поправете ја грешката и повторно
извршете ја програмата.
в) Ископирајте ја четвртата линија од програмата и поставете ја како
петта линија. Извршете ја програмата. Кој е резултатот од
извршувањето?

30
1. Основи на програмирање

1.7 Алгоритамски контролни структури

За опис на текот на алгоритмите при структурното програмирање, се ко-


ристат посебни т.н. алгоритамски контролни структури или управувачки
структури. Со нив не се извршуваат никакви пресметки, туку се одредува редо-
следот на извршување на алгоритамските чекори, т. е. се управува со редоследот
на извршување на чекорите. Во теоријата на програмирањето е познато дека се-
кој алгоритам може да се изрази со користење на некоја комбинација од следниве
алгоритамски контролни структури:
 Редоследна или секвенца (англ. sequence).
 Избор или селекција (англ. selection).
 Повторување или итерација (англ. iteration).
Првата алгоритамска контролна структура е позната и
под името линиска структура, втората е позната и под името
разгранета структура, а третата е позната и под името циклич-
на структура.
Секоја контролна структура има само една влезна точка
(влез) и само една излезна точка (излез), слика 1.7.1. Слика 1.7.1

Редоследна контролна структура

Оваа алгоритамска контролна структура се состои од


алгоритамски чекори кои се извршуваат по оној редослед по
кој се наведени. Графички, структурата е претставена на слика
1.7.2.
Секоја редоследна контролна структура претставува
посебна целина и може да се појави каде било во алгоритамот.
Затоа е потребно да се означат почето- почеток
кот и крајот на структурата. Тоа се прави чекор А;
со зборовите почеток (англ. begin) и чекор Б;
крај (англ. end), слика 1.7.3. ...
Притоа знакот ; (точка и запирка) чекор Т;
се користи за разделување на чекорите крај
во редоследната контролна структура.
Слика 1.7.2 Последниот чекор може, но не мора, да Слика 1.7.3
има точка и запирка. Содржината на ре-
доследната контролна структура е еден блок од чекори и, за поголема преглед-
ност, тој се пишува малку повлечено надесно од зборовите почеток и крај. Збо-
ровите почеток и крај се пишуваат во иста вертикала. Ова важи за сите алгори-
тамски контролни структури. Овој начин на пишување на алгоритмите и на
програмите се нарекува назабување (англ. indentation), а се користи за поголема
прегледност и за полесно распознавање на алгоритамските контролни структури.

31
ПРОГРАМИРАЊЕ

Редоследната контролна структура најчесто се користи во чекорите за


задавање на почетни вредности на податоците и при пресметувања. На пример:
почеток {Почетни вредности}
a  3;
b  5.74;
c  ‒34;
крај
Притоа стрелката налево  се користи како симбол за доделување вред-
ности на променливите.
Алгоритмите треба да содржат голем број коментари за нивно дообјас-
нување. Коментарите може да се стават на кое било место во алгоритамот, и тоа
во големи загради, како коментарот {Почетни вредности} во горниот пример.

1.8 Јазикот С++

Во 1972 година во лабораториите „АT&T Bell Labs“ е дизајниран јазикот


С од страна на Dennis Ritchie (Денис Ричи). Во него се вградени неколку особини
кои ги немале тогашните програмски јазици:
 Дозволува пристап до ресурси на многу ниско ниво.
 Погоден e за системско програмирање.
 Може да се извршува на различни машински платформи.
 Работи под опкружување на различни оперативни системи.
Во 1980 година во јазикот С се додадени можности за работа со т.н. кла-
си4 и таа верзија на јазикот С е наречена „С со класи“.
Понатамошниот развој на оваа верзија, односно нејзиното надградување,
довело до нов јазик во 1983 година кој е наречен С++, бидејќи претставува над-
градба на С. С++ претставува јазик за т.н. објектно ориентирано програмира-
ње.
C++ е дизајниран од Bjarne Stroustrup (Бјарне Строуструп), а целта е:
 да биде јазик за општа намена подобар од јазикот С,
 да поддржува апстрактни типови5 податоци,
 да поддржува објектно ориентирано програмирање.
Денес, С++ спаѓа меѓу најкористените јазици за изработка на програми од
разни видови, кои може да варираат од кориснички апликации за најразлични на-
мени, па сè до системски алатки.
Во претходните глави преку некои примери и вежби видовме како изгле-
да една програма во С++. Според дадените примери, за да напишеме една про-
грама, потребно е да користиме повеќе знаци – дел од нив да ги комбинираме во

4
Класа е апстрактен тип на податок.
5
Апстрактен тип е замислен тип на податок. На пример, тип ученик.
32
1. Основи на програмирање

целини (зборови и слично). Во продолжение, ќе ги разгледаме неопходните


делови од кои се состојат програмите во С++.

Елементи на јазикот С++

Јазикот С++ има азбука, која е множеството на дозволени знаци (симбо-


ли):
 Малите букви од англиската азбука: a – z.
 Големите букви од англиската азбука: А – Z.
 Цифрите: 0 – 9.
 Специјалните знаци: ~ ! @ # $ % ^ & * ( ) – + = { } [ ] : ; ʼ...‘ „...“ < > ? /
Од азбуката на C++ се формираат зборови кои може да бидат:
 клучни зборови,
 бројни, симболички и текстуални (стринг) константи,
 имиња (идентификатори),
 оператори.
Посебен вид симболи се одделувачите (сепараторите) со кои се одделу-
ваат зборовите еден од друг. Тоа се:
 Празно место (бланко).
 Нов ред.
 Табулатор.

Изглед на една едноставна програма во С++


Излез на екранот

Во продолжение, даваме уште еден пример за програма во С++:


// Prva C++ programa Red 0
#include <iostream> // Red 1
using namespace std; // Red 2
// Red 3
int main() // Red 4
{ // Red 5
cout << "Zdravo, kako ste ? "; // Red 6
return 0; // Red 7
} // Red 8
Слика 1.8.1
Програмата печати на екранот
Zdravo, kako ste?
Да го објасниме секој ред од програмата:

33
ПРОГРАМИРАЊЕ

Ред 0: коментар кој почнува со //;


Ред 1: директива за вклучување на библиотеката iostream;
Ред 2: директива за „претпоставка на префикс std“;
Ред 3: празна линија која се игнорира при извршувањето;
Ред 4: почеток на главна функција наречена main();
Ред 5: првиот дел од големите загради за почеток на телото на функцијата;
Ред 6: наредба за печатење
cout - наредба за печатење
<< - оператор за печатење
"Zdravo, kako ste ? " - текст кој се печати
; ‒ знак за крај на наредбата
Ред 7: наредба која враќа вредност 0 од функцијата main().
Ред 8: вториот дел од големите загради за крај на телото на функцијата
main().
Во дадената програма, Ред 0 не му кажува ништо на компјутерот. Затоа,
тој ред (таа линија) се нарекува коментар. Коментар е текст кој е корисен за оној
што го чита програмскиот код (наменет за лична прегледност и за други лич-
ности кои ќе ја читаат програмата, на пример други програмери кои треба да ја
доработат, изменат или подобрат програмата). Често се случува програмерот да
напише коментар со цел да може полесно да ја разбере кога подоцна самиот тој
ќе ја разгледува програмата.
И во останатите редови се појавува по еден коментар. Тоа е точно текстот
Ред 1, Ред 2… Лесно се забележува дека секој коментар започнува со //. Значи,
сè што ќе напишеме по знакот две коси црти // во даден ред, нема да биде про-
читано од преведувачот.
Ред 1 и Ред 2 содржат претпроцесорски директиви и нив ќе ги објасниме
во понатамошниот текст. Засега, треба да гледаме на нив како на неопходен дел
од програмите кои ќе ги пишуваме.
Исто така, Ред 4, Ред 5, Ред 7 и Ред 8 содржат задолжителен дел од секоја
програма. Тоа се редови во кои се најавува, започнува и враќа вредност и завр-
шува главната функција (функцијата main()), која ја има во секоја програма С++.
Ред 4 и Ред 7 понекогаш може да се малку поразлични, но тоа ќе биде понатаму
објаснето. Засега, запаметете ги како неопходен дел од програмата.
Остана подетално да го разгледаме Ред 6. Ред 6 содржи наредба (исказ) со
која на компјутерот му кажуваме (наредуваме) да отпечати нешто на екранот.
Тоа е наредбата:
cout << "Zdravo, kako ste ? ";
Точно она што се наоѓа во наводници ќе биде отпечатено на екранот.

34
1. Основи на програмирање

Значи, ако сакаме да се напише уште нешто на екранот, што може да на-
правиме? Едноставно под горната наредба (Ред 6 и Ред 7) ќе додадеме уште една
наредба „cout“ (Ред 6 b на слика 1.8.2):
cout << "Dali e se vo red? ";
Со извршување на ваквата програма на екран ќе добиеме:
Zdravo, kako ste?Dali e se vo red?
Доколку сакаме да има празно место помеѓу двете реченици, ќе мораме
да додадеме празно место на крајот на првата реченица или на почетокот на вто-
рата реченица. Доколку, пак, помеѓу споменатите две наредби (Ред 6 и Ред 6 b)
додадеме уште една наредба (во Ред 6 a):
cout << endl;
и ја извршиме ваквата програма, на екранот ќе добиеме:
Zdravo, kako ste?
Dali e se vo red?
Како што забележуваме, наредбата:
cout << endl;
го предизвикува следново: она што програмата ќе го отпечати во понатамошното
нејзино извршување, ќе се печати во нов ред (следниот ред по редот во кој е
испишано Zdravo, kako ste?).
Комплетната програма сега би изгледала вака:
// Prva C++ programa Red 0
#include <iostream> // Red 1
using namespace std; // Red 2
// Red 3
int main() // Red 4
{ // Red 5
cout << "Zdravo, kako ste? "; // Red 6
cout << endl; // Red 6 а
cout << "Dali e se vo red? "; // Red 6 b
return 0; // Red 7
} // Red 8
Слика 1.8.2
Трите наредби во програмата се наредени една под друга. Тие точно така
и ќе бидат извршени од компјутерот, прво едната, потоа втората, па третата, т. е.
наредбите ќе бидат извршени по редослед. Затоа и ваквата последователност од
наредби се нарекува „редоследна структура“.
Во наредбата cout можеме да комбинираме повеќе делови. На пример,
горните три наредби може да се спојат во една:
cout << "Zdravo, kako ste ? " << endl << "Dali e se vo red ? ";
Едноставно ги одделуваме деловите со <<.
Со наредбата cout, можеме да отпечатиме и броеви, па дури и вредности
на аритметички изрази. На пример, да ја разгледаме програмата на слика 1.8.3.

35
ПРОГРАМИРАЊЕ

// Nova C++ programa Red 0


#include <iostream> // Red 1
using namespace std; // Red 2
// Red 3
int main() // Red 4
{ // Red 5
cout << "Broj" << 532; // Red 6
cout << "Zbir" << 12 + 55; // Red 7
cout << "Razlika" << " " << 12 – 55; // Red 8
return 0; // Red 9
} // Red 10
Слика 1.8.3
Вежби:

Вежба 1.8.1
Во програмата на слика 1.8.3 погледнете ги наредбите за печате-
ње на екранот. Како се постигнува празно место помеѓу различните де-
лови од cout кои се печатат?

Вежба 1.8.2
Направете програма која ќе ги отпечати Вашето име и презиме, а
во вториот ред ќе го отпечати бројот на Вашите години.

Вежба 1.8.3
Поправете ја претходната програма да го отпечати бројот на ме-
сеци наместо бројот на години.

Вежба 1.8.4
Направете програма која ќе го отпечати резултатот од множењето
на 1 234 до 5 678. Проверете дали сте добиле точен резултат со помош на
калкулатор.

Вежба 1.8.5
Направете програма која ќе го отпечати резултатот од множењето
на 123 456 со 7 891 011. Што добивте како резултат? Дали тоа е точниот
резултат?

36
1. Основи на програмирање

1.9 Податоци и променливи

Величини и податоци

Величина е мерка за некоја карактеристика на даден предмет или појава.


На пример, следните карактеристики имаат своја величина: должина, волумен,
маса, боја, возраст, брзина и др. Величините имаат вредности кои се изразуваат
во мерките или вредностите од некое множество. На пример: cm е мерка за дол-
жина, m3 е мерка за волумен, kg е мерка за маса, години е мерка за возраст, m/sek
е мерка за брзина итн.
Вредностите со кои се изразуваат величините се нарекуваат податоци.
Тоа значи дека податоците имаат вредност. Податоците се обработуваат со ал-
горитми, т. е. со програми.
Во многу случаи податокот, т. е. вредноста на некоја величина не се ме-
нува. На пример, вредноста на математичките броеви е = 2.71 и π = 3.146 нико-
гаш не се менува и затоа велиме дека тие се константи (англ. constants).
Од гледна точка на програмските јазици, константите се податоци за кои
се одделува место во работната меморија на компјутерот, кои имаат сопствено
име и на кои вредностите не им се менуваат за време на извршување на програ-
мата.
За разлика од константите, вредноста на некои величини се менува. На
пример, возраста на некој човек, температурата во текот на денот, брзината на
некој автомобил итн. може да добиваат различни вредности и затоа велиме дека
нивните вредности се променливи. Ваквите податоци кои може да имаат промен-
ливи вредности се нарекуваат променливи (англ. variables).
Од гледна точка на програмските јазици, променливите се податоци за
кои се одделува место во работната меморија на компјутерот, кои имаат сопстве-
но име и кои може да примаат различни вредности во процесот на извршување
на програмата.
Математичките формули најчесто вклучуваат во себе променливи. На
пример, p = a  b е формула за пресметување на плоштината на правоаголник.
Понекогаш се вклучени и константи (плоштината на круг е r2π), а понекогаш се
јавуваат и броеви (волуменот на топка е 4r3π/3).
Поимите константа и променлива ги поврзуваме со употребата на мемо-
ријата на компјутерот. За секоја константа и променлива се одделува место во
меморијата, каде што се чува вредноста на податокот (променлива или констан-
та). Местото се состои од една или повеќе мемориски локации. Почетната
мемориска локација има адреса во форма на цел број, што го определува местото
на податокот во меморијата. Кога во програмата користиме некоја променлива
или константа, нејзината вредност се чита или запишува на адресата во мемори-

6
Децималните броеви во програмските јазици се одделуваат со точка.
37
ПРОГРАМИРАЊЕ

јата на која е зачувана. За да не ја памтиме адресата во меморијата каде што сме


зачувале некоја вредност, едноставно смислуваме име за таа мемориска локација.
Со програмските јазици може да се обработуваат различни податоци, ка-
ко на пример: цели броеви, реални броеви, знаци, текстови итн. Велиме дека тоа
се податоци од различен тип. Како што веќе рековме, покрај типот, податоците
имаат име и вредност. Затоа велиме дека податоците ги имаат следниве карак-
теристики:
 Име.
 Тип.
 Вредност.

Имиња на податоците

Имињата (идентификаторите) на податоците во С++ се формираат со


почитување на следниве правила:
 Името започнува со буква или подвлечена црта.
 Малите и големите букви се разликуваат.
 Името може да содржи цифри.
 Името не смее да содржи специјален знак, како: !, @, #, $, ^ итн.
На пример, правилни имиња на податоци се:
a, Iti, i2j3, _ime, radius, R, _char, TiUci.
Неправилни имиња на податоци се:
5_ka, $dolar#i, char.
За имиња на податоци не се препорачуваат резервираните зборови или
зборови слични на резервираните. На пример:
CHAR (сличен на char)
_float (содржи резервиран збор)
__ (две подвлечени црти)

Типови податоци

Тип на податок претставува начин на интерпретирање на содржината на


една или повеќе последователни локации во меморијата во која е сместен некој
податок.
Постојат две основни групи на типови податоци во С++:
 Основен (прост) тип.
 Апстрактен тип.
Во следнава табела се наведени само типовите податоци кои ќе ги раз-
гледаме во книгава:

38
1. Основи на програмирање

Основни типови податоци


аритметички
целоброен int
реален со обична точност float
реален со двојна точност double
знаковен char
логички bool
низа
Аритметичките типови имаат и поттипови:
целоброен тип
означен неозначен
short int unsigned short int
int unsigned int
long int unsigned long int

реален тип знаковен тип


float char
double unsigned char
long double

Зборовите long, short, signed и unsigned се таканаречени спецификатори


кои се употребуваат заедно со основните типови. Тие го менуваат начинот на ин-
терпретирање на податоци кај основните типови.
Спецификаторот short не може да се примени за реален тип податоци.
Спецификаторите signed и unsigned определуваат дали ќе се паметат и
позитивните и негативните броеви или само позитивните броеви. Ако е бројот
unsigned, тогаш се смета дека бројот е секогаш позитивен.

Константни и променливи податоци

За да може да меморираме податоци кои ни се потребни при извршу-


вањето на програмата, ние мора да ги декларираме (најавиме) некаде во прог-
рамата. При декларација на податоци, се задава типот и името, а може (но не
мора) и почетната вредност.
Податоците, соодветно на величините, може да бидат константни и про-
менливи.
Константни податоци или скратено константи се оние чија вредност
(содржина на локацијата во меморијата) не се менува за време на извршување на
програмата. Константен податок или константа се декларира со зборот const по
кој се наведуваат типот и името, а потоа мора да следи вредност:
const тип име = вредност;

39
ПРОГРАМИРАЊЕ

Примери:
const int m = 3;
const int х = 10, у = 12;
const double pi = 3.1415;
const char da = 'D';
Ако не се наведе типот, се подразбира типот int.
Променливи податоци или скратено променливи се оние податоци чија
вредност (содржина на локацијата во меморијата на која се наоѓаат) може да се
менува за време на извршување на програмата.
Променливите податоци се декларираат со:
тип име;
или
тип име = вредност;
Последниов начин претставува истовремено декларација и иницијализа-
ција (доделување почетна вредност) на променлива.
Примери:
int i, j;
int m = 10, n = 17 ;
float e = 2.7182;
За да може да се користи во програмата, податокот мора да е дефиниран.
Тој се дефинира со доделување вредност при декларирање (со иницијализација)
или со наредбата за доделување.
Наредбата за доделување е:
име = вредност;
Пример
#include <iostream>
main()
{
short ed_cena, vkupno; /* Deklaracija na promenlivi */
short parcinja = 1000; /* Deklaracija so inicijalizacija*/
ed_cena = 50; /* Dodeluvanje vrednost */
}

Вежби

Вежба 1.9.1
За да ја отпечатиме вредноста на една променлива (да речеме
именувана со m), едноставно ја користиме наредбата cout << m;. Може-
ме да правиме и комбинации со текст и изрази, како во примерите во
претходните поглавја.
Направете 3 програми во кои ќе ги вклучите наредбите за декла-
рирање и иницијализирање наведени во последните три примери. Потоа,
40
1. Основи на програмирање

програмите дополнете ги со наредби за печатење на екранот со кои ќе ги


отпечатите вредностите на сите декларирани променливи. Што се случу-
ва кога печатите вредност на неиницијализирана променлива?

Вежба 1.9.2
Направете програма во која ќе декларирате и иницијализирате две
променливи со наредбата int a = 12, b = 7;. Потоа отпечатете ги
нивниот збир, разлика и производ во три последователни редови на
екранот.

Вежба 1.9.3
Нека е дефинирано:
int x;
float y;
char z;
x = 2; y = 5.8; z = 'P';
Со која наредба ќе се отпечатат вредностите на променливите x, y
и z, така што да бидат одвоени со по едно празно место, а потоа да се
премине во нов ред?

1.10 Типови податоци

Целоброен тип податоци

Целоброен тип податок, деклариран со зборот int, може да има вредност


на кој било цел број (… ‒2, ‒1, 0, 1, 2...).
Во табела 1.10.1 се дадени целобројни типови податоци, нивните вред-
ности и количината на меморијата7 што ја зафаќаат.
Тип Вредности Меморија
short int ‒32768... 32767 16 бита
int ‒32768... 32767 32 бита
long int ‒2147483648... 2147483647 32 бита
unsigned short int 0... 65535 16 бита
unsigned int 0... 4294967295 32 бита
unsigned long int 0... 4294967295 32 бита
Табела 1.10.1
За операции со целобројни типови податоци, се користат следниве арит-
метички оператори:

7
Количината на меморијата што ја зафаќаат типовите податоци може да варира од една
компјутерска платформа до друга.
41
ПРОГРАМИРАЊЕ

+ собирање
‒ одземање и негација
* множење
/ делење (реални броеви) и цел дел од количник (цели броеви)
% делење по модул (остаток од делење)
Операторот за делење / може да се користи за операнди со различни ти-
пови. Притоа, ако двата операнди се целобројни и резултатот ќе биде
целоброен. На пример:
10 / 4 = 2,
10 / 4.0 = 2.5
Примери:
7 / 3 = 2
205 / 20 = 10
205 % 20 = 5
‒25 % 3 = ‒1
7.0 / 4 = 1.7500
Со употреба на загради, се менува редоследот на извршување на опера-
циите одреден со приоритетите на операторите.
Примери:
(1 + 2 * (3 + 4)) % (5 ‒ 6)
(1 + 2 * 7) % (5 ‒ 6)
(1 + 14) % (‒1)
15 % (‒1)
0
Стандарден оператор за доделување вредност е = .
Примери:
int prvbroj, vtorbroj, ;
short int cifra;
...
prvbroj = (1 + 2 * 7) % (5 ‒ 6);
prvbroj = prvbroj + cifra;
vtorbroj = vtorbroj / cifra;
С++ го дозволува и следниов начин на доделување вредности:
x = (y = 10) * (z = 5) при што се добива x = 50
x = y = z = 20 при што се добива x = 20, y = 20, z = 20

Скратена форма на операторите

Операторите во С++ може да се користат во т.н. скратена форма, која се


гради со аритметички оператор и операторот за доделување:
оператор =
Скратените форми на операторите за целобројни податоци се:
+= ‒= *= /= %=
42
1. Основи на програмирање

Примери:
prvbroj += cifra; е исто што и prvbroj = prvbroj + cifra;
vtorbroj /= cifra; е исто што и vtorbroj = vtorbroj / cifra;

Знаковен тип податоци

Податоците од знаковен тип може да имаат вредност кој било знак или
која било целобројна вредност. Тие може да бидат променливи или константни
податоци. Се декларираат со зборот char.
Примери:
char a;
char znak = '+';
const char evro = 'E';
char denar = 'd';
char ascii = 120;
Податоците од знаковен тип може да се третираат како кој било цело-
броен тип. Со нив може да се извршуваат аритметички операции, тие може да се
читаат, да се печатат и да се споредуваат.
Вредностите и опсегот на податоците од знаковен тип се дадени во
табела 1.10.2.
Тип Вредности Меморија
char ‒128... 127 8 бита
unsigned char 0... 255 8 бита
Табела 1.10.2
Реален тип податоци

Во С++ се вградени два реални типа податоци: float и double.


Податоците од реален тип може да бидат константни и променливи, а се
декларираат со зборовите float и double. Иницијализацијата се врши како и кај
целобројниот тип податоци.
Примери:
float x;
const float g = 9.81;
double tezina;
double iznos = 12345.67;
Прецизноста на податоците од типот float и double е различна:
 Податоците од типот float зафаќаат 32 бита и имаат 7 значајни цифри.
 Податоците од типот double податоците зафаќаат 64 бита и имаат 15
значајни цифри.
Нивните вредности се дадени во табела 1.10.3.

43
ПРОГРАМИРАЊЕ

Тип Вредности Меморија


float 3.4  10‒38... 3.4  1038 32 бита
double 1.7  10‒308... 1.7  10308 64 бита
long double 3.4  10‒4932... 1.1  104932 80 бита
Табела 1.10.3
Аритметички оператори за податоци од реален тип се:
+ собирање
‒ одземање или негација
* множење
/ реално делење (ако барем еден од податоците е реален)
И овие оператори може да се користат во стандардна и во скратена фор-
ма.
+= ‒= *= /=

Претставување на децималните податоци

Децималните податоци во програмските јазици се претставуваат на два


начини:
 Со неподвижна точка (f-формат).
 Со подвижна точка (e-формат)
Примери:
f-формат e-формат
76.5432  10 )
3
1234.56 76.5432е+3 (=
‒25. ‒25.е-1 (= ‒25.0  10‒1)
2  10 = 2000)
3
0.5432 2e3 (=
‒.5432 ‒.345е-2 (= ‒0.345  10‒2)

Конверзија на типот на податоците

Во изразите со мешани типови податоци, како на пример:


5 + 7.34
129.56 ‒ 1.3е+2
се врши конверзија на типовите со помала прецизност во типови со поголема
прецизност и од целобројни во реални вредности.
Кога е неопходно, автоматски се врши имплицитна конверзија на типот.
Не е дозволено користење на операторот % на реални операнди.
Пример:
int k;
к = 5 + 7.34 (= 5.0 + 7.34 = 12.34)
Прво се врши конверзија на 5 во 5.0 и потоа имплицитна конверзија на
12.34 во 12, вредност што му се доделува на к. Проверете.
44
1. Основи на програмирање

Експлицитна конверзија на типот се врши преку операторот ( ) кој се


нарекува оператор cast. Тој се употребува така што прво се задава типот во кој се
претвора вредноста, а по него во заградите следува изразот чиј тип се менува. На
пример:
int(5 + 7.34) (= 12)
Изразот 5 + 7.34 е од реален тип. Со примена на овој оператор, вредноста
на изразот експлицитно се претвора во типот int.
Следните примери, исто така, илустрираат конверзија:
double(3 * 5) (= 15.0)
cout << int('a') << endl;
Овој оператор може да се користи и така што типот во кој се претвора
вредноста се задава во загради. Претходните примери, исто така, може да се
претстават на следниов начин:
(int)(5 + 7.34) (= 12)
(double)(3 * 5) (= 15.0)
cout << (int) 'a' << endl;
При операциите со податоци од целоброен и од реален тип, може да се
користат вградени математички функции, како на пример:
sqrt(), exp(), sin(), fabs()
но претходно треба да се наведе преведувачката директива за вклучување на
математичката библиотека во која се наоѓаат овие вградени функции:
#include <math.h>

Логички тип податоци

Податоците чија вредност може да биде или true или false се од логички
тип. Тие се декларираат со зборот bool.
Примери:
bool dane;
bool semafor = true;
Со податоците од логички тип може да се користат и логичките операто-
ри (функции):
&& логичко И (AND)
|| логичко ИЛИ (OR)
! логичко НЕ (NOT)
Со сите претходно наведени типови податоци може да се користат рела-
циските оператори:
< помало
<= помало или еднакво
> поголемо
>= поголемо или еднакво
== еднакво
!= различно
45
ПРОГРАМИРАЊЕ

Приоритет на операторите

Операторите кои досега ги наведовме за различни типови податоци има-


ат свои приоритети при пресметување на изразите:
највисок NOT !
унарен минус 
аритметички + ‒ * / %
релациски < <= > >=
еднаквост == !=
AND &&
OR ||
најнизок доделување = += ‒= *= /= %=

1.11 Читање и печатење на податоци

Читањето вредности на податоци во С++ е организирано како поток


(англ. stream) од знаци. Стандардниот влезен и стандардниот излезен поток се
вршат со помош на рутини8 (англ. routines) кои се наоѓаат во библиотеката
<iostream>, која, пак, се вклучува во секоја програма со директивата:
#include <iostream>
Во неа се дефинирани операторите:
>> влезен оператор
<< излезен оператор
Операторот << значи „прати на“, a операторот >> значи „преземи од“.
Наредбите за влез и излез се:
cin ‒ наредба за внесување вредности преку тастатурата
(за стандарден влезен поток),
cout ‒ наредба за печатење вредности на екранот
(за стандарден излезен поток).
При читање на вредности на податоците, се прескокнуваат празните мес-
та, табулаторите и знаците за крај на ред (англ. return). Читањето на вредностите
започнува од првиот знак кој не е бланко.
На пример, ако се декларирани променливите i и x:
int i;
double x;
читањето вредности за нив од тастатурата се врши со наредбата:
cin >> i >> x;
Ако на променливите celbroj и realenbroj им доделиме вредности:
celbroj = 123;

8
Рутина е која било функција која може да се повикува и извршува каде било во програ-
мата.
46
1. Основи на програмирање

realenbroj = 456.78;
тогаш со наредбата:
cout << celbroj << realenbroj;
ќе се отпечати
123456.78
За разделување на отпечатените вредности се користат еден или повеќе
бланко знаци. Така, со следнава наредба
cout << celbroj << ʼ ‘ << realenbroj << endl;
ќе се отпечати:
123 456.78
endl е оператор за крај на линијата, т. е. служи за преминување во следната
линија. За печатење во нов ред, се користи и знакот '\n' .
На пример, со наредбата:
cout << celbroj << ʼ\n‘ << realenbroj << '\n‘;
или
cout << celbroj << endl << realenbroj << endl;
ќе се отпечати:
123
456.78
Неколку специфични знаци, кои имаат специјално значење кај наредбата
за печатење, се печатат со користење на т.н. излезни секвенци. Во следнава
табела се прикажани некои од излезните секвенци.
Излезна секвенца Опис
\“ печатење наводници
\\ печатење коса црта
\a печатење ѕвоно (аларм)
\n поставување на покажувачот на почетокот на
следната линија
\r поставување на покажувачот на почетокот
на тековната линија
\t поместување на покажувачот на следната
таб-позиција

Примери

Пример 1.11.1
Во следнава задача се разгледува едноставна програма во С++ за со-
бирање на два броја, во која ќе илустрираме некои од особините разгледани во
претходниот дел од текстот.
// Sobiranje na dva broja

#include <iostream>
using namespace std;
47
ПРОГРАМИРАЊЕ

int main()
{ // почеток на main()
int broj1; // deklaracija na celobrojnata
// promenliva broj1
cout << "Vnesete prv cel broj\n";
cin >> broj1; // citanje vrednost na broj1
int broj2, zbir; // deklaracija na celobrojnite
// promenlivi broj2 i zbir
cout << "Vnesete vtor cel broj\n";
cin >> broj2; // citanje vrednost na broj2

zbir = broj1 + broj2; /* naredba za dodeluvanje */

cout << "Zbirot e" << zbir << endl;


return 0;
} // kraj na main
Како што кажавме, коментарите во С++ се пишуваат со ставање на знакот
// пред коментарот и се протегаат сè до крајот на тој ред.
Коментар кај кој треба да го означиме почетокот и крајот, се става помеѓу
ознаките /* и */. Таквиот коментар може да заврши пред крајот на редот или да
се протега во неколку последователни редови.
Претпроцесорската директива
#include <iostream>
му кажува на претпроцесорот да ја вклучи датотеката <iostream>, која содржи
дефиниција на рутини за влезно-излезни операции.
Линијата
main()
е непоходен дел од секојa програмa и претставува име на главната функција.
Променливите во С++ може да се декларираат каде било во програмата, а
може да се користат по линијата во која се декларирани.
Линијата:
int broj2, zbir; // deklaracija
демонстрира декларирање на две променливи.
Наредбата:
cout << "Vnesete prv cel broj\n";
го користи стандардниот излезен поток cout и операторот << за да се отпечати
наведениот текст на екранот од мониторот. Кога претходната наредба ќе се из-
врши, таа му испраќа поток од знаци Vnesete prv cel broj на стандардниот из-
лез cout. Оваа наредба би можеле да ја прочитаме како: „на стандардниот излез
cout се испраќа текстот Vnesete prv cel broj, како поток од знаци“.
Рековме дека знакот \n е излезна секвенца со која се поставува покажу-
вачот на почетокот од следната линија.

48
1. Основи на програмирање

Следната наредба:
cin >> broj1;
го користи стандардниот влезен поток cin и операторот >> за преземање пода-
тоци кои се внесуваат преку тастатурата како низа од знаци. Оваа наредба може
да се прочита како „cin го чита потокот од знаци кој се внесува преку тастатурата
и му го доделува на променливата broj1“. Во конкретниов случај, знаците кои се
внесуваат се цифри на бројот, цифрите се конвертираат во цел број и тој ѝ се
доделува на целобројната променлива broj1.
Линијата:
cout << "Zbirot e" << zbir << endl;
содржи една наредба cout за печатење на повеќе вредности. Пред секоја вред-
ност, се наведува операторот <<. Со првиот оператор, се печати (испраќа на
екран) текстот Zbirot e, а со вториот оператор се печати вредноста на промен-
ливата zbir. По третиот оператор, е наведена наредбата endl (скратено од end
line), со која покажувачот на екранот се поставува на почетокот од следниот ред.

Пример 1.11.2
Да се декларираат, внесат и отпечатат податоци од целоброен тип, реален
тип и знаковен тип.
#include <iostream>
using namespace std;

int main()
{
int x; // Deklaracija na podatok od celobroen tip
float y; // Deklaracija na podatok od realen tip
char z; // Deklaracija na podatok od znakoven tip

cout << "Vnesete cel broj";


cin >> x;
cout << "Vnesete realen (decimalen) broj ";
cin >> y;
cout << "Vnesete string";
cin >> z;

cout << "Vneseniot podatok od celobroen tip e: " << x << endl;
cout << "Vneseniot podatok od realen tip e: " << y << endl;
cout << "Vneseniot podatok od znakoven tip e: " << z << endl;
return 0;
}

49
ПРОГРАМИРАЊЕ

Пример 1.11.3
Следнава програма илустрира некоректно користење на променливата
vkupno бидејќи ѝ се доделува вредност која е поголема од опсегот на вредности
според декларацијата.
#include <iostream>
using namespace std;
int main()
{
short ed_cena, vkupno; /* Deklaracija na promenlivi */
short parcinja = 1000; /* Deklaracija so inicijalizacija*/
ed_cena = 50; /* Dodeluvanje vrednost */
vkupno = ed_cena * parcinja;
cout << "Vkupnata cena za " << parcinja;
cout << " parcinja e " << vkupno << endl;
return 0;
}
Излезот на оваа програма е:
Vkupnata cena za 1000 parcinja e ‒15536.

Пример 1.11.4
Даден е цел трицифрен број k. Да се напише програма во која преку
тастатурата се внесува бројот k и потоа се печати збирот на неговите цифри.
(На пример, за влез 543, на излезот се печати 12).

Решение: За да го пресметаме збирот на цифрите, треба да ја најдеме и


изделиме секоја цифра од тој број: цифрата на единиците, на десетките и на стот-
ките.
За даден број и за секоја од цифрите ќе имаме по една променлива од
целоброен тип: int k, e, d, s; е – цифрата на единиците, d – цифрата на десетките и
ѕ – цифрата на стотките. ако може по s да стои точка
Прво треба да се внесе бројот k со наредбата: cin >> k; Потоа, треба да се
пресметаат соодветните цифри со користење на операциите за делење и остаток
при делење, со следниве наредби:
e = k % 10;
d = k / 10 % 10;
s = k / 100;
На крај го печатиме збирот.
#include <iostream>
using namespace std;
int main()
{
int k, e, d, s;
cin >> k;
e = k % 10;
50
1. Основи на програмирање

d = k / 10 % 10;
s = k / 100;
cout << e + d + s << endl;
return 0;
}

Вежби

Вежба 1.11.1
Нека е дефинирано:
int x;
float y;
char z;
Со која наредба ќе се внесат вредностите на променливите x, y и z?

Вежба 1.11.2
Да се решат следниве задачи:
1. Да се напише програма за пресметување на производот на два
внесени броја.
2. Пресметајте ја разликата на два внесени броја.
3. За четири броеви, внесени преку тастатурата, да се пресмета нивната
средна вредност.
4. Напишете програма која на екранот ќе го даде следниов излез:
* * * *
* *
* * * *
5. Напишете програма која на екранот ќе го даде следниов излез:
* * *
* *
* *
* * *
6. Напишете програма која на екранот ќе го даде следниов излез:
*
* *
* *
7. Напишете програма која за внесен трицифрен број ги печати секоја
од неговите цифри во посебен ред.
Пример:
Vnesi broj: 897
Cifrite se:
8
9
7

51
ПРОГРАМИРАЊЕ

8. За целите броеви од 0 до 3 да се отпечати таблица со нивните


квадрати и кубови, т. е.:
Broj kvadrat kub
0 0 0
1 1 1
2 4 8
3 9 27

Вежба 1.11.3
Од 1990 година, во организација на Здружението на информатича-
рите на Македонија, секоја година се одржуваат државни натпревари по
информатика. Во учебников ќе бидат наведени задачи од натпреварите
кои може да се решат со досегашните знаења.
Од стекнатите знаења во оваа глава, учениците се во можност да ги
решат следните задачи:
1. За даден интервал [а,b], најдете го збирот на сите непарни пози-
тивни броеви помеѓу а и b.
2. Најверната другарка на Стојче е Пуфи. Таа обожава да носи шноли во
својата коса и секогаш доаѓа на училиште со шноли во најмногу 3 бои
(жолта, црвена и сина). Стојче сака секогаш бројот на шноли кои ги
има Пуфи во косата да е делив со 3. Затоа, тој секогаш си носи бели
шноли и ѝ дава на Пуфи за да го направи вкупниот број на шноли де-
лив со 3. Бидејќи Стојче мора да има шноли и за наредните денови,
ако знаете по колку шноли има Пуфи во косата од секоја боја, пресме-
тајте му на Стојче колку најмалку бели шноли треба да ѝ даде на
Пуфи за да постигне вкупен број на шноли делив со 3.
3. Во една земја за формирање на влада коалицирале две партии: ПА и
ПБ. При формирањето на владата, било одлучено дека ќе има нај-
многу N министерства, подредени по значајност (М1, М2, М3...). Се-
кој член на партиите можел да предложи како да изгледа новата вла-
да. Предлогот вклучувал: број на министерства и во кое министер-
ство од која партија ќе биде министерот. Така, на пример, предлози
кои биле дадени се:
N = 3: М1 – ПА, М2 – ПБ, М3 – ПА;
N = 4: М1 – ПА, М2 – ПА, М3 –ПА, М4 – ПА;
N = 1: М1 – ПБ;
итн.
Бидејќи процесот на предлагање траел долго, биле дадени сите
можни предлози за големина на влада од 1 до N министри. Напишете
програма која, за дадено N, ќе пресметува колку различни предлози
биле дадени.
4. Иван ја игра својата омилена компјутерска игра, која има неколку
нивоа. Иван почнува од ниво 1 и треба да потроши P поени за да дој-
52
1. Основи на програмирање

де на ниво 2. Но за секое следно ниво треба да потроши D повеќе по-


ени отколку за претходното ниво. На пример, за P = 5 и D = 10, за да
премине од ниво 1 на ниво 2, Иван ќе потроши 5 поени, за премин
од ниво 2 на ниво 3, треба да потроши 15 поени, за премин на след-
ното ниво треба да потроши 25 поени итн. Ако знаете дека сега Иван
е на ниво N, пресметајте колку вкупно поени биле потрошени за
премин на ниво N + 1.
5. Во играта Мало лото се извлекуваат 5 различни броеви со вредности
помеѓу 1 и 9. Потоа, броевите се подредуваат од најмал до најголем и
добитната комбинација се објавува. Ако Ви е дадена добитната ком-
бинација, Ваша задача е да го најдете најголемиот трицифрен број кој
може да се формира од петте дадени броеви и да го отпечатите него и
бројот кој е двапати поголем од него.

53
ПРОГРАМИРАЊЕ

Резиме

 За да може да се изведуваат какви било активности, треба да се познава точ-


ниот редослед на елементарните активности што треба да се извршат.
Листата на активностите (чекорите) запишани според редоследот на извршу-
вање се нарекува алгоритам.
 Зависно од алгоритамските чекори, алгоритамот може да биде општ и де-
тален.
 Алгоритмите може да се запишат текстуално со псевдојазик или графички со
блок-дијаграм. Графичкото претставување може да биде со стандардни или
со структурирани блок-дијаграми. За графичко претставување на алгорит-
мите и процесите во некој алгоритам, се користи јазикот Unified Modeling
Language – UML.
 Структурираното програмирање е начин на програмирање во кој се ко-
ристат техниките: програмирање одгоре надолу и модуларно програмирање.
 Сите програми кои може да ги извршува компјутерот се наречени софтвер.
 Програмите може да бидат системски или апликативни.
 Процесот на пишување програма се нарекува програмирање, а луѓето што
програмираат се нарекуваат програмери.
 Програмата што ја пишуваат програмерите е изворна програма, која се пре-
ведува со преведувач во извршна програма.
 Програмските јазици се вештачки јазици кои се делат на: виши програмски
јазици, симболички јазици и машински јазик.
 Денес, има разни интегрирани развојни околини за програмирање во С++, а
најпознати се: Microsoft Visual Studio, Visual Studio Code, Code::Blocks и
други.
 Текот на секој алгоритам може да се контролира со користење на следниве
алгоритамски контролни структури: редоследна или секвенца, избор или
селекција и повторување или итерација.
 Јазикот С++ е јазик за објектно ориентирано програмирање.
 Податоците во С++ може да бидат константи или променливи.
 Секој податок има: име, тип и вредност.
 Типовите податоци во С++ може да бидат од основен тип или од апстрактен
тип.
 Основни (прости) типови податоци се: целоброен (int), реален (float, double),
знаковен (char) и логички (bool).

54
2. Основни контролни структури

2. ОСНОВНИ КОНТРОЛНИ СТРУКТУРИ


Во оваа глава ќе се запознаете со следното:

 Споредбени и логички изрази и операции со нив.


 Алгоритамска контролна структура за избор од две можности
ако-тогаш-инаку и ако-тогаш.
 Контролна наредба за избор од две можности if и if-else.
 Условен оператор ?:.
 Алгоритамска контролна структура за избор од повеќе можности
случај.
 Контролна наредба за избор од повеќе можности switch.
 Алгоритамска контролна структура за повторување со излез на
почетокот од циклусот додека-извршувај.
 Оператори за инкрементирање и за декрементирање.
 Контролна наредба за повторување со излез на почетокот од циклусот
while.
 Алгоритамска контролна структура за повторување со излез на крајот од
циклусот извршувај-додека.
 Контролна наредба за повторување со излез на крајот од циклусот do-
while.
 Алгоритамска контролна структура за повторување со броење на
циклусите за-до-чекор.
 Контролна наредба за повторување со броење на циклусите for.

55
ПРОГРАМИРАЊЕ

Клучни зборови

do-while за-намалувај-до
for извршувај-додека
if Иницијализација
if-else Логички израз
switch Логички операции
while Неточно (false)
Ажурирање Оператор за декрементирање
ако-или-ако-инаку Оператор за инкрементирање
Повторување со броење на
ако-тогаш
циклусите
Повторување со излез на крајот од
ако-тогаш-инаку
циклусот
Алгоритамска контролнa
Повторување со излез на почетокот
структурa за повторување со излез
од циклусот
на почетокот од циклусот
Алгоритамска контролна
структура за избор од две Постфиксен
можности
Алгоритамска контролна
структура за избор од повеќе Прекин
можности
Алгоритамска редоследна
Префиксен
контролна структура
Вгнездување случај
Висечко else Точно (true)
Де Морганови закони Условен оператор ?:
додека-извршувај Циклично повторување
за-до-чекор циклус
за-зголемувај-до

56
2. Основни контролни структури

2.1 Споредбени и логички изрази

Споредбените изрази овозможуваат да се провери релацијата помеѓу


аритметичките величини. Како што наведовме, за типот на податок bool во прет-
ходната глава, можеме да ги користиме следните знаци или комбинации од зна-
ци, како релациски оператори:
> Поголемо < Помало
>= Поголемо или еднакво <= Помало или еднакво
== Еднакво != Различно
Примери: 5 > 7; 2 + 3 <= 10; 1 + 8 != 7 + 2;
Секој споредбен израз е операција од два операнди. Резултатот е една од
логичките вредности точно или неточно.
Во првиот споредбен израз од претходните примери, првиот споредбен
израз има вредност „неточно“ (false), операнди му се 5 и 7, а оператор е >.
Вториот споредбен израз има „вредност“ точно (true), операнди се 2 + 3 и
10, а оператор е <=.
Логичките вредности во С++ може да се претстават со броеви. Прифа-
тено е логичката вредност ,,точно‘‘ да се претставува со бројот 1, додека логич-
ката вредност ,,неточно‘‘ со бројот 0. Од друга страна, пак, секој број различен
од нула се смета за „точно“ во јазикот С++, додека нулата се смета за „неточно“.
Во горните примери, изразите ги добиваат вредностите 0, 1 и 0.

Логички операции и изрази

Во компјутерските програми често има потреба да се комбинираат


неколку споредбени изрази истовремено. На пример, имаме потреба да
провериме дали еден број припаѓа во интервалот од 0 до 90 без 90. Тогаш тој
треба да е поголем или еднаков на 0 и помал од 90. (Слично може да се провери и
дали еден број не припаѓа на даден интервал).
Во такви случаи, со помош на споменатите логички оператори за кон-
јункција, дисјункција и негација (&&, || и !), се прави комбинација од
споредбени изрази.
Споменатите примери би се претставиле:
(x >= 0 && x < 90) и !(x >= 0 && x < 90)
И споредбените и логичките изрази со еден збор ќе ги нарекуваме изрази
или услови.

57
ПРОГРАМИРАЊЕ

Вежби

Вежба 2.1.1
Одредете ја вредноста на следните споредбени изрази:
а) 3 > 5;
б) 7 + 8 <= 3;
в) 9 + 4 == 8 + 5;
Која е нивната бројна вредност?

Вежба 2.1.2
Ако а и b се реални променливи со вредности 3 и 5.6, одредете ја
вредноста на следниве изрази:
!7
7 && а
(а * 0) && (b + 1)
(а * 0) || (b + 1)
!(а < b)
!(a > b)
!((a – b) * 3 && b)
Која е нивната бројна вредност?

2.2 Алгоритамска контролна структура за избор од две


можности

Контролните (управувачките) структури за избор се користат за избор на


една од можните насоки на продолжување на дејството во алгоритамот, во за-
висност од некој услов. Условот, најчесто, е некој израз што може да добива раз-
лични вредности.
Во зависност од вредноста на изразот, се избира понатамошниот тек на
алгоритамот.
Постојат два вида контролни структури за избор:
 Избор од две можности.
 Избор од повеќе можности.
Со алгоритамската контролната структура за избор од две можности се
врши избор на едната од двете можности на продолжување на алгоритамот, во
зависност од вредноста на некој израз. Изразот може да има само две вредности:
точно и неточно. Тие се нарекуваат логички вредности и затоа изразот се наре-
кува логички израз.
Контролната структура за избор од две можности графички е претставе-
на на слика 2.2.1.

58
2. Основни контролни структури

Ако вредноста на логичкиот израз е точ-


но, тогаш се извршува чекор А, инаку, ако вред-
носта е неточно, се извршува чекор Б. Затоа, оваа
контролна структура се нарекува ако-тогаш-ина-
ку (англ. if-then-else).
Текстуалниот запис во псевдојазикот на
контролната структура е даден на слика 2.2.2.
Контролната структура почнува со ако, а завршу-
ва со крај_ако {логички израз}.
ако логички израз
тогаш
чекор А;
инаку
чекор Б;
крај_ако {логички израз}
Слика 2.2.1
Слика 2.2.2
На пример, на слика 2.2.3 е користена оваа контролна структура за нао-
ѓање на поголемиот од броевите a и b.
ако a > b Алгоритамската контролна структура за
тогаш избор од две можности ја користевме во ал-
pogolem  a; горитамот за наоѓање на најголемиот од три да-
инаку дени броја. Алгоритамот е даден (текстуално)
pogolem  b; на слика 1.3.1 и (графички) на слика 1.3.7.
крај_ако {a > b} ако логички израз
тогаш
Слика 2.2.3 почеток
Кажавме дека чекорите во еден чекор А1;
алгоритам може да бидат поопшти и да се чекор А2;
состојат од повеќе поедноставни чекори ...
или дури и од цели контролни структури. чекор Аn;
Ако чекор А и чекор Б од слика 2.2.2 се крај
состојат од други контролни структури, инаку
тогаш тие може, но не мора, да се означат почеток
со зборовите почеток и крај, како на сли- чекор Б1;
ка 2.2.4. чекор Б2;
...
чекор Бm;
крај
крај_ако {логички израз}

Слика 2.2.4

59
ПРОГРАМИРАЊЕ

Контролната структура за избор од две можнос-


ти може да се користи и кога една од можностите на
логичкиот израз не содржи извршни чекори. Во тој слу-
чај, нејзиниот запис и графичкото претставување ќе би-
дат како на слика 2.2.5 а и б.
ако логички израз Ваквата контролна
тогаш структура се нарекува ако-
чекор А; тогаш (англ. if-then).
крај_ако {логички израз} На пример, за нао-
ѓање на поголемиот од два
Слика 2.2.5 а дадени броја a и b, со ко-
ристење на оваа контролна
структура, ќе запишеме:
pogolem  b;
ако a > b Слика 2.2.5 б
тогаш
pogolem  a; алгоритам Најголем
крај_ако {a > b} почеток
почеток
На слика 2.2.6 е даден текстуалниот a  ... ;
запис на алгоритамот за задачата за наоѓање на b  ... ;
најголемиот од три дадени броја (даден на c  ... ;
слика 1.3.1 и слика 1.3.7), со користење на крај
контролната структура ако-тогаш. p  b;
ако a > b
Вежби тогаш
p  a;
Вежба 2.2.1 крај_ако {a > b}
Одговорете: Кои се можните n  c;
чекори за одредување на средната ако p > c
вредност на три броја? тогаш
n  p;
Вежба 2.2.2. крај_ако {p > c}
Што ќе се отпечати по извршу- печати n;
вањето на следниов алгоритамски сег- крај {Најголем}
мент:
ако a < b Слика 2.2.6
тогаш
pom  a;
инаку
pom  b;
крај_ако {a > b}
печати pom;
60
2. Основни контролни структури

Вежба 2.2.3
За следниве задачи да се напишат алгоритми со користење на ре-
доследната контролна структура и структурата за избор од две мож-
ности.
1. Да се пресметаат квадратот и кубот на природниот број n.
2. Да се пресметаат обиколката на кружницата и плоштината на кругот
со радиус r.
3. Да се прочита трицифрен природен број и да се отпечати средната
цифра.
4. Да се прочитаат три броја и да се утврди дали може да бидат страни
на триаголник.
5. Да се подредат три броја по големина.
6. Да се утврди дали природниот број n е парен или непарен.
7. Да се реши линеарната равенка: ax + b = 0.
8. Да се реши линеарната неравенка: ax + b > 0.

2.3 Контролни наредби за избор од две можности

Контролна наредба за избор if

Со контролната наредба за избор if се изразува алгоритамската контролна


структура за избор од една можност ако-тогаш:
Контролна структура Контролна наредба
ако услов if (услов)
тогаш {
чекор 1; наредба 1;
... ...
чекор р; наредба m;
крај_ако {услов} }

Ако услов има вредност true, тогаш се извршуваат наредбите од телото на


контролната наредба, а ако услов има вредност false, наредбите не се извршу-
ваат. Услов може да биде израз од кој било податочен тип. Притоа, ако тој има
вредност различна од 0, се третира како true, а инаку како false.
Логичките изрази во С++ се градат со релациски и со логички оператори.
Примери за логички изрази се следните:
a > b && a >= c
alfa < 90 && beta > 0 || (alfa – beta) > 0
!(x <= y) исто со x > y
!(a > b && a >= c) исто со a <= b || a < c
!(x != y || x > y) исто со x == y && x <= y

61
ПРОГРАМИРАЊЕ

Следниве два примери ја илустрираат контролната наредба if:

Пример: Пример:
if (x < 0) int x;
xaps = –x; if (x)
cout << x << endl;

Контролна наредба за избор if-else

Со оваа контролна наредба за избор се реализира алгоритамската кон-


тролна структура за избор од две можности ако-тогаш-инаку.
Контролна структура Контролна наредба
ако услов if (услов)
тогаш {
{ наредби А;
чекори А; }
} else
инаку {
{ наредби Б;
чекори Б; }
}
крај_ако {услов}

Забелешка:
Со чекори А ќе го означиме блокот чекори:
чекор А1;
...
чекор Ај;
Истото важи и за чекори Б, наредби А и наредби Б.
Ако некој од блоковите наредби А или наредби Б има само една наредба,
тогаш не мора да се стават заградите:
if (услов)
наредба 1;
else
наредба 2;
Контролните наредби за избор if и if-else може да се вгнездуваат една во
друга. Притоа, треба да се води сметка дека преведувачот во С++ секое else го
поврзува со претходното if. На пример, во следниот програмски сегмент, за a < b
нема ништо да се отпечати бидејќи else е врзано со второто if, а не со првото:
if (a > b)
if (a > c)
cout << "Najgolem broj e " << a;
62
2. Основни контролни структури

else
cout << "Najgolem broj ne e " << a;
Ова е наречено проблем на висечко else (англ. dangling-else problem).
Ако вгнездувањето се врши во else, се добива контролната структура
ако-или-ако-инаку.
Пример:
if (услов 1)
наредба 1;
else if (услов 2)
наредба 2;
else if (услов 3)
наредба 3;
else
наредба 4;
а
if (услов 1)
наредба 1;
else if (услов2)
{ наредба 2;
if (услов 3)
наредба 3;
}
else
наредба 4;
б
Горните два примери под а) и под б) се различни. Во случајот под а),
наредба 4 ќе се изврши само ако сите три услови не се исполнети, а во случајот
под б), кога не се исполнети првиот и вториот услов, независно дали е исполнет
третиот услов.
Рековме дека услов претставува логички израз кој може да има само две
вредности: true или false. Во него може да се користат релациските и логичките
оператори со кои се запознавме претходно.
Важат и Де Моргановите закони за:
дистрибуција на негацијата и И: !(m || n) дава !m && !n
дистрибуција на негацијата и ИЛИ: !(u && v) дава !u || !v

63
ПРОГРАМИРАЊЕ

Примери:

Пример 2.3.1
Да се провери дали зададен агол е остар или не.

алгоритам Агол
почеток
печати „Внесете агол во степени: “;
читај аlfa;
ако ((аlfa > 0) И (alfa < 90))
тогаш
печати „Аголот е остар.“;
инаку
печати „Аголот не е остар.“;
крај_ако {((alfa > 0) И (alfa < 90))
крај {Aгол}

#include <iostream>
using namespace std;

int main()
{
int alfa;
cout << "Vnesete agol vo stepeni: " << endl;
cin >> alfa;
if ((alfa > 0) && (alfa < 90))
cout << "Agolot e ostar. " << endl;
else
cout << "Agolot ne e ostar. " << endl;
return 0;
}

Пример 2.3.2
Да се провери дали зададен број е поголем, еднаков или помал од 5.

алгоритам Броеви
почеток
печати „Внесете број и притиснете Enter: “;
читај i;
ако i > 5
тогаш
печати „Бројот е поголем од 5. “;
печати „i = “, i;
64
2. Основни контролни структури

инаку
ако i < 5
тогаш
печати „Бројот е помал од 5.“;
инаку
печати „Бројот е еднаков на 5.“;
крај_ако {i < 5}
крај_ако {i > 5}
крај {Броеви}

#include <iostream>
using namespace std;

int main()
int i;
cout << "Vnesete broj i pritisnete Enter: " << endl;
cin >> i;
if (i > 5)
{
cout << "Brojot e pogolem od 5. " << endl;
cout << "i = " << i << endl;
}
else
if (i < 5)
cout << "Brojot e pomal od 5. " << endl;
else
cout << "Brojot e ednakov na 5. " << endl;
return 0;
}

Пример 2.3.3
Да се погоди кој број помеѓу 1 и 10 го замислил компјутерот.
алгоритам ПогодувањеБрој
почеток
zamislenBroj  7;
печати „Внесете број помеѓу 1 и 10: “;
читај broj;
ако broj = zamislenBroj
тогаш
печати „Браво, погодивте.“;
инаку
печати „Жалам, не погодивте.“;
печати „Замислениот број е: “;
65
ПРОГРАМИРАЊЕ

печати zamislenBroj;
крај_ако {broj = zamislenBroj}
крај {ПогодувањеБрој}
#include <iostream>
using namespace std;

int main()
{
int zamislenBroj = 7, broj;
cout << "Vnesete broj megju 1 i 10: " << endl;
cin >> broj;
if (broj == zamislenBroj)
cout << "Bravo, pogodivte. " << endl;
else
{
cout << "Zalam, ne pogodivte! " << endl;
cout << "Zamisleniot broj e ";
cout << zamislenBroj << endl;
}
return 0;
}
Пример 2.3.4
Да се одреди најголемиот од три дадени броја.

алгоритам НајголемБрој
почеток
печати „Внесете три различни броја: “;
читај a, b, c;
ако a > b
тогаш
ако a > c
тогаш
печати a;
инаку
печати c;
крај_ако {a > c}
инаку
ако b > c
тогаш
печати b;
инаку
печати c;
крај_ако {b > c}
66
2. Основни контролни структури

крај_ако {a > b}
крај {НајголемБрој}
#include <iostream>
using namespace std;

int main()
{
int a, b, c;
cout << "Vnesete tri razlicni broja: " << endl;
cin >> a >> b >> c;
if (a > b)
if (a > c)
cout << a << endl;
else
cout << c << endl;
else
if (b > c)
cout << b;
else
cout << c;
return 0;
}

Условен оператор ?:
Условниот оператор се користи за претставување на едноставни наредби
if-else. Неговата синтакса е:
услов? израз Т : израз Н;
Прво се пресметува услов чија вредност може да биде true или false. Ако е
true, тогаш се пресметува израз Т, а ако е false се пресметува израз Н.
На пример:
if (m > n)
s = m – n;
else
s = n – m;
Програмскиот сегмент може да се запише и на следниов начин:
s = (m > n) ? (m – n) : (n – m);
Со следнава наредба ќе се отпечати „paren.“ ако променливата broj има
парна вредност, во спротивно ќе се отпечати „neparen.“.
cout << "Brojot " << broj << " e " << (broj % 2) ? "paren." :
"neparen.";
На пример, за broj = 5 ќе се отпечати:
Brojot 5 e neparen.
67
ПРОГРАМИРАЊЕ

Вежби

Вежба 2.3.1
Да се одговори на следниве прашања:
1. Од каков тип е изразот кај структурата за избор од две можности?
2. Која структура се добива со вгнездување на наредбите if-else?

Вежба 2.3.2
Да се најде грешката во следниов програмски сегмент:
if (x = a)
cout << x << " ima ista vrednost so a. " ;
else
cout << x << " ima razlicna vrednost od a. ";

Вежба 2.3.3
Да се утврди што ќе се отпечати при извршување на следниов
програмски сегмент:
int i = 0, n;
float a = 1;
char c = 'a';
a++;
if (c == a && i == 0)
n = 1;
else
n = 2;
cout << 'n = ' << n << endl;
Резултатот да се провери со вметнување на дадениот програмски
сегмент во програма и нејзино извршување.

Вежба 2.3.4
Да се напишат алгоритми со контролните структури за избор од
две можности ако-тогаш или ако-тогаш-инаку и програми со наредби-
те if или if-else.
1. За внесен агол  помал од 180о и да се утврди дали е остар, прав или
тап.
2. Да се подредат три броја по големина во растечки редослед.
3. Да се најде најголемиот од три реални броја.
4. Да се утврди дали три цели броја можат да бидата страни на
триаголник.
5. Да се одреди дали некоја година е престапна.

68
2. Основни контролни структури

2.4 Алгоритамска контролна структура за избор од повеќе


можности

Кога има повеќе можности за продолжување на дејството во алгоритамот,


се користи алгоритамската контролна структура за избор од повеќе можности.
Изборот на една од можностите се врши во зависност од вредноста на некој
податок или на некој аритметички израз.
Оваа алгоритамска контролна
структура графички е претставена на
слика 2.4.1. Вредноста на израз може
да биде a, b... k или израз да не добие
ниту една од тие вредности. Во случај
израз да добие вредност a, дејството
продолжува со чекор А, во случај
вредноста на израз да е b, дејството
продолжува со чекор Б итн. Во случај
израз да не добие ниту една од вред-
ностите a, b... k, тогаш дејството про-
должува со чекор Х.
Од досега кажаното се гледа
дека со оваа алгоритамска контролна
структура се врши избор на еден од
повеќе можни случаи. Затоа, таа се
нарекува избор во случај или, пократ-
ко, само случај (англ. case). Нејзиниот
запис со псевдојазикот е даден на сли-
ка 2.4.2.
случај израз
a: чекор А;
прекин;
b: чекор Б;
Слика 2.4.1
прекин;
... Вредностите што може да ги добие израз, како и
k: чекор К; ознаките а, b... k, мора да бидат константи од целоброен,
прекин; знаковен, логички или наброив тип. Тие не може да
инаку бидат променливи.
чекор Х; По чекорите А, Б... К, е наведена алгоритамската
крај_случај {израз} контролна структура прекин, со која се прекинува из-
вршувањето на останатите чекори во контролната
Слика 2.4.2 структура случај и дејството продолжува со чекорот
или контролната структура по крај-случај {израз}. (За
алгоритамската контролна структура прекин ќе зборуваме подоцна).
69
ПРОГРАМИРАЊЕ

Алгоритамот за задачата за алгоритам Успех


испишување на општиот успех на почеток
ученик кога е даден бројниот успех читај n;
5, 4, 3, 2 и 1, со користење на кон- случај n
тролната структура случај, е даден 5: печати „Одличен“;
на слика 2.4.3. прекин;
4: печати „Мн. добар“;
Вежби прекин;
3: печати „Добар“;
Вежба 2.4.1 прекин;
Размислете и одговорете: 2: печати „Доволен“;
1. За што се користи алго- прекин;
ритамската контролна 1: печати „Недоволен“;
прекин;
структура за избор од по-
инаку
веќе можности случај? печати „Грешка“;
2. Дали со користење само крај_случај {n};
на алгоритамската кон- крај {Успех}
тролна структура за из- Слика 2.4.3
бор од повеќе можности
може да се избере најголемиот од 5 броја?
3. Од кој тип мора да бидат вредностите на логичкиот израз во кон-
тролната структура за избор од повеќе можности?

Вежба 2.4.2
За следниве задачи да се напишат алгоритми, со користење на
алгоритамската контролна структура за избор од повеќе можности
случај.
1. Да се внесе буква и да се утврди дали е голема или мала.
2. Да се внесе агол α и да се утврди дали е остар или тап.
3. Да се внесе природен број помал од 10 и да се отпечати дали е прост,
делив со 2, делив со 3 или совршен.
4. Да се внесат два броја и еден оператор: +, –, * или / и да се отпечати
резултатот од соодветната операција.
5. Да се отпечати следново мени:
1. Професор по македонски јазик
2. Професор по математика
3. Професор по информатика
4. Професор по физика
Потоа во зависност од внесениот број (еден од броевите 1, 2, 3, 4), да
се отпечати името на соодветниот професор.

70
2. Основни контролни структури

2.5 Контролна наредба за избор switch

Со оваа контролна наредба се реализира алгоритамската контролна


структура за избор од повеќе можности (случај). Нејзината синтакса е:
Контролна структура Контролна наредба
случај израз switch (израз)
a: чекори А; {
прекин; case a: наредби А;
b: чекори Б; break;
прекин; case b: наредби Б;
... break;
k: чекори К; ...
прекин; case k: наредби К;
инаку чекори Х; break;
крај_случај {израз}
default: наредби Х;
}
Изразот во загради (израз) може да биде кој било израз чии вредности се
целобројни. Ознаките a, b... k се константи или целобројни изрази. Се извршу-
ваат сите наредби по ознаките сè до првата наредба break, чие дејство е скок
(излез) на крајот на наредбата switch. Затоа, мора да се користи наредбата break
по секој case. Ако не се наведе наредбата break, извршувањето продолжува со
наредбите од следниот дел case.
Ако израз не добие ниту една вредност од наведените по зборот case, то-
гаш се извршуваат наредбите по зборот default. Одделот default е опционален, не
мора да се наведе.
Во следниот пример, во зависност од вредноста на znak, се извршува
соодветната аритметичка операција:
switch (znak) {
case '+' : cout << znak << "plus ";
break;
case '– ': cout << znak << "minus";
break;
case '*': cout << znak << "po";
break;
case '/': cout << znak << "vrz";
break;
default:
cout << znak << endl;
break;
}
Следната наредба switch ја прикажува вредноста на znak ако тој е
самогласка:

71
ПРОГРАМИРАЊЕ

switch (znak) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
cout << znak << endl;
break;
}

Примери

Пример 2.5.1
Да се внесе цифра меѓу 1 и 9 и да се отпечати дали е парна или непарна.
Ако не сме внеле цифра меѓу 1 и 9, да се даде коментар за грешен влез.

алгоритам Број
почеток
печати „Внесете број помеѓу 1 и 9: “;
читај broj;
случај broj
1, 3, 5, 7, 9:
печати „Внесовте непарен број.“;
2, 4, 6, 8:
печати „Внесовте парен број.“;
инаку
печати „Бројот не е меѓу 1 и 9.“;
крај_случај {broj}
крај {Број}

#include <iostream>
using namespace std;

int main() {
int broj;
cout << "Vnesete broj pomegju i i 9: ";
cin >> broj;
switch (broj) {
case 1:
case 3:
case 5:
case 7:
case 9:
cout << "Vnesen e neparen broj. " << endl;
72
2. Основни контролни структури

break;
case 2:
case 4:
case 6:
case 8:
cout << "Vnesen e paren broj." << endl;
break;
default:
cout << "Brojot ne e megju 1 i 9." << endl;
}
return 0;
}

Пример 2.5.2
Да се состави алгоритам со кој ќе се одреди бројот на денови за
внесен месец. Месеците се внесуваат со редниот број: 1, 2... 12.

алгоритам ДеновиВоМесец
почеток
печати „Внесете го редниот број на месецот: “;
читај meces;
случај mesec
1, 3, 5, 7, 8, 10, 12: печати „Месецот има 31 ден.“;
4, 6, 9, 11: печати „Месецот има 30 дена.“;
2: печати „Февруари во престапни години има 29
дена. Во сите останати има по 28 дена.“;
инаку: печати „Внесовте грешен број на месец.“;
крај_случај {mesec}
крај {ДеновиВоМесец}

Вежби

Вежба 2.5.1
Одговорете на следниве прашања:
1. Со кои наредби се реализирани контролните структури за избор во
C++?
2. Што ќе се отпечати како резултат од извршување на следниве
програмски сегменти:
a)
char znak;
znak = 'c';
switch( znak ) {
case 'a':
73
ПРОГРАМИРАЊЕ

case 'e':
case 'i':
case 'o':
case 'u':
cout << "Samoglaska." << endl;
break;
default:
cout << "Soglaska." << endl;
}

б)
char znak;
znak = 'a';
switch( znak ) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
cout << "Samoglaska." << endl;
break;
default:
cout << "Soglaska." << endl;
}

Вежба 2.5.2
Да се решат следниве задачи со користење на наредбата switch.

1. Да се определи оценка за ученик според освоените бодови ако


оценувањето се извршува според следната скала: помалку од 60 –
недоволен, од 60 до 69 – доволен, од 70 до 79 – добар, од 80 до 89 –
многу добар и повеќе од 90 – одличен.
2. Напишете програма која ќе симулира едноставен калкулатор со
следните операции: +, , * и /.

74
2. Основни контролни структури

2.6 Алгоритамска контролнa структурa за повторување со


излез на почетокот од циклусот

Алгоритамските контролни структури за повторување се користат тогаш


кога е потребно една група алгоритамски чекори да се извршат повеќепати. Едно
извршување на чекорите се нарекува еден циклус, слика 2.6.1. Затоа, таквото
повторување на извршувањето на група алгоритамски
циклус
чекори се нарекува циклично повторување.
чекор А;
Да ја разгледаме следнава задача:
чекор Б;
Да се најде збирот на првите 10 природни броеви.
...
Збирот ќе го најдеме на следниов начин: на поче-
чекор М;
токот збирот е 0 и прв природен број кој го додаваме на
крај_циклус
збирот е 1. Потоа, на збирот го додаваме следниот приро-
Слика 2.6.1 ден број, тоа е 2, па следните: 3, 4... итн. сè додека не го до-
дадеме и бројот 10.
Можеме да забележиме дека за наоѓање на збирот се извршуваат само две
дејства:
 Додавање број на збирот.
 Зголемување на бројот за 1.
Ако почетната вредност на збирот е 0 и првиот природен број е 1, постап-
ката можеме текстуално да ја претставиме со следниот циклус:
zbir  0; Чекорите во циклусот се повторуваат
broj  1; сè додека не го додадеме и бројот 10. Значи,
циклус 10 пати услов за прекинување на повторувањето на
– додади го broj на zbir; циклусот е broj да ја достигне вредноста 10.
– зголеми го broj за 1; За прекинување на некое циклично
крај_циклус повторување, се испитува некој услов. Тој
може да се испитува пред почетокот на ци-
клусот или по неговото завршување. Трет начин на прекинување на повтору-
вањето е кога циклусот ќе се повтори одреден број пати. Затоа, се воведени три
форми на алгоритамските контролни структури за повторување:
 Повторување со излез на почетокот од циклусот.
 Повторување со излез на крајот од циклусот.
 Повторување со броење на циклусите.

75
ПРОГРАМИРАЊЕ

Алгоритамската контролна структура за повторување со излез на почето-


кот од циклусот може да се запише како на слика 2.6.2.
Структурата се состои од чекорите А, Б...
додека услов извршувај М. Едно извршување на чекорите од А до М е еден
чекор А; циклус. Пред почетокот на секој циклус, се испи-
чекор Б; тува дали е исполнет условот (услов), кој претста-
... вува логички израз со две вредности: точно и
чекор М; неточно. Додека е исполнет (точен) условот (ус-
крај_додека {услов} лов), се извршуваат чекорите од циклусот и деј-
Слика 2.6.2 ството се враќа на почетокот од циклусот. Кога во
некое испитување на условот (услов), ќе се конста-
тира дека тој не е исполнет (не е точен), се прескокнуваат сите чекори и деј-
ството продолжува со чекорот по крај_додека {услов}. Затоа, структурата се
нарекува додека-извршувај (англ. while-do).
Бидејќи условот се испитува пред секој циклус, може да се случи условот
да не е исполнет уште при првото испитување и притоа, е можно да не се изврши
ниту еден циклус.
Графичкото претставување на алго-
ритамската контролна структура додека-из-
вршувај е дадено на слика 2.6.3.
Во задачата за збирот на првите 10
природни броеви, кажавме дека циклусот ќе
се повторува додека broj е помал или ед-
наков на 10. Значи условот ќе биде broj ≤ 10.
Алгоритамот и неговиот графички приказ, со
користење на алгоритамската контролна
структура додека-извршувај, ќе бидат како
на слика 2.6.4 а и б.
алгоритам ЗбирДо10
почеток
zbir  0;
broj  1;
додека broj  10 извршувај
zbir  zbir + broj;
broj  broj + 1;
крај_додека {broj  10}
печати zbir;
крај {ЗбирДо10}
Слика 2.6.4 а
Слика 2.6.3

76
2. Основни контролни структури

За алгоритамот од слика 2.6.4 а


може да забележиме дека во чекорите
zbir  zbir + broj;
и
broj  broj + 1;
се врши доделување вредности. Во првиот
чекор, се доделува нова вредност на zbir,
така што на старата вредност се додава
вредноста на broj. Во вториот чекор, се до-
делува нова вредност на природниот број
broj, која се добива со зголемување на broj
за 1 итн.

Вежби

Вежба 2.6.1
Размислете и одговорете:
1. За кои типови проблеми се ко-
ристат алгоритамските кон-
тролни структури за повтору-
вање?
2. Која алгоритамска контролна
структура за повторување ќе ја
користиме доколку е можно
структурата да не се изврши
ниту еднаш? Зошто?

Вежба 2.6.2
Што работи следниов алго- Слика 2.6.4 б
ритамски сегмент:
додека r | k извршувај {r | k значи r го дели k без остаток}
печати r;
k  k / r;
крај_додека { r | k }

Вежба 2.6.3
Што печати следниов алгоритам:
алгоритам Непознат
почеток
печати „Внесете број: “;
читај n;
s  0;
77
ПРОГРАМИРАЊЕ

i  1;
додека i  n извршувај
печати „Внесете број: “;
читај x;
s  s + x;
i  i + 1;
крај_додека {i  n}
печати s;
крај {Непознат}

Вежба 2.6.4
Да се напишат алгоритми за следниве задачи со користење на ал-
горитамската контролна структура додека-извршувај.
1. Да се пресмета аритметичката средина на природните броеви до n.
2. Да се пресмета сумата 1 + 4 + 7 + 11 +… + n.
3. Да се внесе природен број и да се утврди колку цифри има.
4. Да се пресмета збирот на цифрите на природниот број n.
5. Да се најде бројот кој ги има истите цифри со природниот број n, но
во спротивен редослед.
6. Да се најдат сите делители на природниот број n.

2.7 Контролна наредба за повторување while

Пред да се запознаеме со наредбата while, ќе објасниме за специфичен


вид оператори во С++.

Оператори за инкрементирање и за декрементирање

Во С++ се користат оператори за зголемување или за намалување на


вредноста на некоја променлива за 1. Тие се наречени оператори за инкременти-
рање и за декрементирање. Операторот за инкрементирање е ++, а за декремен-
тирање е . Инкрементирањето или декрементирањето на вредноста на про-
менливата х може да се врши во префиксна (++х или х) или постфиксна (х++
или х) форма. Во првиот случај, инкрементирањето или декрементирањето се
извршува пред, а во вториот по пресметување на изразот во кој учествува про-
менливата х.
Оператор Форма Инкремент Декремент
++ ++х префиксен
х++ постфиксен
 х префиксен
х постфиксен
78
2. Основни контролни структури

Пример:
Вредност на х пред Израз Вредност на Вредност на х по
пресметувањето изразот пресметувањето
5 ++х 6 6
5 х++ 5 6
5 х 4 4
5 х 5 4
Инкрементирањето или декрементирањето може да се смета како краток
запис на наредба за доделување, преку која на дадена променлива ѝ се доделува
вредност различна за 1 од нејзината дотогашна вредност.
Следнава програма илустрира употреба на оператор за инкрементирање:
#include <iostream>
using namespace std;

int main() {
int a, b, c;
a = b = c = 1;
cout << a << " " << b << " " << c << endl;
a = b + c++;
cout << a << " " << b << " " << c << endl;
a = b = c = 1;
a = b + ++c;
cout << a << " " << b << " " << c << endl;
return 0;
}
По извршување на програмата, излезот е:
1 1 1
2 1 2
3 1 2

Контролната наредба while се користи за реализација на алгоритамската


контролна структура додека-извршувај.
Контролна структура Контролна наредба
додека услов извршувај while (услов)
чекор А; { наредба 1;
чекор Б; наредба 2;
... ...
чекор М; наредба m;
крај_додека {услов} }

Притоа, важи дека условот (услов) е логички израз кој може да има
вредност true или false. Условот (услов) се испитува пред почетокот на секој
циклус. Ако вредноста на условот (услов) е true (или е израз со вредност различна
79
ПРОГРАМИРАЊЕ

од 0), тогаш се извршува следниот циклус, а ако вредноста на условот (услов) е


false (или е израз еднаков на 0), тогаш не се извршува следниот циклус, туку се
скока на крајот од телото на наредбата while и се продолжува со следната наред-
ба по наредбата while.
Ако условот (услов) не е исполнет уште при првиот циклус, тогаш наред-
бата while не се извршува ниту еднаш.
Примери
Пример 2.7.1
Да се пресмета збирот на првите n природни броеви.
алгоритам Збир
почеток
broj  0;
zbir  0;
печати „Внесете го n = “;
читај n;
додека broj < n извршувај
broj  broj + 1;
zbir  zbir + broj;
крај_додека {broj < n}
печати „Збирот на првите “, n, „ природни броеви e “, zbir;
крај {Збир}
#include <iostream>
using namespace std;

int main() {
int n;
int broj = 0;
int zbir = 0;
cout << "Vnesete go n = ";
cin >> n;
while (broj < n) {
++broj;
zbir += broj;
}
cout << "Zbirot na prvite " << n;
cout << " prirodni broevi e " << zbir << endl;
return 0;
}
По извршување на програмата, излезот е:
Vnesete go n = 7
Zbirot na prvite 7 prirodni broevi e 28

80
2. Основни контролни структури

Пример 2.7.2
Да се пресмета бројот на знаци во еден ред внесен текст.
Објаснување: За прекинување на повторувањето, честопати се користи
споредба со одреден знак или текст. Во следнава програма, повторувањето се
извршува додека вредноста на променливата znak е различна од знакот за крај на
линијата '\n'.
#include <iostream>
using namespace std;

int main() {
char znak;
cout << "Vnesete tekst: ";
int brojznaci = 0;
cin.get (znak);
while (znak != '\n') {
++brojznaci;
cin.get(znak);
}
cout << "Brojot na vneseni znaci e " << brojznaci << endl;
return 0;
}
Еден можен излез е:
Vnesi tekst: eden dva tri
Brojot na vneseni znaci e 12
Во програмата за читање на еден знак се користи посебна наредба
(функција) cin.get(). Разликата во однос на користење на наредбата cin е следна-
ва: со користење на наредбата cin << znak;, кога на корисникот ќе му се појави
курсорот кој му покажува да внесе знак, корисникот треба да внесе еден знак и
да притисне Enter или празно место за да може знакот да се внесе во меморија и
да се продолжи со извршување на програмата. Со користење на наредбата
cin.get(znak);, кога на корисникот ќе му се појави курсорот кој му укажува да
внесе знак, корисникот треба да внесе еден знак, без да притисне Enter или што
било друго. Знакот кој го внел ќе се внесе во меморијата и ќе се продолжи со
извршување на програмата. Еден совет кој треба да се запамети е: доколку е
можно, во иста програма да се користи само наредбата cin или само наредбата
cin.get(). Ова е важно за помалку искусните програмери затоа што комбинаци-
јата на овие две наредби може да предизвика некои странични ефекти.

Пример 2.7.3
Да се најде најголемиот заеднички делител за два природни броја.
Објаснување: Најголемиот заеднички делител (НЗД) за два броја може да
биде помалиот од нив ако се броевите деливи еден со друг, или првиот број по-

81
ПРОГРАМИРАЊЕ

мал од помалиот, со кој се деливи и двата броја. Затоа, прво претпоставуваме


дека НЗД е помалиот од нив, а ако не е, тогаш со наредбата while го намалуваме
НЗД за 1 во секој циклус додека не најдеме број со кој се деливи двата дадени
броја.
Испитувањето дали бројот е делив со НЗД се врши со операторот %, кој
го дава остатокот од делењето.
#include <iostream>
using namespace std;

int main() {
int nzd, a, b;
cout << "Vnesete dva prirodni broja: " << endl;
cin >> a;
cin >> b;
if (a < b)
nzd = a;
else
nzd = b;
while ((a % nzd != 0) || (b % nzd != 0))
nzd = nzd – 1;
cout << "Najgolem zaednicki delitel na " << a;
cout << " i " << b << " e " << nzd << endl;
return 0;
}
Излезот од извршување на програмата е:
Vnesete dva prirodni broja:
80
120
Najgolem zaednicki delitel na 80 i 120 e 40

Вежби

Вежба 2.7.1
Да се даде одговор на следниве прашања:
1. Која е општата синтакса на наредбата while?
2. Какви вредности може да прими условот во наредбата while?

Вежба 2.7.2
Да се најде грешката во следниов програмски сегмент:
x = 1;
while (x >= 0)
suma = suma + x;

82
2. Основни контролни структури

Вежба 2.7.3
Да се утврди што ќе се отпечати по извршување на следниов про-
грамски сегмент:
i = 0;
while (i < 10) {
i = i + 2;
cout << i << endl;
}

Вежба 2.7.4
Да се испечатат целите броеви од 1 до 20, со користење на на-
редбата while и контролна променлива i.

Вежба 2.7.5
Да се решат следниве задачи со користење на наредбата while:
1. Да се пресмета сумата на n цели броеви.
2. Да се пресмета производот на внесени цели броеви додека се внесува
број различен од нула.
3. Да се провери дали природниот број n е прост или не е.
4. Да се отпечатат сите прости броеви помали од природниот број n.
5. Да се претстави бројот n во бинарниот броен систем.
6. Да се пресмета вредноста на бројот e = 2.718281 со дадена точност ,
1 1 1 1
преку изразот e  1      ... (Точноста  се постигнува
1! 2! 3! 4!
1
кога собирокот < ).
к!
7. Да се пресмета производот 1  2  3 …  n.
8. Да се отпечатат буквите од абецедата од A до Z.
9. Да се пресмета збирот на броевите од a до b со чекор c, т. е.
вредноста на изразот a + (a + c) + (a + 2c) + (a + 3c) +…
10. Да се отпечати спротивниот број на природниот број n кој не завр-
шува со 0.

83
ПРОГРАМИРАЊЕ

2.8 Алгоритамска контролна структура за повторување со


излез на крајот од циклусот

Во задачата за наоѓање на збирот на првите 10 природни броеви од точ-


ката 2.6 Алгоритамска контролна структура за повторување со излез на по-
четокот од циклусот, рековме дека се повторуваат само две дејства:
 Додавање broj на zbir. zbir  0;
 Зголемување на broj за 1.
broj  1;
Можеме да кажеме: циклусите со овие
извршувај
две дејства се извршуваат додека broj има по-
– додади го broj на zbir;
мала или еднаква вредност на 10. Затоа, оваа
– зголеми го broj за 1;
контролна структура се нарекува извршувај-
додека broj ≤ 10;
додека. Тоа можеме да го претставиме како на
крај_ додека {broj ≤ 10}
слика 2.8.1.
печати zbir;
Во оваа контролна структура, условот
дали следниот циклус ќе се изврши или не, се Слика 2.8.1
испитува на крајот по извршување на секој ци-
клус.
Текстуалниот запис на контролната структура извршувај-додека (англ.
do-while) е даден на слика 2.8.2, додека графичкиот
приказ е даден на слика 2.8.3.
извршувај
чекор А;
чекор Б;
...
чекор М;
додека услов;
крај_извршувај {услов}
Слика 2.8.2

Алгоритамот за задачата за збирот на пр-


вите 10 природни броеви изразен текстуално со
контролната структура извршувај-додека е даден
на слика 2.8.4.

Слика 2.8.3
84
2. Основни контролни структури

Графичкиот приказ е даден на слика 2.8.5.


алгоритам Збир
почеток
zbir  0;
broj  1;
извршувај
zbir  zbir + broj;
broj  broj + 1;
додека broj  10;
крај_извршувај {broj  10}
печати zbir;
крај {Збир}
Слика 2.8.4

2.9 Контролна наредба do-while

Оваа контролна наредба се користи за реали-


зација на алгоритамската контролна структура извр-
шувај-додека.
Контролна структура Контролна наредба
извршувај do
чекор А; {
чекор Б; наредба 1;
... наредба 2;
чекор Е; ...
додека (услов); наредба i;
крај_извршувај {услов} }while (услов); Слика 2.8.5

Контролната наредба do-while се користи кога некој програмски сегмент


треба да се изврши барем еднаш, а неговото повторно извршување зависи од не-
кој услов.
Извршувањето се повторува додека е исполнет условот (uslov). Кога
условот (uslov) нема да биде исполнет, повторувањето завршува и дејството
продолжува со следната наредба.

Примери

Пример 2.9.1
Да се најде збирот на првите n природни броеви.

85
ПРОГРАМИРАЊЕ

#include <iostream>
using namespace std;

int main() {
int n;
int broj = 1;
int zbir = 0;
cout << "Vnesete kolku broevi kje sobirate, n = ";
cin >> n;
do {
zbir += broj;
++broj;
} while (broj <= n);
cout << "Zbirot na prvite " << n << " prirodni broevi e ";
cout << zbir;
return 0;
}
По извршувањето на програмата, излезот е:
Vnesete kolku broevi kje sobirate, n = 10
Zbirot na prvite 10 prirodni broevi e 55

Пример 2.9.2
Да се пресмета вредноста на бројот e = 2.718281 со дадена точност ,
1 1 1 1
преку изразот e  1      ... (Точноста  е постигната кога последниот
1! 2! 3! 4!
1
собирок  ).
k!
алгоритам БројотЕ
почеток
печати „Внеси ја точноста  за пресметување на бројот е (пр., 0.001)“;
читај ;
e  1;
i  1;
clen  1;
извршувај
clen  clen / i;
e  e + clen;
i  i + 1;
додека clen >= ;
крај_извршувај
печати „Бројот е со точност “, , „ изнесува “, e;
крај {БројотЕ}

86
2. Основни контролни структури

#include <iostream>
using namespace std;

int main() {
int i;
double e, eps, clen;
cout << "Vnesete tocnost, eps = "; cin >> eps;
e = 1;
i = 1;
clen = 1;
do {
clen /= i;
e += clen;
i++;
}while (clen >= eps);
cout << "Brojot e so tocnost " << eps << " iznesuva " << e;
return 0;
}

Вежби
Вежба 2.9.1
Oдговорeтe на следниве прашања:
1. Која контролна структура се реализира со наредбата do-while?
2. Која е разликата помеѓу наредбата while и do-while?
Вежба 2.9.2
Да се утврди што извршува следниов програмски сегмент:
x = 1; i = 0;
do {
x++;
i += x;
}while (x <= 10);
Вежба 2.9.3
Да се утврди што ќе се отпечати како резултат на извршување на
следниов програмски сегмент:
i = 0;
do {
i += 2;
cout << i << endl;
}while (i < 5);
Вежба 2.9.4
Да се отпечатат сите цели броеви од 1 до 20, со користење на
наредбата do-while.
87
ПРОГРАМИРАЊЕ

2.10 Алгоритамска контролна структура за повторување


со броење на циклусите

Кај претходно разгледаните алгоритамски контролни структура за повто-


рување, циклусот се повторува додека е исполнет некој услов или до исполнува-
ње на некој услов. Притоа не се знае колку пати ќе се повтори циклусот, т. е. кол-
ку циклуси ќе се извршат.
Во алгоритамската контролна структура за повторување со броење на
циклусите, бројот на повторувања на циклусот е однапред познат. Поточно ре-
чено, тој број може да се пресмета од параметрите на структурата.
Повторувањата се бројат со посебен бројач, за кој се задаваат почетната и
крајната вредност, а се задава и големината на чекорот со кој се менуваат вред-
ностите од почетната до крајната
(Овој поим за чекор не е во врска за brojac  pocetna до krajna чекор iznos
со поимот алгоритамски чекор). чекор А;
Циклусот се извршува за чекор Б;
секоја вредност на бројачот (bro- ...
jac) од почетната (pocetna) вред- чекор M;
ност до крајната (krajna) вредност, крај_за {brojac}
во секој чекор за одреден iznos. Слика 2.10.1а
Затоа, оваа алгоритамска контрол-
на структура се нарекува за-до-
чекор (англ. for-to-step). Таа се за-
пишува во форма како на слика
2.10.1 а. Структурата графички е
претставена на слика 2.10.1 б.
Циклусот се повторува за
вредности на brojac, и тоа: pocetna,
pocetna + iznos, pocetna + 2  iznos,
pocetna + 3  iznos итн. сè додека не
се добие вредност на бројачот (bro-
jac) поголема од крајната (krajna)
вредност.
Променливите brojac, pocet-
na, krajna и iznos мора да бидат по-
датоци од ист тип. Вредноста на
brojac не смее да се менува во ал-
горитамските чекори од кои се сос-
тои циклусот. Во случај кога почет-
ната (pocetna) вредност е поголем
од крајната (krajna) вредност, цик-
лусот не се извршува ниту еднаш. Слика 2.10.1 б
88
2. Основни контролни структури

Ако iznos е 1, тогаш brojac добива вредности од pocetna до krajna со зго-


лемување по 1. Притоа, iznos не мора да се задава, туку се подразбира дека е 1.
Вквата алгоритамска контролна структура се нарекува за-зголемувај-до (англ.
for-to). Таа може да се запише во следнава форма, слика 2.10.2.
Со користење на контрол- за brojac  pocetna зголемувај до krajna
ната структура за-зголемувај-до, чекор А;
текстуалниот и графичкиот приказ чекор Б;
на алгоритамот за наоѓање на зби- ...
рот на првите 10 природни броеви чекор Ј;
ќе бидат како на слика 2.10.3 и крај_за {brojac}
слика 2.10.4.
Слика 2.10.2
алгоритам ЗбирДо10
почеток
zbir  0;
broj  1;
за brojac  1 зголемувај до 10
zbir  zbir + broj;
broj  broj + 1;
крај_за {brojac}
печати zbir;
крај {ЗбирДо10}
Слика 2.10.3
Рековме дека бројачот не смее да се
менува во циклусот. Меѓутоа, бројачот може
да се користи како променлива во циклусот.
Така, алгоритамот за горната задача може да
се напише на следниот начин, слика 2.10.5.
алгоритам ЗбирДо10
почеток
zbir  0;
за brojac  1 зголемувај до 10
zbir  zbir + brojac;
крај_за {brojac}
печати zbir;
крај {ЗбирДо10}
Слика 2.10.5
Ова не значи дека brojac мора секогаш
да се користи во циклусот. Тоа зависи од
природата на задачата.
Слика 2.10.4
89
ПРОГРАМИРАЊЕ

Да разгледаме уште еден пример.


За да го најдеме збирот:
1 + 4 + 7 + 10 + ... + 100
треба да забележиме дека броевите растат од 1 до 100 со зголемување за 3. Во
алгоритaмот на слика 2.10.6 се користи алгоритамската контролна структура за-
до-чекор, со износ на чекорот 3.
алгоритам ЗбирДоСто Ако се користи бројачот во циклусот,
почеток алгоритамот ќе изгледа како на слика 2.10.7.
zbir  0;
n  1; алгоритам ЗбирДоСто
за i  1 до 100 чекор 3 почеток
zbir  zbir + n; zbir  0;
n  n + 3; за i  1 до 100 чекор 3
крај_за {i} zbir  zbir + i;
печати zbir; крај_за {i}
крај {ЗбирДоСто} печати zbir;
крај {ЗбирДоСто}
Слика 2.10.6
Слика 2.10.7
Почетната вредност на бројачот може да биде поголема од крајната
вредност и тогаш износот на чекорот се задава да биде негативен. Текстуалниот
и графичкиот приказ се исти како на слика 2.10.1 а и слика 2.10.1 б, со тоа што
износот е негативен.
Во случај кога износот на чекорот е негативен и почетокот е помал од
крајот, циклусот нема да се изврши ниту еднаш.
На пример, збирот на првите 10 алгоритам Збир10До1
природни броеви може да се пресмета со почеток
собирање на броевите од 10 до 1. Алгори- zbir  0;
тамот е даден на слика 2.10.8. за broj  10 до 1 чекор – 1
Aкo износот на чекорот е – 1, ал- zbir  zbir + broj;
горитамската контролна структура се крај_за {broj}
нарекува за-намалувај-до (англ. for- печати zbir;
downto). Таа може да се запише во след- крај {Збир}
нава текстуална форма, слика 2.10.9.
Слика 2.10.8
за brojac  pocetna намалувај до krajna
На пример, алгоритамот од
чекор А;
слика 2.10.8, изразен со контролната
чекор Б;
... структура за-намалувај-до, е даден
чекор Н; на слика 2.10.10.
крај_за {brojac}
Слика 2.10.9
90
2. Основни контролни структури

алгоритам Збир10До1 Контролните структури за-зго-


почеток лемувај-до и за-намалувај-до имаат по-
zbir  0; себно значење бидејќи може да се приме-
за broj  10 намалувај до 1 нат за секој линеарно подреден тип пода-
zbir  zbir + broj; тоци. Да се потсетиме дека линеарно
крај_за {broj} подреден тип податоци се оние податоци
печати zbir; во кои секој има свој претходник (освен
крај {ЗбирДо10} првиот) и свој следбеник (освен послед-
ниот).
Слика 2.10.10
Во ваквите податоци, со структу-
рата за-зголемувај-до се преминува на следбеникот на тековниот податок, а со
структурата за-намалувај-до, се преминува на претходникот на тековниот по-
даток.
Ќе наведеме два примери:
Алгоритамот за печатење алгоритам Абецеда
на буквите од абецедата од A до Z почеток
и од Z до A ќе изгледа како на за bukva  ʼA‘ зголемувај до ʼZ‘
слика 2.10.11. печати bukva;
Во некои алгоритми пот- крај_за {bukva}
ребно е да се употребат повеќе ал- за bukva  ʼZ‘ намалувај до ʼA‘
горитамски контролни структури печати bukva;
за повторување. Притоа, некоја крај_за {bukva}
контролна структура може да се крај {Абецеда}
наоѓа во друга. Тоа се нарекува Слика 2.10.11
вгнездување (англ. nesting).
Во случај на вгнездување на циклусите, сите чекори на едниот циклус
мора да се наоѓаат во другиот циклус, односно не смее да има сечење (преклопу-
вање) на циклусите, како на слика 2.10.12. На слика 2.10.13 а, б и в се дадени
дозволени начини на вгнездување на циклусите.

Слика 2.10.12 а б
в
Слика 2.10.13
91
ПРОГРАМИРАЊЕ

На пример, алгори-
алгоритам ТаблицаМножење
тамот за таблицата за мно-
почеток
жење до 10 ќе изгледа како
на слика 2.10.14. за i  1 зголемувај до 10
печати „Множење со “, i ;
за j  1 зголемувај до 10
ipoj  i  j;
печати i, „  “, j, „ = “, ipoj;
крај_за {j}
крај_за {i}
крај {ТаблицаМножење}
Слика 2.10.14

Вежби

Вежба 2.10.1
Размислете и одговорете: Доколку знаеме колку пати треба да се
реализира некоја редоследна структура, која структура за повторување е
најверојатно дека ќе ја користиме?

Вежба 2.10.2
Што прави следниов алгоритамски сегмент:
zbir  0;
за broj  2 до 10 чекор 2
zbir  zbir + broj;
крај_за {broj}
печати zbir;

Вежба 2.10.3
Што прави следниов алгоритамски сегмент:
zbir  0;
за broj  2 до 10 чекор 2
zbir  zbir + broj;
печати zbir;
крај_за {broj}
Која е разликата меѓу претходните два алгоритамски сегменти?

Вежба 2.10.4
Покажете како треба да се модификуваат алгоритмите дадени на
сликите 2.10.8 и слика 2.10.10 за да се пресмета збирот на парните бро-
еви од 10 до 1.
92
2. Основни контролни структури

Вежба 2.10.5
За следниве задачи да се напишат алгоритми со користење на ал-
горитамските контролни структури: за-до-чекор, за-зголемувај-до или
за-намалувај-до.
1 1 1
1. Да се пресмета производот: 1    ... .
2 3 n
2. Да се пресмета збирот:
1 + (1 + 2) + (1 + 2 + 3) + (1 + 2 + 3 + 4) +… + (1 + 2 +… + n).
3. Да се пресмета збирот:
(1 + 2 +… + n) + (2 + 3 +… + n) +… + (n – 1 + n) + n.
4. Да се најдат Питагорините броеви до 100. (Питагорини броеви се
тројките броеви (x, y, z) за кои важи x2 + y2 = z2) .
5. Да се најдат сите совршени броеви до 1 000. (Совршен број е оној кој
е еднаков на збирот на своите делители без самиот број).
6. Да се најдат сите пријателски броеви до 10 000. (Два броја се прија-
телски ако збирот на делителите на едниот број е еднаков на другиот
и збирот на делителите на другиот број е еднаков на првиот. Во
делители на бројот не спаѓа самиот број).

2.11 Контролна наредба for

Со оваа контролна наредба се реализира алгоритамската контролна


структура за повторување со броење на циклусите за-до-чекор, слика 2.10.1 а.
Општиот облик на контролната наредба for е:
for(иницијализација; услов; ажурирање)
{
наредба А;
наредба Б;
...
наредба К;
}
Иницијализација е дел во кој се задава почетната вредност на променли-
вата која го контролира циклусот. Овој дел се извршува еднаш пред да започне
циклусот.
Услов е делот за испитување на условот под кој повторувањата треба да
запрат. Овој дел испитува дали контролната променлива пред започнувањето на
секој циклус ја достигнала или надминала крајната вредност. Ако услов е точен,
тогаш циклусот ќе се повтори, инаку повторувањата ќе прекинат и програмата ќе
продолжи со следната наредба.

93
ПРОГРАМИРАЊЕ

Делот за ажурирање се извршува на крајот од секој циклус. Целта на из-


разот за ажурирање е да ја промени (зголеми или намали) контролната промен-
лива.
Една можна форма на наредбата for е следнава:
for (brojac = pocetna; brojac <= krajna; brojac = brojac + 1) {
наредба А;
наредба Б;
...
наредба Т;
}
Испитувањето дали вредноста на brojac е помала или еднаква од крајната
вредност (krajna) е вградено во наредбата for.
Условот brojac <= krajna е логички израз кој се испитува пред почетокот
на секој циклус и ако има вредност true, циклусот се извршува, а ако има вред-
ност false, циклусот не се извршува.
Изразот brojac = brojac + 1 се пресметува по извршување на секој циклус.
Следниот програмски сегмент го пресметува збирот на непарните при-
родни броеви до n.
#include <iostream>
using namespace std;

int main() {
int n, broj, zbir = 0;
cin >> n;
for (broj = 1; broj <= n; broj += 2)
zbir += broj;
cout << "Zbirot na neparnite broevi do " << n << " e ";
cout << zbir << endl;

return 0;
}
Наредбата for дозволува иницијализација и ажурирање на повеќе промен-
ливи.
Во делот за иницијализација може да се иницијализираат повеќе промен-
ливи. Притоа, тие се одделуваат со запирки. Претходниот пример може да се на-
пише и на следниов начин:
#include <iostream>
using namespace std;

int main() {
int n, broj, zbir = 0;
cin >> n;
for (broj = 1, zbir = 0; broj <= n; broj += 2)
zbir += broj;
94
2. Основни контролни структури

cout << "Zbirot na neparnite broevi do " << n << " e ";
cout << zbir << endl;

return 0;
}
Условот (услов) може да биде кој било логички израз во кој може да се
користат релациски и логички оператори. На пример, услов во претходната про-
грама може да биде: broj <= n && (broj % 2 == 1). Програмата со овој услов ќе
биде:
#include <iostream>
using namespace std;

int main() {
int n, broj, zbir = 0;
cin >> n;
for (broj = 1, zbir = 0; ( broj <= n ) && ( broj % 2 == 1 ); broj += 2)
zbir += broj;
cout << "Zbirot na neparnite broevi do " << n << " e ";
cout << zbir << endl;

return 0;
}
Во делот за ажурирање може да се ажурираат повеќе променливи, при
што тие се одделуваат со запирки. На пример:
#include <iostream>
using namespace std;

int main() {
int n;
cin >> n;
for (int i = 1, j = n; i <= n && j >= 1; ++i, – –j)
cout << i + j << endl;
return 0;
}
Делот за иницијализација и ажурирање може да биде и празен. Тоа е по-
кажано на следнава програма.
#include <iostream>
using namespace std;

int main() {
int n;
cin >> n;
int i = 1, j = n;
for (; i <= n && j >= 1;) {
++i;
95
ПРОГРАМИРАЊЕ

– –j;
cout << i + j << endl;
}
return 0;
}
Наредбите for може да се вгнездуваат една во друга:
#include <iostream>
using namespace std;

int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j)
cout << i << " * " << j << " = " << i * j << "\t";
cout << endl << endl ;
}
}

Примери
Пример 2.11.1
Да се најдат сите Питагорини броеви помали од природниот број n.
Објаснување: Питагорини броеви се секоја тројка природни броеви x, y и
z што го задоволуваат равенството x2 + y2 = z2. (За да не се повторуваат тројките,
како на пр., 3, 4, 5 и 4, 3, 5, х ќе се менува од 1 до вредност не поголема од у, т. е.
 n2 
до (ако х = у)   ).
 2 
 
алгоритам ПитагориниБроеви
почеток
печати „До кој природен број?“;
читај n;
 n2 
за x  1 зголемувај до  
 2 
 
за y  x зголемувај до n
z   x 2  y 2  ;
 
ако z ≤ n И x2 + y2 = z2
тогаш
печати „Питагорина тројка: “, x, y, z;
крај_ако {z ≤ n И x2 + y2 = z2}
крај_за {y}
96
2. Основни контролни структури

крај_за {x}
крај {ПитагориниБроеви}

#include<iostream>
#include<cmath>
using namespace std;

int main() {
int n, x, y, z;
cout << „Do koj priroden broj: “;
cin >> n;

for (x = 1; x <= sqrt( n * n / 2 ); x++) {


for (y = x; y <= n; y++) {
z = sqrt(x * x + y * y);
if ((z <= n) && (x * x + y * y == z * z)) {
cout << "Pitagorina trojka: " << x << " " << y;
cout << " " << z << endl;
}
}
}
return 0;
}

Пример 2.11.2
Да се најдат сите совршени броеви помали од природниот број n.
Објаснување: Природните броеви кои се еднакви на збирот на своите
делители, без самиот број, се нарекуваат совршени броеви. (На пример: 6, 28,
496...).
алгоритам СовршениБроевиДоN
почеток
печати „До кој број? “;
читај n;
печати „Совршени броеви до “, n, “ се: “;
за broj  2 зголемувај до n
zbir  0;
за delitel  1 зголемувај до  broj 
 2 
ако delitel | broj
тогаш
zbir  zbir + delitel;
крај_ако {delitel | broj}
крај_за {delitel}
97
ПРОГРАМИРАЊЕ

ако zbir = broj


тогаш
печати broj;
крај_ако {zbir = broj}
крај_за {broj}
крај {СовршениБроевиДоN}
#include <iostream>
using namespace std;

int main() {
int n, broj, delitel, zbir;
cout << "Do koj broj, n = ";
cin >> n;
cout << "Sovrsheni broevi do " << n << " se: ";
for (broj = 1; broj < n; broj++) {
zbir = 0;
for (delitel = 1; delitel <= (broj / 2); delitel++) {
if (broj % delitel == 0)
zbir = zbir + delitel;
}
if (zbir == broj)
cout << broj << ", ";

}
return 0;
}

Вежби
Вежба 2.11.1
Да се одговори на следниве прашања:
1. Која контролна структура се реализира со наредбата for?
2. Што се врши во делот за иницијализација на наредбата for?

Вежба 2.11.2
Да се утврди што извршува следниов програмски сегмент:
for (x = 1, i = 0; x <= 10; x++)
i += x;

Вежба 2.11.3
Да се утврди што ќе се отпечати како резултат од извршување на
следниов програмски сегмент:
for (i = 0, j = 0; i < 5; i++, j– –)
cout << i + j << endl;
Вежба 2.11.4
98
2. Основни контролни структури

Да се отпечатат сите цели броеви од 1 до 20 со користење на


наредбата for.

Вежба 2.11.5
Да се најде најмалиот заеднички содржател (НЗС) на два
природни броја.

Вежба 2.11.6
Да се напишат програми кои на екранот ќе ги отпечатат следниве
фигури:

а) Правоаголник од mредици со по n ѕвездички.


*****...
*****...
*****...
...

б) Рамнокрак правоаголен триаголник со страна n.


*
**
***
****
*****

или

*****
****
***
**
*

в) Табела од нули и единици со m редици и n колони.


101010…
010101…
101010…
010101…
101010…
010101…

г) Песочен часовник со страна n, за n непарен број.


99
ПРОГРАМИРАЊЕ

...
*******
*****
***
*
***
*****
*******
...

д)
*****+
****++
***+++
**++++
*+++++

ѓ)
*****
* *
* *
* *
*****

е)
+*+*+
*****
+*+*+
*****
+*+*+

ж)
*
***
*****
*******
*****
***
*

100
2. Основни контролни структури

Резиме

 Споредбените изрази овозможуваат да се провери релацијата помеѓу


аритметичките величини.
 Алгоритамски контролни структури за избор се: ако-тогаш-инаку, за
избор од две можности или ако-тогаш (ако една од можностите нема че-
кори) и случај, за избор од повеќе можности.
 Контролни наредби за избор се: if-else, if и switch, соодветни на алго-
ритамските контролни структури за избор.
 Условниот оператор ?: се користи за претставување на едноставни наред-
би if-else.
 Алгоритамски контролни структури за повторување се: додека-извршу-
вај, за излез на почетокот од циклусот, извршувај-додека, за излез на
крајот од циклусот и за-до-чекор, за повторување со броење на циклуси-
те.
 Контролни наредби за повторување се: while, do-while и for, соодветни
на алгоритамските контролни структури за повторување.

101
ПРОГРАМИРАЊЕ

102
3. Сложеност на алгоритми

3. СЛОЖЕНОСТ НА АЛГОРИТМИ
Во оваа глава ќе се запознаете со следното:

 Временска и просторна сложеност на алгоритми.


 Сложеност од „големо О“.
 Видови сложеност на алгоритми: константна, линеарна, логаритамска,
линеарно-логаритамска, квадратна, степена, експоненцијална,
факториелна.

Клучни зборови

Временска сложеност Логаритамска сложеност


Експоненцијална сложеност Полиномна сложеност
Квадратна сложеност Просторна сложеност
Константна сложеност Степена сложеност
Линеарна сложеност Факториелна сложеност
Линеарно-логаритамска сложеност

103
ПРОГРАМИРАЊЕ

Ефикасноста и сложеноста на алгоритмите се оценува според брзи-


ната на извршување и потребната меморија. Времето на извршување ја
одредува т.н. временска сложеност, а големината на потребната меморија
ја одредува т.н. просторна сложеност. Временската сложеност е многу
поважна од просторната бидејќи денешните компјутери имаат доволно ме-
морија и техники за нејзино проширување. Но, денес, сѐ уште има пробле-
ми за кои нема доволно брзи алгоритми кои се извршуваат во задоволи-
телно време.
Проблемот (задачата) кој се решава може да биде:
 решлив ако постои алгоритам за негово решавање, инаку е нерешлив,
 изводлив ако постои алгоритам кој дава задоволителни резултати со
користење на расположливите ресурси, но во разумно време.
Ефикасноста на еден алгоритам се мери според временската сложеност,
која се означува со T(n), каде n е димензијата на проблемот. Најчесто n претста-
вува број на податоци кои се обработуваат. Со зголемување на бројот на подато-
ци, се зголемува и времето на извршување.
Во табела 3.1 се претпоставени времињата на извршување на три алго-
ритми: a, b и c, во зависност од бројот на влезни податоци n.
n Ta(n) = n Tb(n) = n2 Tc(n) = 2n Tb(n) / Тa(n) Tc(n) / Tb(n)

10 10 100 1.024 10 10,24


15 15 225 32.768 15 145,64
20 20 400 1.048.576 20 2.621,44
25 25 625 33.554.432 25 53.687,09
30 30 900 1.073.741.824 30 1.193.046,47
Табела 3.1
Од споредбата на времињата на извршување во последните две колони,
очигледно е дека најефикасен е алгоритамот a, потоа b, а најнеефикасен е c.
Затоа, можеме да кажеме дека ако односот на времињата на извршување
Ta (n)
на алгоритмите  1 , тогаш алгоритамот a е поефикасен од алгоритамот b.
Tb (n)
Да претпоставиме дека времето на извршување на некој алгоритам d се
менува по равенката:
Td(n) = 5n2 + 3n – 10
Дали овој алгоритам е побрз од алгоритамот b?
За да одговориме на прашањето, ќе ги споредиме двата алгоритми. Во
следнава табела 3.2 се дадени вредностите на времињата на извршување и
нивната споредба.

104
3. Сложеност на алгоритми

n Tb(n) Td(n) Td(n) / Tb(n)

10 100 520 5,200


15 225 1160 5,155
20 400 2050 5,125
25 625 3190 5,104
30 900 4580 5,089
… … … …
100 10.000 50290 5,029
… … … …
1000 1.000.000 5.002.990 5,00299

Табела 3.2
Од табела 3.2 се гледа дека за големи вредности на n, односот на вре-
мињата на извршување на алгоритмите d и b е константен и изнесува 5. Затоа,
можеме да напишеме дека Td(n)  5Tb(n), односно велиме дека временската сло-
женост на алгоритамот d е еднаква со временската сложеност на алгоритамот b.
Тоа се запишува како Td(n)  O(n2), а се чита „големо О од n2“.
Ќе наведеме неколку примери. T(n) Сложеност
Поопшто, ако важи T(n)  cf(n), ка- 3n – 10 O(n)
де f(n) е позната функција, а с константа, 3n2 – 10 O(n2)
велиме дека сложеноста на алгоритамот е 7n3 + 5n2 – 4n + 9 O(n3)
„големо О од f(n)“. Со други зборови, вре- n! O(n!)
мето на извршување T(n) асимптотски се
приближува кон функцијата f(n).
Буквата О доаѓа од зборот order (ред) на функцијата: n, n2, n3, logn, n! итн.
Нотацијата „големо О“ се користи за класификација на алгоритмите, според
најлошото време на извршување на алгоритмите.
Точната дефиниција на сложеност на алгоритам гласи:

Дефиниција:
T(n) = O(f(n)) за n   ако c > 0 и n0,
така што ќе важи T(n)  cf(n) за n > n0.

Ова е прикажано на цртежот од слика 3.1.

105
ПРОГРАМИРАЊЕ

Слика 3.1
Според сложеноста, алгоритмите може да се поделат на две групи:
 Алгоритми со полиномна сложеност.
 Алгоритми со експоненцијална сложеност.
Алгоритми со полиномна сложеност се оние за кои важи
T(n)
lim  const  0 , P(n) = aknk + ak‒1nk‒1 +... + a0 , за некое k  0.
n  P(n)
Тоа се запишува како T(n) = O(nk).
Ако важи lim T(n)   тогаш алгоритамот има експоненцијална сложеност.
n P(n)
Според функцијата со која се изразува сложеноста, постојат следниве
видови сложеност на алгоритми:
 Константна f(n) = constant
 Линеарна f(n) = n
 Логаритамска f(n) = log2n
 Линеарно-логаритамска f(n) = n· log2n
 Квадратна f(n) = n2
 Степенска f(n) = nk (k > 2)
 Експоненцијална f(n) = kn (k > 1)
 Факториелна f(n) = n!

106
3. Сложеност на алгоритми

Константна сложеност O(1)

Алгоритми со константна сложеност се оние во кои се извршуваат само


елементарни операции, како собирање, множење, делење итн. Тие имаат при-
ближно исто време на извршување, независно од бројот и од вредноста на влез-
ните податоци. На пример, времето за пресметување на вредноста на квадратната
функција f(x) = ax2 + bx + c не зависи од вредноста на аргументот х бидејќи вре-
мето на извршување на операциите множење, степенување и собирање не зависи
од големината на х.

Линеарна сложеност O(n)

Кај алгоритмите со линеарна сложеност, времето на извршување се зго-


лемува со брзината на порастот на влезните податоци.
Алгоритми со линеарна сложеност се оние во кои има една контролна
структура за повторување или повеќе, една по друга. На пример: сума на броеви,
најголем (најмал) елемент во низа, табелирање функција, Питагорини броеви,
број цифри на природен број и други.
Ќе го разгледаме алгоритамот за сумата на првите n природни броеви,
слика 3.3.
Ако времето на извршување на чеко- алгоритам Збир
рот s  s + i; е 1 временска единица, тогаш почеток
извршувањето на n циклуси е tn. Ако прет- s  0;
поставиме дека чекорите s  0; и печати s; за i  1 зголемувај до n
се извршуваат по една временска единица, s  s + i;
тогаш T(n) = n + 2  n за n ≥ 1, т. е. крај_за {i}
сложеноста на алгоритамот е линеарна O(n). печати s;
Да претпоставиме дека наместо чеко- крај {Збир}
рот s  s + i; имаме неколку чекори за чие
Слика 3.3
извршување се потребни k временски едини-
ци. Тогаш T(n) = kn + 2  kn = kT(n), т. е. сложеноста останува O(n).

Квадратна сложеност O(n2)


за i  1 зголемувај до n
Да го разгледаме алгоритамскиот
сегмент од слика 3.4. за j  1 зголемувај до i
чекор А;
Ќе претпоставиме дека времето на
… }t
извршување на сите чекори од внатрешниот
чекор М;
циклус е t.
крај_за {j}
За секоја вредност на i, се извршува-
крај_за {i}
ат n циклуси за ј. Бидејќи има n циклуси за
i, тогаш се извршуваат вкупно n  n циклу- Слика 3.4
107
ПРОГРАМИРАЊЕ

си. Значи, сложеноста на алгоритамскиот сегмент со два вгнездени циклуси е


квадратна, т. е. O(n2).
Сложеноста можеме полесно да ја испитаме и на следниов начин.
Бидејќи испитувањето на условот за извршување на следниот циклус во
контролната структура за‒зголемувај‒до се врши на почетокот пред секој
циклус, а крајот на циклусот се означува само еднаш, тогаш можеме да ги
изброиме чекорите, како што е претставено на слика 3.5.
C(n) = 2n + n2 + tn2 + 1 = (t + 1)n2 + 2n + 1  O(n2)

Слика 3.5

Пример:
Да се одреди сложеноста на алго-
ритамскиот сегмент даден на слика 3.6.

За секоја вредност на i од 1 до n,
внатрешното повторување ќе се изврши i
циклуси, односно:
за i = 1, j = 1 ‒ 1 циклус
за i = 2, j = 1, 2 ‒ 2 циклуси
за i = 3, j = 1, 2, 3 ‒ 3 циклуси Слика 3.6
...
за i = n, j = 1, 2, 3, 4... n ‒ n циклуси.
Вкупно 1 + 2 + 3 +…+ n = n(n + 1) / 2 циклуси, што е пропорционално со
n2 / 2, т. е. со n2. Значи, сложеноста е O(n2).
Алгоритми со квадратна сложеност се оние во кои има две вгнездени
контролни структури за повторување. Такви алгоритми се: сортирање низа со
истовремено наоѓање најголем и најмал елемент, бинарно барање елемент во
низа, сортирање низа со метода на меурче, печатење на таблицата за множење,
збир на елементите на дводимензионална низа, најголем (најмал) елемент во
дводимензионална низа, колку пати се јавуваат буквите од абецедата во низа и
други.

108
3. Сложеност на алгоритми

Степенска (полиномна) сложеност O(nk)

Во алгоритамскиот сегмент од слика 3.7 се вгнездени к повторувања, се-


кое со n циклуси. Ако се собере означениот број чекори на извршување, ќе се
добие вкупниот број чекори, и тоа:
C(n) = 1 + 2n + 2n2 +... + 2nk‒1 + nk + tnk = (t + 1)nk + 2nk‒1 +… + 2n + 1.
Добивме полином по n, од кој заклучуваме дека сложеноста е O(nk).

Слика 3.7
Логаритамска сложеност O(log2n)

Алгоритми со логаритамска сложеност се оние чие време на извршување


T(n) се изразува преку логаритамската функција log2n. Тоа значи дека ако е n =
2k, времето на извршување на алгоритамот ќе биде k. Ако бројот на податоци се
удвојува, т. е. n = 2k+1, тогаш времето на извршување ќе се зголеми само за 1, т. е.
ќе биде k + 1. Оттука заклучуваме дека времето на извршување малку се
зголемува и покрај удвојувањето на податоците, односно ако бројот на податоци
се зголемува експоненцијално по функцијата 2k, сложеноста на алгоритамот се
зголемува логаритамски. Затоа, овие алгоритми се најефикасни.
Алгоритми со логаритамска сложеност се оние во кои може димензијата
да се преполовува. На пример, алгоритамот за рекурзивно бинарно барање
елемент во сортирана низа има логаритамска сложеност.

Пример:
Да ја најдеме сложеноста на алгоритамот за пресметување на збирот на
низата 1 + 2 + 22 + 23 + 24 +… до елементот 2k < n, слика 3.8. Треба да одредиме од
колку циклуси се состои повторувањето. Од 2k < n, се добива k < log2n, односно
се извршуваат log2n циклуси, што значи дека сложеноста е O(log2n).

109
ПРОГРАМИРАЊЕ

Алгоритми со логаритамска сложеност алгоритам ЗбирГеоПрогресија


има при решавање проблеми чија димензија почеток
може да се преполовува при секоја итерација. s  0;
Општиот концепт на овие алгоритми е: q  1;
 Се преполовува димензијата на извршувај
проблемот. s  s + q;
 Се повторува преполовувањето до q  2q;
проблем со димензија 1. додека q < n;
 Се решава проблемот со димензија 1. крај_извршувај
печати s;
крај {ЗбирГеоПрогресија}

Слика 3.8
Линеарно-логаритамска сложеност O(nlog2n)

Концептот за овие алгоритми е:


 Се преполовува димензијата на проблемот.
 Во секоја половина секвенцијално се обработуваат податоците.
 Се повторуваат преполовувањето и обработката до проблем со димензија
1.
Времето на извршување на алгоритамот е:
T(n)  (број_на_преполовувања) х (број_на_секв_обработени_податоци)
T(n)  (log2n)  n
Пример за алгоритми со линеарно-логаритамска сложеност се: брзо
сортирање (англ. Quick sort), сортирање со мешање (англ. Merge sort), сортира-
ње со купови (англ. Heap sort) и други.

Експоненцијална сложеност O(kn)

Експоненцијални алгоритми постојат за многу тешки проблеми. Има


проблеми за кои засега нема откриено други алгоритми освен експоненцијал-
ните. Нивната сложеност е многу голема. Затоа, за многу проблеми и денес се
бараат алгоритми со помала сложеност од експоненцијалните.
Да го разгледаме алгоритамскиот сегмент од слика 3.9. Тој се состои од n
повторувања секое со k циклуси.
Ако ги собереме сите чекори, ќе добиеме:
C(n) = 1 + 2k + 2k2 +... + 2kn‒1 + kn + tkn = (t + 1)kn + 2kn‒1 +... +2k2 + 2k + 1
Сложеноста е O(kn).
За k = n, сложеноста е O(nn).

110
3. Сложеност на алгоритми

Слика 3.9
Пример за алгоритам со експоненцијална сложеност (2n) е алгоритам за
наоѓање на бројот на подмножества од дадено множество.
Во следната табела се претставени подмножествата на дадено множество.
Множество Број Подмножества Број
елемент подмножеств
и а
{} 0 {} 1 = 20
{a} 1 {},{a} 2 = 21
{a, b} 2 {}, {a}, {b}, {a, b} 4 = 22
{a, b, c} 3 {}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, 8 = 23
b, c}
{a, b, c, d} 4 {}, {a}, {b}, {c}, {d}, {a, b}, {a, c}, {a, 16 = 24
d}, {b, c}, {b, d}, {c, d}, {a, b, c}, {a, b,
d}, {a, c, d}, {b, c, d}, {a, b, c, d}
... ... ... ...
{a, b, c, N 2n
d…}
Бројот на подмножества од множество со n елементи е 2n.

111
ПРОГРАМИРАЊЕ

Факториелна сложеност O(n!)

На слика 3.10 е даден алгоритамски сегмент со факториелна сложеност.


Според наведениот број чекори при извршување, вкупниот број чекори е:
C(n) = 1 + 2n + 2n(n ‒ 1) + n(n – 1)(n – 2) +... + (t + 1)n!
од што заклучуваме дека сложеноста е O(n!)

Слика 3.10
Пример за алгоритам со факториелна сложеност (n!) е алгоритам за
наоѓање на бројот на пермутации од n елементи класа n.
Во следната табела се претставени пермутации на n елементи.
Множество Број Подмножества Број
елемент подмножеств
и а
{a} 1 {a} 1 = 1!
{a, b} 2 {a, b}, {b, a} 2 = 2!
{a, b, c} 3 {a, b, c}, {a, c, b}, {b, a, c}, {b, c, a}, 6 = 3!
{c, a, b}, {c, b, a}
{a, b, c, d} 4 {a, b, c, d}, {a, b, d, c}, {a, c, b, d}, 24 = 4!
{a, c, d, b}, {a, d, b, c}, {a, d, c, b}
{b, a, c, d}, {b, a, d, c}, {b, c, a, d},
{b, c, d, a}, {b, d, a, c}, {b, d, c, a}
{c, a, b, d}, {c, a, d, b}, {c, b, a, d},
{c, b, d, a}, {c, d, a, b}, {c, d, b, a}
{d, a, b, c}, {d, a, c, b}, {d, b, a, c},
{d, b, c, a}, {d, c, a, b}, {d, c, b, a}
... ... ... ...
{a, b, c, d...} n n!
Бројот на пермутации од n елементи класа n е n!.

112
3. Сложеност на алгоритми

Вежби

Вежба 3.1.1

Одговорете на следните прашања:


1. Каква може да биде сложеноста на алгоритмите? Кој тип на
сложеност е поважен и зошто?
2. Како се делат алгоритмите според сложеноста?
3. Кои видови сложеност на алгоритми постојат, според функцијата со
која се споредува времето на извршување на алгоритамот?
4. Објаснете ги видовите сложеност и наведете барем по еден пример.

Вежба 3.1.2
Да се одреди сложеноста на следниве алгоритамски сегменти:
brojac  0;
brojac 0; за i  1 зголемувај до n
за i 1 зголемувај до n за j  1 зголемувај до n
за j 1 зголемувај до i * i ако i = j
brojac  brojac + 1; тогаш
крај_за {j} за k  1 зголемувај до n
крај_за {i} brojac  brojac + 1;
а крај_за {k}
крај_ако {i = j}
крај_за {j}
крај_за {i}
б
brojac  0;
за i  1 зголемувај до n
за j  1 зголемувај до i * i
за k  1 зголемувај до j * j
brojac  brojac + 1; brojac  0;
крај_за {k} за i  1 зголемувај до 3n
крај_за {j} за j  1 зголемувај до 4n
крај_за {i} ако i < j
тогаш
в за k  1 зголемувај до 5n
brojac  brojac + 1;
крај_за {k}
крај_ако {i<j}
крај_за {j}
г крај_за {i}

113
ПРОГРАМИРАЊЕ

Резиме

 Постои временска (времето на извршување) и просторна (потребната


меморија) сложеност на алгоритми.
 Сложеноста на алгоритмите може да биде полиномна и експоненцијална.
 Според функцијата со која се изразува сложеноста на алгоритмите, пос-
тојат следните видови сложеност: константна, линеарна, логаритамска,
линеарно-логаритамска, квадратна, степена, експоненцијална и фактори-
елна.

114
4. Потпрограми - Функции

4. ПОТПРОГРАМИ – ФУНКЦИИ
Во оваа глава ќе се запознаете со следното:

 Подалгоритми.
 Програмирање одгоре надолу и модуларно програмирање.
 Формални и вистински аргументи, параметри и аргументи.
 Влезни параметри, излезни параметри, листа на параметри.
 Функциски подалгоритми (функции) и процедурални подалгоритми
(процедури).
 Аргументи пренесени по вредност.
 Функции со повратна вредност.
 Функции, библиотечни функции, кориснички дефинирани функции.
 Дефиниција и декларација на корисничка функција со повратна вредност.
 Функциски прототип.
 Функциски потпис.
 Влезни формални аргументи и излезни формални аргументи.
 Функции без повратна вредност.
 Референтни параметри, референцирање, референца, референтна
променлива.
 Аргументи пренесени по референца.
 Глобални, локални и статички променливи.
 Хедер-датотеки, библиотечни функции: математички, функции за
генерирање случајни броеви, функции за работа со знаци и функции за
работа со стрингови.

115
ПРОГРАМИРАЊЕ

Клучни зборови

cmath Подалгоритам
cstdlib Подрачје на видливост
iomanip Подрачје на пристап
iostream Потпрограми
rand Програмирање одгоре надолу
random Процедурални подалгоритми
string Процедури
Аргумент на функција Лажни случајни броеви
Аргументи Рандомизација
Аргументи пренесени по вредност Референтна променлива
Аргументи пренесени по
Референтни параметри
референца
Библиотечни функции Референца
Вистински аргументи Референцирање
Влезни параметри Скриена променлива
Влезни формални аргументи Статичка променлива
врати Структурни алгоритми
Глобални променливи Формални аргументи
Живот на променлива Функции
Излезни параметри Функции без повратна вредност
Излезни формални аргументи Функции со повратна вредност
Кориснички дефинирани функции Функциски подалгоритми
Листа на параметри Функциски потпис
Локални променливи Функциски потпрограми
Модуларно програмирање Функциски прототип
Оператор за разрешување на
Хедер-датотека
подрачјето на видливост
Параметри

116
4. Потпрограми - Функции

4.1 Подалгоритми

Во структурното програмирање (објаснето во поднасловот Структури-


рани алгоритми од потточката 1.3 Претставување на алгоритмите) се корис-
тат две техники за програмирање, и тоа:
 Програмирање одгоре надолу (англ. top-down programming).
 Модуларно програмирање (англ. modular programming).
Програмирањето одгоре надолу се врши со разделување (расчленување)
на задачата на помали и поедноставни задачи, кои ќе ги наречеме подзадачи.
Ако е потребно, и тие подзадачи понатаму се разделуваат на уште поедноставни
додека не се добијат задачи што лесно се програмираат.
Секоја подзадача од така расчленетата задача може да се разгледува како
посебна целина, независно од другите. За секоја подзадача може да се напише
посебен алгоритам, кој ќе го наречеме подалгоритам.
На пример, алгоритамот за наоѓање на најголемиот од три дадени броја
може да се напише на следниов начин, слика 4.1.1.
алгоритам НајголемОдТриБроја
почеток
читај a, b, c;
ако a > b
тогаш
pogolem  a
инаку
pogolem  b;
крај_ако {a > b}
p  pogolem;
ако p > c
тогаш
pogolem  p
инаку
pogolem  c;
крај_ако {p > c}
n  pogolem;
печати n;
крај {НајголемОдТриБроја}
Слика 4.1.1
Во алгоритамот двапати се бара одредување на поголемиот од два броја:
а и b и p и c. Тоа може да се издвои како посебен алгоритам, односно како под-
алгоритам.
Меѓутоа, се јавува проблем како да се напише тој подалгоритам за да мо-
же со него да се извршат двете споредувања: a и b во првото и p и c во второто
117
ПРОГРАМИРАЊЕ

споредување. Исто така, подалгоритамот треба да врши споредување на кои било


два броја. За да се овозможи тоа, подалгоритамот се пишува во општа форма.
Еден подалгоритам се запишува како и секој друг алгоритам. И во него
може да се внесуваат и да се печатат податоци, да се декларираат променливи, да
се дефинираат типови и константи, да се доделуваат вредности на променливите,
да се извршуваат различни пресметувања и други операции кои може да се извр-
шат и во алгоритмите.
Подалгоритмите, исто како и алгоритмите, се именуваат. На пример: Po-
golem(), Prost(), Najmal(), Замена(), Поместување()итн.
Суштината на подалгоритмите е во тоа што тие може да се користат во
различни алгоритми, а и на повеќе места во ист алгоритам. Тоа е овозможено
преку механизмот на формални1 аргументи (англ. formal arguments) и вистин-
ски аргументи (англ. actual arguments). Во литературата, формалните аргументи
често се нарекуваат параметри (англ. parameters), а вистинските аргументи само
аргументи. Ние ќе ги користиме последните два термини.
Параметрите се променливи кои се користат во дефиницијата на под-
алгоритмите, а аргументите се променливи или константи кои се користат при
повик на подалгоритамот.
Параметрите може да бидат влезни параметри (англ. input parameters),
излезни параметри (англ. output parameters) и влезно-излезни параметри (англ.
input/output parameters). Тие се ставаат во загради по името на подалгоритамот и
ја прават т.н. листа на параметри (англ. parameters list).
Општиот запис на секој подалгоритам е:
ИмеНаПодалгоритамот (листа_на_параметри) {
тело на подалгоритамот (чекори)
}
Листата на параметрите во подалгоритамот може да биде празна (без
параметри), може да има само влезни параметри, а може да има и влезни и излез-
ни параметри.
Независно дали има или нема влезни параметри, подалгоритамот може
да:
 нема излезен резултат,
 има еден излезен резултат,
 има повеќе излезни резултати.
Во многу програмски јазици, подалгоритмите се наречени:
 функциски подалгоритми (со еден излезен резултат),
 процедурални подалгоритми (со или без излезни резултати).

1
Формалните аргументи го добиле името бидејќи тие немаат вредност, туку до-
биваат вредности само при повик за извршување на подалгоритамот.
118
4. Потпрограми - Функции

Секој подалгоритам може да се реализира како процедурален, но не и


како функциски. Секој функциски подалгоритам, пак, може да се изрази како
процедурален.
Процедуралните подалгоритми може да немаат или да имаат излезни ре-
зултати. Ако имаат само еден излезен резултат, полесно се реализираат како
функциски подалгоритми.

4.2 Функциски подалгоритми и потпрограми

Функциските подалгоритми

Функциските подалгоритми го добиле името по тоа што имаат само еден


излезен резултат, исто како и функциите во математиката. На пример:
y = 5, y = f(x) = 2x2 – 3x + 1,
z = g(a, b) = a2 + b2 – 1, u = h(p, q, r) = 2p + q – r3 – 2
Од дефинициите на функциите погоре, гледаме дека вредноста на про-
менливата y зависи од аргументот х, вредноста на променливата z зависи од ар-
гументите a и b, а вредноста на променливата u зависи од аргументите p, q и r.
Исто како и математичките функции, функциските подалгоритми може
да немаат влезни параметри (y = 5), да имаат еден (f(x)) или повеќе (g(a, b) и h(p,
q, r)) влезни параметри, а секогаш имаат само еден излезен резултат (y, z и h).
Општата синтакса на функциски подалгоритам е:
ImeNaPodalgoritamot (листа_на_влезни_параметри) {2
тело на подалгоритамот (чекори)
врати израз;
}
Во листата на влезни параметри нема излезен параметар, туку излезниот
резултат се враќа со чекорот врати. Резултатот може да биде една променлива
или израз од повеќе променливи со единствена вредност. Вредноста на резулта-
тот се враќа во алгоритамот (или друг повикувач3), во чекорот каде што е пови-
кан подалгоритамот.
На пример, подалгоритамот за наоѓање на поголемиот од два броја може
да се дефинира како функциски подалгоритам, слика 4.2.1.
подалгоритам Pogolem(broj1, broj2)
почеток
ако broj1 > broj2
тогаш
pogolem  broj1
инаку

2
Имињата на функциските подалгоритми ќе ги пишуваме на латиница.
3
Повикувач може да биде и друг подалгоритам.
119
ПРОГРАМИРАЊЕ

pogolem  broj2;
крај_ако {broj1 > broj2}
врати pogolem;
крај {Pogolem}
Слика 4.2.1
Името на подалгоритамот е Pogolem(), а има два влезни параметри broj1 и
broj2.
Резултатот кој се пресметува во функцискиот подалгоритам се враќа со
чекорот
врати pogolem;
Секој функциски подалгоритам се повикува со чекор за доделување
променлива  ImeNaPodalgoritamot (листа_на_аргументи);
или во друг чекор само со наведување на неговото име.
На пример, функцискиот подалгоритам од слика 4.1.2 може да се повика
со чекорот за доделување
p  Pogolem(a, b);
Тој може да се повика и во чекорот за печатење
печати Pogolem(p, c);
За листата на аргументите и листата на влезните параметри важат след-
ните правила:
 Бројот на аргументите е ист со бројот на параметрите.
 Редоследот на аргументите е ист со редоследот на параметрите.
 Типот на секој аргумент е ист или конвертибилен со типот на
соодветниот параметар.
При повикот на подалгоритамот Pogolem(broj1, broj2) со чекорот
p  Pogolem(a, b);
вредностите на аргументите a и b се пренесуваат (копираат) во влезните пара-
метри broj1 и broj2 од дефиницијата на подалгоритамот. Резултатот од подал-
горитамот (поголемиот од броевите a и b) ѝ се доделува на променливата р.
При повикот на подалгоритамот Pogolem(broj1, broj2) со чекорот
n  Pogolem(p, c);
прво се врши пренесување (копирање) на аргументите p и c во влезните пара-
метри broj1 и broj2, а резултатот од извршувањето на подалгоритамот (поголе-
миот од броевите p и c) ѝ се доделува на променливата n.
Процесот во кој вредностите на аргументите се пренесуваат во парамет-
рите се нарекува пренесување по вредност (англ. pass by value).
Сега можеме да го напишеме алгоритамот за наоѓање на најголемиот од
три дадени броја со повикување на функцискиот подалгоритам Pogolem(broj1,
broj2), како што е прикажано на слика 4.2.2.
алгоритам Најголем
почеток
читај a, b, c;
120
4. Потпрограми - Функции

p  Pogolem(a, b);
n  Pogolem(p, c);
печати n;
крај {Најголем}
Слика 4.2.2
Бидејќи во многу проблеми се бара решавање на исти задачи, пожелно е
за нив да се напишат подалгоритми. На пример, подалгоритми за: збирот на бро-
еви, производот на броеви, аритметичката средина, геометриската средина, НЗД,
НЗС, утврдување дали некој природен број е прост, најмал елемент во низа, нај-
голем елемент во низа итн.

Пример 4.2.1
Збирот на првите n природни броеви се јавува во повеќе задачи и затоа е
корисно да го напишеме како функциски подалгоритам, на пример, под име Zbir-
Od1DoN(n) (слика 4.1.4) и да го повикуваме каде што е потребно.
подалгоритам ZbirOd1DoN(n)
почеток
zbir  0;
broj  1;
повторувај
zbir  zbir + broj;
broj  broj + 1;
додека broj ≤ n;
крај_повторувај {broj ≤ n}
врати zbir;
крај {ZbirOd1DoN}
Слика 4.2.3
Со повикување на подалгоритамот ZbirOd1DoN(n), во алгоритамот од
слика 4.2.2 се пресметува збирот на првите n природни броеви, за n = 1, 2... m, и
тоа:
1
1+2
1+2+3
...
1 + 2 + 3 +... + m
алгоритам ЗбирДоM
почеток
печати „Внесете до кој природен број барате збир, m = “;
читај m;
за n  1 зголемувај до m
zbirNaPrirodniBroeviDoN  ZbirOd1DoN(n);
121
ПРОГРАМИРАЊЕ

печати „Збирот на природните броеви до “, n, „ e “,


zbirNaPrirodniBroeviDoN;
крај_за {n}
крај {ЗбирДоN}
Слика 4.2.4
Функции со повратна вредност

Реализацијата на подалгоритмите во С++ се врши со функциски потпро-


грами наречени само функции (англ. functions).
Функциите (функциските потпрограми) во С++ може да бидат:
 Библиотечни функции.
 Кориснички дефинирани функции.
Библиотечните функции во С++ се наоѓаат во стандардната библиотека
на С++ (англ. C++ Standard Library).
Кориснички дефинираните функции (англ. user-defined functions) или са-
мо кориснички функции (англ. user functions) се функции напишани од прог-
рамерите.
Библиотечните функции и корисничките функции (со кои се кодира
функциски подалгоритам) кои даваат (враќаат) само еден резултат, т. е. само
една вредност се нарекуваат функции со повратна вредност.
Општата форма на дефиницијата на корисничка функција со поврат-
на вредност во С++ е:
тип име (листа_на_параметри){
тело на функцијата (наредби) Наслов на
return израз; функцијата
}
тип – типот на вредноста која ја враќа
функцијата,
име – името на функцијата,
листа_на_параметри – ги содржи имињата на параметрите и
нивните типови одделени со запирки.
Забелешки:
 Насловот на функцијата не завршува со (;).
 Листата на параметрите мора да ги содржи и имињата и типовите на
параметрите.
 израз е резултатот од функцијата (повратна вредност) кој може да биде
израз (од променливи и/или константи и/или функции) или една
променлива и кој/а мора да е од ист тип со тип на функцијата.
Декларација на корисничка функција со повратна вредност во С++
се врши со наредбата со форма
тип име (листа_на_параметри);
122
4. Потпрограми - Функции

Забелешки:
 Ако не се наведе типот (тип) на функцијата, се подразбира типот int.
 Името (име) на функција (по конвенција) ќе го пишуваме како и
променливите4, т. е. со мала почетна буква. Ако името се состои од
повеќе збора, секој следен збор ќе го пишуваме со голема буква.
 Листата на параметрите (листа_на_параметри) мора да ги содржи
типовите на параметрите, но не мора да ги содржи имињата.
 Декларацијата на дадена функција завршува со знакот точка и запирка (;).
Декларацијата на функција се нарекува функциски прототип.
Со функцискиот прототип се опишува интерфејсот на функцијата, однос-
но се добиваат информации за бројот и типот на параметрите кои треба да бидат
познати пред да се повика функцијата, како и за типот на резултатот.
Ќе наведеме неколку примери за функциски прототипови на кориснич-
ките функции:
int mnozi(int m, int n); - име: mnozi
- параметри: m и n
- типот на резултатот е: int
float koren(float x); - типот на резултатот е: float
int pomal(int, int); - листа без имиња на параметрите
double f(int a, b); - неисправно, треба: double f(int a, int b);
long plostina(int a, int b); - типот на резултатот е: long
Делот од функцискиот прототип кој ги содржи името и листата на пара-
метрите се нарекува функциски потпис.
На пример, функциски потписи се:
mnozi(int m, int n);
koren(float b);
pomal(int, int);
stipendija(int a, float c);
plostina(int, int);
Функција со повратна вредност се повикува со наредба за доделување
променлива = име(листа_на_аргументи);
Листата на аргументи (листа_на_аргументи) и листата на параметри
(листа_на_параметри) на функцијата име мора да имаат:
 ист број на аргументи и параметри,
 ист редослед на аргументите и параметрите,
 ист или конвертибилен тип5 на соодветните аргументи и параметри.
Ќе наведеме примери за повик на функции:

4
Имињата на функциите со повратна вредност може да се користат во изрази, а и
како аргументи на други функции, т. е. исто како и променливите.
5
Кога се врши автоматска конверзија на типот на аргументот во тип на парамета-
рот.
123
ПРОГРАМИРАЊЕ

proizvod = mnozi(a, b);


kvKoren = koren(12.345);
n = pomal(c, p);
stipendija = vkupnaStipendija(osnovnaStipendija,prosecnaOcena);
При повик на функција со повратна вредност, вредностите на аргументи-
те (кои претходно мора да се дефинирани – имаат вредност) се пренесуваат (ко-
пираат) во соодветните параметри.
На пример, при повикот
proizvod = mnozi(a, b);
вредностите на аргументите a и b се пренесуваат (копираат) во параметрите m и
n од дефиницијата на функцијата mnozi()
int mnozi(int m, int n){...}
Функциите кои се дефинирани по главната функција main(), се деклари-
раат (со наведување на нивниот прототип) пред главната функција за да може да
се повикуваат во главната функција, односно за да знае преведувачот кога ја пре-
ведува главната функција што претставуваат тие имиња. По правило, за една
функција А да може да се повика од функцијата Б, мора функцијата А да е дефи-
нирана или во најмала рака декларирана пред дефиницијата на функцијата Б.
Во дефиницијата на функција со повратна вредност мора да се наведе
што се враќа како резултат при нејзиното извршување, било да се повикува од
главната функција main() или од друга функција.
Една функција може само еднаш да се дефинира во истата програма.

Пример 4.2.2
Да се напише функција со повратна вредност за пресметување на најголе-
миот од три дадени броја.

Функцијата ќе ја напишеме според подалгоритамот од слика 4.2.1, а


функцијата main() според алгоритамот од слика 4.2.2. Тие се дадени на слика
4.2.5

.
Слика 4.2.5
124
4. Потпрограми - Функции

Слика 4.2.5 (продолжение)


При дефинирањето на функцијата pogolemBroj(), се задаваат имињата и
типовите на параметрите broj1 и broj2, како и типот на функцијата (типот на по-
вратната вредност) int.
По внесување на трите броја a, b и c, се повикува функцијата со аргумен-
тите a и b на десната страна во наредбата за доделување
p = pogolemBroj(a, b);
Притоа, вредностите на аргументите a и b се пренесуваат во параметрите broj1 и
broj2. При извршување на функцијата, поголемата вредност од broj1 и broj2 ѝ се
доделува на променливата pogolem.
Со наредбата
return pogolem;
функцијата pogolemBroj() ја враќа вредноста на променливата pogolem во глав-
ната програма.
Со наредбата за доделување
p = pogolemBroj(a, b);
125
ПРОГРАМИРАЊЕ

вратената вредност на променливата pogolem ѝ се доделува на променливата p.


Извршувањето на наредбата за доделување
p = pogolemBroj(a, b);
е претставено шематски на слика 4.2.6.

Слика 4.2.6
При извршување на следната наредба за доделување, во која повторно се
повикува функцијата pogolemBroj(), на променливата n ѝ се доделува вредноста
на поголемиот од броевите b и c,
n = pogolemBroj(p, c);
По извршување на оваа наредба, променливата n го содржи најголемиот
од броевите a, b и c.
Еден резултат од извршување на програмата е:

Вежби

Вежба 4.2.1
Напишете функција abs() која ќе ја пресметува апсолутната вред-
ност за даден цел број. Резултатот исто така треба да е цел број.

Вежба 4.2.2
Напишете функција која црта „крадратчиња“ со ѕвездички за да-
ден аргумент N.
126
4. Потпрограми - Функции

Искористете ја функцијата во главната програма за да ја исцртате


следната слика:
****
****
****
****
**
**
***
***
***

Вежба 4.2.3
Напишете функција zbirOd1DoN() која ќе го наоѓа збирот на бро-
евите од 1 до N и притоа ќе има помала сложеност на применетиот
алгоритам од оној претставен на слика 4.2.3.

Вежба 4.2.4
Да се напишат функциски подалгоритми и функции со повратна
вредност за следниве задачи:
1. Да се пресмета аритметичката средина на првите n природни броеви.
2. Да се пресмета периметарот на многуаголник, при што ќе се користи
функција со повратна вредност за пресметување на растојанието
меѓу две точки во рамнина.
3. Да се провери дали некој природен број е палиндром. (Палиндром е
оној број кој се чита исто и однапред и одназад).
4. Да се скрати дропката a (во која a и b се цели броеви) со делење на a
b
и b со нивниот НЗД. За наоѓање на НЗД на a и b, да се напише
посебна функција.
5. Да се најде најголемиот заеднички делител за n броеви. За наоѓање
на НЗД на два броја, да се напише посебна функција.
6. Да се пресмета бројот на цифрите на природниот број n.
7. Да се најде бројот на 0 (нули) и на 1 (единици) во голем декаден број,
чии цифри се само 0 или 1.
8. Да се најде разликата на два бинарни броја изразени како цели декад-
ни броеви чии цифри се само 0 или 1.
9. Да се провери дали природниот број n е совршен. (Совршени броеви
се оние кои се еднакви на збирот на своите делители без самиот
број).
10. Да се провери дали природниот број n е прост или не е. (Природниот
број р е прост ако е делив само со 1 и со самиот себеси).
127
ПРОГРАМИРАЊЕ

4.3 Процедурални подалгоритми и потпрограми

Процедурални подалгоритми

Подалгоритмите кои немаат излезен резултат или имаат повеќе излезни


резултати се нарекуваат процедурални подалгоритми или само процедури
(англ. procedures). Нивната листа на параметри може да има влезни параметри,
излезни параметри и влезно-излезни параметри6.
Процедуралните подалгоритми се користат најчесто во случаи кога про-
цедурата мора да врати повеќе од една вредност.
На пример, при решавање на систем од две равенки со две непознати, ре-
шението се состои од две вредности за двете непознати. Или, при решавање на
квадратна равенка, решението се состои од две вредности за квадратните корени
и слично.
Постојат случаи кога со исти влезни параметри на подалгоритамот, треба
(или сакаме) да добиеме повеќе резултати. На пример, ако сакаме да ги најдеме
збирот, разликата, производот и количникот на два броја, ќе користиме процеду-
рален подалгоритам. Ако користиме функциски подалгоритми, ќе ни се потребни
4 функциски подалгоритми.
Општата синтакса на процедурален подалгоритам е:
Име (листа_на_влезни_на_излезни_ и_на_влезно/излезни_параметри) {
тело на подалгоритамот (чекори)
}
Забележуваме дека нема чекор за враќање на резултат како кај функцис-
ките подалгоритми.
Процедуралниот подалгоритам се повикува само со своето име, а во заг-
рада се наведуваат аргументите:
Име(листа_на_влезни_на_излезни_и_на_влезно/излезни_аргументи);
Забелешка: Процедурален подалгоритам не може да се повика во друг
чекор од алгоритамот за да врати една вредност, како што може да се повика
функциски подалгоритам.
За да се разликуваат влезните, излезните и влезно-излезните параметри
во процедуралните подалгоритми, пред влезните параметри ќе ставаме стрелка
надолу , а пред излезните параметри стрелка нагоре . Ако некој параметар е
влезно-излезен, тогаш пред него ќе ставаме двонасочна стрелка . Овие ознаки
не ги користевме кај функциските подалгоритми бидејќи кај нив сите параметри
се влезни.
Процедуралните подалгоритми ќе ги објасниме на последниот пример.

6
Во програмските јазици постојат различни начини за означување на влезните,
излезните и влезно-излезните параметри. Најчесто се означуваат со in, out и
inout.
128
4. Потпрограми - Функции

Пример 4.3.1
Да се напише процедурален подалгоритам за пресметување на збирот,
разликата, производот и количникот на два декадни броја.

Процедуралниот подалгоритам ќе го наречеме Операции(), слика 4.3.1.


По името, во згради, се наведува листа на параметрите на подалгоритамот. Оваа
листа (за разлика од листата кај функциските подалгоритми) може да содржи и
влезни и излезни параметри, како во овој пример. Влезните параметри се broj1 и
broj2, а излезните параметри се zbir, razlika, proizvod и kolicnik.
подалгоритам Операции( broj1,  broj2,  zbir,  razlika,  proizvod,  kolicnik)
почеток
zbir  broj1 + broj2;
razlika  broj1 – broj2;
proizvod  broj1 · broj2;
kolicnik  broj1 / broj2;
крај {Операции}
Слика 4.3.1
Влезните параметри broj1и broj2 се нарекуваат и влезни формални аргу-
менти, додека излезните параметри zbir, razlika, proizvod и kolicnik се нареку-
ваат и излезни формални аргументи.
За наоѓање на збирот, разликата, производот и количникот на броевите a
и b, подалгоритамот може да се повика со наредбата
Операции(a, b, z, r, p, k);
Променливите a и b се влезните аргументи, а променливите z, r, p и k се
излезните аргументи. Притоа, во листата на аргументите не мора да се ставаат
ознаки дали е аргументот влезен, излезен или влезно-излезен. Битно е бројот и
редоследот на аргументите и на параметрите да се исти, а типот на аргументите
треба да е ист или конвертибилен со типот на параметрите.
При повикувањето на подалгоритамот Операции(), се врши копирање на
влезните аргументи во влезните параметри, а по завршување на подалгоритамот,
се врши копирање на излезните параметри во излезните аргументи:
 Вредноста на аргументот a се копира во параметарот broj1.
 Вредноста на аргументот b се копира во параметарот broj2.
 Вредноста на параметарот zbir се копира во аргументот z.
 Вредноста на параметарот razlika се копира во аргументот r.
 Вредноста на параметарот proizvod се копира во аргументот p.
 Вредноста на параметарот kolicnik се копира во аргументот k.
Алгоритамот за пресметување на збирот, разликата, производот и колич-
никот на два броја, со користење на процедуралниот подалгоритам Операции(), е:

129
ПРОГРАМИРАЊЕ

алгоритам АритметичкиОперации
почеток
печати „Внесете два природни броја: “;
печати „Прв број, a = “;
читај a;
печати „Втор број, b = “;
читај b;
печати „За внесените броеви “, a, „ и “, b, „ : “;
Операции(a, b, z, r, p, k);
печати „Збир = “, z“;
печати „Разлика = “, r“;
печати „Производ = “, p“;
печати „Количник = “, k“;
крај {АритметичкиОперации}
Слика 4.3.2
Во потточката 4.1 Подалгоритми спомнавме дека секој функциски
подалгоритам може да се изрази како процедурален ако се стави повратната
вредност како излезен параметар во листата на параметрите на процедуралниот
подалгоритам. Спротивното не важи, т. е. не може секој процедурален подалго-
ритам да се изрази како функциски.

Пример 4.3.2
Функцискиот подалгоритам за наоѓање на поголемиот од два броја (сли-
ка 4.2.1) да се дефинира како процедурален подалгоритам.

Повратната вредност pogolem од функцискиот подалгоритам на слика


4.2.1 ќе ја напишеме како излезен параметар во листата на параметрите, а чеко-
рот врати pogolem; ќе го избришеме, слика 4.3.3.
подалгоритам Поголем( broj1,  broj2,  pogolem)
почеток
ако broj1 > broj2
тогаш
pogolem  broj1
инаку
pogolem  broj2;
крај_ако {broj1 > broj2}
крај {Поголем}
Слика 4.3.3
За наоѓање на поголемиот од броевите a и b и за да се стави резултатот во
променливата p, подалгоритамот треба да се повика со чекорот
Поголем(a, b, p);
130
4. Потпрограми - Функции

При повикувањето на подалгоритамот, се врши копирање на аргументите


во соодветните параметри. Во нашиот пример, во параметарот broj1 се копира
вредноста на аргументот a, во параметарот broj2 се копира вредноста на аргумен-
тот b, а во аргументот p се копира вредноста на параметарот pogolem.
По извршувањето на подалгоритамот Поголем(a, b, p), променливата p ќе
ја содржи вредноста на поголемиот од броевите a и b, која ја добила преку пара-
метарот pogolem.
Со повикот
Поголем(p, c, n);
во параметрите broj1 и broj2 се пренесуваат вредностите на аргументите p и c, а
вредноста на параметарот pogolem се пренесува во n.
Алгоритамот за наоѓање на најголемиот од трите дадени броја, со корис-
тење на процедуралниот подалгоритам Поголем(), ќе се запише на следниов
начин, слика 4.3.4.
алгоритам Најголем
почеток
читај a, b, c;
Поголем(a, b, p);
Поголем(p, c, n);
печати n;
крај {Најголем}
Слика 4.3.4
Пример 4.3.3
Да се заменат вредностите на две променливи.
Ова е класичен пример за користење на процедурални подалгоритми би-
дејќи задачата не може да се реши со функциски подалгоритам. Подалгоритамот
мора да има два излезни резултати.
Подалгоритамот за замена на вредностите на променливите edna и druga,
ќе го напишеме така што параметрите edna и druga ќе ги означиме како влезно-
излезни.
подалгоритам Замена( edna,  druga)
почеток
pomosna  edna;
edna  druga;
druga  pomosna;
крај {Размена}
Слика 4.3.5

131
ПРОГРАМИРАЊЕ

Функции без повратна вредност

Процедуралните подалгоритми во С++ се реализираат со функции без


повратна вредност. Нивниот тип е void. Затоа, се нарекуваат и функции void.
Дефиницијата на функцијата без повратна вредност pecatenje() е:
void pecatenje( string poraka, float rezultat ){
cout << poraka << rezultat << endl;
// poraka ‒ e string
// rezultat – е резултат од пресметките
}
Повикот на функција без повратна вредност се разликува од повикот на
функција со повратна вредност бидејќи функција без повратна вредност се пови-
кува само со своето име и листата на аргументите и не може да се повика во дру-
га наредба, како што може да се повика функција со повратна вредност.
На пример:
pecatenje("\nRezultatot e: ", x );
Функција без повратна вредност може да биде и без параметри.
На пример:
void vlez() {
cout << "Vnesuvanje na vlezni podatoci\n";
}
или
void izlez(void) { // So parametarot void e isto
// kako i bez nego
cout << "Pecatenje na izleznite podatoci\n";
}
Повикот на овие функции без повратна вредност може да биде:
vlez(); vlez(void); izlez(); izlez(void);
Од функција без повратна вредност, т. е. од функција од типoт void се
излегува без наредбата return (како во функција со повратна вредност), автомат-
ски по нејзиното извршување. Но може да се излезе и од кое било место во тело-
то на функција без повратна вредност со наредбата return без параметар.
На пример:
void kvadratenKoren(double broj ) {
if(broj < 0) {
cout << "Brojot e negativen i nema kvadraten koren. " <<
endl;
return;
}
else
cout << "Kvadraten koren od "<< broj << " e "
<< sqrt(broj ) << endl;
cout << "Kraj na funkcijata. " << endl;
}
132
4. Потпрограми - Функции

Повикот на функцијата е само со наведување на името и листата на аргу-


менти.
На пример, со
double broj = 2;
kvadratenKoren(broj);
ќе се отпечати

Ако се повика функцијата со


double broj = ‒2;
kvadratenKoren(broj);
ќе се отпечати

Гледаме дека во второто повикување не се извршува наредбата


cout << "Kraj na funkcijata void. " << endl;
како при првото повикување бидејќи функцијата завршува со наредбата return.

Пример 4.3.4
Да се напишат главна функција и функција од типoт void за пресметува-
ње на квадратите и на квадратните корени на првите n природни броеви.

Слика 4.3.6
133
ПРОГРАМИРАЊЕ

Слика 4.3.6 (продолжение)


Излезот од програмата е:

Референтни параметри

Референцирање, кажано кратко, е доделување друго име на иста промен-


лива. На пример:
int b = 3;
int &r = b;
Со втората наредба се декларира референцата r, која упатува на промен-
ливата b.
Знакот & (амперсанд) се чита „референца“. Променливата r е референтна
променлива (англ. reference variable) или кратко референца (англ. reference).
Втората наредба се чита: „r е целобројна референца иницијализирана на
b“ или „r е целобројна референца која упатува на b“.
При декларирање на референца, таа мора да се иницијализира така што ѝ
се доделува променливата на која упатува. По декларирање и иницијализирање
на дадена референца, таа не може да се промени да упатува на друга променлива.
Но може да се декларираат повеќе референци кои упатуваат на иста променлива.
Исто така, типот на референцата мора да е ист со типот на променливата
на која упатува.

134
4. Потпрограми - Функции

Бидејќи референцата упатува на некоја променлива, често велиме дека


референцата е друго име за променливата. На пример, ако ги отпечатиме промен-
ливата b и референцата r која упатува на неа:
int b;
int &r = b;
b = 3;
cout << "Promenliva b = " << b << endl;
cout << "Referenca r = " << r << endl;
ќе се добие иста вредност.

На следнава скица (слика 4.3.7) е илустрирана референцата r која упатува


на променливата b во меморијата. Бидејќи и b и r се променливи кои зафаќаат
простор во меморијата (се наоѓаат на некои адреси), упатувањето се врши така
што референцата r ја содржи адресата на променливата b.

Слика 4.3.7
Примената на референците како референтни параметри во функциите без
повратна вредност, ќе ја објасниме на задачата за замена на вредностите на две
променливи. Според процедуралниот подалгоритам од слика 4.3.5, ќе напишеме
функција zamena() со референтни параметри, слика 4.3.8. За да знае преведува-
чот дека параметрите се референтни, пред нив се става знакот &.
void zamena(int &prv, int &vtor ) {
int pom;
pom = prv;
prv = vtor;
vtor = pom;
cout << "a = " << prv << " i b = " << vtor << endl;
}
Слика 4.3.8
Исто така, ако се користи прототипот на функцијата, треба да се означи
дека параметрите се референтни.
void zamena(int &, int &);

135
ПРОГРАМИРАЊЕ

Знакот & може да се стави каде било помеѓу типот и името на парамета-
рот:
int &prv int &prv int &prv
Програмата е дадена на слика 4.3.9.

Слика 4.3.9
Резултатот по извршување на програмата е:

Овој механизам на пренесување вредности од повикувачот во функцијата


и спротивно е наречен пренесување по референци (англ. pass-by-references), а
аргументите се нарекуваат аргументи пренесени по референца.
Повикот на функција од типот void се врши со наредба која се состои од
името на функцијата и листата на аргументи. На пример, функцијата zamena() ќе
се повика со наредбата:
136
4. Потпрограми - Функции

zamena(a, b);
Притоа, бројот и редоследот на аргументите мора да одговара на бројот и
редоследот на параметрите. Но
 типовите на аргументите кои се пренесуваат по вредност може да бидат
константи, променливи или изрази, чии типови се исти или конвертибил-
ни со типовите на соодветните вредносни параметри,
 типовите на аргументите кои се пренесуваат по референца, мора да бидат
променливи (не константи или изрази) и тоа од ист тип како соодветните
референтни параметри.
При повикување на функција од типот void со референтни параметри, не
се креираат нови променливи за референтните параметри, како што се прави за
вредносните параметри. За време на извршувањето на функција од типот void ре-
ферентните параметри се третираат како други имиња за соодветните
аргументи од повикот. Тоа се пос-
тигнува така што на референтните
параметри им се доделува адресата
на соодветните аргументи. Затоа,
сите измени во референтните па-
раметри, всушност, се вршат врз
соодветните аргументи бидејќи
тие се различни имиња на иста ме-
мориска локација.
Скицата на слика 4.3.10 го
илустрира извршувањето на прог- Слика 4.3.10
рамата од слика 4.3.9.

Пример 4.3.5
Да се подредат три броја по големина.
Програмата е дадена на слика 4.3.11.

Слика 4.3.11
137
ПРОГРАМИРАЊЕ

Слика 4.3.11 (продолжение)


Еден излез по извршување на програмата е:

Вежби

Вежба 4.3.1
Да се напишат процедурални подалгоритми и функции без пов-
ратна вредност за следниве задачи:

1. Да се најдат најмалиот и најголемиот број од 5 зададени броја. Колку


аргументи може да има овој процедурален подалгоритам?
2. Да се најдат НЗД и НЗС за два броја. Дали може да се напише еден
функциски подалгоритам кој може да пресмета и НЗД и НЗС? Зош-
то?
3. Да се реши квадратната равенка ax2 + bx + c = 0.
4. Да се реши системот од две линеарни равенки со две непознати:
a1 x + b1 y = c1
a2 x + b2 y = c2
5. Да се најдат првите два пријателски броеви од интервалот m до n.
(За два броја велиме дека се пријателски ако збирот на делителите
на првиот број е еднаков на вториот број, а збирот на делителите на
вториот број е еднаков на првиот број).
138
4. Потпрограми - Функции

6. Да се најдат бинарниот, окталниот и хексадецималниот запис на де-


кадниот број n.
7. Да се најдат најголемиот и најмалиот број кои може да се формираат
од цифрите на природниот број n.
8. Да се најде збирот на два агли изразени во степени, минути и секун-
ди.
9. Да се најде возраста на човек како разлика на денешниот ден и ро-
денденот. Денот, месецот и годината да се внесуваат како цели бро-
еви.
10. Да се генерира Паскаловиот триаголник за n = 5:

1 n=0
1 1 n=1
1 2 1 n=2
1 3 3 1 n=3
1 4 6 4 1 n=4
1 5 10 10 5 1 n=5

4.4 Глобални, локални и статички променливи7

Променливите кои се креирани во програмите и во потпрограмите имаат


одредено подрачје на видливост (англ. scope of visibility) наречено и подрачје
на пристап (англ. scope of access). Подрачје на видливост на некоја променлива
се смета она подрачје во кое има пристап до променливата, т. е. со неа може да
се вршат операции.
Некои променливи може да се користат во целата програма, некои во
целата функција, а некои само во делови од функцијата.
Според подрачјето на видливост, променливите може да бидат:
 Глобални променливи.
 Локални променливи.
Подрачјето на видливост на глобалните променливи, односно пристапот
до нив е целата програма, т. е. главната функција и сите кориснички дефинирани
функции во истата датотека во која е главната функција.
Имињата на кориснички дефинираните функции во една програма се тре-
тираат како глобални променливи и затоа, една функција може да се повика во
која било друга функција во програмата. Функција во С++ не може да се дефини-
ра во телото на друга функција.
Подрачјето на видливост на локалните променливи, односно пристапот
до нив е само телото на функцијата во која се декларирани, само насловот на

7
Оваа потточка е изборна.
139
ПРОГРАМИРАЊЕ

функцијата или само блокот помеѓу две загради {}. Видливоста започнува со
декларацијата на локалната променлива.
Параметрите на една функција се третираат како локални променливи во
целата функција. Исто така, локалните променливи во една функција се видливи
во сите вгнездени наредби, а локалните променливи декларирани во телото на
некоја наредба, не се видливи надвор од нејзиното тело.
За една променлива велиме дека е скриена (прекриена со друга промен-
лива) во некој блок или во цела функција ако не е видлива (не може да се корис-
ти) во тој блок или во таа функција. Тоа значи дека ако во подрачјето на видли-
вост на некоја променлива (на пример, int x = 1;) има блок (во наредба) во кој е
декларирана променлива со исто име (int x = 2;), во тој блок ќе биде видлива са-
мо променливата х со вредност 2.

Пример 4.4.1
Со овој пример ќе ја демонстрираме видливоста на променливите во една
програма.

Во програмата од слика 4.4.1, променливата ovaaGodina е декларирана


како глобалнa променливa, а променливите lani и idnaGodina се декларирани ка-
ко локални променливи во функциите main() и mojaFunkcija(). До глобалната
променлива ovaaGodina може да се пристапи и од главната функција main() и од
функцијата mojaFunkcija(). До локалната променлива lani може да се пристапи
само од main(), а не од mojaFunkcija(), а до локалната променлива idnaGodina се
пристапува само од mojaFunkcija(), а не од main().
Во примерот, глобалната променлива ovaaGodina со вредност 2020 е пре-
криена (скриена) во mojaFunkcija() бидејќи е повторно декларирана како локална
променлива со вредност 2030. Сето ова е јасно од излезот на програмата:

Со анализа на програмата и добиениот резултат (во продолжение), се


гледа која глобална или локална променлива каде е видлива.
Интересно е дека до глобалната променлива ovaaGodina (= 2020), која е
прекриена во функцијата mojaFunkcija() со истоимената локална променлива
ovaaGodina (= 2030), се пристапува со т.н. оператор за разрешување на подрач-
јето на видливост (англ. scope resolution operator), чиј знак е (::).
140
4. Потпрограми - Функции

Времето од креирањето на една променлива во меморијата (веднаш по


извршување на наредбата за декларација) до нејзиното исчезнување (крајот на
блокот, крајот на функцијата или крајот на програмата) се нарекува живот на
променливата (англ. life-time).

Слика 4.4.1
Глобалните променливи живеат цело време додека се извршува програ-
мата.

141
ПРОГРАМИРАЊЕ

Локалните променливи живеат од моментот на креирањето до крајот на


подрачјето на видливост, кое може да биде целата функција или само блок меѓу
две загради {}.
Може да се постават следниве правила за подрачјето на видливост на
променливите:
Локалните променливи не може да се користат надвор од подрачјето на
видливост.
Глобалните променливи може да се користат во целата програма.
Променливите декларирани во еден блок (функција, тело на наредба – for,
while, do-while) може да се користат само во него.
Променлива декларирана во една функција не може да се користи во дру-
га функција.
Променливата може да биде скриена во некој дел од своето подрачје на
видливост ако во тој дел е повторно декларирана под исто име.
Две функции со исто име може да имаат исто подрачјето на видливост са-
мо ако имаат различни листи на аргументи.
Променливите може да бидат и статички (англ. static). Тие се декларира-
ат со зборот static.
На пример:
static int broj = 7;
static double iznos;
iznos = 123.45;
Локалните статички променливи се однесуваат како глобални промен-
ливи. Тие живеат од нивната декларација до завршувањето на програмата. При-
тоа, се иницијализираат само еднаш при декларацијата или при доделувањето
вредност во првиот повик на функцијата во која се локални променливи. По из-
вршување на функцијата во која се декларирани и враќање на дејството во пови-
кувачот (во main() или друга функција), статичките локални променливи ја задр-
жуваат добиената вредност, т. е. не се уништуваат како нестатичките локалните
променливи. При секое следно повикување на функцијата, ја имаат состојбата
(вредноста) добиена во претходното повикување.
Глобалните променливи и локалните статички променливи почнуваат да
живеат со првото извршување на нивната дефиниција.
Статичките променливи ќе ги објасниме со следниов пример.

Пример 4.4.2
Во програмата од слика 4.4.2, функцијата f() се повикува 5 пати.

Во првото повикување на функцијатаf(), статичката променлива pocetok


се иницијализира на вредност 0, а нестатичката променлива brojac на вредност
100. Со наредбите за инкрементирање, тие добиваат вредност 1 и 101.

142
4. Потпрограми - Функции

При второто повикување на функцијата f(), статичката променлива poce-


tok не се иницијализира повторно (иако пак се извршува наредбата за деклара-
ција и иницијализација), туку (бидејќи е статичка) си ја задржува вредноста 1 од
првото повикување на функцијата. Затоа, со наредбата за инкрементирање, до-
бива вредност 2. Нестатичката променливата brojac повторно се иницијализира
на вредност 100 и потоа се инкрементира на 101.
Истото се повторува при секое повикување на функцијата f().

Слика 4.4.2
Излезот по извршување на програмата е:

Ова значи дека статичката променлива brojac се иницијализира само ед-


наш (при првиот повик на функцијата f()) и живее како глобална променлива до
завршувањето на програмата.
Ако променливата brojac не е статичка, тогаш излезот ќе биде:

143
ПРОГРАМИРАЊЕ

Треба многу да се внимава при користењето на глобалните и на статич-


ките променливи бидејќи до нив се пристапува од сите функции во програмата.
Можно е да дојде до измена на нивната содржина во некоја функција, а по пре-
минот во друга функција, таа измена да предизвика грешки.
За разлика од глобалните променливи, глобалните константи е пожелно
да се користат за да не се повторува нивната дефиниција во повеќе функции.
Ова ќе го покажеме на следниов пример.
Пример 4.4.3
Во програмата на слика 4.4.3 се дефинирани две стринг-константи PLOS-
TINA и VOLUMEN и една реална константа PI. Тие може да се користат во про-
грамата и во сите функции кои таа ги повикува.

Слика 4.4.3
144
4. Потпрограми - Функции

Слика 4.4.3 (продолжение)


Пример за излез од програмата е:

4.5 Библиотечни функции

Во досегашните примери, кога требаше да го пресметаме квадратот или


кубот на некој број, тоа го правевме со множење на бројот двапати или трипати.
На пример:
int x, x2, x3;
x = 12;
x2 = x * x;
x3 = x * x * x;
Но, како ќе пресметаме х10? Или, како ќе најдеме 3 12 .
За вакви и слични пресметувања, кои често се користат во програмите,
сите програмски јазици имаат библиотеки со вградени функции, кои може да ги
користат програмерите. Така, јазикот С++ содржи стандардна библиотека (англ.
C++ Standard Library).
Функциите од библиотеките на С++ се нарекуваат и вградени функции
(англ. build-in functions). Нивното име се пишува со мали букви бидејќи имињата
се резервирани зборови. На пример, pow(), sqrt, substring() итн.
Стандардната библиотека С++ содржи повеќе датотеки наречени дато-
теки-заглавие или хедер-датотеки (англ. header files), кои содржат групи од
слични функции, како:
<iostream> Функции за влез и за излез.

<iomanip> Функции за форматирање и за манипулатори.

145
ПРОГРАМИРАЊЕ

<cstdlib>
Општа библиотека: контрола на програмата, случајни броеви,
сортирање, барање итн.

<cmath> Општи математички функции.

<string> Функции за работа со стрингови.

<random> Функции за генерирање случајни броеви.


За да се користи некоја функција од библиотеката на С++ во програмата,
на почетокот на програмата треба да се вклучи библиотеката со директивата #in-
clude, како што го правевме тоа и досега. Притоа, библиотеката се става во аг-
лести загради (знаците за помало и поголемо).
Во продолжение, ќе разгледаме некои почесто користени функции.

Математички функции

Да повториме кратко за функции од математиката.


На пример, функцијата f(x) = x е линеарна функција, f(x) = x2 е квадратна
функција, f ( x )  x е функција за наоѓање на квадратниот корен од х итн. f(x)
означува правило по кое се пресметува некоја нова вредност. На пример, прави-
лото за пресметување на квадратот на некој број е тој да се помножи сам со себе,
а се запишува со f(x) = x · x или пократко х2. Вредноста која ќе се добие за х = 5 е
25 и се означува со некој друг број, на пример у, т. е. у = 25. За секој број х
(наречен аргумент на функцијата), се добива различна вредност на у. Тоа се
запишува и со y = f(x) или y = x2.
Во програмирањето, аргументот и вредноста на функцијата се променли-
ви од одреден тип. На пример:
int x, y;
x = 5;
y = x * x;
или
2
y = pow(x, 2); // Funkcija za stepenuvanje x
Најчесто користени математички функции се:
pow(x, y) – Експоненцијална функција xy.
exp(x) – Експоненцијална функција ех, е = 2.71828.
sqrt(x) – Квадратен корен од х, x .
3
cbrt(x) – Кубен корен од х, x.

8
Овој број е основа на природните логаритми, а се нарекува Неперов број (John
Napier, XVII век, шкотски математичар).
146
4. Потпрограми - Функции

log(x) – Логаритамска функција ln(x), со основа е = 2.7182.


log10(x) – Логаритамска функција log(x), со основа 10.
fabs(x) – Апсолутна вредност од х, |x|.
ceil(x) – Заокружување на х на најмалиот реален број не помал од х.
floor(x) – Заокружување на х на најголемиот реален број не поголем од х.
trunc(x) – Отсекување само на реалниот дел лево од децималната точка.
round(x) – Заокружување на најблискиот реален број до х (без децимали).
fmod(x, y) – Остаток од количникот х / у како реален број.
modf(x & integralen) – Разделување на децималниот број х на интегрален и на
децимален дел. За знакот & ќе зборуваме подоцна.
sin(x) – Тригонометриска функција sin(x).
cos(x) – Тригонометриска функција cos(x).
tan(x) – Тригонометриска функција tg(x)
Овие функции му овозможуваат на корисникот да изврши низа матема-
тички пресметки. Функциите се користат така што се пишуваат името на функ-
цијата и листата со аргументи ставени во мали загради.
Во претходниот пример напишавме
y = pow(x, 2);
Десната страна од наредбата означува повик на функцијата со име pow и
со аргументи х и 2. Со повикување на функцијата, се извршува програмата под
име pow(), која се чува во библиотеката <cmath> и резултатот се доделува на
променливата у.
Со следната наредба за печатење на квадратниот корен од бројот 900.0, се
повикува функцијата со име sqrt и со аргумент 900.0
cout << sqrt(900.0);
Со оваа наредба се печати вредноста што ја враќа функцијата.
Наведените математички функции се функции со повратна вредност.
Аргументите на функциите може да бидат константи, променливи или
цели изрази. На пример, за c = 12, d = 3.0, g = 4.0, наредбата
cout << sqrt(c + d * f);
ќе ги пресмета и отпечати квадратниот корен на 12 + 3.0 * 4.0 = 25.0, т. е. 5.00.
Во следните примери е прикажано користењето на некои од наведените
математички функции.

147
ПРОГРАМИРАЊЕ

Пример 4.4.1

Слика 4.4.1

Резултатот од извршување на програмата е:

148
4. Потпрограми - Функции

Пример 4.4.2

Слика 4.4.2
Излезот од програмата е:
149
ПРОГРАМИРАЊЕ

Функција за генерирање случајни броеви

Во програмирањето често се јавува потреба од генерирање случаен број.


Затоа, во С++ постои посебна функција rand(), која генерира случаен број поме-
ѓу 0 и 32 7679.
На пример:

Ако сакаме ова множество {0, 1, 2, 3, ... , 32 767} да го сведеме на одре-


ден интервал [0, max], тогаш ќе ја користиме формулата
rand() % (max + 1);
На пример, случајни броеви од интервалот [0, 99] се:

За да почнуваат случајните броеви од 1, формулата е:


1 + rand() % (max + 1);
На пример, случајни броеви од претходниот пример во интервалот [1,
100] се:

Ако сакаме интервалот на случајно генерираните броеви да започнува од


одреден број (на пример poceten), тогаш формулата е:
poceten + rand() % (max + 1);
На пример, интервалот [1, 100] може да биде [51, 150] со
51 + rand() % 100;

По извршување на програмата во која се користи ист израз за генерирање


случајни броеви, ќе се генерира иста низа на случајни броеви. Тоа е така бидејќи

9
Постои константа RAND_MAX чија вредност може да се отпечати.
150
4. Потпрограми - Функции

при секое повикување на функцијата rand() од стандардната библиотека на


С++, се извршува иста програма.
За да се генерира нова низа на случајни броеви, при секое повикување на
функцијата rand(), се врши рандомизација (англ. randomizing) со задавање раз-
лична неозначена целобројна вредност како aргумент на функцијата srand().
Оваа функција треба да се изврши пред повикување на функцијата rand().
На пример, ако во претходниот пример, пред генерирањето на случајните
броеви се изврши функцијата
srand(123);
ќе се генерираат следниве случајни броеви:

Ако се изврши повторно функцијата


srand(321);
ќе се генерираат други случајни броеви:

Забележуваме дека функцијата srand() се повикува само со своето име,


без наредбата за доделување. Тоа значи дека оваа функција не враќа вредност.
Има и други такви функции кои се нарекуваат функции без повратна вредност
(англ. non value-returning functions).

Функции за работа со знаци

Во C++ се воведени повеќе функции за работа со знаци. Тие се наоѓаат во


библиотеката <cctype>, која мора да се вклучи на почетокот од програмата.
isdigit(z) ‒ true, ако z е цифра (0, 1... 9).
isalpha(z) ‒ true, ако z е буква.
islower(z) ‒ true, ако z е мала буква.
isupper(z) ‒ true, ако z е голема буква.
isblank(z) ‒ true, ако z е празно место.
isspace(z) ‒ true, ако z е празен простор: ʼ \t‘, ʼ\n‘, ʼ\v‘, ʼ\f‘, ʼ\r‘10.
isalnum(z) ‒ true, ако z е буква или цифра.
ispunct(z) ‒ true, ако z е интерпункциски знак: . , ; : ‘ " ? / ! – (
) [ ] { } < >... итн
isprint(z) ‒ true, ако z е знак што се печати. На пример, ʼ\n‘, ʼ\t‘ и
други не се печатат.
tolower(z) ‒ ако z е голема буква, ја конвертира во мала буква.
toupper(z) ‒ ако z е мала буква, ја конвертира во голема буква.

10
ʼ\t‘ – хоризонтален табулатор, ʼ\n‘ – нова линија, ʼ\v‘– вертикален табулатор, ʼ\f‘–
нова страница, ʼ\r‘ ‒ претходна линија.
151
ПРОГРАМИРАЊЕ

Вежби

Вежба 4.5.1
Да се напише програма која ќе „замислува“ еден број меѓу 1 и 1 000 и ќе
му дава на корисникот до 10 можности да го погоди бројот. По секое погодува-
ње, програмата треба да отпечати една од следните пораки:
 „Ne pogodivte. Brojot koj e zamislen e pogolem od brojot so koj probavte.“
 „Ne pogodivte. Brojot koj e zamislen e pomal od brojot so koj probavte.“
 „Ne pogodivte. Ja ispushtivte Vashata posledna shansa i so toa VE POBE-
DIV!“
 „Pogodivte! Chestito! ME POBEDIVTE!“
Откако ќе ја завршите програмата, извршете ја неколкупати и обидете се
да го откриете бројот кој го замислил компјутерот. Дали може да смислите стра-
тегија за секогаш да победувате?

Резиме

 Суштината на подалгоритмите е во тоа што тие може да се користат во раз-


лични алгоритми или подалгоритми, а и на повеќе места во ист алгоритам
и/или подалгоритам.
 Користењето на подалгоритмите е овозможено преку механизмот на пара-
метри (формални аргументи) и аргументи (вистински аргументи).
 Параметрите може да бидат влезни, излезни и влезно-излезни.
 Постојат два вида подалгоритми, и тоа: функциски подалгоритми (со кои се
добива само еден резултат) и процедурални подалгоритми (со кои се добива-
ат повеќе резултати).
 При повик на функциски подалгоритам, се врши пренесување (копирање) на
влезните аргументи во влезните параметри.
 Функциските потпрограми – функции, може да бидат: библиотечни функции
и/или кориснички дефинирани функции.
 Фунциите во С++ може да бидат: функции со повратна вредност (од кој било
тип на повратната вредност) и функции без повратна вредност (од типот
void).
 При повик на функција, листата со аргументите и листата со параметрите на
функцијата мора да имаат:
 ист број на аргументи и параметри,
 ист редослед на аргументите и параметрите,
 ист или конвертибилен тип на аргументите и соодветните параметри.
 Функција со повратна вредност во С++ се повикува со наредбата за доделу-
вање или во друга наредба или израз.
 Процедурален подалгоритам се повикува само со своето име, а во загради се
ставаат аргументите.
152
4. Потпрограми - Функции

 Функциите во С++ кои не враќаат вредност се од типот void.


 Функциите од типот void во С++ се повикуваат само со своето име и листата
на аргументи.
 При повик на функција со повратна вредност, се користи механизам за пре-
несување аргументи по вредност, при што тие не се менуваат во повикува-
чот (функцијата main() или друга функција).
 При повикување на функција од типот void со референтни параметри, не се
креираат нови променливи за референтните параметри, туку референтните
параметри се третираат како други имиња за аргументите од повикот.
 Функциите кои се дефинирани по главната програма, се декларираат (со на-
ведување на својот прототип) пред главната функција main().
 Променливите можат да бидат глобални и локални.
 Во С++ постои библиотека на функции кои се наоѓаат во т. н. хедер-да-
тотеки. Најчесто користени функции од библиотеката се: математичките,
функцијата за генерирање случајни броеви, функциите за работа со знаци и
функциите за работа со стрингови.

153
ПРОГРАМИРАЊЕ

154
5. Низи

5. НИЗИ
Во оваа глава ќе се запознаете со следното:

 Еднодимензионални низи.
 Именувана константа (константна променлива).
 Декларација и иницијализација на еднодимензионална низа,
иницијализирачка листа.
 Наредба for базирана на опсег.
 Сортирање на низа.
 Класен шаблон vector.
 Текстуални низи. Декларација и иницијализација.
 Функции за работа со текстуални низи.
 Класен шаблон string.
 Дводимензионални низи – матрици.
 Декларација и иницијализација на дводимензионална низа.
 Пресметување на димензиите на низа.

Клучни зборови

Дводимензионална низа
Еднодимензионална низа
Иницијализација на низа
Иницијализирачка листа
Матрица
Наредба for базирана на опсег
Низа
Симболичка константа

155
ПРОГРАМИРАЊЕ

5.1 Еднодимензионални низи

За решавање на проблеми со голем број податоци, податоците се органи-


зираат во посебни структури наречени низи (англ. arrays).
Да се потсетиме за аритметички и геометриски низи. Низата а1, а2... аn се
нарекува аритметичка ако разликата на кои било два соседни елементи е иста, а
кај геометриската низа количникот на кои било два соседни елементи е ист. Исто
така, гледаме дека сите елементи имаат исто име, а индексите им се 1, 2, 3... n.
Индексот го означува редниот број на елементот во низата: 1 – првиот елемент, 2
– вториот елемент итн. n го означува n-тиот елемент.
Индексите може да се означат како точки на бројна оска, т. е. во еден пра-
вец, една димензија. Должината е една димензија. Површината (правоаголник)
има должина и ширина, значи две димензии. Просторот (зграда) има три
димензии: должина, ширина и висина.

Затоа, низите со еден индекс (една димензија) се нарекуваат еднодимен-


зионални низи (англ. one dimensional arrays).
Ако знаеме дека низата има n елементи, тогаш се запишува со: а1, а2... аn.
Или, пократко со a[i]n или само a[]n, што значи дека индексот i има вредности од
1 до n. Се користи и следната ознака [а]n, при што со n се означува дека низата е
еднодимензионална и дека индексите се од 1 до n. Во литературата се користи и
ознаката a[1..n]. Последнава ознака ќе ја користиме во алгоритмите.
Во програмските јазици, променливите што добиваат вредности на пода-
тоци од еднодимензионална низа се запишуваат на тој начин што индексот се
става во средни загради: a[1], a[2]..., a[n] или ocenka[1], ocenka[2]..., ocenka[n].
Иако името на сите елементи им е исто, тие се различни променливи кои се раз-
ликуваат по индексот.
Во многу програмски јазици индексите почнуваат од 0 до n – 1.
Низите во С++ се означуваат на истиот начин, при што индексите се не-
негативни цели броеви, а првиот индекс секогаш е 0. За низа од n елементи,
индексите се 0, 1, 2, 3..., n – 1. На пример, за низа од n елементи ознаката е a[]n, а
елементите се: a[0], a[1]..., a[n – 1]. Ако сакаме да ја означиме само низата, без
бројот на елементи, тогаш ќе користиме ознака а[] за да се разликува од промен-
лива со исто име.

156
5. Низи

Декларација на еднодимензионални низи

Еднодимензионалните низи како променливи во С++ се декларираат на


следниов начин
тип име[број];
тип ‒ е тип на елементите на низата (short, int, long, long long, float,
double, char, boolean, string итн.).
име ‒ е името на низата.
број ‒ е број на елементи на низата и тој мора да биде литерал или
именувана константа поголема од 0.

Примери

Пример 5.1.1
int a[5];
Низата a[] има 5 елементи и тоа: a[0], a[1], a[2], a[3] и a[4]. Типот на еле-
ментите на низата е int и на нив може да им се доделуваат само целобројни вред-
ности.
Пример 5.1.2
float br[25];
Низата br[] е од тип float и има 25 елементи. Општиот к-ти елемент се
означува со br[k], а индексот k може да има вредности 0, 1... 24. Значи, елемен-
тите се: br[0], br[1]... br[24].

Пример 5.1.3
string ime[15], prezime[30];
Се декларираат две низи ime[] и prezime[] чии елементи може да имаат
вредности само стрингови. За стринг ќе објасниме малку подолу.

Пример 5.1.4
const int BROJELEMENTI = 100;
char c[BROJELEMENTI];
Во примеров, бројот на елементи на низа c[] е претходно зададен како
именувана константа (англ. named constant), наречена и константна промен-
лива (англ. constant variable), BROJELEMENTI.

Пример 5.1.5
int k = 10;
float u[k];
Според стандардот на С++, оваа декларација e погрешна бидејќи бројот
на елементи мора да е константен. Сепак, при користење на актуелните околини

157
ПРОГРАМИРАЊЕ

за програмирање, кои го користат преведувачот g++, оваа декларација нема да


направи проблем.
За да означиме специфичен елемент на низата, ги задаваме името на ни-
зата и позицијата на тој елемент во низата. Во табела 5.1 е дадена целобројна
низа со име d. Оваа низа се состои од 10 елементи. До секој од овие елементи мо-
же да се пристапи преку името на низата и индексот на елементот во низата пос-
тавен во средни загради [].
Така, првиот елемент е d[0], a елементот i е d[i – 1].

Табела 5.1.1
Вредност на
Елемент
елементот
0 е индекс на првиот елемент на низата. d[0] ‒567
d[1] 8
d[2] 9
d[3] 72
d[4] 345
d[5] ‒78
d[6] 78
d[7] 9
d[8] 10
9 е индекс на последниот елемент на низата. d[9] 987
Индексот на елементите на дадена низа може да биде константа, промен-
лива или израз чија вредност е ненегативна и во опсег на индексите од 0 до n ‒ 1
(ако должината на низата е n). Така, за a = 7 и b = 2 елементот
d[ a + b ‒ 1 ]
всушност, е елементот d[8].
Внимавајте: Во C++, преведувачот нема да пријави грешка доколку
пристапите до елемент кој не се наоѓа во границите на низата (на пример, да се
обидете да пристапите до седмиот елемент на низа која има големина 5). Но
ваквите грешки може да предизвикаат проблем за време на извршување на
програмата (т.н. runtime error). Велиме „може“ бидејќи оперативниот систем ќе ја
„сруши“ Вашата програма само доколку се обидете да пристапите до меморија
која тој не ви ја доделил. Сепак, дури и да не се „сруши“ Вашата програма, таа
скоро сигурно нема добро да работи ако пристапувате до непостојни елементи од
низата.

158
5. Низи

Иницијализација на низа и доделување вредности на


елементите

На елементите на низата може да им се доделуваат вредности со наредба


за доделување или при иницијализација.
Во наредните примери се илустрирани различни начини на доделување
вредности на елементи на низа.

Пример 5.1.6
Доделување вредности може да се врши посебно на секој елемент:
int a[10];
a[0] = 1; a[9] = 10; a[3] = ‒4; a[5] = 5;

Пример 5.1.7
Доделувањето вредности може да се врши и преку изрази во кои се прес-
метува вредноста на индексите на низата. На пример, ако елементот a[5] = 24, со
наредбите:
int c = 3;
int d = 2;
a[c + d] += 6;
на елементот a[5] му се зголемува вредноста за 6, т. е. неговата вредност сега ќе
биде 30.

Пример 5.1.8
Доделување вредности на елементите на низата може да се врши и при
декларирањето, т. е. со иницијализирачка листа.
int a[] = {5, ‒2, 7, ‒3, 6};
Вредностите на елементите ќе бидат: a[0] = 5, a[1] = ‒2, a[2] = 7, a[3] = ‒3,
a[4] = 6. Должината на низата (бројот на елементи) при ваква иницијализација ја
одредува самиот преведувач.
По декларацијата и иницијализацијата на низата
char bukvi[] = {'a', 'b', 'c'};
вредностите на елементите ќе бидат: a[0] = 'a', a[1] = 'b', a[2] = 'c'.

Пример 5.1.9
Ако има помалку вредности во иницијализирачката листа отколку што
има елементи во низата, останатите елементи на низата се иницијализираат на
нула.
Со следнава декларација и иницијализација
int nekoi[10] = {3, ‒1, 4};
елементите на низата ќе се иницијализираат со следните вредност: 3, –1, 4, 0, 0, 0,
0, 0, 0, 0. Нулите ги пополнува преведувачот.

159
ПРОГРАМИРАЊЕ

Слично, со
int nuli[100] = {};
се декларира низа од целобројни елементи под име nuli, при што сите елементи
се иницијализираат на 0.
Со декларацијата и иницијализацијата
char samoglaski[5] = {'a'};
експлицитно се доделува вредноста 'a' на нултиот елемент од низата, а сите
останати елементи автоматски се иницијализираат на празни места.
Забелешка: Во С++ нема автоматска иницијализација на низи. Мора
барем еден елемент да е иницијализиран, за потоа сите останати елементи да би-
дат иницијализирани.

Пример 5.1.10
Димензијата на низата може да се пресмета автоматски ако елементите се
зададени при иницијализација. При следната декларација и иницијализација
double ovie[] = {2.34, ‒5.67, 3.45, 7.89 };
не е зададена должината на низата, а ја одредува преведувачот, според зададе-
ниот број на елементи, т. е. низата ovie ќе има должина 4.
Слично, со декларацијата и иницијализацијата
string denovi[] = {"Pon","Vto","Sre","Cet","Pet","Sab","Ned"};
должината на низата denovi е 7.
Со следнава декларацијата и иницијализација
int cifri[] = {1, 2, 3, 4, 5};
се декларира низа со должина 5 и се иницијализираат сите елементи.
Од друга страна, со следнава декларација и иницијализација на низата
int v[5] = {1, 2, 4, 5, 6, 9};
се јавува синтаксичка грешка бидејќи има 6 иницијализирачки вредности, а низа-
та може да има најмногу 5 елементи.

Пример 5.1.11
Низите не може:
 да се доделуваат една на друга:
int a[2] = {1, 2};
int b[2];
b = a; // neispravno
 да се иницијализираат една со друга:
int c[2] = a; // neispravno
 да се печатат само преку името1:
cout << a; // neispravno
 да се споредуваат2:
if (a == b) // neispravno

1
Се печати адресата на низата.
2
Се споредуваат адресите на низите.
160
5. Низи

 да бидат повратна вредност од функција3:


return a; // neispravno
Специфицирање на должината на низата може да се врши и со симбо-
личка константа. Симболичката константа се задава со претпроцесорската ди-
ректива #define.
На пример:
#define PI 3.1415;

Пример 5.1.12
Во овој пример се користи претпроцесорската директива #define, со која
се дефинира симболичка константа DOLZINA чија вредност е 10, слика 5.1.1.

Слика 5.1.1
Програмата ги иницијализира првите два елементи на низата со вредност
1, а останатите со 0. Со наредбата for на елементите од третиот до десеттиот им
се доделуваат вредности по формула. (Која?)
Излезот при извршување на програмата е:

3
Се враќа покажувач на низата. За покажувачи ќе зборуваме подоцна.
161
ПРОГРАМИРАЊЕ

Слика 5.1.1
Пример 5.1.13
Програмскиот сегмент за читање елементи на целобројна низа од n еле-
менти a[]n е:
for (int i = 0; i < n; i++)
cin >> a[i];

Пример 5.1.14
Програмскиот сегмент за печатење елементите на низата b[]n е:
for (int i = 0; i < n; i++)
cout << a[i] << endl;

Пример 5.1.15
Програмскиот сегмент за наоѓање на збирот на елементите на низата од n
елементи c[]n е:
zbir = 0;
for (int i = 0; i < n; i++)
zbir += c[i];
Истиот програмски сегмент може да се користат и за пресметување на
производот на елементите на низата, само треба да се сменат наредбите:
zbir = 0; со proizvod = 1;
zbir += c[i]; со proizvod *= c[i];
Овие сегменти може да се користат за која било операција со елементите
на низата. Тие овозможуваат да пристапиме до секој од елементите на низата,
еден по еден, од првиот до последниот и да направиме некоја операција со него.
Овој процес се нарекува изминување на низа.

Пример 5.1.16
Во примерот на слика 5.1.2 се илустрирани декларација, иницијализација
и доделување вредности на елементите на низи од типот: int, float, char и string.

162
5. Низи

Слика 5.1.2

163
ПРОГРАМИРАЊЕ

Излезот од програмата е:

Во С++ постои операторот sizeof, со кој може да се добие големината на


меморијата зафатена од некој тип или од израз (променлива).
Операторот sizeof може да се примени и на низа, при што ќе се добие
големината на низата во бајти, која зависи од бројот на елементи. За да го доби-
еме бројот на елементи на низата, треба големината на низата (во бајти) да ја
поделиме со големината на типот на елементите на низата (во бајти).
На пример:
char znaci[] = {'@', '#', '$', '%', '^'};
dolzina = sizeof znaci / sizeof(char);
или
dolzina = sizeof znaci / sizeof(znaci[0]); // znaci[0] e prviot element

Решени задачи

Задача 5.1.1
Да се напишат алгоритам и програма со која секој елемент од бројната
низа a[]n ќе го промени знакот, + во – и – во +.

164
5. Низи

Алгоритамот и програмата се дадени во продолжение.


алгоритам ПроменаНаЗнацитеНаНиза
почеток
a[1..n];
печати „Внесете го бројот на елементи на низата, n = “;
читај n;
за i  1 зголемувај до n
читај ai;
крај_за{i}
за i  1 зголемувај до n
ai  ‒ai;
крај_за{i}
печати „Низата со променети знаци на елементите е: “;
за i  1 зголемувај до n
печати ai;
крај_за{i}
крај{ ПроменаНаЗнацитеНаНиза }

Слика 5.1.3
165
ПРОГРАМИРАЊЕ

Слика 5.1.3 (продолжение)


Еден излез од извршување на програмата е:

Задача 5.1.2
Да се напише програма за наоѓање на најголемиот и на најмалиот еле-
мент во бројната низа а[]n, со посебни функции.

Објаснување: На почетокот се зема дека најголем елемент е првиот, а1.


Потоа, се споредува вториот елемент а2 со најголемиот (а тоа е првиот) и пого-
лемиот од нив се зема за најголем. Понатаму, сите останати елементи а3, а4... аn се
споредуваат со дотогаш најдениот најголем елемент и ако се најде поголем од
него, се зема тој да биде најголем. Притоа, се памти и неговата позиција во низа-
та.
Ќе наведеме пример. Нека е низата а = {2, ‒1, 7, 9, 3}.
i аi аi > max Max index
1 2 2 1
2 ‒1 (‒1 > 2) не
3 7 (7 > 2) да 7 3
4 9 (9 > 7) да 9 4
5 3 (3 > 9) не
166
5. Низи

Значи, најголем е 4-тиот елемент со вредност 9.


Постапката за наоѓање на најмалиот елемент во низата е слична. Ќе ја
илустрираме на истиот пример.
i аi аi < min Min index
1 2 2 1
2 ‒1 (‒1 < 2) да ‒1 2
3 7 (7 < ‒1) не
4 9 (9 < ‒1) не
5 3 (3 < ‒1) не
Значи, најмал е 2-риот елемент со вредност ‒1.
Во дефиницијата на функција која има аргументи низи, низите се пишу-
ваат само со типот и името, по кое се ставаат средни загради за да се знае дека
е низа, а не променлива.
На пример:
void NajgolemElement(double a[], double brojnaelementi, double &pozicija,
double &najgolem)
Притоа, низата се третира како референтен аргумент иако не е ставен зна-
кот &. Тоа значи дека сите измени на елементите на низата кои ќе настанат при
извршување на функцијата, остануваат и по враќање во главната функција.
При повикување на функција со аргумент низа, се пишува само името
на низата и тоа без загради:
NajgolemElement(a, n, redenbroj, najgolem);
Притоа, големината на низата се пренесува како аргумент по вредност.
Во некои случаи кога не сакаме да се променат вредностите на елементи-
те во функцијата во која е пренесена низата, бидејќи се третира како референца,
треба да се означи како константна со квалификаторот const.
Функциите за наоѓање на најголемиот и на најмалиот елемент во низа,
како и главната функција во која се повикуваат тие функции, се дадени на слика
5.1.4.

Слика 5.1.4
167
ПРОГРАМИРАЊЕ

Слика 5.1.4 (продолжение 1)

168
5. Низи

Слика 5.1.4 (продолжение 2)


Пример на излез од програмата е:

Наредба for базирана на опсег

Во Пример 5.1.15 збирот на елементите на низа од n елементи c[]n се


пресметува со следниот програмски сегмент:
zbir = 0;
for (int i = 0; i < n; i++)
zbir += c[i];
Како поедноставен запис, според поновите станадарди на С++ може да се
користи таканаречената наредба for базирана на опсег (анг. range-based for),
слика 5.1.5.
for (променлива: низа){
наредба А;
наредба Б;
...
наредба К;
}
Слика 5.1.5
‒ променлива е променлива од типот на низата.
‒ низа е името на низата.

169
ПРОГРАМИРАЊЕ

Во телото на наредбата for базирана на опсег не може да има и наредби за


ознаки или операции со индексите.
Ќе наведеме неколку примери.

Примери

Пример 5.1.17
Програмскиот сегмент од Пример 5.1.15 за збир на елементите на низата
c[] може да се запише на следниов начин:
for(int broj: c)
zbir += broj;

Пример 5.1.18
Во Задача 5.1.2, наредбата for за збир на елементите:
for (i = 0; i < n; i++) {
zbir += k*a[i];
k = ‒k;
}
може да се напише и со наредбата for базирана на опсег:
for(double broj: a) {
zbir += k * broj;
k = ‒k;
}

Пример 5.1.19
За наоѓање на најмалиот или на најголемиот елемент во низа:
double najmal = a[0];
double najgolem = a[0];
for(auto broj: a) {
if(broj < najmal)
najmal = broj;
if(broj > najgolem)
najgolem = broj;
}

Вежби

Вежба 5.1.1
Решете ги следните задачи на тој начин што за секоја следна зада-
ча ќе го користите кодот од претходната задача, со мала измена/допол-
нување.
1. Иницијализирајте низа од 17 елементи уште при декларирањето.
Низата е: 1, 9, 22, 17, ‒4, 3, ‒1, 9, 12, 58, ‒7, 0, 4, 5, 33, 18, ‒55.
а) Отпечатете ги елементите од низата во еден ред, одделени со по
едно празно место.
170
5. Низи

б) Отпечатете ги елементите од низата во еден ред, одделени со за-


пирка помеѓу елементите.
в) Отпечатете го секој втор елемент од низата во еден ред, одделени
со по едно празно место.
г) Отпечатете ги сите парни елементи од низата во еден ред, одделе-
ни со по едно празно место.
д) Отпечатете ги сите елементи од низата кои се негативни броеви
во еден ред, одделени со по едно празно место.
2. Преку тастатурата внесете n елементи во една низа. Потоа, внесете
вредност за бројот к.
а) Отпечатете ги сите елементи од низата кои се помали од к, во еден
ред, одделени со по едно празно место.
б) Сите елементи од низата зголемете ги за к и отпечатете ја новодо-
биената низа.
в) Сите парни елементи од низата помножете ги со к и отпечатете ја
новодобиената низа.
3. Преку тастатурата внесете n елементи во една низа. Најдете го нај-
големиот елемент во низата и отпечатете го.
4. Преку тастатурата внесете n елементи во една низа. Најдете го најма-
лиот елемент во низата и сите елементи од низата намалете ги за
вредноста на најмалиот елемент. Отпечатете ја новодобиената низа.

Вежба 5.1.2
Да се напишат програми за следниве задачи:
1. Да се провери дали во бројната низа a[]n се наоѓа елемент со вредност
v.
2. Да се најде производот на елементите на целобројната низа a[]n.
3. Да се пресмета аритметичката (А) и хармониската (Н) средина на
бројната низа a[]n.
a1  a 2  ...  a n n
A H
n 1 1 1
  ... 
a1 a 2 an
4. Да се најде колку елементи од бројната низа a[]n имаат помала вред-
ност од v, а колку поголема.
5. Од низата броеви a[]n да се пресмета посебно збирот на парните и
збирот на непарните броеви.
6. Да се издвојат во посебни низи елементите на низата a[]n со парни
индекси и со непарни индекси.
7. Да се изврши циклично поместување на елементите на низа од знаци
a[]n за к места надесно или налево.
8. Да се формира нова низа c[]n, чии елементи се збир на соодветните
елементи на низите a[]n и b[]n, т. е. ci = ai + bi, за i = 0, 1... n – 1.
171
ПРОГРАМИРАЊЕ

9. Да се пресмета производот на елементите на бројните низи a[]n и


b[]n, т. е. a0b0 + a1b1 +. . . + an ‒ 1bn ‒ 1.

Вежба 5.1.3
Одговорете на следните прашања:
1. Како се декларира еднодимензионална низа?
2. Од каков тип на податок треба да биде индексот на елементите на
еднодимензионална низа?
3. Ако е декларирана еднодимензионална низа
int a[10];
кои вредности може да ги прими индексот на елементите на низата?
4. На кои начини може да се врши доделување вредности на елементи-
те на еднодимензионална низа?
5. На кои начини може да се врши иницијализирање на елементите на
еднодимензионална низа?
6. Како се одредува димензијата на еднодимензионална низа?
7. Напишете ја синтаксата на наредбата for базирана на опсег.

5.2 Сортирање на низа и класен шаблон vector

Да го разгледаме следниот проблем: дадена ни е низата a = { 5, 4, 2, 1, 5,


3} и потребно е нејзините елементи да ги подредиме во растечки {1, 2, 3, 4, 5, 5}
или во опаѓачки {5, 5, 4, 3, 2, 1} редослед. Ваквото подредување на низа, според
вообичаената терминологија во програмирањето, се нарекува сортирање (англ.
sorting).
Да започнеме со следниот алгоритам (за сортирање во растечки редос-
лед): ја изминуваме низата а[] и секој елемент го споредуваме со сите елементи
кои доаѓаат по него во низата, до последниот. При споредувањето, доколку еле-
ментот што го споредуваме е поголем од некој од елементите со кои го споре-
дуваме, тие два елемента ќе си ги заменат местата. По споредување на нултиот
елемент со останатите елементи од низата, на нулта позиција ќе се доведе најма-
лиот елемент од низата. Истото важи и за првиот, па за вториот и за сите следни
елементи до претпоследниот. Програмскиот код на функцијата sort() која го реа-
лизира овој алгоритам е даден на слика 5.2.1.
Анализата на временската сложеност на овој алгоритам е едноставна: за
секој елемент од низата треба да се направат споредби со околу n /2 елементи.
Така, за првиот елемент (на позиција 0) треба да се направат n ‒ 1 споредба, за
вториот елемент (на позиција 1), треба да направиме n ‒ 2 споредби итн. до пос-
ледниот елемент за кој треба да се направат 0 споредби. Збирот е 0 + 1 + 2 + 3 +...
n(n−1)
+ (n ‒ 1) е збир на првите n ‒ 1 природни броеви) и изнесува . Значи, алго-
2
2
ритамот има временска сложеност O(n ).
172
5. Низи

Следниот алгоритам кој


ќе го разгледаме е познат под и-
мето подредување со Сортирање
со меурче (англ. bubble sort). О-
вој алгоритам работи преку заме-
на на соседни елементи кои се
наоѓаат во погрешен редослед,
слика 5.2.2. Името на алгорита-
мот доаѓа од таму што помалите
Слика 5.2.1 елементи испливуваат (како ме-
урчиња) до врвот на листата. И
тој, како и претходниот алгоритам има квадратна временска сложеност O(n2).
Анализата на времен-
ската сложеност на овој алго-
ритам е малку потешка од онаа
на претходниот алгоритам би-
дејќи сега имаме циклус за кој
не знаеме колку пати ќе се извр-
ши. Всушност, почетната пози-
ција на елементите има многу
значајна улога при одредување-
то на времето на извршување на
овој алгоритам. Доколку низата
е веќе подредена, сложеноста е
линеарна O(n) и тоа е најдобро-
то време на извршување на ал- Слика 5.2.2
горитамот. Доколку имаме голе-
ми елементи на почетокот {5, 1, 2, 3, 4, 5}, тие не претставуваат сериозен про-
блем бидејќи брзо се преместуваат до нивната крајна позиција. Но доколку има-
ме мали елементи на крајот од низата {2, 3, 4, 5, 5, 1}, тие многу бавно се движат
до почетокот. На пример, за да се подреди низата {2, 3, 4, 5, 5, 1}, потребен е
квадратен број на операции. Во просек, подредувањето со алгоритамот на меурче
е еден од најбавните алгоритми за подредување, но е за нијанса побрз (во просе-
чен случај) од претходно разгледаниот алгоритам од слика 5.2.1.

173
ПРОГРАМИРАЊЕ

Класен шаблон vector

C++ нуди „помодерни“ начини за зачувување на повеќе вредности во


стилот на низата, како дел од таканаречената стандардна библиотека на шаблони
во С++ (англ. Standard Template Library – STL). За ова ќе се дискутира повеќе во
една од следните теми. Сега ќе споменеме само за вектор (англ. vector) и ќе об-
јасниме само дел од неговите можности.
Векторот претставува низа чија големина се определува динамички, т. е.
за време на извршување на програмата. За разлика од низите, векторот нуди ед-
ноставни функции преку кои мо-
же да се одреди или промени не-
говата големина, да се додаде
или избрише одреден елемент
итн.
Следнава програма креи-
ра празен вектор, додава не-
колку елементи (од типот string)
во векторот и, на крајот, ја печа-
ти неговата содржина, слика
5.2.3.
До елементите на векто-
рот пристапуваме на идентичен
начин како што пристапуваме и
до елементите на една низа т. е.
преку индексите. Како што може
да забележите од програмата
дадена на слика 5.2.3, елементи Слика 5.2.3
во векторот додаваме со повик
на функцијата push_back(). На тој начин, ја зголемуваме големината на векторот
за 1.
Бројот на елементи во векторот може да се открие со повик на функцијата
size().
Една од придобивките при користење на вектори е дека два вектори мо-
же да се споредат со примена на операторите == и !=. Притоа, споредувањето се
врши елемент по елемент. Сложеноста на оваа постапка е O(n). Друга придо-
бивка е што за сортирање на вектор може да се искористи веќе постоен алгори-
там за сортирање кој за да го користиме мора да ја вклучиме библиотеката
<algorithm> во нашата програма. Пример за ова е даден на слика 5.2.4. Повеќе за
вектори ќе научите понатаму.

174
5. Низи

Вежби

Вежба 5.2.1
Решeте ги
следните задачи со
употреба на едноди-
мензионална низа и-
ли вектор. По пот-
реба, направете сор-
тирање на низата.
1. Напишете прог-
рама која ги на-
оѓа трите раз-
лични најголеми
броеви во една
низа.
2. Најдете го еле-
ментот кој се по-
јавува најголем
број пати во ни-
зата.
3. Напишете прог-
рама која ќе ги Слика 5.2.4
преуреди еле-
ментите на една низа која се состои од нули и единици, на тој начин
што прво ќе бидат сите нули, а потоа сите единици.
4. Напишете програма која ќе ги преуреди елементите на низата така
што прво ќе се бидат позитивните броеви, птоа нулите и на крајот
негативните броеви. Притоа, релативниот распоред на броевите
треба да е како во првата низа.
5. Најдете го најмалиот елемент кој се појавува парен број пати во ед-
нодимензионална низа.

Вежба 5.2.2
Денес правеле тест дел од учениците (n < 100) од еден клас. За
секој од нив го внесуваме неговиот реден број (< 1000) и резултатите на
тестот. Отпечатете ги редните броеви на 5-те ученици кои имале најдобар
резултат на тестот (< 100) и просечниот резултат на тие 5 ученици.

175
ПРОГРАМИРАЊЕ

5.3 Текстуални низи

Во јазикот С (кој бил претходник на С++) биле дефинирани низи од зна-


ци, наречени текстуални низи или С-стрингови како посебен тип. Постојат
многу функции за работа со овие низи, наследени од јазикот С. Тие се користат и
во С++, посебно за апликации во кои се обработуваат текстови.
Текстуалните низи завршуваат со т.н. нулти знак (англ. null-character)
'\0'. Затоа, се наречени и текстуални низи кои завршуваат со нулти знак
(англ. null-terminated character sequences).

Декларација и иницијализација на текстуална низа

Текстуалните низи се декларираат со резервираниот збор char


char име[должина];
Должината на низата секогаш е поголема за 1 од бројот на знаци.
Текстуалните низи ќе ги објасниме на примери.

Пример 5.3.1
По декларацијата на текстуалната низа
char ime[10];
се резервира меморија чии елементи немаат дефинирани вредности. На крајот на
текстуалната низа автоматски се поставува нулти знак.
? ? ? ? ? ? ? ? ? \0
0 1 2 3 4 5 6 7 8 9
Пример 5.3.2
Доделувањето вредности на текстуална низа најчесто се врши при
декларација и иницијализација, преку доделување на текстуална константа.
Притоа, секој елемент добива вредност и се поставува знакот за крај на низата.
Со следнава декларација и иницијализација
char ime[11] = "MAKEDONIJA";
текстуалната променлива ime[] во меморијата ќе зафаќа 11 бајти.
M A K E D O N I J A \0
0 1 2 3 4 5 6 7 8 9 10
Ако декларацијата е
char ime[10] = "MAKEDONIJA";
ќе се јави грешка

бидејќи во декларираната должина на низата [10] не може да се стават 10 знаци


од името MAKEDONIJA плус нултиот знак '\0'.

176
5. Низи

Знците во текстуална низа имаат индекси, почнувајќи од првиот кој има


индекс 0. Taкa, во текстуалната низа ime[], која е иницијализирана со текстуаната
константа "MAKEDONIJA" со должина 11, првиот знак 'M' има индекс 0, вто-
риот знак 'A' има индекс 1, последниот знак 'A' има индекс 9.

Пример 5.3.3
На елементите на текстуалната низа може посебно да им се доделуваат
вредности (знаци) кои се од типот char:
ime[0] = 'M';
ime[2] = 'C';

Пример 5.3.4
Со следнава декларација и иницијализација
char prezime[15] = "Jovancevski";
се декларира низата prezime[] со должина од 15 знаци (се резервира меморија од
15 бајти), а нултиот знак се става веднаш по доделената текстуална константа.
Содржината на преостанатите три бајти не е позната.
J o v a n c e V s K i \0 ? ? ?
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Пример 5.3.5
Ако не се знае должината на текстуалната низа, тогаш при иницијализа-
ција во меморијата, се резервира простор со должина еднаква на бројот на знаци
на низата плус еден бајт за нултиот знак '\0' за крај.
Со наредбата
char godina[] = "prva";
се декларира и иницијализира низа со должина 4, а во меморијата се резервираат
5 бајти.
p r v a \0
0 1 2 3 4
Пример 5.3.6
Текстуална низа може да се иницијализира и со иницијализирачка листа.
Следната иницијализација
char grad[]= {'S', 'k', 'o', 'p', 'j', 'e'};
не е правилна бидејќи нема нулти знак на крајот. При ваквата иницијализација,
мора да се внимава експлицитно на последниот елемент од текстуалната низа да
му се додели вредност '\0'. Правилна иницијализација би била:
char grad[] = {'S', 'k', 'o', 'p', 'j', 'e', '\0'};
Ако ја отпечатиме низата grad[] по првата иницијализација,

ќе видиме дека таа содржи и други знаци. Додека, по втората иницијализација ќе


добиеме точна содржина

177
ПРОГРАМИРАЊЕ

Последната иницијализација е иста со


char grad[] = "Skopje";

Забелешка: Текстуална низа, за разлика од другите типови променливи,


не може да се декларира и потоа да ѝ се додели текстуална константа. На пример,
за следниве две наредби се јавува грешка:

Пример 5.3.7
Со текстуалните низа се вршат операции за споредување со користење
на релациските оператори, и тоа:
== еднакво
<> различно
< помало
> поголемо
<= помало или еднакво
>= поголемо или еднакво
Во следната наредба if
if(ime > prezime)
cout << "Imeto e pogolemo od prezimeto" << endl;
споредувањето на текстуалните низи ime[] и prezime[] се врши знак по знак,
според лексикографската вредност на знаците во абецедата, т. е. според вреноста
на знаците ASCII.
Следната наредба содржи логички израз формиран од елементи на тек-
стуалната низа grad[] и релациски оператори:
if(grad[0] == 'S' || grad[0] == 's')
cout << "Gradot zapocnuva na bukvata S ili s. ";
Забелешка: Треба да се нагласи разликата помеѓу знаковните константи
заградени со наводници "..." и со полунаводници ' '.
Вредноста 'j' претставува еден знак и има големина од еден бајт.
Вредноста "j" претставува текстуална низа од еден знак и зафаќа два бај-
ти во меморијата бидејќи завршува со нултиот знак '\0' и го има следниот из-
глед:
ј \0
0 1

178
5. Низи

Печатење и читање на текстуални низи

За да се отпечати текстуална низа потребно е да се наведе само името, без


загради. На пример:
char zbor[] = "primer";
cout << zbor;
Кога се врши читање на текстуална низа со cin, исто така, се наведува са-
мо името. Читањето се врши до првиот бланко знак. Ова е покажано со следниот
пример.

Пример 5.3.8
Во програмата на слика 5.3.1 се покажани доделување, читање и печа-
тење на текстуална низа.

Слика 5.3.1
Излезот е:

Пример 5.3.9
Ако треба да се прочита текстуална низа која содржи и бланко знаци, то-
гаш се користи функцијата cin.getline(promenliva, dolzina), која е слична со функ-
цијата getline(cin, promenliva) за читање стрингови.
Во оваа функција, promenliva е името на текстуалната низа, а dolzina е
константа со која се задава должината (во знаци, т. е. бајти) на promenliva. Затоа,
promenliva ќе содржи dolzina – 1 знаци бидејќи последниот знак ќе биде нултиот
179
ПРОГРАМИРАЊЕ

знак. Тоа значи дека од внесената низа преку тастатурата ќе се прочитаат првите
dolzina – 1 знаци.
Ако во претходната програма (слика 5.3.1), место
cin >> vnesenaNiza;
се стави наредбата
cin.getline(vnesenaNiza, 12);
се резервира простор за низата vnesenaNiza од 12 знаци, а ќе се прочитаат првите
11 знаци внесени од тастатурата.
Излезот ќе биде:

Ако сакаме да се прочитаат сите знаци од внесената низа преку тастату-


рата, тогаш ќе резервираме повеќе бајти отколку што претпоставуваме дека ќе
биде долга влезната низа, но не повеќе од декларираната димензија на низата.
На пример, ако низата е декларирана со должина [10], тогаш вториот
аргумент во функцијата getline() не треба да биде поголем од 10.

Пристап до елементите на текстуална низа

Текстуалните низи може да се обработуваат како која било друга низа.


Притоа, треба да се внимава секогаш последниот елемент од низата да има
вредност '\0'. Во спротивно, може да дојде до непредвидлив резултат при извр-
шувањето.

Пример 5.3.10
На слика 5.3.2 е прикажано некоректно завршување на текстуална низа.

Програмата може да го има следниов излез:

Коректен изглед на излезот

се добива ако се додаде наредбата


niza[6] = '\0'; // ili niza[6] = 0

180
5. Низи

Слика 5.3.2
Пример 5.3.11
Текстуалната низа може да се внесе и знак по знак, слика 5.3.3.

Слика 5.3.3

181
ПРОГРАМИРАЊЕ

Излезот е:

Пример 5.3.12
Поради особината на текстуалните низи да завршуваат со специјалниот
знак '\0', должината на низата може да се определи преку наоѓање на нултиот
знак '\0' во низата. Тоа е илустрирано во следнава програма.

Слика 5.3.4
Излезот од оваа програма е:

182
5. Низи

Функции за работа со текстуални низи

Нека се s, s1, s2 и s3 текстуални низи, декларирани со доволна големина.


За работа со текстуални низи, постојат повеќе функции. Ќе наведеме
неколку.

strlen(s1); – Функција за должината на низата (број знаци без


нултиот знак).
strcpy(s1,s2); – функција од тип void за копирање на s2 во s1.
strncpy(s1,s2,n); – функција од тип void за копирање на првите n знаци од
s2 во s1.
strcat(s1,s2); – функција void за спојување на s1 и s2.
strncat(s1,s2,n); – функција void за спојување на s1 и првите n знаци од s2.
strcmp(s1,s2); – Функција за споредување на s1 и s2.
strncmp(s1,s2,n); – Функција за споредување на првите n знаци од s1 и s2.
Функциите strcmp() и strncmp() враќаат вредност:
0 – ако се низите еднакви,
+к – ако е s1 > s2 лексикографски,
‒к – ако е s1 < s2 лексикографски.

Решени задачи

Задача 5.3.1
Да се провери дали некој збор е палиндром.

Слика 5.3.7
183
ПРОГРАМИРАЊЕ

Слика 5.3.7 (продолжение)


Излезот од програмата е:

Задача 5.3.2
Да се најде колку пати се јавува секој знак (што го има) во некој текст.

Објаснување: Постапката која е применета во алгоритамов е следна: за


секој знак, почнувајќи од првиот, се проверува дали го има во знаците пред него.
Ако го нема, значи дека е нов знак и се бара колку пати се јавува до крајот на
текстот.
Програмата е дадена на слика 5.3.8.
Еден излез од извршување на програмата е:

184
5. Низи

Слика 5.3.8

Шаблонот string

Стандардната библиотека на шаблони нуди посебен шаблон string за ра-


бота со текстуални податоци. Досега, во неколку програми, веќе беше користен
овој шаблон, а овде подетално да ги наведеме фунциите кои тој ги нуди.
Најпрво, треба да се каже дека string всушност дава еден вид проширу-
вање на операциите кои се нудат од vector<char>. Како таков контејнер, string ги
нуди повеќето функции кои ги нуди и вектор: size, empty, push_back, begin, end,
resize, clear, insert и erase. Дополнително, string (како и vector) овозможува при-
стап до елемент на произволна позиција преку индексот. Во овој случај, тоа се
185
ПРОГРАМИРАЊЕ

знаците во текстот. За разлика од vector<char>, шаблонот string нуди неколку


функции за операции со текстуални податоци. На пример, два стринга можеме да
ги споиме, односно вториот да го додадеме на првиот со помош на операторот
'+'. Имено, два стринга str1 и str2 може да ги споиме во нов стринг со нивно
едноставно „собирање“: str1 + str2 или, доколку е тоа потребно, str1 += str2. Ова е
прикажно и преку програмата на слика 5.3.9.
Повеќе околу можностите кои ги нуди шаблонот string ќе покажеме по-
натаму преку примери.

Слика 5.3.9

186
5. Низи

Вежби

Вежба 5.3.1
Да се напишат програми за следниве задачи со користење на тек-
стуални низи:
1. Да се најде спротивниот збор (текст) на даден збор (текст).
2. Да се одреди колку пати се наоѓа даден знак во текст.
3. Да се најдат сите имиња во даден текст. (Имињата се зборови кои
почнуваат со голема буква).
4. Во даден текст да се најде растојанието помеѓу два дадени збора.
(Растојанието е број на знаци помеѓу нив.)
5. Да се внесат n зборови и со спојување на секој збор на крајот на
претходниот со празно место меѓу нив, да се формира текстуална ни-
за.
6. Да се најде најдолгиот збор во дадена текстуална низа.
7. Да се одреди колку пати и на кои позиции започнува даден збор во
текстуална низа.
8. Да се избришат буквите кои се повторуваат последователно во даден
текст. (На пример: „Јас суум тукааа дојјден порраноо“, а треба „Јас
сум тука дојден порано“).
9. Да се изврши циклично поместување на знаците во текстуална низа
за к места налево или надесно.
10. Да се сортираат n имиња по абецеден редослед на првата буква.

Вежба 5.3.2
Да се даде одговор на следните прашања:
1. Како се декларира текстуална низа?
2. На кои начини може да се иницијализира текстуална низа?
3. Со кој знак мора да завршуваат текстуалните низи?
4. Што е погрешно во следната декларација?
char grad[]={'K', 'a', 'v', 'a', 'd', 'a', 'r', 'c', 'i'};
5. Ако текстуалната променлива jas треба да се иницијализира на
вредност „Jovanov“, колкава мора да биде нејзината најмала
димензија?
6. Како може да се додели вредност на текстуална низа?
7. Кои релациски оператори се користат при работа со текстуални
низи?
8. Ако вредноста на текстуалната низа која треба да се прочита се
состои од повеќе зборови, со која наредба треба да се прочита?
9. Со која функција се одредува должината на тeкстуална низа?
10. Со која функција се врши споредување на две текстуални низи? Кој
може да биде резултатот од споредувањето?
187
ПРОГРАМИРАЊЕ

5.4 Дводимензионални низи

Во потточката 5.1 Еднодимензионални низи рековме дека податоците


кои имаат една димензија може (математички) да се претстават со низи со еден
индекс: а1, а2... аn, или скратено a[]n. Овие низи во програмските јазици, па и во
С++, се запишуваат со индекси во средни загради: a[0], a[1]... a[n – 1]. Притоа,
индексите почнуваат од 0.
Има примери во математиката и во други области, каде што за запишу-
вање на некои податоци мора да се користат 2, 3... и повеќе индекси.
На пример, знаеме дека секоја точка во рамнина е одредена со две димен-
зии – координати: х-координата и у-координата, т. е. А(х, у), слика 5.4.1.

Слика 5.4.1
Слично, оценките на учениците од еден клас по сите предмети (да прет-
поставиме 12) може да се прикажат со табела со две димензии, со редици (хори-
зонтално, прва димензија) и колони (вертикално, втора димензија).
1 2 3 4 5 6 7 8 9 10 11 12
Предмет → p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 Prosek
Ученик ↓
1 u1 3 4 5 2 3 4 3 4 5 3 3 2
2 u2 4 5 4 5 3 4 5 4 5 5 5 4
3 u3 5 5 5 5 2 4 4 4 4 2 4 5
… ...
Prosek
Слика 5.4.2
Овие податоци може да се запишат како дводимензионална низа, при
што едната димензија е ученици (u), а другата димензија е предмети (p). Значи,
секоја оценка во табелата има два индекси. Ако низата ја именуваме со o (скрате-
но од ocenki), тогаш вредностите на елементите на дводимензионалната низа се

188
5. Низи

оценките на учениците по предметите. На пример, o(u2, p7) = 5, o(u3, p10) = 2 итн.


Или, пократко, само со индексите, o2,7 = 5, o3,10 = 2 итн.
Ако знаеме дека има m ученици и n предмети, тогаш низата (математич-
ки) се запишува со: o1,1, o1,2..., o1,n, o2,1, o2,2..., o2,n, o3,1..., om,1, om,2..., om,n.
Или, попрегледно,
Дводимензионална низа се означува
 o1,1 o1, 2  o1, j  o1, n  со o[i,j]m,n, што значи дека индексот i има
o  вредности од 1 до m, а индексот ј има вред-
 2,1 o2, 2  o2, j  o2, n  ности од 1 до n. Пократко, низата се означува
      
  со o[]m,n, при што m, n покажува дека низата
o
 i ,1 oi ,1  oi, j  o i ,n  е дводимензионална и се знае дека првиот
        индекс е од 1 до m, а вториот од 1 до n.
  Во литературата се користи и записот
om,1 om, 2  om, j  om ,n  o[1..m][1..n].
Општиот елемент се означува со oi,j.
(Дводимензионалните низи во математиката се нарекуваат матрици).
Ваквите дводимензионални низи во програмските јазици, па и во С++, се
запишуваат со o[m][n], а општиот елемент е со два индекси во средни загради,
о[i][j]. На пример, o[2][7] = 5, o[3][10] = 2 итн. (Погрешно е претставувањето o[2,
7]).

Декларација, иницијализација и доделување вредности на


елементите на дводимензионални низи

Декларацијата на дводимензионална низа е слична со декларацијата на


еднодимензионална низа:
тип име [број1] [број2];

тип ‒ е типот на елементите на низата (short, int, long, float, double,


char, boolean, string итн.).
име ‒ е името на низата.
број1 и број2 ‒ се димензиите на низата и тие мора да бидат литерали
или именувани константи поголеми од 0.
За да биде веднаш појасно, во горната табела со оценки за ученици, број1
ќе биде бројот на ученици во класот (бројот на редици), а број2 ќе биде бројот на
предмети (бројот на колони).
Двата индекси на дводимензионална низа започнуваат од 0.
Првите индекси на дводимензионална низа се: 0, 1, 2..., број1 ‒ 1.
Вторите индекси на дводимензионална низа се: 0, 1, 2... број2 ‒ 1.

189
ПРОГРАМИРАЊЕ

Примери
Пример 5.4.1
Со декларацијата
int a[3][4];
се декларира низата а[]3, 4 од 12 елементи, на кои првиот индекс им е 0, 1 или 2, а
вториот индекс им е 0, 1, 2 или 3. Оваа низа графички може да се прикаже со та-
бела со 3 редици и 4 колони:
колони
(втор индекс)
0 1 2 3
редици

0 а0,0 а0,1 а0,2 а0,3


(прв
1 a1,0 a1,1 a1,2 a1,3
индекс)
2 a2,0 a2,1 a2,2 a2,3
Елементите на низата во С++ се запишуваат со индексите во средни заг-
ради.
0 1 2 3
0 a[0][0] a[0][1] a[0][2] a[0][3]

1 a[1][0] a[1][1] a[1][2] a[1][3]

2 a[2][0] a[2][1] a[2][2] a[2][3]

Вредности на елементите на дводимензионална низа се доделуваат со


наредбата за доделување.
Пример 5.4.2
Со следниве наредби
float c[10][15];
c[0][4] = ‒5.23f; c[9][2] = 7.543f;
се декларира низата с[][] од 10 х 15, т. е. 150 елементи и им се доделуваат вред-
ности на елементите c[0][4] и c[9][2]. (Но не се познати вредностите на другите
елементи).
Дводимензионална низа може да се иницијализира при декларирање и со
иницијализирачка листа.
Пример 5.4.3
Со наредбата
int d[3][2] = {};
се иницијализираат сите елементи на низата d на вредност 0.
Со наредбата
char bukvi[3][2] = {'a', 'b’, 'c'};
190
5. Низи

се декларира и иницијализира дводимензионалната низа bukvi.


0 1
0 a b
1 c
2
Ако нема доволно вредности во иницијализирачката листа за иницијали-
зирање на сите елементи на низата, остатокот се иницијализира со празно место.
Со наредбата
int d[3][2] = {‒3, 5, 4};
се иницијализираат три елементи со зададените вредности, а останатите со 0.

0 1
0 ‒3 5
1 4 0
2 0 0

Пример 5.4.4
Со наредбата
int d[3][2] = {{‒3, 5 },{ 4, 1 },{ 7, ‒2 }};
се декларира и иницијализира низа од 3 редици (секоја редица се става во големи
загради) и 2 колони (секоја редица има по 2 елементи), според податоците од
иницијализирачката листа. Истата декларација може да се запише и попрегледно:
int d[3][2] = {
{‒3, 5},
{4, 1},
{7, ‒2}
};
0 1
0 ‒3 5
1 4 1
2 7 ‒2
Исто така, ако нема доволно елементи за иницијализирање на некоја ре-
дица, останатите елементи во неа се иницијализираат со 0:
int d[3][2] = {{‒3},{4, 1},{7}};
0 1
0 ‒3 0
1 4 1
2 7 0
Истите декларации и иницијализации може да се направат и со следниве
наредби
int d[][2] = {{‒3, 5},{4, 1},{7, ‒2}};
и
int d[][2] = {{‒3},{4, 1},{7}};
191
ПРОГРАМИРАЊЕ

при што големината на првата димензија не мора да се наведе. Преведувачот сам


ја пресметува.
Меѓутоа, не може да се декларира со наредбата
int d[][] = {{‒3, 5},{4, 1},{7, ‒2}};
бидејќи преведувачот не знае по колку елементи да земе од секоја редица (внат-
решната заграда). Може да земе по 1 или по 2. Затоа, може да се изостави само
големината на првата димензија.

Пример 5.4.5
Димензиите на низата може да се зададат и преку константи.
Со наредбите
const int m = 10;
const int n = 5;
float b[m][n];
се декларира дводимензионална низа со 10 редици и 5 колони, т. е. првиот
елемент е b[0][0], а последниот е b[9][4].
Но не мора да се користи целата низа b[m][n] елементи, туку може само
дел од неа. На пример, можеме да зададеме помали димензии на низата:
int redici = 4;
int koloni = 3;
и да се користи само делот b[redici][koloni].

Пресметување димензии на дводимензионална низа


Ако низата a[]m,n e иницијализирана со иницијализирачка листа, тогаш за
одредување на должината (бројот на редици) во C++ се користи функцијата
sizeof().
bajtiElement = sizeof(a[0][0]); ‒ број бајти на еден елемент.
bajtiRedica = sizeof(a[0]); ‒ број бајти на една редица.
bajtiNiza = sizeof(a) ‒ број бајти на цела низа.
Потоа може да се пресмета:
dolzina = bajtiNiza / bajtiElement;
koloni = bajtiRedica / bajtiElement;
redici = dolzina / koloni;

Пример 5.4.6
Програмскиот сегмент за читање елементи на дводимензионалната низа
а[]m,n е:
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
cin >> a[i][j];

Пример 5.4.7
Програмскиот сегмент за печатење на дводимензионалната низа b[]m,n е:

192
5. Низи

for(int i = 0; i < m; i++) {


for(int j = 0; j < n; j++)
cout << "\tb[" << i << "," << j << "] = " << b[i][j];
cout << endl;
}

Пример 5.4.8
Програмскиот сегмент за наоѓање на збирот на елементи на целобројната
дводимензионална низа c[]m,n е:
int zbir = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++)
zbir += c[i][j];
}
Пример 5.4.9
Со програмата од слика 5.4.3 се илустрирани декларација, иницијализа-
ција, читање и печатење на дводимензионална низа.

Слика 5.4.3
193
ПРОГРАМИРАЊЕ

Слика 5.4.3 (продолжение)

Решени задачи

Задача 5.4.1
Да се отпечати таблицата множење до n.

Програмата е дадена на слика 5.4.4.

Слика 5.4.4

194
5. Низи

Слика 5.4.4 (продолжение)


Еден излез од програмата е:

Задача 5.4.2
Да се најдат најмалиот и најголемиот елемент во дводимензионална низа.
За читање, за печатење и за наоѓање на најмалиот и на најголемиот елемент да се
напишат посебни функции.

Објаснување: Во програмата се користат функциите citanje2DNiza(), peca-


tenje2DNIza(), max2DElement() и min2DElement().

195
ПРОГРАМИРАЊЕ

Слика 5.4.5
196
5. Низи

Слика 5.4.5 (продолжение)


Излезот од извршување на програмата е:

197
ПРОГРАМИРАЊЕ

Вежби
Вежба 5.4.1
Да се напишат програми за следниве задачи :
1. Да се најде аритметичката средина на елементите на дводимензио-
налната низа a[]m,n.
2. Да се пресмета збирот на две дводимензионални низи со исти димен-
зии, c[]m,n = a[]m,n + b[]m,n (Збирот на i,j-тиот елемент е ci,j = ai ,j + bi ,j).
3. Да се формира дводимензионалнa низа a[][]n,n што ќе ги содржи бро-
евите од 1 до n2 во облик на змија. На пример, за n = 3, низата го има
следниот изглед:
1 2 3
6 5 4
7 8 9
4. Да се најдат максималните елементи по редици и минималните еле-
менти по колони во дводимензионална низа a[]m,n.
5. Да се најде посебно збирот на елементите на главната дијагонала и
збирот на елементите на споредната дијагонала на дводимензионал-
ната низа q[][]n,n
6. Да се најде збирот на елементите над главната дијагонала на дводи-
мензионалната низа a[]n,n.
7. Да се избришат i-тата редица и j-тата колоната од дводимензионал-
ната низа a[]m,n.
8. Да се пресмета збирот на елементите кои лежат на дијагоналите кои
минуваат низ елементот ai,j на дводимензионалната низа a[]m,n.
9. Да се заротираат колоните на дводимензионалната низа a[]m,n за к
места налево (или надесно).
1 4 9 16 25 …
10. Да се генерира следнава дводимензио- 2 3 8 15 24 …
нална низа a[]m,n. 5 6 7 14 23 ...
10 11 12 13 22 ...
17 18 19 20 21 ...
26 27 ... ... ... ...

198
5. Низи

Вежба 5.4.2
Да се даде одговор на следните прашања:
1. Како се декларира и иницијализира дводимензионална низа?
2. Како можеме да декларираме дводимензионална низа b[][] со 4
редици и 3 колони?
3. Дали во дефинираната низа b[][] во претходната задача постојат
елементите: b[3][4], b[4][3], b[0][4], b[0][3], b[3][0] и b[4][0]?
4. Нека е дадено
int a[5][5] = {1, 2, 3, 4, 5, 6, 7, 8};
Која е вредноста на елементот a[1][3]?
5. Ако е декларирано
double d[10][10];
каде е грешката во наредбава
d[5][10] = 4.55;
6. Што ќе отпечати следниов програмски сегмент:
int i, j, niza[5][5];
for(i = 0, j = 0; i < 5; i++, j++)
niza[i][j] = i + j;
for(i = 0, j = 0; i < 5; i++, j++)
cout << niza[ i ][ j ] << endl;
7. Да се напише програмски сегмент за читање на елементите на дводи-
мензионалната низа a[]m, n.
8. Да се напише програмски сегмент за печатење на дводимензионал-
ната низа a[]m, n.

Резиме

 Низите се посебни структури на податоци кои имаат исто име, но различ-


ни вредности, а се разликуваат според индексите.
 Ако низата има еден индекс, таа е еднодимензионална, со два индекси е
дводимензионална, со три индекси е тридимензионална итн.
 Низата може да се иницијализира со доделување вредности на елементи-
те или со иницијализирачка листа.
 Во наредбата for базирана на опсег не е битен редоследот на елементите.
 Текстуалните низи се низи од знаци. Тие завршуваат со нултиот знак '\0‘.
 Постојат повеќе функции за работа со текстуални низи: strlen(), strcpy(),
strcat(), strcmp() итн. Тие се наоѓаат во шаблонот string, кој е дел од STL.
 Вектор е, всушност, диманичка низа. Класниот шаблон vector содржи
функции за работа со динамички низи.
 Дводимензионалната низа се нарекува и матрица.

199
ПРОГРАМИРАЊЕ

200
6. Датотеки

6. ДАТОТЕКИ
Во оваа глава ќе се запознаете со следното:

 Датотеки, влезни, излезни и влезно-излезни.


 Физички датотеки, логички датотеки.
 Поток од податоци, влезен поток, излезен поток. Поток базиран на бајт.
 Текстуални датотеки, бинарни датотеки.
 Оператор за екстархирање, оператор за инсертирање.
 Организација на датотеки. Записи, полиња, маркер за крај на запис,
маркер за крај на датотека.
 Секвенцијални и случајни датотеки.
 Функции за работа со датотеки.

Клучни зборови

close Излезна датотека


exit Клуч
fstream Логичка датотека
ifstream Маркер за крај на датотека
ios::app Маркер за крај на записот
ios::in Оператор за екстрахирање
ios::out Оператор за инсертирање
open Податочен поток
ostream Поле
record Поток
Бинарна датотека Поток базиран на бајт
Влезен поток Поток базиран на знак
Влезна датотека Секвенцијална датотека
Влезно-излезна датотека Случајна датотека
Датотека Текстуална датотека
Запис Физичка датотека
Излезен поток

201
ПРОГРАМИРАЊЕ

Терминот датотека (англ. file) го означува секое множество пода-


тоци зачувани на надворешни мемории под едно име. Тие може да содр-
жат различни податоци, како: текст, броеви, слики, звук итн.
Датотеките може да се поделат на:
 влезни датотеки – оние од кои може само да се чита.
 излезни датотеки – оние во кои може само да се запишува.
 влезно-излезни датотеки – оние од кои може да се чита и во кои може
да се запишува.
Читање податоци од датотека и запишување податоци во датотека
се врши на ист принцип како што се читаат и запишуваат податоци преку
терминалот (тастатурата и екранот). Оперативниот систем ги третира тас-
татурата и екранот како посебни (стандардни) датотеки за влез и за излез.
При читањето, податоците се читаат од датотеката и се запишуваат во ме-
моријата, а при запишувањето, податоците се читаат од меморијата и се
запишуваат во датотеката. Овој пренос на податоците од датотека во ме-
морија и спротивно можеме да го замислиме како „поток од податоци“.
Затоа, во С++ таквиот пренос на податоци е наречен поток (англ. stream).
И во жаргонот на С++ често се користи терминот податочен поток (англ.
data stream).
Рековме дека датотеките се чуваат на надворешни мемории. Таквите да-
тотеки се нарекуваат физички датотеки. Оперативните системи имаат посебен
модул за работа со датотеки наречен модул за управување со податоците – кој
извршува операции со датотеките, како: креирање нова датотека, бришење пос-
тојна датотека, запишување во датотека, читање од датотека, копирање датотека
итн. Исто така, оперативните системи имаат начин за означување на крајот на
датотеката т.н. маркер за крај (англ. end-of-file marker).
Физичките датотеки
имаат име и тип, па затоа, се
запишуваат во форма
име.тип, слика 6.1. Тие има-
ат и други параметри (атри-
бути), како: големина, датум
на креирање, датум на пос-
ледна измена итн.
За наставка на датоте-
Слика 6.1
ките најчесто ќе ја користиме
.dat за да се препознава дека тоа е датотека со податоци, но некогаш може и
попрактичен да биде пристапот за наставка на датотеката да се користи .txt. Така,
датотеката ќе може едноставно да ја прегледаме или уредиме и со наједноставен
текстуален уредувач како Notepad.

202
6. Датотеки

За обработка на податоците кои се чуваат во физичките датотеки, пот-


ребни се соодветни програми (апликации). Секој програмски јазик во кој е напи-
шана апликацијата содржи наредби, со кои, при нејзино извршување, се внесу-
ваат (читаат) податоците од физичка датотека во меморијата за да се обработат.
Исто така, програмските јазици имаат и наредби со кои обработените податоци
(резултатите) се запишуваат во физички датотеки.
Датотеките може да бидат текстуални датотеки (англ. text files) или
бинарни датотеки (англ. binary files). Во текстуалните датотеки се запишува и
чита знак по знак, а во бинарните датотеки се запишува и чита бајт по бајт. Затоа,
податочните потоци со кои се пристапува до овие датотеки се нарекуваат поток
базиран на знак (англ. character-based stream), односно поток базиран на бајт
(англ. byte-based stream).
Бидејќи во текстуалните датотеки и во бинарните датотеки се запишува
редно, т. е. секвенцијално (знак по знак или бајт по бајт), овие датотеки се наре-
куваат секвенцијални датотеки. На пример, бројот 123 како текст „123“ во тек-
стуална датотека се запишува како низа од три знаци (цифрите: 1, 2 и 3) секој за-
пишан како Unicode, и тоа:
1 = 4910 = 3116 = 001100012
2 = 5010 = 3216 = 001100102
3 = 5110 = 3316 = 001100112
Бројот 123 во бинарната датотека се запишува како бинарен број
12310 = 7B16 = 011110112 .
Операциите (читање, запишување и модификација) со текстуалните да-
тотеки може да се вршат и преку текст-уредувач, а операциите со бинарните да-
тотеки мора да се вршат преку програми.
При обработката на податоци прочитани од датотеки, апликациите кори-
стат посебни типови променливи, со кои се симулираат физичките датотеки.
Овие променливи се наречени променливи за логички датотеки или само ло-
гички датотеки. На пример, ако физичката датотека има име ucenici.dat, прог-
рамата може да ја наречеме со некое логичко име: tekst, vlez, izlez и сл.
Рековме дека читањето и печатењето податоци се врши со потоци. Пода-
тоците се читаат од стандардниот влезен уред (најчесто тастатурата) како влезен
поток (англ. input stream), а се печатат на стандардниот излезен уред (најчесто на
екранот на мониторот) како излезен поток (англ. output stream).
Функциите за управување со влезниот и со излезниот поток се наоѓаат во
библиотеката <iostream> и затоа, таа се вклучува во секоја апликација која об-
работува податоци од датотеки. Во неа се дефинирани и два посебни типа про-
менливи, променливи за влезен поток – istream и променливи за излезен поток –
ostream. Стандардните променливи cin и cout се променливи декларирани од овие
типови:
istream cin;
ostream cout;

203
ПРОГРАМИРАЊЕ

Со cin е поврзан операторот за екстрахирање (>>, англ. extraction opera-


tor), т. е. за читање податоци од влезниот поток, а со cout е поврзан операторот
за вметнување (инсертирање) (<<, англ. insertion operator), т. е. за печатење
(вметнување) податоци во излезниот поток.
Слично како што се читаат податоци од тастатурата и се печатат на ек-
ранот на мониторот така се читаат и печатат податоци во датотеките. Промен-
ливите cin и cout оперативниот систем ги гледа како влезна и излезна логичка
датотека.
Функциите за операции со корисничките датотеки во C++ се наоѓаат во
посебни библиотеки, и тоа: <fstream>, <ifstream> и <ofstream>. Имињата се кра-
тенки од: file stream – fstream, input file stream – ifstream и output file stream – of-
stream. За да може да се користат функциите од овие библиотеки, тие треба да
бидат вклучени во апликациите со директивата #include.
На пример:
#include <fstream>
#include <ifstream>
#include <ofstream>

Влезни датотеки
Типот на променливите за влезна датотека, т. е. за физичка датотека од
која само се читаат податоци е ifstream.
Декларирање на променлива за влезна датотека (име на логичка датотека)
се врши со
ifstream именапроменлива; // ime na logichka datoteka za chitanje
На пример:
ifstream datoteka;
ifstream vlezna, pomdat;
За да може да се читаат податоци од влезната (физичката) датотека, нејзе
мора да ѝ се придружи променлива од типот ifstream со
именапроменлива.open(именадатотека);
 именапроменлива е името на променливата за влезната датотека (логич-
ката датотека),
 именадатотека е името на физичката датотека,
 open() е функцијата за отворање на датотеката, која е дефинирана во биб-
лиотеката <fstream>.
На пример, со
vlezna.open("Podatoci.dat");
се поврзува променливата за влезната датотека vlezna со физичката датотека
Podatoci.dat, односно се отвора физичката датотека Podatoci.dat за читање по-
датоци од неа.
Поврзувањето на променливата за влезната датотека со физичката датоте-
ка може да се направи и при нејзиното декларирање.
204
6. Датотеки

На пример:
ifstream vlezna("Podatoci.dat");
Името на физичката датотека може да зададе и преку терминал.
На пример:
ifstream vlezna;
char imeVlezna[10];
cout << "Vnesete go imeto na datotekata: ";
cin >> imeVlezna;
vlezna.open(imeVlezna);
Пред да се отвори некоја датотека за читање, пожелно е да се провери да-
ли постои таа датотека. На пример:
if (!vlezna) {
cout << "NE mozam da ja otvoram vleznata datoteka. \n";
exit(1); // Kraj na programata so pojava na greska.
}

Излезни датотеки
Типот на променливите за излезна датотека, т. е. за физичка датотека
од која само се читаат податоци е оfstream.
Декларирање на променлива за излезна датотека (логичка датотека) се
врши со
ofstream именапроменлива; // ime na logichka datoteka za zapisuvanje
На пример:
ofstream datIzlez;
ofstream izlezna, pomIzlez;
За да може да се запишат податоци во излезната (физичката) датотека,
нејзе мора да ѝ се придружи променлива од типот оfstream со
именапроменлива.open(именадатотека);
 именапроменлива е името на променливата за излезната датотека,
 именадатотека е името на физичката датотека,
 open() е функција за отворање на датотеката, која е дефинирана во
библиотеката <fstream>.
На пример, со:
datIzlez.open("Rezultati.dat");
izlezna.open("IzleznaDatoteka.dat");
pomIzlez.open("pomosna.dat");
се поврзуваат секоја од променливите за излезната датотека (datIzlez, izlezna и
pomIzlez) со соодветните физички датотеки (Rezultati.dat, IzleznaDatoteka.dat и
pomosna.dat), односно се отвораат физичките датотеки за запишување податоци
во нив.
Поврзувањето на променливата за излезната датотека со физичката дато-
тека може да се направи и при нејзиното декларирање. На пример:
ofstream datIzlez("Rezultati.dat");

205
ПРОГРАМИРАЊЕ

Во следниов пример се отвора датотека за запишување, чие физичко име


се задава преку терминал:
ofstream izlezna;
char imeIzlezna[10];
cout << "Vnesete go imeto na datotekata: ";
cin >> imeIzlezna;
izlezna.open(imeIzlezna);
Притоа, ако не постои датотека со зададеното име, таа се креира, a ако ве-
ќе постои датотека со зададеното име, тогаш старата содржина се заменува со нова.
Затоа, пред да се отвори некоја датотека за запишување, добро е да се ис-
пита дали веќе постои датотека со тоа име за да не ја избришеме нејзината со-
држина1.
На пример:
if(izlezna) {
cout << "Datoteka so toa ime vekje postoi. \n";
exit(1); // Kraj na programata so pojava na greska.
}

Влезно-излезни датотеки

За да може да се чита од некоја датотеката и во неа да се запишува, треба


да се декларира променлива за влезно-излезната датотека од типот fstream
fstream именапроменлива; //ime na logicka datoteka za citanje i
// za zapisuvanje
На пример:
fstream datoteka;
fstream d1, d2;
Поврзување на променливата за влезно-излезната датотека со физичката
датотека се врши на истиот начин како и кај влезните или излезните датотеки.
Меѓутоа, овде мора да се нагласи за што се отвора датотеката: за читање, за запи-
шување или за допишување (додавање) податоци во неа. Начинот (модот) на кој
се отвора датотеката за наведените операции се задава со посебен параметар
именапроменлива.open(именадатотека, параметар);
Во следнава табела 6.1 се прикажани вредностите на параметар со кои
се контролира режимот на работа со дадена датотека.
параметар Начин на отворање на датотеката
ios :: in Влезна датотека.

1
Најчесто се испитува дали сме успеале да отвориме излезна датотека на дискот за да
може да продолжиме со запишување во неа. Некогаш не е можно да се отвори за запишу-
вање од разни причини: немаме привилегија за запишување во папката во која сакаме да
ја запишеме датотеката, надворешниот диск е преполн, веќе постои датотеката и таа е
„read-only“ итн.
206
6. Датотеки

ios :: out Излезна датотека.


ios :: app Излезна датотека за допишување на крајот.
ios :: ate Отвора постојна датотека и се позиционира на крајот на
датотеката. Но може да се запишува каде било во датотеката.
ios :: nocreate Отвора датотека само ако постои таа.
ios :: noreplace Отвора датотека само ако не постои таа.
ios :: trunc Отвора постојна датотека и ја брише старата содржина.
Ios :: binary Отвора датотека во бинарен мод. Ако не е назначено, датотека се
отвара во текстуален мод.
Табела 6.1
Примери
Пример 6.1
Отворање влезна датотека за читање:
dat1.open("Prva.dat", ios :: in);

Пример 6.2
Отворање излезна датотека за запишување:
dat2.open("Vtora.dat", ios :: out);

Пример 6.3
Отворање датотека за допишување податоци во неа:
dat3.open("Treta.dat", ios :: app);

Пример 6.4
Параметрите за начинот на работа со датотеките може да се комбинираат
со операторот Или (|).
На пример, со
dat4.open("Cetvrta.dat", ios :: in | ios :: app);
датотеката се отвора за читање и за допишување податоци во неа.

207
ПРОГРАМИРАЊЕ

Организација, читање од датотека и запишување во датотека

Податоците во датотека се запишуваат во т.н. записи (англ. records).


Записите се состојат од повеќе податоци, а се запишуваат и читаат како посебна
целина, слика 6.2.

Слика 6.2
Сите записи се состојат од ист број и тип податоци, наречени полиња
(англ. fields), одделени со празно место. На пример, реченицата
Jovana Jovanovska zenski 14 134
има пет полиња, од кои полињата за име, за презиме и за пол се текстуални поли-
ња (стрингови), а другите две полиња се од целоброен тип.
Секој запис во датотеката завршува со маркер за крај на записот (англ.
end-of-record marker, EOR marker).
Исто така, секоја датотека завршува со маркер за крај на датотеката
(англ. end-of-file marker, EOF marker).
Најчеста организација на датотеките е секвенцијална и случајна2. Записи-
те во секвенцијалните датотеки (англ. sequential files) се организирани после-
дователно, еден по друг. Секој запис има свој претходник (освен првиот) и свој
следбеник (освен последниот). Затоа, за да се стигне до кој било запис, мора прво
да се пристапи до првиот запис од датотеката и понатаму да се поминат сите за-
писи до бараниот.
Записите во случајните датотеки (англ. random-access files) се органи-
зирани со т.н клуч (англ. key). Едно поле од записот се одредува како клуч и пре-
ку него се пристапува директно до записот со одреден клуч.

2
Случајните датотеки нема да ги обработуваме.
208
6. Датотеки

За запишување во датотека, се користи операторот за инсертирање <<,


слично како кога се запишува на стандардниот излез, т. е. на мониторот.
На пример:
ofstream izlezna;
izlezna.open("test.dat");
int a;
char tekst[20];
izlezna << a << tekst;
Слично, за читање од датотека, се користи операторот за екстрахирање
>>, како што се чита од тастатурата:
ifstream vlezna;
vlezna.open("test.dat");
int a;
char tekst[20];
vlezna >> a >> tekst;

Затворање датотека
Датотека се затвора со функцијата close().
На пример:
vlezna.close();
Со оваа наредба се затвора датотеката по завршување на операциите со
неа.
Еднаш затворена датотека во апликацијата не се користи ниту како влез-
на ниту како излезна сè додека не се отвори повторно.
До затворање на датотека доаѓа и автоматски кога извршувањето на
апликацијата ќе излезе од подрачјето на користење (видливост) на логичката
датотека со која е поврзана физичката датотека.

Некои поважни функции за работа со датотеки

seekg()  е функција за движење низ влезна датотека.


seekp()  е функција за движење низ излезна датотека.
eof()  логичка функција за испитување дали е крај на датотеката.
clear()  ресетирање на датотеката за читање од почеток.
getline()  функција за читање цела линија (запис) од датотека.

Решени задачи

Задача 6.1
Следнава апликација креира излезна датотека, запишува податоци во неа,
ја затвора, потоа ја отвора како влезна датотека и од неа ги чита податоците и ги
печати на екранот во следната форма:
209
ПРОГРАМИРАЊЕ

Слика 6.3

210
6. Датотеки

Задача 6.2
Во задачава се покажува како може да се
ископира една датотека во друга знак по знак. Да-
тотеката од која се копира се чита знак по знак со
функцијата get(), слика 6.5. Потоа, датотеката во
која е ископирана првата, се копира на екранот од
мониторот, при што екранот се гледа како датоте-
ка со име cout. Бидејќи функцијата kopiranjeDa-
toteka() се користи и за копирање (печатење) на
стандардниот излез cout (која е променлива од ти-
пот ostream), првиот параметар на функцијата е од
типот ostream.
Влезната датотека може да се креира со кој
било уредувач на текст, најчесто Notepad или
WordPad, слика 6.4.
За копирање една датотека во друга е напи-
шана функцијата
kopiranjeDatoteka(ostream & izlezna, ifstream Слика 6.4
& vlezna)
чии аргументи се променливата за излез од типот ostream и променливата за влез
од типот ifstream. Бидејќи променливата за излез cout е од типот ostream, функ-
цијата може да се повикува и со
kopiranjeDatoteka (cout, vlezna);

Слика 6.5
211
ПРОГРАМИРАЊЕ

Слика 6.5 (продолжение)


Излезот е во следната форма:

Задача 6.3
Да се формираат и спојат две текстуални датотеки.
Во програмата од слика 6.6 се спојуваат двете датотеки Tekst1.dat и
Tekst2.dat. За креирање на датотеките, се повикува функцијата kreiranjeDatoteka()
од типот void, во која се внесуваат записите како цели линии додека не се внесе
запис со една точка. Потоа, се отвора првата датотека Tekst1.dat за додавање (со
пaраметарот ios :: app) и на нејзиниот крај се додава втората датотека Tekst2.dat.
Ако се внесат двете датотеки Tekst1.dat и Tekst2.dat,

212
6. Датотеки

тогаш по додавање на Tekst2.dat на крајот одTekst1.dat, излезот ќе биде:

Слика 6.6
213
ПРОГРАМИРАЊЕ

Слика 6.6 (продолжение)


Задача 6.4
Да се формира текстуална датотека со податоци за ученици.
Датотеката се формира со внесување на цели записи и на крајот се става
знакот ^Z со Ctrl + Z, кој го означува крајот на датотеката (англ. End-Of-File,
EOF).

Слика 6.7
214
6. Датотеки

Слика 6.7 (продолжение)


Пример од извршување на програмата:

215
ПРОГРАМИРАЊЕ

Задача 6.5
Да се напише програма за пресметување на
просечниот успех на ученик.

Датотеките често се користат при тестирање на


апликациите за да не се губи време во внесување пода-
тоци. На пример, во неколку решени задачи од книга-
та, се внесуваат предметите кои се изучуваат во некое
училиште. Наместо внесување на предметите при се-
кое извршување на програмата, тие може да се стават
во датотека и оттаму да се читаат.
Секвенцијалните датотеки може да се уредат
со кој било уредувач (најчесто со Notepad или Word-
Pad). На пример, следнава датотека со предмети (сли-
ка 6.8) е уредена со Notepad.
При решавање на задачата, ќе ја користиме да- Слика 6.8
тотеката со предмети од слика 6.8, од која се читаат
предметите. Програмата е дадена на слика 6.9. Во неа предметите се читаат од
датотеката како стрингови.
Да напоменеме дека името на физичката датотека се внесува како стринг
и се поврзува со логичката датотека.

Слика 6.9
216
6. Датотеки

Слика 6.9 (продолжение)


Еден пример од извршување на програмата е:

217
ПРОГРАМИРАЊЕ

Вежби

Вежба 6.1.1
Да се даде одговор на следните прашања:
1. Која библиотека од C++ треба да се вклучи за да се работи со дато-
теки?
2. Од кој тип се влезните, а од кој тип се излезните датотеки во С++?
3. Што е влезен поток, а што е излезен поток?
4. За што служи логичката датотека?
5. Кој е операторот за екстрахирање од влезен поток, а кој е за инсер-
тирање во излезен поток?
6. Што е потребно да се дефинира за да се отвори влезна датотека за
читање?
7. Што е потребно да се дефинира за да се отвори излезна датотека за
запишување?
8. Кои се карактеристиките на променливите за влезно-излезните дато-
теки? Од кој тип се тие променливи?
9. Како се отвора датотека за допишување во неа?
10. Како се врши контрола на начинот на отворање на влезно-излезна да-
тотека?
11. Кои модови за пристап до секвенцијалните датотеки постојат?
12. Како се задава името на физичката датотека преку тастатурата?
13. Кои се двете основни организации на датотеките?
14. Од што се состои записот во една датотека?
15. Со што завршува секоја датотека?
16. Која е разликата помеѓу секвенцијалните и случајните датотеки?
17. Со која функција се проверува крајот на датотеката?
18. Со која функција се чита цел запис?
19. Со која комбинација на копчиња се означува крајот на датотеката
при уредување со некој уредувач?

Вежба 6.1.2
Да се дополни Задача 6.5 така што датотеката да ги содржи и
предметите и оценките за еден ученик.

Вежба 6.1.3
Да се решат следните задачи:
1. Да се креираат датотека со предмети како во Задача 6.5 и датотека
со оценки за сите ученици од еден клас. Записите во датотеката со
оценки да содржат број во дневникот на ученикот и оценки по 12
предмети. Да се напише програма со која ќе се пресметаат средната
оценка на секој ученик и средната оценка на целиот клас.
218
6. Датотеки

2. Да се најдат најмалиот и најголемиот елемент во дводимензионална


низа, така што таа да се чита од датотека. Датотеката да се креира со
некој уредувач на текст.
3. Да се провери дали во некој текст се јавува одреден поттекст и ако се
јавува, на кои позиции почнува, така што текстуалната низа (текстот)
да се чита од датотека. Датотеката да се креира со некој уредувач на
текст.
4. Да се најде колку пати се јавува секој знак (што го има) во некој
текст, така што текстуалната низа (текст) да се чита од датотека.
Датотеката да се креира со некој уредувач на текст.
5. Во датотека „vlezna.txt“ се запишани два природни броја m, n > 1. Да
се прочитаат броевите и во излезна датотека izlez.txt да се исцрта
правоаголник од ѕвездички со должина n и висина m.
Пример:
45
*****
* *
* *
*****
6. Во секој од редовите на датотека spisok.txt се запишани резултати за
по еден ученик, и тоа по редослед: име, презиме, поени на тест 1,
поени на тест 2, поени на тест 3. Поените се ненегативни цели броеви
помали од 100.
Во друга датотека spisok_ocenki.txt да се запишат имињата на
учениците и нивната оценка (име, презиме, оценка). Оценката се
пресметува така што се наоѓа аритметичката средина од поените на
тестовите и според следната табела:
[0, 30] – 1,
(30, 54] – 2,
(54, 72] – 3,
(72, 90] – 4,
(90, 100] – 5.
7. Во датотека vlez.txt е запишан текст кој се состои од букви, цифри и
интерпункциски знаци, кои формираат валидни реченици. Да се
изброи колку реченици има во текстот. (За валидна реченица се
смета дел од текстот кој започнува со голема буква и завршува со
интерпункциски знак: точка, прашалник или извичник).

219
ПРОГРАМИРАЊЕ

Резиме

 Датотеките се податоци зачувани под едно име на некоја надворешна мемо-


рија.
 Датотеките може да бидат влезни, излезни и влезно-излезни.
 Физичките датотеки имаат име и тип.
 Операции со датотеки се: креирање нова датотека, бришење постојна дато-
тека, запишување во датотека, читање од датотека, копирање датотека и
други.
 Променливите cin и cout оперативниот систем ги гледа како влезна и излезна
датотека.
 Типот на влезна логичка датотека е ifstream, на излезна логичка датотека е
ofstream, а на влезно-излезна логичка датотека е fstream.
 Пред да се отвори некоја датотека за читање или за запишување, пожелно е
да се провери дали постои таа датотека.
 Податоците во датотека се запишуваат во записи.
 Организацијата на датотеките е секвенцијална и случајна.

220
7. Претставување на податоците во компјутерот

7. ПРЕТСТАВУВАЊЕ НА ПОДАТОЦИТЕ ВО
КОМПЈУТЕРОТ
Во оваа глава ќе се запознаете со следното:

 Бројни системи (декаден, бинарен, октален и хексадецимален).


 Претворање на броевите од еден во друг броен систем.
 Претставување на податоците во компјутерот: претставување на знаците,
на сликите и на звукот.
 Претставување на броевите во компјутерот: претставување на целите
броеви, претставување на децималните броеви.
 Операции со бинарни броеви: собирање, одземање, множење и делење.

Клучни зборови

ASCII (American Standard Code


for Information Interchange) ИНИЛИ
Бинарен броен систем Логички функции
Бит за знак Логичко коло
Бројач Мантиса
Бројни системи НЕ
Булови функции НИ
Втор комплемент НИЛИ
Графичка резолуција Обична точност
Двојна точност Октален броен систем
Декаден броен систем Подвижна точка
Експонент Позициски броен систем
И Пиксел
ИИЛИ Прв комплемент
ИЛИ Преполнување
Инвертор Хексадецимален броен систем

221
ПРОГРАМИРАЊЕ

7.1 Бројни системи

На сите ни е познат декадниот броен систем, во кој секојдневно пресме-


туваме. Знаеме дека во него се користат цифрите 0, 1, 2, 3, 4, 5, 6, 7, 8 и 9. Исто
така, знаеме дека броевите во овој броен систем може да бидат цели и децимал-
ни.
Секоја цифра во бројот има своја важност. На пример, цифрите во деци-
малниот број 9275.34 ја имаат следнава важност: 5 ‒ единици, 7 ‒ десетки, 2 ‒
стотки, 9 ‒ илјади, 3 ‒ десетинки и 4 ‒ стотинки, односно бројот може да се запи-
ше како
1 1
9 ∙ 1000 + 2 ∙ 100 + 7 ∙ 10 + 5 ∙ 1 + 3 ∙ 10 + 4 ∙ 100
или како
9 ∙ 103 + 2 ∙ 102 + 7 ∙ 101 + 5 ∙ 100 + 3 ∙ 10−1 + 4 ∙ 10−2 (1)
Ако ги погледнеме степените на основата 10, ќе забележиме дека тие се
цели броеви: 3, 2, 1, 0, ‒1, ‒2. Овие степени ја одредуваат важноста на соод-
ветната цифра во бројот, во зависност од тоа на кое место (позиција) таа се наоѓа.
Ваквите бројни системи се нарекуваат позициски бројни системи.
Општиот облик на бројот N во позицискиот броен систем е:
N = 𝑎𝑛−1 𝑎𝑛−2 … 𝑎2 𝑎1 𝑎0 𝑎−1 𝑎−2 … 𝑎−𝑚 (2)
во кој ai, n − 1 ≤ i ≤ −m се цифри на бројот. Така, за n = 4, m = 2, a3 = 9, a2 = 2, a1
= 7, a0 = 5, a‒1 = 3 и a‒2 = 4, во декадниот броен систем се добива бројот во (1).
Освен декадните, постојат и други бројни системи, во зависност од осно-
вата (базата) на бројниот систем. Најчесто, основата се означува со b. Ако погле-
даме како го добивме бројот 9275.34 во (1) и наместо 10 ставиме b, тогаш тој мо-
же да се запише како
9b3 + 2b2 + 7b1 + 5b0 + 3b‒1 + 4b‒2.
Така, бројот запишан во (2), во броен систем со основа b се добива како
N = an ‒ 1bn ‒ 1 + an ‒ 2bn ‒ 2 +… + a3b3 + a2b2 + a1b1 + a0b0 + a‒1b‒1 + a‒2b‒2 + ... + a‒mb‒m
или запишано пократко
N = ∑i= −m
i = n−1 a i b
i
(3)
Може да се забележи дека степенот на основата со која се множи некоја
цифра е, всушност, индексот на цифрата. Индексите на цифрите за целиот дел
се: 0, 1, 2..., а за децималниот дел се: ‒1, ‒2, ‒3..., како во (2).
Најчесто употребувани бројни системи се:
Декаден  со основа 10 и цифри: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
Бинарен  со основа 2 и цифри: 0, 1.
Октален  со основа 8 и цифри: 0, 1, 2, 3, 4, 5, 6, 7.
Хексадецимален  со основа 16 и цифри: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F.
Компјутерите работат со бинарниот броен систем, а окталниот и хексаде-
цималниот се користат за поефикасно запишување на бинарните броеви на хар-
тија, заради подобра прегледност. На пример, бинарниот број 10111110100110102

222
7. Претставување на податоците во компјутерот

во окталниот систем се претставува со 137 2328, а во хексадецималниот со


BD9A16. Гледаме дека истиот број претставен во бинарниот броен систем има 16
цифри, во окталниот 6, а во хексадецималниот само 4. Ова јасно ни покажува де-
ка е полесно овој број да го меморираме во хексадецималниот броен систем от-
колку во бинарниот.
Во табелата на слика 7.1.1 е дадено претставувањето на броевите од 0 до
15 во четирите наведени бројни системи.
Декаден Бинарен Октален Хексадецимален

0 0000 0 0
1 0001 1 1
2 0010 2 2
3 0011 3 3
4 0100 4 4
5 0101 5 5
6 0110 6 6
7 0111 7 7
8 1000 10 8
9 1001 11 9
10 1010 12 A
11 1011 13 B
12 1100 14 C
13 1101 15 D
14 1110 16 E
15 1111 17 F
Слика 7.1.1
Претворање на броевите од еден во друг броен систем

Кога се внесуваат броеви (податоци) во компјутерот, тие се внесуваат


како декадни броеви. Бидејќи компјутерот работи со бинарни броеви, внесените
декадни броеви треба да се претворат во бинарни. Исто така, кога треба да се от-
печатат бројните резултати од пресметувањата во компјутерот, тие треба од би-
нарен броен систем да се претворат во декадни (или октални или хексадеци-
мални) и дури потоа да се отпечатат. Затоа, во компјутерот се врши претворање
(често велиме и конверзија) на броевите од еден во друг броен систем. Во оваа
точка ќе се запознаеме со начините на кои се врши претворањето на броевите од
еден во друг броен систем.

223
ПРОГРАМИРАЊЕ

Претворање на декадните цели броеви во бинарни,


октални и хексадецимални броеви и спротивно

Претворањето на декадните цели броеви во бинарни се врши со делење


на бројот со 2 и со паметење на остатокот од делењето. Постапката завршува ко-
га количникот ќе добие вредност 0.
Во примерот прикажан на слика 7.1.2 е
дадено претворањето на декадниот број 315 во би-
нарен. Притоа, 315 се дели со 2, остатокот (1) се за-
пишува на десната страна и добиениот количник
(157) пак се дели со 2. Остатокот од делењето (1) се
запишува десно, а добиениот количник (78) пак се
дели со 2 итн. Постапката продолжува додека не се
добие количник 0. Во конкретниов пример, се доби-
ва дека бинарниот еквивалент на декадниот број
31510 е 1001110112. Забележуваме дека бинарниот Слика 7.1.2
еквивалент се претставува оддолу нагоре, односно
од последниот остаток.
Најзначајниот бит или битот со најголема важност во бинарниот број е
најлевиот, а, пак, битот со најмала важност е најдесниот бит.

За претворање на декадните броеви во окталниот или во хексадецимал-


ниот броен систем, се користи истата постапка, само што се дели со 8, односно
со 16. На пример, истиот број 31510 во окталниот и хексадецималниот броен
систем се претвора како што е претставено на слика 7.1.3 а и б.
Окталниот и хексадецималниот еквивалент на декадниот број 31510 се
4738 и 13B16.

Слика 7.1.3
За претворање на бинарните, окталните и хексадецималните броеви во
декадни, може да се искористи формулата (3). Според неа, на слика 7.1.4 е пока-
жано претворањето на бинарниот, окталниот и хексадецималниот број во дека-
ден.

224
7. Претставување на податоците во компјутерот

Слика 7.1.4
Претворање на декадните децимални броеви во бинарни,
октални и хексадецимални броеви и обратно*

Декадните децимални броеви се претвораат во бинарни така што се прет-


вора посебно целиот, а посебно децималниот дел. Целиот дел се претвора како
цел број, на начинот што го покажавме во претходните потточки. Децималниот
дел се претвора со следната постапка: се множи децималниот дел со 2 и се памти
целиот дел од производот. Потоа, пак се множи со 2 само децималниот дел од
претходно добиениот производ и се памти целиот дел од новодобиениот произ-
вод итн. Постапката продолжува додека децималниот дел од производот не биде
0 или до бројот на битови со кои сакаме да го претставиме децималниот број во
бинарен систем.
На пример, на слика 7.1.5 е покажано претворањето на децималниот број
0.962510 во бинарен. Според опишаната постапка, од секој производ се памти са-
мо целиот дел, кој може да биде 0 или 1. Вака добиените битови се запишуваат
одгоре надолу и го претставуваат бинарниот
еквивалент на децималниот број. Значи,
0.9062510 = 0.111012.
Да напоменеме дека оваа постапка
не е секогаш конечна и затоа, се прекинува
Слика 7.1.5 по добивање на одреден број битови.
За претворање на декадните деци-
мални броеви во октални или хексадецимални, се користи истата постапка, само
што се множи со основата на овие системи 8, односно 16. Тоа е покажано на сли-
ка 7.1.6 а и б. Окталниот еквивалент на декадниот децимален број 0.914062510 е
0.7248, а хексадецималниот еквивалент на декадниот децимален број:
0.909179687510 е 0.E8C16.

225
ПРОГРАМИРАЊЕ

Слика 7.1.6
Претворањето на децималните бинарни броеви во декадни се врши по
формулата (3). На пример, претворањето на бројот 0.111012 е прикажано на
слика 7.1.7.
0.111012 = 1 · 2‒1 + 1 · 2‒2 + 1 · 2‒3 + 0 · 2‒4 + 1 · 2‒5 =
1 1 1 1 29 = 0.90625
  0  10
2 4 8 32 32

Слика 7.1.7
По истата формула, може да се претвораат и броевите од другите бројни
системи. На слика 7.1.8 е покажано претворањето на окталниот децимален број и
на хексадецималниот децимален број во декаден децимален број.
0.7248 = 7 · 8‒1 + 2 · 8‒2 + 4 · 8‒3 = 0.875 + 0.03125 + 0.0078125 = 0.914062510
0.E8C16 = E · 16‒1 + 8 · 16‒2 + C · 16‒3 = 0.875 + 0.03125 + 0.0029296875 =
= 0.909179687510
Слика 7.1.8
Претворање на броевите меѓу бинарен, октален и
хексадецимален броен систем

Постои полесен начин за претворање на бинарните броеви во октални и


хексадецимални. Тоа се прави со групирање на битовите во групи по 3 за ок-
талниот, односно по 4 за хексадецималниот броен систем, почнувајќи од деци-
малната точка лево и десно. За секоја група битови се запишува цифрата во ок-
талниот, односно во хексадецималниот броен систем. И спротивното претвора-
ње, од окталниот или хексадецималниот во бинарниот броен систем, се врши
така што за секоја цифра се пишува бинарниот еквивалент. На пример, бројот
315.914062510 во бинарниот броен систем е 100111011,1110101002. Неговото
претворање од бинарен во октален и спротивно е дадено на слика 7.1.9, а од би-
нарен во хексадецимален и спротивно е дадено на слика 7.1.10.
1 0 0 1 1 1 0 1 1 . 1 1 1 0 1 0 1 0 0 0 0 01 0 0 11 1 0 11 . 1 1 10 1 0 1 0 0 0 0 0
           
4 7 3 . 7 2 4 1 3 B . E A 0

Слика 7.1.9 Слика 7.1.10

226
7. Претставување на податоците во компјутерот

Вежби

Вежба 7.1.1

Одговорете на следните прашања:


1. Кои се особините на декадниот броен систем?
2. Што се позициски бројни системи?
3. Што е важност на цифрата во бројот во позицискиот броен систем?
4. Кој е општиот облик на бројот во позицискиот броен систем со основа b?
5. Што е база на позицискиот броен систем?
6. Како може да се запише скратено општиот облик на број во позицискиот
броен систем со основа b?
7. Кои се најчесто употребувани бројни системи?
8. Зошто се врши претворање на броевите од еден во друг броен систем?
9. Како се претвораат декадните броеви во броеви со друга основа?
10. Како се претвораат меѓу себе броевите во бинарниот, окталниот и хексаде-
цималниот броен систем?

Вежба 7.1.2

1. Да се најде декадниот еквивалент на бинарниот број 110010101012.


2. Да се најде декадниот еквивалент на окталниот број 27048.
3. Да се најде декадниот еквивалент на хексадецималниот број ACE2816.
4. Да се претвори бинарниот број 110010101012 во број од окталниот броен
систем и во број од хексадецималниот броен систем.

7.2 Претставување на податоците во компјутерот

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


броеви, текст, слика и звук. За добивање информации од податоците, потребно е
тие да се обработат. Пред да може да се обработи со компјутер кој било податок,
тој треба да се претстави во форма погодна за обработка со компјутер.
Рековме дека податоците во компјутерите се претставуваат со цифрите на
бинарниот броен систем 0 и 1.
Бинарниот броен систем има основа 2, бидејќи има 2 цифри 0 и 1. Како
што веќе рековме, во информатиката се користат уште два бројни системи, ок-
талниот и хексадецималниот.
Постојат повеќе причини зошто во компјутерите се користи бинарниот
броен систем. Ќе наведеме неколку:
 Со цифрите 0 и 1 може да се претстави секоја информација.

227
ПРОГРАМИРАЊЕ

 Аритметичките операции со овие две цифри се многу едноставни. Тие се


извршуваат на ист начин како и аритметичките операции во декадниот
броен систем.
На пример:

Кај декадното собирање велиме дека 9 плус 7 е еднакво на 16,


пишуваме 6 (= 16  10, т. е. = 16  основата), а пренесуваме 1. Потоа, 2
плус 7 е 9 и еден што пренесовме е 10. Пишуваме 0 (10  основата), а пре-
несуваме 1. Истото е и кај бинарното собирање. 1 плус 1 е 2, пишуваме 0
(2  2, т. е. = 2  основата), а пренесуваме 1. 1 плус 1 плус 1 е еднакво на
3, пишуваме 1 (= 3  2, т. е. = 3  основата), а пренесуваме 1.
 Цифрите 0 и 1 во електрониката се претставуваат со две вредности на на-
пон. На пример, 1 се претставува со напон поголем од U волти1, а 0 со на-
пон помал од U волти. Затоа, претставувањето на податоците се врши со
низи од електрични импулси, а извршувањето на аритметичките и други
операции со електрични импулси се врши со голема брзина.
 Постојат физички медиуми со особина да паметат само две состојби што
се претставуваат со 0 и 1. Најмногу се користат магнетните и оптичките
материјали.
Магнетните материјали имаат особина да го чуваат магнетизмот на неко-
ја точка. Ако магнетизираната точка претставува бинарна единица (1), а немаг-
нетизираната бинарна нула (0), тогаш низа од магнетизирани и немагнетизирани
точки претставува запис на низа од битови.
Кај оптичките материјали се детектира рефлектираната ласерска светли-
на. Ако од една точка се рефлектира појака светлина, значи дека таа е бинарна
единица (1), а ако се рефлектира послаба светлина, значи дека таа е бинарна нула
(0).

7.2.1 Претставување на знаците

Рековме дека податоците кои се обработуваат со компјутер се: броеви,


знаци, слика (видео) и звук.
Во компјутерите се користи англиската абецеда (A до Z, a до z), арап-
ските цифри 0, 1... 9 и специјални знаци како : , ; + = # & @ ! ʼ‘ ( ) [ ] { ] < > / итн.
Претставувањето на сите знаци во компјутерот е стандардизирано со т.н.
стандард ASCII (American Standard Code for Information Interchange), слика
7.2.1.1. Тоа дава можност за претставување на 27 = 128 различни знаци, од кои 32

1
Вредноста на U зависи од технологијата на изработка на електронските кола.
228
7. Претставување на податоците во компјутерот

се т.н. контролни знаци (кои не може да се печатат), а 96 се знаци кои може да се


печатат.
Кодот ASCII на некој знак се добива со запишување на горните три бита
од колоната на слика 7.2.1.1, а потоа на левите четири бита од редицата. На
пример, кодот на буквата М е 1001101, кодот на знакот & е 0100110, кодот на
буквата А е составен од колоната 101 и редицата 0001 и изнесува 1010001 итн.
На овој начин, со 7 бита може да се кодираат најмногу 128 различни знаци со ко-
дови од 0000000 до 1111111 (декадно од 0 до 127). Кога се користи и осмиот бит,
тогаш со кодовите од 1000000 до 11111111 (декадно од 128 до 255), се кодираат
графичките знаци.
Првите 32 кодови ASCII од 0000000 до 0011111 (колоните 000 и 001) се
контролни знаци кои не може да се печатат.
Втората група од 32 знаци (колоните 010 и 011) се интерпункциски и спе-
цијални знаци, како и цифрите од 0 до 9.
Третата група од 32 знаци (колоните 100 и 101) се кодови на 26 големи
букви од англиската абецеда и 6 специјални знаци.
Последните 32 знаци (колоните 110 и 111) се кодови на малите букви од
англиската абецеда и неколку специјални и контролни знаци.
000 001 010 011 100 101 110 111
0000 NUL DLC SP 0 @ P ` p
0001 SOH DC1 ! 1 A Q a q
0010 STX DC2 " 2 B R b r
0011 ETX DC3 # 3 C S c s
0100 EOT DC4 $ 4 D T d t
0101 ENQ NAK % 5 E U e u
0110 ACK SYN & 6 F V u v
0111 BEL ETB ' 7 G W u v
1000 BS CAN ( 8 H X h x
1001 HT EM ) 9 I Y i y
1010 LT SUB * : J Z j z
1011 VT ESC + ; K [ k {
1100 FF FS , < L / l /
1101 CR GS - = M ] m }
1110 SO RS . > N ^ n |
1111 SI VS / ? O _ o DEL
Слика 7.2.1.1
Според 5-от и 6-от бит, може да се одреди групата на која припаѓа знакот,
и тоа:
бит 5 бит 6 група
0 0 Контролни знаци
0 1 Интерпункциски знаци и цифри
229
ПРОГРАМИРАЊЕ

1 0 Големи букви и специјални знаци


1 1 Мали букви и специјални знаци
Покрај кодот ASCII, постојат и кодот BCD (Binary Coded Decimal) и про-
ширениот код BCD наречен EBCDIC (Extended BCD Interchange Code).
Во поново време, сѐ пораширена е употребата на 16-битни шеми за коди-
рање на знаци. Тие овозможуваат претставување на множество на кодови со
големина од 65 536 знаци. Со тоа се надминува ограничувањето на еднобајтните
шеми на 256 знаци. Еден од најприфатените 16-битни стандарди е Уникод (ан-
гл. Unicode), кој овозможува кодирање на симболите и знаците на сите пишувани
јазици кои се користат во светот. Уникод денес е стандард. Во него се дефинира-
ни повеќе формати за трансформација (англ. Unicode Transformation Formats –
UTF), и тоа: UTF-8, UTF-16 и UTF-32. Најчесто користени формати се UTF-8 и
UTF-16. UTF-8 е доминантен формат. Над 95 % од веб-страниците на интернет
користат UTF-8. Тој се користи во програмските јазици и во повеќето оперативни
системи. Во UTF-8 се користи еден бајт (8 бита) за првите 128 знаци и до 4 бајти
за другите знаци. Првите 128 кодови на Уникод ги претставуваат знаците ASCII,
што значи дека секој текст на ASCII е исто така текст UTF-8.

7.2.2 Претставување на сликите

Начинот на претставување на бројните и текстуалните податоци со бито-


ви се користи и за претставување на слики.
На пример, на слика 7.2.2.1 е претставен дел од слика, како мрежа од цр-
ни и бели квадратчиња. Ако белите квадратчиња ги означиме со 0, а црните со 1,
тогаш сликата можеме да ја претставиме со табела од нули и единици, како на
слика 7.2.2.2.. Тоа, пак, може да се запише во бинарна форма, како низа од нули
и единици.
Ако сликата ја претставиме со
000000000000000000
000001111111111000 погуста мрежа од квадратчиња (по-
000001111111111000 мали квадратчиња), тогаш ќе доби-
000111100000011110
000111100000011110 еме пофина слика. Едно квадратче се
011110000000000110 нарекува пиксел (англ. pixel). Голе-
011110000000000110
011110000000000000 мината на овие квадратчиња кај де-
011110000000000000 нешните компјутери е многу мала.
011110000000000000

Слика 7.2.2.1 Слика 7.2.2.2

Бројот на пиксели со кои се прикажува сликата се нарекува


графичка резолуција.
Прикажувањето претставено на слика 7.2.2.1 е наједноставно. Но за при-
кажување на сите параметри на еден пиксел, како: осветленост, контраст, боја
итн., се користат повеќе битови: 8, 16, 32, 64, 128 итн.
230
7. Претставување на податоците во компјутерот

7.2.3 Претставување на звукот

Слично како сликите и звукот се претставува


во бинарна форма. Звукот може да се прикаже графич-
ки како непрекинат (аналоген) сигнал, кој го репрезен-
тира движењето на звучниот бран, слика 7.2.3.1. Ос-
новни карактеристики на звучниот бран се амплиту-
дата (висината) и фреквенцијата.
Фреквенција е број на промени на некоја
величина во една секунда.
Претставувањето на звукот се врши така што на
точно одредени временски интервали се земаат делови
(примероци, семплови) од звучниот бран со одредена Слика 7.2.3.1
должина, слика 7.2.3.1. Тие содржат податоци за неговата амплитуда и за фрек-
венцијата во тој момент, што може да се изразат со броеви. На пример, еден дел
може да има амплитуда 17 и фреквенција 100, друг дел амплитуда 10 и фреквен-
ција 120 итн. Податоците за секој дел се кодираат со одреден број битови, на
пример 8, 16 или повеќе. Бројот на земените примероци во една секунда може да
биде неколку десетици илјади и се нарекува фреквенција на земање примероци.
Поголемиот број на примероци во секунда дава поквалитетен дигитализиран
звук.

7.2.4 Претставување на броевите во компјутерот

Броевите во компјутерот се претставуваат, во зависност од должината на


зборовите (16, 32, 64, 128 бита) и од тоа дали се цели или децимални броеви.
Посебно ќе го објасниме претставувањето на целите броеви и на
децималните броеви.

Претставување на целите броеви

Целите броеви може да бидат:


 Означени.
 Неозначени.
Во означените броеви битот со најголема важност е:
0 за позитивен број
1 за негативен број.
Во неозначените броеви, битот со најголема важност е битот на бројот.
Бројот на нумеричките вредности кои може да се претстават со неозначе-
ни броеви долги n бита е 2n, и тоа од 0 до 2n ‒ 1.

231
ПРОГРАМИРАЊЕ

n ‒ 1 n ‒ 2 n ‒3 5 4 3 2 1 0
0 0 0 0 0 0 0 0 … 0 0 0 0 0 0 0 0
n ‒ 1 n ‒ 2n ‒ 3 5 4 3 2 1 0
n
2 –1 1 1 1 1 1 1 1 … 1 1 1 1 1 1 1 1

Означените броеви се претставуваат на следниов начин:


n‒1 n‒2 n‒3 5 4 3 2 1 0
S 1 0 0 1 1 1 … 1 0 0 1 1 1 0 0

0 − позитивен
S е битот за знакот на бројот. 𝑆={
1 − негативен

Опсегот на означените броеви претставени со n-битен збор x е:


‒2n ‒ 1  x  2n ‒ 1 ‒ 1
и има вкупно 2n ‒ 1 (негативни) + 1 (нулата) + (2n ‒ 1 ‒ 1) (позитивни) = 2n броеви.
На пример, за n = 16 најголемиот цел број е 2n ‒ 1 ‒ 1 = 215 ‒ 1 = 32 767, т. е.
кога сите битови се 1 и битот за знак е 0, а најмалиот цел број е ‒2n ‒ 1 = ‒215 = ‒32
768, т. е. кога сите битови се 0 и битот за знак е 1. Нулата се претставува со сите
битови 0 и битот за знак 0, слика 7.2.4.1.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Најголемиот 16-битен цел број
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Најмалиот 16-битен цел број
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Нула
Слика 7.2.4.1
Во случај на 32-битни зборови, опсегот е:
31 31
‒2  x  2 ‒ 1
т. е. ‒2147483648  x  2147483647
За 8-битни зборови, овој опсег е од ‒128 до 127, додека за 5-битни зборо-
ви, опсегот на целите броеви е ‒16  x  15.
Во табела 7.2.4.1 се дадени целите декадни броеви од ‒16 до +15 и нив-
ните бинарни еквиваленти.

232
7. Претставување на податоците во компјутерот

декаден бинарен декаден бинарен


број број број број

 
16 bita
  
16 bita

0 00...00000 ‒16 11...10000
1 00…00001 ‒15 11…10001
2 00…00010 ‒14 11…10010
3 00…00011 ‒13 11…10011
4 00…00100 ‒12 11…10100
5 00…00101 ‒11 11…10101
6 00…00110 ‒10 11…10110
7 00…00111 ‒9 11…10111
8 00…01000 ‒8 11…11000
9 00…01001 ‒7 11…11001
10 00…01010 ‒6 11…11010
11 00…01011 ‒5 11…11011
12 00…01100 ‒4 11…11100
13 00…01101 ‒3 11…11101
14 00…01110 ‒2 11…11110
15 00…01111 ‒1 11…11111
Табела 7.2.4.1
Негативните броеви не се добиваат со едноставно ставање вредност 1 на
најзначајниот бит, туку како втор комплемент на позитивните броеви.
‒5 = 11011 од (+5 = 00101  (прв комплемент) 11010 + 1  11011)
При аритметичките операции со броевите ограничени во некој опсег од
n‒1
‒2 до 2n ‒ 1 ‒ 1, може да дојде до грешка, односно до т.н. преполнување (англ.
overflow) кога резултатот е надвор од опсегот. Тоа се случува кога резултатот е
помал од ‒2n ‒ 1 или поголем од 2n ‒ 1 ‒ 1.
На пример, за n = 8, опсегот на броевите е од ‒128 до 127. Во тој случај,
збирот на броевите 100 + 30 ќе се запише како негативен број, што се гледа од
собирањето на нивните бинарни записи. Нивниот збир е бројот 01100100
‒126 бидејќи збирот 10000010 е втор комплемент на бројот 126. + 00011110
10000010
Претставување на децималните броеви*

Честопати се работи со многу големи и со многу мали броеви. На пример,


во нашата галаксија има преку 200 000 000 000 ѕвезди, масата на електронот е 9,1
 10‒31 kg и слично. За нивното претставување во компјутерот, се користи т.н.
претставување со подвижна точка (или подвижна запирка). На пример, бројот
237,56 може да се претстави како 2,3756  102 или 0,00023756  106 или 2375600 

233
ПРОГРАМИРАЊЕ

10‒4 итн. Тоа значи дека децималната запирка можеме да ја ставиме каде било, а е
одредена со експонентот на бројот 10.
За бинарните броеви се користи експонент на бројот 2, така што општиот
облик на децимален бинарен број е M  2E, во кој M се нарекува мантиса, а E
експонент. На пример, децималниот бинарен број 11010.001 се запишува како
0.11010001  2101, со мантисата M = 0.110100012 и со експонентот E = 1012. Ако
бројот е 0.0001011012, тој се запишува како 0.101101  2‒11, т. е. со мантисата M =
0.1011012 и со експонентот E = ‒112. На ваков начин се обезбедува мантисата да е
1
помеѓу 0.10...0  M  0.11...1 , односно 2 ≤ М < 1.
Бидејќи по децималната точка секогаш има 1, велиме дека мантисата е
нормализирана и најчесто тој бит не се запишува.
Во персоналните компјутери се користи стандардот на организацијата
IEEE2, во кој мантисата се запишува со вредност 1  M  2, т. е. има вредност од
1.00... 0 до 1.11... 1, односно во облик 1 + F, во кој F е децималниот дел десно од
децималната точка и има вредност од 0.00… 0 до 0.11… 1. На овој начин скри-
ениот бит 1 се подразбира и не се запишува, а со тоа се обезбедува уште еден бит
повеќе за претставување на експонентот. Така, бројот 11010.1012 може да се за-
пише како 1.1010101  2100, т. е. со децималната мантиса F = 1010101 и со екс-
понентот E = 100. Значи, бројот го има обликот (1 + F)  2E.
Мантисата и експонентот се претставуваат во компјутерот, во зависност
од должината на зборовите. Ако компјутерот има w-битни зборови, тогаш прет-
ставувањето се врши како на слика 7.2.4.2. Ознаката S е битот за знакот на бро-
јот, и тоа 0 за позитивен и 1 за негативен број. Бројот на битови за експонентот E
е е, а m е бројот на битови за децималната мантиса F.
m+e m+e‒1 m m‒1 ... 2 1 0
S E + 2e ‒ 1 ‒ 1 F
1 бит e бита m бита
Слика 7.2.4.2
Бидејќи експонентот може да биде и негативен, се врши поместување за
2e ‒ 1 – 1 места, така што E + 2e ‒ 1 – 1 секогаш треба да биде позитивен број меѓу
00... 0 и 11... 1 со должина од е бита.
Во персоналните компјутери, според стандардот IEEE, во 32-битните
зборови експонентот има должина од 8 бита (e = 8), а децималната мантиса од 23
бита (m = 23). Тоа е т.н. претставување со обична точност.
Со двојна точност, броевите се претставуваат со 64-битни зборови. Екс-
понентот има 11 бита, додека децималната мантиса има 52 бита. Значи, со обич-
ната точност поместувањето на експонентот е за 27 – 1 = 127, а со двојната точ-
ност за 210 – 1 = 1023.

2
IEEE – Institute of Electrical and Electronics Engineers.
234
7. Претставување на податоците во компјутерот

Да го претставиме бројот 11010.1012 со обична точност.


11010.1012 = 1.1010101  2100, т. е. F = 10101012 и E = 1002, додека S = 0
бидејќи е позитивен број. Поместувањето на експонентот е за 12710, т. е. 410 +
12710 = 13110 = 100000112, така што бројот ќе биде претставен на следниов начин:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 0 0 1 1 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Да наведеме уште еден пример. Кој број е претставен на следнава слика?
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
1 1 0 0 0 1 0 0 0 0 0 1 1 1 0 1 0 1 1 0 0 0 00 0 0 0 0 0 0 0 0
Од битот за знакот S = 1, гледаме дека бројот е негативен. Експонентот
има вредност E = 10001000 – 01111111 = 10001000 + 10000001 = 000010012 = 910.
Децималниот дел на мантисата F = 0.0011101011, затоа
M = 1 + F = 1.0011101011.
Бројот е x = (–1)S  M  2E = –1001110101.12.
Ако е бројот периодичен, тогаш тој се заокружува и неговата мантиса се
претставува со 23 бита. На пример, 1 / 10 = 1.100110011001  2100 .
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 0 0 1 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1
На овој начин, експонентот е во опсег од –126 до +127. Значи, најмалиот
позитивен број кој може да се претстави со 32 бита е:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
кој изнесува (1 + 0.000… 0)  21 ‒ 127 = 2‒126  1.2  10‒38 .
Најголемиот позитивен број претставен со 32 бита е:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
кој изнесува (1.111… 1)  2254 ‒ 127 = (1.111… 1)  2127  3.4  1038 .
Нулата се претставува со експонент со сите бита 0.
 се претставува со експонент со сите бита 1, а на мантисата 0.
Може да се претстават и помали броеви од 2‒126, само што тие нема да би-
дат нормализирани.
На пример, 2‒127 = 2‒126  2‒1 = 0.1  2‒126 може да се претстави како
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Исто така, 2‒149 = 2‒127  2‒22 = 0.00000000000000000000001  2‒127 се прет-
ставува како

235
ПРОГРАМИРАЊЕ

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
и тој е, всушност, најмалиот позитивен број што може да се претстави со дупли
збор. Значи, може да се претстават и сите броеви помеѓу 2‒126 и 2‒149.
За поголеми броеви и поголема точност се користи 64-битно претста-
вување, во кое експонентот се претставува со 11 бита, а мантисата со 52 бита.
Значи, најголемиот експонент е 1 023, а најмалиот експонент е –1 022. Најмалиот
позитивен број кој може да се претстави е 2‒1022  2.2  10‒308, а најголемиот е 21024
 1.8  10308 .

Вежби

Вежба 7.2.1
Одговорете на следните прашања:
1. Зошто кај компјутерите се користи бинарниот броен систем?
2. Како се претставуваат знаците во компјутерот:
3. Што е код ASCII, а што Unicode?
4. Како се претставуваат сликите во компјутерот, а како звукот?
5. Што е пиксел?
6. Што е резолуција?
7. На кој начин се врши дигитализација на звукот во компјутерот?
8. Како се претставуваат целите броеви во компјутерот?
9. *Како се претставуваат децималните броеви во компјутерот?

7.3 Операции со бинарни броеви

Споменавме дека броевите во компјутерот се претставени со бинарниот


броен систем и сите операции со нив се извршуваат во овој систем. Во оваа пот-
точка ќе ги објасниме аритметичките операции со бинарните броеви: собирање,
одземање, множење и делење. Важно е да ја совладате операцијата собирање, а
другите операции се претставени за оние што сакаат повеќе да знаат. Доста
интересно е и како се множи и дели со 2 и тоа е разгледано најдолу во овој дел.

Собирање

Основно правило при собирањето на две цифри во кој било бро- 175
ен систем е: ако збирот е поголем или еднаков на основата, тогаш од не- + 29
го се одзема основата и се пишува остатокот, а на погорната (полевата) 204
позиција се пренесува една единица. На пример, при собирање на брое-

236
7. Претставување на податоците во компјутерот

вите 175 и 29 велиме: 5 и 9 се 14, т. е. 14 ‒ основа = 14 ‒ 10 = 4. Значи пишуваме


4, а пренесуваме 1 во погорната позиција (десетките). Потоа, 7 и 2 се девет и пре-
несената 1 се 10, т. е. 10 ‒ 10 = 0. Значи, пишуваме 0, а пренесуваме 1.
Истото важи и во бинарниот броен систем. На пример, при со- 1101
бирање на броевите 11012 и 01012 велиме: 1 и 1 се 2, т. е. 2 ‒ основа = 2 ‒ + 0101
2 = 0. Значи, пишуваме 0, а пренесуваме 1. Потоа, 0 и 0 се 0 и прене- 10010
сената 1 се 1 итн.
Бидејќи во бинарниот броен систем има само
две цифри (0 и 1), лесно можеме да ја прикажеме табе- + 0 1
лата на собирање во овој броен систем. 0 0 1
Да наведеме уште еден пример кога имаме да 1 1 0
собираме повеќе броеви. И во овој случај, собирањето и пренос 1
се врши исто како и во декадниот броен систем. Од зби-
рот се одзема основата сѐ додека не се добие остаток 110101
помал од основата. Се пишува остатокот, а преносот е, 110011
всушност, бројот на одземања на основата од збирот 010110
(еднаш, двапати итн.). Практично, преносот се пресме- + 100111
тува како количник на збирот со основата, а се пишува 1221221  пренос
остатокот од делењето. 10100101  збир

Одземање

При одземањето, основното правило е: кога се одзема поголем број од


помал, тогаш се позајмува една единица од цифрата на погорната позиција од
тековната. Во следниот пример (257 ‒ 179), при одземање во декадниот броен
систем, велиме: 9 од 7 не може да се одземе. Позајмуваме 1 од погорната позици-
ја (од 5), го множиме со 10 (со основата) и го додаваме на 7, па одземаме 9 од 17
итн.
14 Истото се прави и во бинарниот броен систем.
1 4 17 0 2
2 5 7 1 1 1 0 На прикажаниот пример, велиме 1 од 0 не може да се
одземе. Позајмуваме 1 од погорната позиција, го мно-

1 7 9

 0 1 0 1 жиме со 2 (основата) и го додаваме на 0, па одземаме
7 8 1 0 0 1 1 од 2. Останатите случаи при одземање се јасни.

Ова е прикажано во табелата на одземање во ‒ 0 1


бинарниот броен систем.
0 0 1
Меѓутоа, ваквиот начин на одземање во би-
и позајмено 1
нарниот броен систем е тешко да се реализира. За-
тоа, одземањето се реализира со собирање. Пред да 1 1 0
го објасниме тоа, ќе видиме како се претставуваат негативните броеви во бина-
рниот броен систем.

237
ПРОГРАМИРАЊЕ

Знаеме дека во декадниот броен систем цели броеви се: ..., ‒ n , ‒ (n ‒ 1),...
‒ 3, ‒ 2, ‒ 1, 0, 1, 2, 3,... n ‒ 1, n,... Една од особините на целите броеви е дека
збирот на позитивен и негативен цел број со иста апсолутна вредност е 0, т. е.
+5 + (‒5) = 0, +21 + (‒21) = 0 итн.
Значи, и во бинарниот броен систем мора да важи оваа особина. Таа може
да се примени во случај кога ни е познат некој број и сакаме да го најдеме него-
виот спротивен број (со иста апсолутна вредност, но со спротивен знак). На при-
мер, ако е даден бројот
а = 101102, кој е бројот ‒а?
Поаѓајќи од правилото:
(+а) + (‒а) = 0,
можеме да пресметаме
(‒а) = 0 ‒ (+а), т. е. (‒а) = 00000 ‒ 10110.
Бидејќи од 0 не може да се одземе 1, треба да позајмиме 1 од погорната
позиција. Но бидејќи сите претходни цифри се 0, тогаш за да има од каде да по-
зајмиме, пред првата нула допишуваме 1.
Во конкретниов случај, со одземање со позајмување добиваме:
100000 Значи бројот (‒а) = 010102. 10110
‒ 10110 Ако го провериме условот (+а) + (‒а) добиваме: --------> + 01010
001010 Ако ја отфрлиме првата цифра 1, гледаме дека збирот е 100000
0.
Бидејќи бројот 100 000 = 25, заклучуваме дека спротивен (негативен број)
се добива со формулата
(‒a) = 2n – (+a)
во која n е бројот на битови на бројот (+а).
Добивањето на спротивен број (‒а) најчесто се врши на поедноставен (по-
лесен) начин. Прво се комплементира бројот (+а), така што единиците се замену-
ваат со нули, а нулите со единици. Така добиениот број се нарекува прв компле-
мент на (+а). Ако на него се додаде +1, ќе се добие број кој се нарекува втор
комплемент на (+а), кој е, всушност, (‒а).
На пример, за бројот (+а) = 10110 добиваме:

Значи, се добива бројот (‒а) = 01010.


Сега да се вратиме на одземањето на два бинарни броеви b и a.
Од b ‒ a = b + (‒a), гледаме дека одземањето се сведува на собирање со
вториот комплемент на бројот (+а).
На пример, 14 – 5 = 14 + (‒5). Го бараме вториот комплемент на 5:

238
7. Претставување на податоците во компјутерот

Битот со најголема важност едноставно го отфрламе и го добиваме бројот


10012 = 910.
Множење*
Множењето во бинарниот броен систем се врши на ист начин како и во
декадниот, односно првиот множител се множи со секоја цифра од вториот
множител и, притоа, производот се запишува за едно место во лево.
На пример:
Табелата за множење е:
 0 1
0 0 0
1 0 1

Овој начин на множење не се користи во компјутерите, туку се користат


други побрзи постапки, односно методи за множење, како:
 Техника со пренос (англ. carry propagate multiplier).
 Полно собирачко дрво (англ. full adder tree).
 Компресија на колони (англ. column compression).
 Собирачи со памтење на преносот (анг. cary save multipliers).

Делење*

Делењето се врши со одземање, исто како и во декадниот броен систем.


Во компјутерите се 1 0 0 1 1 1 1 1 1 : 1 1 1 0 1 = 1 0 1 1
вградуваат други постапки ‒ 1 1 1 0 1
засновани на множење, кои 0 1 0 1 0 1
се многу побрзи од класич- ‒ 0 0 0 0 0
ната постапка за делење. 1 0 1 0 1 1
Постојат: ‒ 1 1 1 0 1
 директни и 0 1 1 1 0 1
 индиректни методи. ‒ 1 1 1 0 1
Директните методи 0 0 0 0 0 0
се слични на објаснетата постапка, т. е. со одземање на делителот. Тие бараат
додатен хардвер.
Индиректните се итеративни постапки со кои се бара реципрочната вред-
ност на делителот и потоа таа се множи со деленикот.
239
ПРОГРАМИРАЊЕ

Множење и делење со 2

Знаеме дека множењето со 10 во декадниот броен систем се врши со до-


пишување 0 на крајот од бројот (1710  1010 = 17010). На ист начин се множи со 2 и
во бинарниот броен систем. На пример, 1011012  102 = 10110102, што е покажано
и на долниот пример каде што е извршено бинарно множење.
Исто така, при множење со 10n во декадниот броен сис-
тем, на десната страна од бројот допишуваме n нули. Тоа важи
и за множење со 2n на бинарен број. Допишуваме n нули на
десната страна од бројот. На пример:
10011101  23 = 10011101000
Всушност, ова правило важи при множење на кој било
број со bn во броен систем со основа b.
Ако се множи децимален број, тогаш децималната точка се поместува за
онолку места надесно колку што е степенот на основата.
На пример:
123.4567  103 = 123456.7
1001.1101  23 = 1001110.1
При делењето со 2n, операциите во бинарниот броен систем се вршат на
ист начин како и во декадниот, така што се поместува децималната точка за о-
нолку места налево колку што е степенот на основата.
На пример, 1001110.1  2‒3 = 1001.1101 итн.

Вежби

Вежба 7.3.1
Пресметајте:
1. 100010 + 101100
2. 111 + 10001
3. 1100 + 10011
4. 10110111100 * 10
5. 10110111100 / 10
6. 10110111100 * 100

240
7. Претставување на податоците во компјутерот

Резиме

 Бројните системи во кои за секоја цифра се знае позицијата во бројот, се


нарекуваат позициски бројни системи.
 Позициски бројни системи се: декадниот, бинарниот, окталниот, хексаде-
цималниот и други.
 Во компјутерите се користи бинарниот броен систем со цифри 0 и 1
бидејќи: со 0 и 1 може да се претстави секоја информација, аритметич-
ките операции се исти како во декадниот броен систем, цифрите 0 и 1 во
електрониката се претставуваат со две вредности на напонот и постојат
физички медиуми способни да паметат само две состојби кои се детекти-
раат како 0 и 1.
 Знаците во компјутерот се претставуваат со т.н. табела Уникод во која се
кодирани симболите и знаците на сите пишувани јазици кои се користат
во светот. Првите 128 кодови на Уникод ги претставуваат знаците ASCII.
 Сликите во компјутерот се претставуваат со пиксели, а секој пиксел се
кодира со повеќе бита.
 Звукот во компјутерот се претставува со кодирање на амплитудата или на
фреквенцијата.
 Целите броеви може да бидат означени и неозначени. Означените броеви
се позитивни, со прв бит 0 или негативни, со прв бит 1.
 Децималните броеви се претставуваат со подвижна точка, со мантиса и
експонент.
 Децималните броеви со обична точност зафаќаат 32 бита, а со двојна точ-
ност 64 бита.
 Прв комплемент на бинарен број се добива кога ќе се заменат единиците
со нули, а нулите со единици. Кога на првиот комплемент ќе се додаде 1,
се добива втор комплемент.
 Со бинарни броеви може да се изведуваат аритметичките операции:
собирање, одземање, множење и делење.
 Разликата на два бинарни броја се наоѓа кога првиот број ќе се собере со
вториот комплемент на вториот број.
 Множењето и делењето на бинарен број со 2n се врши со поместување на
децималната запирка надесно т. е. налево за n места.

241
ПРОГРАМИРАЊЕ

242
8. Класи и објекти

8. КЛАСИ И ОБЈЕКТИ
Во оваа глава ќе се запознаете со следното:

 Објекти и објектно ориентирано програмирање.


 Атрибути на објект (идентитет) и својства на објект (однесување).
 Класа, хиерархија на класи и класни дијаграми.
 Интерфејс на објект.
 Членови на класа: членови податоци и членки функции.
 Примерок (инстанца) и инстанцирање на објекти.
 Дефинирање класа и декларирање објекти.
 Приватно (private) и јавно (public) подрачје на класа.
 Полиња на класа, функции за поставување податоци на полињата, функ-
ции за земање (добивање) резултати.
 Операторот точка за избор на член.
 Променливи на објект.
 Директен пристап до членови на класа.

Клучни зборови

private Операторот точка


public Податок член на класа
Атрибут Примерок (инстанца)
Инстанцирање Променливи на објектот
Интерфејс Состојба
Класа Функција за земање податоци
Класен дијаграм Функција за поставување податоци
Објект Функција членка на класа
Однесување Хиерархија на класи

243
ПРОГРАМИРАЊЕ

Нашиот реален свет се состои од објекти (англ. objects). Ако замижеме и


си ја замислиме (претставиме) околината околу нас, ќе сфатиме дека околината
се состои од објекти. Така работи нашиот мозок. Тој создава претстава на околи-
ната од објекти, а надополнување на претставата на околината со тоа што се слу-
чува во неа, се врши со нашите сетила за слух, мирис, вкус, допир и вид.
Значи, сè што гледаме околу нас се објекти: дрвја, птици, сонце, деца, ку-
ќи, риби, згради, планини, јаболка, автомобили итн. Некои објекти не се физич-
ки, како: прозорец на оперативниот систем Windows, датотека запишана на диск,
куќна адреса, филм, приказна, број, збор, буква, цифра, сметка во банка, компју-
терска програма, месец, ден во неделата, песна итн.
Некои објекти се единствена (неделива) целина: буква, цифра, чаша, мо-
нета итн. Повеќето објекти се составени од помали објекти: бројот (се состои од
цифри), автомобилот (се состои од мотор, каросерија, седишта, тркала итн.),
месецот (се состои од денови) итн.
Некои објекти се различни: птици, дрвја, филмови итн. Некои објекти се
слични: гулаб, врапче, кокошка, штрк итн. бидејќи сите се птици. Затоа, велиме
дека птиците се посебна група животни. Рибите, исто така, се посебна група жи-
вотни. За групите се користат и термините: вид, тип, род или класа. На пример,
велиме дека зимзелените дрвја се посебен вид дрвја, а џиповите се посебен тип
автомобили. Мачките се посебен род животни, а лаптопите се посебна класа
компјутери.
Во објектно ориентираното програмирање (англ. Object-oriented progra-
mming – OOP) се користи терминот класа. На пример, класа Птици, класа Фил-
мови, класа Триаголници итн.
Секој поединечен објект има свои карактеристики (атрибути).
Објектите кои припаѓаат на една класа имаат исти или слични каракте-
ристики.
На пример:
Птиците имаат: две нозе, две крилја и клун.
Автомобилите имаат: марка, тип, сила, тркала и седишта.
Прозорците на Windows имаат: тип, форма, големина, менија
и копчиња.
Настаните што се случуваат во околината се предизвикани од објектите,
т. е. од нивното однесување. На пример, пеење на птица, ѕвонење на телефон, ла-
ење на куче, пливање на риба итн.
Однесувањето на објектите зависи од нивните својства (способности).
На пример:
Птиците: одат, летаат, пеат.
Автомобилите: мируваат, се движат, кочат.
Прозорците на Windows се: активни, неактивни, минимизирани.
Според однесувањето, може да се одреди каков е тој објект, т. е. каква е
неговата состојба. На пример, птицата е во состојба на летање, рибата е во сос-
244
8. Класи и објекти

тојба на пливање, прозорецот на Windows е во активна состојба, процесорот е во


состојба на чекање, пченицата е во состојба на зреење, автомобилот без кочници
е во лоша состојба итн.
Некои објекти извршуваат одредени активности (телефонот ѕвони, гула-
бот лета, тревата расте итн.), а со некои може да се извршуваат активности (вело-
сипедот се вози, со телефон се праќаат пораки, преку Viber се разговара итн.).
Од досега реченото, може да се заклучи дека секој објект има:
 идентитет, т. е. претставува нешто посебно (според атрибутите),
 однесување (според неговите својства),
 состојба (изразена со неговото однесување во тој момент или со
вредностите на неговите атрибути).
Рековме дека објектите со слични својства (и/или однесување) и каракте-
ристики се од иста класа (англ. class). На пример, птиците се една класа (имаат
исти карактеристики: крилја, клун итн. и слично однесување – летаат), а рибите
се друга класа (имаат шкрги, живеат во вода, пливаат). Куќите се посебна класа
објекти, автомобилите се, исто така, посебна класа објекти итн.
Во некоја класа објекти има и поткласи. На пример, класата Zivotni ги
има поткласите: Ptici и Ribi, класата Ucilista ги има поткласите: OsnovniUcilista и
SredniUcilista. Класата Vozila ги има поткласите: Avtomobili, Avioni, Brodovi итн.
Некоја поткласа може да има и свои поткласи. На пример, поткласата
SredniUcilista ги има поткласите: Gimnazii и StrucniUcilista. Тоа може да се
прикаже и графички со дијаграм како дрво, слика 8.1.1.

Слика 8.1.1
Ваквиот распоред на класите се нарекува хиерархија на класите (англ.
class hierarchy).
Друг пример е хиерархијата на класите на животни, а дел од неа е
прикажан на слика 8.1.2.

245
ПРОГРАМИРАЊЕ

Слика 8.1.2
На слика 8.1.3 е прикажана хиерархија на класите на геометриски форми.

Слика 8.1.3
Објектите од една класа се слични, ама не се еднакви, т. е. во една класа
нема два еднакви (идентични) објекти. На пример, ако класата Ucenici е класа на
сите ученици од едно училиште, во неа нема два исти објекти бидејќи нема два
идентични ученици.
Сите ученици имаат исти податоци, и тоа: име, презиме, година во која
учат, клас, број во дневникот, оценки итн. Значи, сите ученици се објекти со исти
карактеристики (атрибути), но со различни вредности на карактеристиките, раз-
лични имиња и/или презимиња, различни класови итн.
Вредностите на атрибутите на објектите се податоци: броеви, имиња, тек-
стови, слики и др.
На пример, ако ја има класата Pravoagolnik, атрибути на нејзините објекти
се страните dolzina и sirina. Но кои било два објекти правоаголници може да има-
ат различни вредности на атрибутите dolzina и sirina. На пример, ако именуваме
два објекти од класата Pravoagolnik како pravoagolnikEden и pravoagolnikDrug
(слика 8.1.4), гледаме дека вредностите на нивните атрибутите dolzina и sirina се
различни.

246
8. Класи и објекти

Значи, секој објект е посебен, т. е. има свој идентитет, свое однесување и


своја состојба. Идентитетот најчесто се изразува преку името, како pravoagolnik-
Eden и pravoagolnikDrug, кои се различни објекти.
Однесувањето се изразува преку акциите што може да ги извршуваат об-
јектите од една класа. На пример, кучињата лаат, кавалот свири, детето игра. Е-
ден објект ќе изврши некоја акција ако се побара од него. Ако му наредите на ку-
чето да го донесе фрленото стапче, тоа ќе го донесе. Ако дувнеме во кавалот, тој
ќе свири. Ако го притиснеме копчето за вклучување на радиото, тоа ќе почне да
работи. Ако кликнеме на копчето Send, напишаната електронска порака ќе се
испрати.

Слика 8.1.4
Се поставува прашањето: Како да се побара од некој објект да изврши
некоја акција? Тоа се прави така што треба да му испратиме некоја порака. На
пример, на кучето му „праќаме порака“, велејќи му „донеси го стапчето“, на ка-
валот со дување му „праќаме порака“ за да свири, преку копчето за вклучување
на радиото му „праќаме порака“ да работи, преку копчето Send „праќаме порака“
(до некој објект) да ја испрати електронската порака итн.
Објектите ги примаат пораките преку своите сетила (животните) или пре-
ку соодветни физички елементи (кај радиото, кај автомобилот и сл.) или преку
програмски елементи (копче, мени, наредба и сл.). Тие елементи формираат т.н.
интерфејс (англ. interface) на објектот. Интерфејсот на објектите претставува
„врска“ со околината, т. е. со други објекти.
За да одговори на одредена „порака“, објектот треба да изврши соодветна
акција. Сите акции кои може да ги изврши еден објект ја сочинуваат неговата
функционалност. Тоа значи дека за секоја акција, објектот извршува посебна
функција. На пример, за да лета птицата, треба да ги рашири крилјата и со нив да
замавнува. За да го донесе кучето фрленото стапче, треба да истрча до него, да го
земе и да се врати назад. За да се испрати електронска порака, апликацијата по-
викува соодветна програма и бара процесорот да ја изврши. За да ги дознаеме
плоштината и обиколката на некој правоаголник, треба да има функција за нивно
пресметување која треба да се повика и изврши итн.
За објектите: pravoagolnikEden и pravoagolnikDrug можеме, на пример, да
пресметаме: obikolka, plostina и dijagonala.
При која било акција што ја извршува објектот, се користат неговите ат-
рибути. Така, птиците за летање ги користат крилјата, кучињата за трчање ги ко-
247
ПРОГРАМИРАЊЕ

ристат нозете, за пресметување на обиколката и плоштината на правоаголник се


користат страните итн. Со еден збор, секој објект има функции чии аргументи се
неговите атрибути.
Затоа, велиме дека атрибутите и однесувањето (функциите) на еден об-
јект се неразделни, односно прават една целина.
Ако ја имаме класата Krug, карактеристика на нејзините објекти е радиу-
сот r. Aко именуваме два објекти од класата Krug, како: krugEden и krugDva
(слика 8.1.5), за нив можеме да пресметаме: obikolka, plostina и dijametar, но не и
dijagonala бидејќи тие немаат дијагонала. Слично, за објектите: pravoagolnikEden
и pravoagolnikDrug не можеме да пресметаме dijametar бидејќи тие немаат дија-
метар. Или, рибите имаат едно однесување (едни функции), а птиците имаат дру-
го однесување (други функции). Од ова може да се заклучи дека објектите од
една класа имаат исти атрибути и исто однесување, кои може да ги немаат објек-
тите од друга класа.

Слика 8.1.5

Програмирањето во кое се користат објекти се нарекува објектно ориен-


тирано програмирање (ООП). Со него се врши „пресликување“ на реалниот свет
во компјутерска програма. Ова ќе го објасниме на неколку примери.
Сите сме виделе машина за пишување, т. е. за отчукување на текст. Де-
нес, таквата машина е компјутерската програма за пишување и уредување текст.
Училишниот дневник е голема тетратка со тврди корици. Денес, постојат
програми кои претставуваат електронски училишни дневници.
Веруваме дека сте слушнале и за виртуелни училишта, виртуелни универ-
зитети и сл., на кои може да се учи и да се добие диплома сосема легално (закон-
ски), како на секое училиште или на универзитет, а никогаш да не отидете фи-
зички во училиштето или на факултетот. И може да ги положите сите предмети,
а да не ги видите професорите. Тоа се, всушност, комплексни компјутерски
апликации, а не физички училишта или факултети.

248
8. Класи и објекти

Во објектно ориентираното програмирање класите може графички да се


претстават со т.н. класни дијаграми (англ. class diagrams), како на слика 8.1.61.
Тие се состојат од три дела. Во горниот дел е името на класата, во средниот дел
се атрибутите на објектите од класата, а во долниот дел се запишуваат функци-
ите2 за објектите од класата.

Pravoagolnik Krug
dolzina: double radius: double
sirina: double obikolka()
obikolka() plostina()
plostina() dijametar()
dijagonala()
Слика 8.1.6

Aтрибутите на објектите се изразени преку соодветни променливи. На


пример, кај објект од класата Pravoagolnik, променливите се: dolzina и sirina.
Мемориските локации кои ги содржат вредностите на променливите ја
изразуваат нивната состојба. Исто така, функциите на објектот: (obikolka(), plos-
tina(), dijagonala()), кои служат за изразување на однесувањето на некој објект, се
наоѓаат во меморијата.
Атрибутите и функциите се нарекуваат членови на класата (англ. class
members), т. е. податоци членови (англ. data members) или членови податоци и
функции членки (англ. function members) или членки функции или накратко
кажано методи. На пример, податоците членови на класата Pravoagolnik се:
dolzina и sirina, а функциите членки се: obikolka(), plostina() и dijagonala().
Секој објект од една класа се нарекува примерок или инстанца (англ.
instance). На пример, објектите: pravoagolnikEden и pravoagolnikDrug се примеро-
ци на објекти од класата Pravoagolnik, објектите: krugEden и krugDva се при-
мероци на објекти од класата Krug.
Креирањето објект од некоја класа се нарекува инстанцирање.
Класата претставува еден вид шема (калап, нацрт, план) по која се креи-
раат (инстанцираат) објекти. На пример, по нацрт за фустан може да се изработат
фустани со различни големини, материјали и бои, по калап за чаша може да се
излеат чаши од различен материјал, по план за двокатна куќа може да се соѕидаат
различни куќи, по шема за слика може да се извезат различни гоблени (со раз-
лични бои и материјали) итн.

1
Овие дијаграми се наречени UML-дијаграми, кратенка од Unified Modeling
Language, јазик за документирање и опис на компјутерски програми.
2
Функциите ќе ги запишуваме со името и мали загради на крајот за да се разли-
куваат од променливи со исто име.
249
ПРОГРАМИРАЊЕ

Објектите: pravoagolnikEden и pravoagolnikDrug (слика 8.1.4), како и


објектите: krugEden и krugDva (слика 8.1.5) се креирани според соодветните
шеми (класни дијаграми) од слика 8.1.6.
Ако извлечеме паралела со досега изучените работи, упростено можеме
да кажеме дека на класата можеме да гледаме како на нов тип на променли-
ва, а на инстанцата (објектот) како на променлива од тој нов тип.

Вежби

Вежба 8.1.1
Да се одговори на следните прашања:
1. Што е објектно ориентирано програмирање (ООП) ?
2. Што претставува класа, а што објект во ООП?
3. Какви членки има класата во ООП?
4. Што е инстанца?
5. Што е класен дијаграм?

Вежба 8.1.2
Да се напише класен дијаграм за класата Triagolnik.

8.1 Дефинирање класи и декларирање објекти

Класа во С++ се дефинира на следниов начин:


class ИмеНаКласа { // наслов
private:
атрибут 1; // податоци членови
...
атрибут n;
public:
функција 1; // функции членки
...
функција m;
};
Слика 8.2.1
Ќе наведеме неколку примери.

Пример 8.2.1
Да се дефинира класата Krug, според класниот дијаграм од слика 8.1.6 и
да се дефинира само една функција членка за пресметување на обиколката на
круг.

250
8. Класи и објекти

Класата Krug е дефинирана на слика 8.2.2.


Во подрачјето (делот) private: на класата е декларирана променливата
radius, која го изразува истоимениот атрибут на објектите од класата Krug.
Променливите во подрачјето private: се нарекуваат полиња (англ.
fields). Значи, променливата radius е поле на класата Krug.
Полињата на класата може да се користат само во телото на класата и во
сите функции дефинирани во класата, ама не може да се користат во друга класа.
Во подрачјето public: на класата има две функции. Со првата (posta-
viRadius()), се поставува вредност на полето radius, преку параметарот rNaKrug
на функцијата postaviRadius().
Со функцијата zemi-
Obikolka(), се пресметува оби-
колката на кругот, која се враќа
со наредбата return O; кај оној
кој ќе ја повика оваа функција.
Променливата О е локална про-
менлива за функцијата zemiO-
bikolka(). Тоа значи дека про-
менливата О не може да се ко-
ристи надвор од функцијата,
ниту во класата ниту во друга
функција.
Вообичаено, во С++ (и
други објектно ориентирани
јазици) се користат посебни Слика 8.2.2
функции за поставување (ан-
гл. set functions) податоци на полињата на класата. Исто така, функциите со кои
се добиваат пресметаните резултати се нарекуваат функции за еземање (англ.
get functions). Затоа, во примерите ќе ја користиме оваа терминологија.
Во главната функција (слика 8.2.3), по внесување на радиусот r, со наред-
бата
Krug krugEden;
се инстанцира (креира) објектот krugEden од класата Krug.
Со наредбата
krugEden.postaviRadius(r);
за објектот krugEden се повикува функцијата postaviRadius(r) со аргументот r.
Притоа, за да се пристапи до функцијата postaviRadius(r), членка на класата
Krug, се користи т.н. оператор точка за избор на член (англ. dot member selec-
tion operator). Тој се поставува меѓу името на објектот и името на функцијата.
Тоа значи дека оваа наредба претставува повик на функција со аргументи. При
нејзиното извршување, вредноста на аргументот r се пренесува во параметарот
rNaKrug на функцијата postaviRadius().
251
ПРОГРАМИРАЊЕ

Десната страна од наредбата


obikolka = krugEden.zemiObikolka();
претставува повик на функцијата zemiObikolka() за објектот krugEden. При
нејзиното извршување, таа ја враќа вредноста на локалната променлива О со
наредбата return О;. Вратената вредност се доделува на променливата obikol-
ka.

Слика 8.2.3
Еден излез од извршување на програмата е:

Конечно да објасниме за последните наредби во сите примери кои ги гле-


дате низ учебников, а кои не се неопходни за точно работење на програмата.
Наредбата
system("Color 17");
се користи за поставување сина боја на позадината (бројот 1) и бела боја на
текстот (бројот 7) за попријатен изглед на приказот на резултатите. Читателот
може да експериментира со оваа наредба, при што првиот број е боја на позади-
ната, а вториот број е боја на текстот. Броевите може да бидат која било комби-
нација на првите 16 хексадекадни броеви: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F.
Наредбата
system("pause");

252
8. Класи и објекти

е наредба за пауза додека не се притисне некое копче од тастатурата и прозоре-


цот за резултати да се затвори.
Пример 8.2.2
Да се напишат класата Pravoagolnik и главната функција во која ќе се
креираат објекти од класата Pravoagolnik, според UML-дијаграмот од слика 8.1.6.
Во класата Pravoagolnik (слика 8.2.4) ќе ги декларираме двете промен-
ливи (dolzina и sirina), кои претставуваат атрибути на објектите од класата
Pravoagolnik.

Слика 8.2.4

253
ПРОГРАМИРАЊЕ

Во класата се дефинирани три функции3. Првата функција postaviStra-


ni() ќе ја користиме за поставување вредности на полињата (атрибутите) на об-
јект од класата Pravoagolnik. Во примеров, функцијата set ја нарековме pos-
taviStrani(). Листата на параметрите на оваа функција е:
(double aStrana, double bStrana)
и се користи само за пренос на аргументите во полињата на класата при повик на
функцијата. Тоа се прави со наредбите во телото на функцијата:
dolzina = aStrana;
sirina = bStrana;
Потоа, полињата стануваат променливи dolzina и sirina и може да се користат
во сите функции во класата.
Втората функција zemiObikolka(), ja пресметува обиколката на правоа-
голникот и ја враќа со наредбата
return O;
Со третата функција zemiPlostina(), се пресметува плоштината на пра-
воаголникот, која се враќа со наредбата
return P;
Четвртата функција zemiDijagonala(), ја пресметува дијагоналата на пра-
воаголникот. Притоа, се користи функцијата sqrt() за пресметување на квадрат-
ниот корен од некоја величина, x .
Во функцијата postaviStrani() од типот void, се наведуваат параметрите
и нивниот тип, а во насловот на функциите zemiObikolka(), zemiPlostina() и
zemiDijagonala() се поставува типот на повратната вредност.
Во главната функција (слика 8.2.5), по читањето на вредностите на про-
менливите a и b, со наредбата
Pravoagolnik pravoagolnikEden;
се креира (инстанцира) објектот pravoagolnikEden од класата Pravoagolnik.

Слика 8.2.5

3
Редоследот на функциите во една класа не е битен. Меѓутоа, логички е први да
бидат функциите со кои се поставуваат вредности на полињата на класата
(атрубутите на објектите), а потоа функциите за работа со полињата.
254
8. Класи и објекти

Слика 8.2.5 (продолжение)


Објектот pravoagolnikEden се креира така што во меморијата се резер-
вира простор за полињата на класата dolzina и sirina, кои се иницијализираат на
подразбирливи (англ. default) вредности, зависно од типот на полето. Во приме-
ров, за типот double подразбирлива вредност е 0.0.

pravoagolnikEden

Креираните полињата dolzina и sirina претставуваат променливи на објек-


тот (примерокот, инстанцата) pravoagolnikEden и се нарекуваат променливи
на објектот (англ. instance variables).
Со наредбата
pravoagolnikEden.postaviStrani(a, b);
се повикува функцијата postaviStrani() за објектот pravoagolnikEden и се пос-
тавуваат вредности на неговите страни (наместо подразбирливите вредности 0.0)
внесени преку тастатурата.
Со следната наредба
obikolka = pravoagolnikEden.zemiObikolka();
прво се повикува функцијата zemiObikolka() за објектот pravoagolnikEden, по-
тоа се извршува, а вредноста што ја враќа се доделува на променливата obikolka.
Исто дејство имаат и наредбите:
plostina = pravoagolnikEden.zemiPlostina();
dijagonala = pravoagolnikEden.zemiDijagonala();
Резултатот од извршување на апликацијата од слика 8.2.5 е:

255
ПРОГРАМИРАЊЕ

Инстанцирањето објекти се нарекува и декларирање променливи од


соодветната класа, што не е грешка бидејќи класата, всушност, претставува тип
на податок. Значи, класите се типови податоци кои ги задава (дефинира) прог-
рамерот. На пример, класата Pravoagolnik е еден тип податоци – објекти, класа-
та Krug е друг тип податоци – објекти итн.

Пример 8.2.3
Да се дефинира класата Uciliste и во неа да се напишат функции потребни
за работа со податоците за училиштето, според следниов класен дијаграм, слика
8.2.6.
Да се напише апликација (програма која содржи функција main()) за тес-
тирање на објекти од класата Uciliste.
Класата Uciliste е дадена на
Uciliste слика 8.2.7. Функциите за поставување
‒ imeNaUciliste: string податоци и земање податоци се слични
‒ imeNaMesto: string како и за класата Pravoagolnik. Да се
+ postaviImeNaUciliste(uciliste: string) потсетиме дека за да се користат функ-
+ postaviImeNaMesto(mesto: string) циите за управување со стрингови, пот-
+ zemiImeNaUciliste(): string ребно е да се вклучи соодветната биб-
+ zemiImeNaMesto(): string лиотека со наредбата
+ prikaziUciliste() #include <string>
Слика 8.2.6

Слика 8.2.7

256
8. Класи и објекти

Слика 8.2.7 (продолжение)


На слика 8.2.8 е дадена главната функција, во која е инстанциран објек-
тот naseUciliste од класата Uciliste. Преку стринговите imeNaNaseUciliste
и imeNaNaseMesto се прочитани името на училиштето и името на местото, а по-
тоа се поставени во објектот naseUciliste со функциите postaviImeNaUcilis-
te() и postaviImeNaMesto(). Со повикување на функцијата prikaziUciliste() за
објектот naseUciliste, се добива излезот од извршување на апликацијата.

Слика 8.2.8
Еден излез од програмата е:
257
ПРОГРАМИРАЊЕ

8.2 Директен пристап до членови на класата

Во апликациите од слика 8.2.3, слика 8.2.5 и слика 8.2.8 се повикуваат


функциите за креираните објекти:
krugEden.postaviRadius(r);
dijagonala = pravoagolnikEden.zemiDijagonala();
naseUciliste.postaviImeNaUciliste(imeNaNaseUciliste);
Пристапот до функциите од јавниот дел на класата е директен со опера-
торот точка, што го објаснивме претходно. Функциите се членки на класата, ис-
то како и податоците. И пристапот до податоците може да биде директен со опе-
раторот точка, но само ако се тие јавни членови на класата.
Директен пристап до приватните податоци членови на класа не е
дозволен.

Слика 8.2.9
На пример, ако во главната функција од слика 8.2.8 ставиме наредби за
директен пристап до приватните податоци членови (слика 8.2.9), ќе добиеме
258
8. Класи и објекти

пораки за грешки, односно пораки дека пристапот до нив не е можен, слика


8.2.10.

Слика 8.2.10
Ако приватните податоци членови на класата Uciliste од подрачјето
private: ги декларираме во подрачјето public:, тогаш со извршување на глав-
ната функција од слика 8.2.9, нема да се јават овие грешки бидејќи пристапот до
јавните членови е директен.

Вежби

Вежба 8.2.1
Внесете ги дадените примери со класите Krug и Pravoagolnik.
Пробајте да додадете по една функција членка и во двата примера и нив
да ги искористите во главната програма.

Вежба 8.2.2
Напишете класа Круг, во која ќе памтите податоци за круг (ради-
усот и координатите на центарот) и напишете функции членки преку кои:
1. ќе може да ја поставите вредноста за радиусот,
2. ќе може да ги поставите вредностите за координатите на центарот,
3. ќе може да го добиете периметарот на кружницата за да го отпечати-
те,
4. ќе може да ја добиете плоштината на кружницата за да ја отпечатите,
5. *ќе пресметате растојание од координатниот почеток до најблиската
точка на кружницата.

259
ПРОГРАМИРАЊЕ

Резиме

 Нашиот реален свет се состои од објекти.


 Секој поединечен објект има свои карактеристики (атрибути), својства (спо-
собности).
 Објектите со слични својства (и/или слично однесување) и карактеристики
се од ист вид или од иста класа.
 Распоредот и зависноста на класите се нарекува хиерархија на класите.
 Секој објект има идентитет, однесување и состојба.
 Во една класа не може да има два објекти со исто име.
 При секоја акција, објектот извршува посебна функција. Атрибутите и одне-
сувањето (функциите) на еден објект се неразделни, т. е. прават една целина
– објект
 Класата претставува еден вид шема (калап, нацрт, план) по која се креираат
(инстанцираат) објекти.
 Креирањето објект од некоја класа се нарекува инстанцирање
 Интерфејсот на објектите претставува „врска“ со околината, т. е. со други
објекти.
 Класните (UML) дијаграми се состојат од три дела (правоаголници): најгоре
е името на класата, во средината се приватните членови (податоците и функ-
циите со предзнак –) и најдолу јавните членови (податоците и функциите со
предзнак +).
 Членовите на некоја класа може да бидат податоци и/или функции.
 Пристапот до јавните членови на класата (податоците и функциите) е дирек-
тен со операторот точка.
 Пристапот до јавните членки функции на класата, надвор од класата, е мо-
жен со операторот точка (.), со референцата на објектот (&) и со покажу-
вачот (*).
 Директен пристап до приватните членови на класа не е дозволен, туку само
преку јавните функции членки на класата.
 Вообичаено, за поставување и за читање вредности на податоците на некој
објект, се користат функции за поставување и функции за земање.
 Во една програма (датотека) може да се дефинираат повеќе класи.

260
9. Динамички структури на податоци

9. СТРУКТУРИ НА ПОДАТОЦИ И СТАНДАРДНА


БИБЛИОТЕКА НА ШАБЛОНИ
Во оваа глава ќе се запознаете со следното:

 Неструктурирани и структурирани податоци.


 Прости и сложени структури на податоци.
 Статички и динамички структури на податоци.
 Листи, линеарна секвенцијална листа: куп, ред.
 Стандардна библиотека на шаблони на С++.
 Функциски шаблони, класни шаблони, контејнери, итератори.
 Класен шаблон array.
 Класен шаблон vector.
 Пар и мапа.
 Контејнери адаптери.
 Алгоритми од стандардната библиотека на шаблони на С++.

Клучни зборови

FIFO – First In First Out Куп


LIFO – Last In First Out Линеарна листа
template Линеарна секвенцијална листа
Апстрактни структури на податоци Листа
Ред со два краја Мапа
Динамички структури на податоци Пар
Итератор Прости структури на податоци
Класен шаблон Ред
Класен шаблон array Сложени структури на податоци
Стандардна библиотека на шаблони на
Класен шаблон vector
C++
Контејнер Статички структури на податоци
Контејнер адаптер Стек
Кружен ред Функциски шаблон

261
ПРОГРАМИРАЊЕ

Типовите податоци може да бидат неструктурирани (наречени и прости


или примитивни) и структурирани. Простите типови податоци може да имаат
вредност само од одредено множество податоци. На пример, целобројните
типови податоци може да имаат вредност на кој било цел број од опсегот на це-
лите броеви во програмскиот јазик. Затоа, простите типови податоци се нареку-
ваат прости структури на податоци.
Прости структури на податоци се: целобројните, знаковните, логичките,
наброивите и реалните.
Структурираните типови податоци претставуваат сложени структури на
податоци составени од прости типови податоци и/или од други структурирани
типови податоци. Такви се: низата, структурата, листата, класата, записот, дато-
теката итн.
Простите структури на податоци и некои од сложените структури кои
зафаќаат фиксна меморија (како еднодимензионалните и дводимензионалните
низи) ги нарекуваме статички структури на податоци. За нив е карактерис-
тично тоа што при извршувањето на програмата, им се доделува фиксна мемо-
рија (на фиксна адреса) која тие ја задржуваат до крајот на извршување на прог-
рамата.
Оние структури на податоци, пак, на кои им се доделува меморија само
кога треба со нив да се изврши некоја операција се нарекуваат динамички
структури на податоци. Тие не се креираат на фиксни локации во меморијата,
туку на оние локации каде што има доволно слободна меморија во тој момент.
Ползата од нив е таа што се штеди меморија бидејќи тие може динамички да се
бришат од меморијата за време на извршување на програмата кога веќе не се
потребни. Ако треба повторно да се извршат некои операции со таква структура,
таа повторно се креира, но не на истото место во меморијата, туку онаму каде
што има слободна меморија во тој момент.
Динамичките структури на податоци најчесто се користат за симулација
на објекти од реалниот живот. Овие структури се нарекуваат и апстрактни
структури на податоци.
Најчесто користени динамички структури на податоци се: динамичка
низа, листа, поврзана листа, куп, ред и дрво.
Дефиницијата на динамичките структури подразбира математичко моде-
лирање и одредување на операциите над нив, а реализацијата подразбира начин
на претставување во меморијата и изведување на дефинираните операции над
нив. На пример, студентите од една студиска година можеме да ги претставиме
со различни структури на податоци, како: динамичка низа (од структури студен-
ти како променливи), поврзана листа со јазли за секој студент итн.

262
9. Динамички структури на податоци

9.1 Листи

Честопати правиме списоци, т. е. листи на разни објекти. На пример, спи-


сок на студенти, список на предмети, листа на задолженија итн. Најчесто, еле-
ментите во листата ги нумерираме линеарно, почнувајќи со 1, 2, 3 итн. Со тоа,
елементите на множеството наведени во листата ги подредуваме последователно
(линеарно) еден зад друг. Линеарното подредување значи дека секој елемент
(освен првиот) има свој претходник и свој следбеник (освен последниот).
Ако множеството елементи во листата е n и ако ја означиме листата со Х,
тогаш елементите можеме да ги нумерираме со x1, x2, x3... xn. Прв елемент во
листата е x1, а последен елемент е xn. Ваквата листа се нарекува линеарна листа.
Ако листата нема елементи (n = 0), велиме дека е празна.
Со линеарна листа може да се извршуваат следниве операции:
 Додавање елемент на почетокот од листата.
 Додавање елемент на крајот од листата.
 Бришење елемент од листата.
 Вметнување елемент во листата (помеѓу два елементи).
 Пристап до (барање на) k-тиот елемент во листа.
 Барање на сите елементи во листата кои имаат иста карактеристика.
 Подредување на елементите на листата, според некоја карактеристика
што ја имаат сите елементи.
 Инвертирање на листата (поставување на елементите во обратен редос-
лед).
 Делење на листата на две или повеќе посебни листи.
 Спојување на две или повеќе листи во една.
Реализацијата на листата како апстрактна структура се врши на повеќе
начини, според операциите кои сакаме да се изведуваат со структурата заради
постигнување поголема ефикасност. Најчесто листата се реализира како:
 динамичка низа,
 линеарна секвенцијална листа,
 линеарна поврзана листа.

9.2 Линеарни секвенцијални листи

Карактеристика на секвенцијалните листи е тоа што нивните елементи во


меморијата се сместуваат секвенцијално (последователно), почнувајќи од некоја
адреса. Тоа значи дека меѓу нив нема празни локации или локации пополнети со
други податоци.
Основни операции со линеарните секвенцијални листи се:
 Ставање (вметнување) елемент.
 Бришење елемент.
263
ПРОГРАМИРАЊЕ

Ставање (вметнување) елемент во линеарна секвенцијална листа на


која било позиција се врши со претходно поместување на елементите од таа по-
зиција до крајот за едно место надесно (според индексите).
Секвенцијалната листа може да ја претставиме како низа:
1 2 3 4 5 6 7 8 9 10 k ‒1 k k+1 . . . m
x . . .
Подалгоритамот за ставање (вметнување) елемент со вредност t на k-тата
позиција во секвенцијалната листа x[]m е даден на слика 9.2.1.
подалгоритам СтавањеЕлементВоСекЛиста( x,  m,  k,  t)
почеток
m  m +1;
за i  m намалувај до k + 1
x i  xi ‒ 1;
крај_за {i}
xk  t;
крај {СтавањеЕлементВоСекЛиста}
Слика 9.2.1
Бришење елемент од линеарна секвенцијална листа се врши така што
се поместуваат сите елементи по него за едно место налево. Според индексите, i-
тиот елемент е полево од (i + 1)-виот елемент. На слика 9.2.2 е даден подалгори-
тамот за бришење на k-тиот елемент од секвенцијалната листа x[]m.
подалгоритам БришењеЕлементОдСекЛиста( x,  m,  k)
почеток
за i  k зголемувај до m ‒ 1
xi  xi + 1;
крај_за {i}
m  m ‒ 1;
крај {БришењеЕлементВоСекЛиста}
Слика 9.2.2
9.2.1 Куп

Куп (англ. stack) е линеарна секвенцијална листа која се карактеризира со


операциите кои може да се извршуваат со неа.
Елементи во купот се додаваат според стратегијата на работа наречена
„последен влезен, прв излезен“ (англ. LastIn FirstOut ‒ LIFO). Тоа значи дека
нов податок во купот се става секогаш по последниот ставен податок, а вадењето
(земањето) податоци се врши во обратен редослед од ставањето. Прв се зема
последниот ставен податок.
За да се следи пополнетоста на купот, се користи т.н. куп-покажувач, кој
секогаш покажува на последниот ставен податок.
На слика 9.2.1.1 е даден графички приказ на куп со m елементи.
264
9. Динамички структури на податоци

Купот може да се дефинира како структура


на податоци која зафаќа посебна (резервирана за
него) меморија со одредена големина.
Купот може да се имплементира преку ста-
тичка низа (како во примерот во продолжение), а и
преку динамичка структура, како динамичка низа,
линеарна поврзана листа1 и преку други структури.
Притоа, тој расте динамички и единствено ограни-
чување на неговата големина е големината на така-
наречената хип меморија (англ. heap).
Со купот се извршуваат следниве основни
операции:
 Иницијализација на празен куп.
 Проверка дали купот е полн.
 Ставање податок во купот (англ. push).
 Проверка дали купот е празен.
 Земање податок од купот (англ. pop).
Иницијализација на куп се врши така што
Слика 9.2.1.1
се задава куп-покажувачот да покажува на првиот
елемент или да не покажува никаде. Во вториот случај, при ставање на првиот
елемент, куп-покажувачот покажува на последниот ставен елемент.
Пред да се стави елемент во купот, треба да се провери дали купот е полн
бидејќи, во тој случај, може да дојде до преполнување и да се јави соодветна

1
*Линеарна поврзана листа е линеарна збирка од елементи наречени јазли, при што се-
кој елемент „покажува“ кон друг елемент (најчесто кон неговиот следбеник или прет-
ходник). Со тоа, на некој начин, одредени елементи се меѓусебно поврзани и оттаму доа-
ѓа терминот „поврзана“ листа. До поврзана листа се пристапува преку „покажувач“ кон
првиот јазол на листата. До секој следен јазол се пристапува преку врската која самиот
јазол ја содржи во себе, а е покажувач кон следен јазол. По конвенција, покажувачот врс-
ка во последниот јазол на листата е поставен на нула (0) за да се означи крајот на листата.
Во поврзана листа податоците се зачувуваат динамички – секој јазол се креира кога тоа е
потребно. Еден јазол може да содржи податоци од произволен тип, па дури и објекти од
други класи. Куповите и редовите (споменати подолу) се, исто така, линеарни податоч-
ни структури, па може да се разгледуваат и како верзии на линеарните поврзани листи
со одредени ограничувања.
Листите од податоци може да се зачуваат во низи, но поврзаните листи имаат не-
колку предности. Поврзаната листа е погодна кога бројот на податочни елементи кои тре-
ба да се претстават во даден момент е непредвидлив. Поврзаните листи се динамички, па
должината на листата може да се зголемува или намалува по потреба, а „стандардната“
низа во C++ има фиксирана големина уште за време на компајлирањето. Затоа, стандард-
ните низи може да се наполнат, а поврзаните листи стануваат полни само кога системот
има недоволно меморија за да ги задоволи побарувањата за динамичка алокација на ме-
морија.
265
ПРОГРАМИРАЊЕ

грешка. Исто така, пред да се земе елемент од купот, треба да се провери дали
купот е празен.
*На слика 9.2.1.2 е дадена програма со која купот се имплементира со
статичка низа, а е дефиниран како објект од класата Kup.

Слика 9.2.1.2

266
9. Динамички структури на податоци

Слика 9.2.1.2 (продолжение 1)

267
ПРОГРАМИРАЊЕ

Слика 9.2.1.2 (продолжение 2)

9.2.2 Ред

Ред (англ. queue) е линеарна секвенцијална листа во која елементите се


ставаат на крајот, а се земаат од почетокот на редот. Затоа, велиме дека фило-
зофијата нa работа на редот е „прв влезен, прв излезен“ (англ. FirsInFirstOut ‒
FIFO). Редот има два покажувачи: едниот покажува на почетокот на редот (poce-
tok), а другиот покажува на крајот на редот (kraj), слика 9.2.2.1.
Редот може да биде со фиксна големина или со неограничена големина
ако е имплементиран како поврзана листа.
Со редот се извршуваат слични операции како и со купот, и тоа:
 Иницијализација на празен ред.
 Проверка дали редот е полн.
 Ставање податок на крајот на редот.
 Проверка дали редот е празен.
 Земање податок од почетокот на редот.
Иницијализацијата се врши така што се задава покажувачот на почетокот
на редот да покажува на почетокот на структурата со која се имплементира редот
(почетокот на низата или почетокот на листата). Покажувачот на крајот на редот
268
9. Динамички структури на податоци

се иницијализира да не покажува никаде или


да покажува на првата празна позиција. Ако
не покажува никаде, тогаш при непразен ред,
се става да покажува на последниот елемент
во редот.
На слика 9.2.2.2 е дадена програмата
во која редот се имплементира со статичка
низа, а е дефиниран како објект од класата
Red. Притоа, покажувачот на почетокот на
редот покажува на првиот елемент, а пока-
жувачот на крајот на редот покажува на пос-
ледниот елемент во редот.
Да напоменеме, кога покажувачот на
крајот на редот ќе покажува на последниот
елемент на низата, а не е празен редот, се вр-
ши поместување на елементите на редот за
едно место нанапред.
Во некои имплементации, при попол-
нување на последната позиција на редот, ста-
вањето елементи може да продолжи во прва-
та позиција на редот ако таа е празна. На тој
начин, се имплементира т.н. кружен ред. Слика 9.2.2.1
Пред да се стави елемент во редот, треба да се провери дали редот е полн
(бројот на елементи е еднаков на капацитетот на редот) бидејќи, во тој случај,
може да дојде до преполнување и да се јави соодветна грешка. Исто така, пред
да се земе елемент од редот, треба да се провери дали редот е празен, т. е. бројот
на елементи е 0.
Ред може да се имплементира со низа или со поврзана листа.
На слика 9.2.2.2 е дадена програма со која редот се имплементира со
статичка низа, а е дефиниран како објект од класата Red.

Слика 9.2.2.2
269
ПРОГРАМИРАЊЕ

Слика 9.2.2.2 (продолжение 1)

270
9. Динамички структури на податоци

Слика 9.2.2.2 (продолжение 2)


271
ПРОГРАМИРАЊЕ

Слика 9.2.2.2 (продолжение 3)

Вежби

Вежба 9.2.1
Одговорете на следните прашања:
1. Што е линеарна листа?
2. *Кои се разликите меѓу линеарна секвенцијална листа и линеарна по-
врзана листа?
3. Која е разликата меѓу линеарна секвенцијална листа и куп?
4. *Која е разликата меѓу линеарна поврзана листа и куп?
5. Која е разликата меѓу куп и ред?

Вежба 9.2.2
Напишете ги следните алгоритми:
1. Напишете алгоритам за инвертирање на низата [ai]n со користење
куп.
2. Напишете алгоритам за наоѓање на обратниот број на природниот
број n со користење куп.
3. Напишете алгоритам во кој ќе се изврши ротација на низа од букви
[ai]n за k-места налево со користење на ред.

9.3 Стандардната библиотека на шаблони на C++

Во стандардната библиотека на С++ (англ. C++ Standard Library) дефи-


нирани се многу класи и структури на податоци, како низи, листи, дрва, мапи и
други. Исто така, се дефинирани и алгоритми за работа со овие структури.
Во С++ може да се дефинираат „функции“ кои ќе извршуваат исти опера-
ции врз различни типови податоци. Секоја таква функција се нарекува функ-
циски шаблон (англ. function template) и таа пред насловот ги содржи резерви-
раниот збор template и листата на параметрите ставени во аглести загради. Овде
272
9. Динамички структури на податоци

нема да навлегуваме во програмерската техника за креирање на функциски шаб-


лони. Со истиот пристап може да се дефинираат и класни шаблони кои, на некој
начин, претставуваат генерички класи.
Класните и функциските шаблони (темплејти) се општи (генерички) кла-
си и функции кои може да се користат за различни типови податоци. Нивното
користење го скратува програмирањето бидејќи извршуваат исти операции за
различни типови податоци и може да се користат во разни апликации.
Стандардната библиотека на шаблони на C++ (скратено ќе користиме
STL) содржи четири основни групи на шаблони, и тоа:
 Контејнери.
 Итератори.
 Алгоритми.
 Функции (функтори).
Во програмите се користат шаблони од сите групи. На пример, алгорит-
мите користат итератори за операции со структури на податоци кои се дефинира-
ни во контејнерите.
Ние ќе се запознаеме со првите три групи шаблони.

Вежби

Вежба 9.3.1
Одговорете на следните прашања:
1. Што е функциски шаблон?
2. Зошто треба да се користат класни и функциски шаблони?
3. Што содржи стандардната библиотека на шаблони на С++?

9.4 Контејнери
Контејнер е збирка од шаблони и алгоритми кои имплементираат општи
структури на податоци. Контејнерот е објект кој содржи други објекти и овозмо-
жува пристап до нив со користење на итератори и функции/членки.
Во контејнерите се имплементирани најчесто користените структури на
податоци, како: низа (англ. array), куп (англ. stack), ред со еден и со два краја (ан-
гл. queue, англ. deque), еднаш и двапати поврзана листа (англ. forward_list, list),
множество (англ. set), мапа (англ. map) и други.
Контејнерите во библиотеката со контејнери се распределени во катего-
рии:
 Секвенцијални контејнери (англ. sequence containers): array, vector, deque,
forward_list, list.
 Адаптери за секвенцијални контејнери (англ. sequence container adapters):
stack, queue, priority_queue.

273
ПРОГРАМИРАЊЕ

 Асоцијативни контејнери (англ. associative containers): set, map, multiset,


multimap.
 Неподредени асоцијативни контејнери (англ. unordered associative contai-
ners): unordered_set, unordered_multiset, unordered_map, unordered_mul-
timap.
Користењето на контејнерите ја олеснува работата на програмерите би-
дејќи тие се добро имплементирани, брзи се и имаат општ интерфејс кој е лесен
за користење.
Секвенцијалните контејнери се користат за структури на податоци од ист
тип, во кои елементите се линеарно подредени. Такви контејнери се:
 Стринг (стринг од знаци) (англ. basic_string).
 Низа (статичка низа) (англ. array2).
 Вектор (динамичка низа) (англ. vector).
 Листа (еднаш поврзана листа и двапати поврзана листа) (англ.
forward_list3 и list).
 Ред со два краја (англ. double-ended-queue).
Класниот шаблон basic_string е дефиниран во хедерот <string> и содржи
функциски шаблони за работа со стрингови од знаци.
Класниот шаблон array е дефиниран во хедерот <array> и содржи функ-
циски шаблони за работа со низи со фиксна должина.
Класниот шаблон vector е дефиниран во хедерот <vector> и содржи функ-
циски шаблони за работа со низи со променлива должина.
Карактеристика на класните шаблони е што тие (покрај специфичните)
имаат исто множество функции/членки. При операции со контејнери, овие функ-
ции/членки користат итератори. Итераторите се слични на покажувачите, но
многу ги олеснуваат операциите со елементите на контејнерот.

Вежби

Вежба 9.4.1
Одговорете на следните прашања:
1. Што се контејнери како дел од STL?
2. Наведете ги типовите на контејнери во STL.
3. Потсетете се за класниот шаблон vector. Наведете некои функции/-
членки на vector.

2
Воведена во С++11.
3
Воведена во С++11.
274
9. Динамички структури на податоци

9.5 Итератори

Итераторите може да покажуваат (упатуваат) на кој било елемент во еден


контејнер, но не мора да се знае позицијата на елементот. Тоа е слично како ко-
ристењето на наредбата for базирана на опсег. На пример, ако треба да ја пресме-
таме сумата на елементите на целобројната низа x[], тоа може да го направиме
без да ја знаеме должината на низата:
int x[] = {1, 3, 5, 7, 9};
int sum = 0;
for(int element: x )
sum += element;
cout << "\nSuma so C-stil niza = " << sum << endl;
Целобројната променлива element во секој циклус добива вредност на
еден елемент од низата x[], почнувајќи од првиот до последниот. Веројатно,
постои некој внатрешен итератор, т. е. некаков покажувач, кој пристапува (ги по-
сетува) до сите елементи на низата само по еднаш и нивната вредност ја додава
на променливата element.
Функциите begin() и end() се членки на секој контејнер. Функцијата be-
gin() враќа итератор кој упатува на првиот елемент во контејнерот, а функцијата
end() враќа итератор кој упатува на непостоен елемент по последниот елемент во
контејнерот. Тоа се користи за одредување на крајот на контејнерот.
Низата во претходниот сегмент може да ја декларираме како контејнер од
типот array:
array <int, 5> x = {1, 3, 5, 7, 9};
int sum = 0;
for(auto i = x.begin(); i < x.end(); i++ )
sum += *i;
cout << "\nSuma so array sablon niza = " << sum << endl;
Бидејќи променливата i нема тип, со клучниот збор auto автоматски се
декларира од типот на елементите кои ѝ се доделуваат. Во примеров, со наред-
бата
auto i = x.begin();
на i ѝ се доделува итератор што упатува на почетниот (прв) елемент во кон-
тејнерот х. Со инкрементирање i++, итераторот i пристапува до следните елемен-
ти на низата и овој итератор i e помал од итераторот кој упатува на елементот по
последниот со наредбата
x.end();
Вредноста на елементот кон кој покажува итераторот во даден момент ја
добиваме преку името на итераторот со знакот * пред него:
sum += *i;
На сличен начин, низата x[] може да се декларира како контејнер од
типот vector:
vector <int> x = {1, 3, 5, 7, 9};
275
ПРОГРАМИРАЊЕ

vector <int> :: iterator k;


int sum = 0;
for(k = x.begin(); k < x.end(); k++)
sum += *k;
cout << "\nSuma so vector sablon niza = " << sum << endl;
Постојат повеќе категории итератори, и тоа:
 Влезен (англ. input) итератор – за читање на елементите од контејнер, од
првиот до последниот, еден по еден.
 Излезен (англ. output) итератор – за печатење на елементите од контејнер,
од првиот до последниот, еден по еден.
 Итератор за напред (англ. forward) – за минување низ контејнер
повеќепати, ама само од првиот до последниот елемент, еден по еден.
 Двонасочен (англ. bidirectional) итератор – за минување низ контејнер во
двата правци, од првиот до последниот и спротивно, еден по еден.
 Итератор со случаен пристап (random access) – за минување низ контејнер
во двата правци, со произволен чекор и пристап до кој било елемент.
Во контејнерите array, vector и deque се користат итератори со случаен
пристап, во контејнерите list, set и map се користат двонасочни итерато-
ри, а во контејнерот forward_list се користи итератор за напред.

Вежби

Вежба 9.5.1
Одговорете на следните прашања:
1. За што се користи итераторот?
2. Наведете 3 категории на итератори.

9.6 Класен шаблон array


Ќе наведеме неколку основни наредби за контејнерот array.
Декларација и иницијализација на контејнерот array
array <типНаПодатоците, должинаНаНизата> имеНаНизата;
Примери:
array <int, 5> x;
x = {1, 2, 3, 4};
array <double, 3> y = {1.2, 3.45, 6.7};
array <char, 4> z = {'a', 'b', 'c', 'd'};
Со следниот програмски сегмент ќе ги отпечатиме низите. Притоа, се ко-
ристи итераторот i, кој покажува на сите елементи во контејнерот од првиот ( i =
x.begin()), до последниот (i < x.end() или i != y.end()). Низ низата може
да се минува и со целоброен бројач, од првиот елемент (z[0]), до последниот
елемент (z[z.size() ‒ 1]), функцијата size() ја дава должината на низата:
276
9. Динамички структури на податоци

cout << "\n x = { ";


for(auto i = x.begin(); i < x.end(); i++)
cout << *i << ' ';
cout << "}\n y = { ";
for(auto i = y.begin(); i != y.end(); i++ )
cout << *i << ' ';
cout << "}\n z = { ";
for(int k = 0; k < z.size(); k++)
cout << z[k] << ' ';
cout << "}\n";
Излезот по извршување на горниот сегмент ќе биде:

Со следниот програмски сегмент ќе ги илустрираме функциите:


at(), front(), back(), empty(), max_size(), fill() и swap().

...
array <char, 4> z = {'a', 'b', 'c', 'd'};
array <char, 4> w = {'q', 'w', 'e', 'r'};
cout << " z = { ";
for(int k = 0; k < z.size(); k++)
cout << z.at(k) << ' ';
cout << "}\n";
cout << "\n Prv element vo nizata e " << z.front() << endl;
cout << "\n Posleden element vo nizata e " << z.back() << endl;
cout << "\n Maksimalen broj elementi vo nizata e " << z.max_size() <<
endl;
cout << "\n Dali e nizata prazna? (1 ‒ da, 0 ‒ ne) " << z.empty() <<
endl;
cout << "\n Dve nizi so ista dolzina moze da si gi zamenat sodrzinite
" << endl;
cout << " Pred zamenata: " << endl;
cout << "z";
pecatiNiza(z);
cout << "w";
pecatiNiza(w);
z.swap(w);
cout << "Po zamenata: " << endl;
cout << "z";
pecatiNiza(z);
cout << "w";
pecatiNiza(w);

277
ПРОГРАМИРАЊЕ

cout << "\n Nizata moze da se ispolni so isti vrednosti na elementite


" << endl;
z.fill('x');
cout << "z";
pecatiNiza(z);
Овде користиме pecatiNiza(), што не е функција, туку кориснички дефи-
ниран функциски шаблон. Не се грижете ако во моментов комплетно не го раз-
бирате овој код.
template <typename T, int dolzina>
void pecatiNiza(array <T, dolzina > & x) {
cout << " = { ";
for(auto i = x.begin(); i < x.end(); i++)
cout << *i << ' ';
cout << "}\n";
}
По извршување на програмскиот сегмент, се добива:

Класниот шаблон за дводимензионална низа е


array <array <типнаподатоците, бројколони>, бројредици> именанизата;
На пример:
array <array <int, 3>, 2> x;
x = {{{1, 5, 4}, {4, ‒2, 1}}};
array <array <int, 2>, 3> a = {{{1, 2}, {4, ‒2}, {5, 1}}};

278
9. Динамички структури на податоци

9.7 Класен шаблон vector


Во овој дел ќе се потсетиме за класниот шаблон vector, со кој се запоз-
навме кога зборувавме за низи. Тука дополнително ќе споменеме уште неколку
можности кои ги нуди овој шаблон. Декларација и иницијализација на контејне-
рот vector
vector <типНаПодатоците> имеНаВекторот;
Примери:
vector <int> x;
x = {1, 2, 3, 4};
vector <double> y = {1.2, 3.45, 6.7};
vector <char> z = {'a', 'b', 'c', 'd'};
vector <long> u(3, 17); //Vektor od tri elementi sekoj so vrednost 17
vector <string> v; // Inicijalizacija so stavanje elementi na krajot
v.push_back("Avtor");
v.push_back("Gjorgji");
v.push_back("Jovancevski");
int a[] = {4, 5, 6};
int n = sizeof(a) / sizeof(a[0]);
vector <int> w(a, a + n); // inicijalizacija so niza
vector<int> t(w.begin(), w.end()); // Inicijalizacija so drug vektor
Со следниот програмски сегмент, ќе ги отпечатиме векторите x, y и z.
Притоа, се користи целобројниот итератор i, деклариран со:
vector <int> :: iterator i;
и реалниот итератор ј, деклариран со:
vector <double> :: iterator j;
Тие покажуваат на сите елементи во контејнерите х и у, од првиот
(x.begin() и y.begin()) до последниот (x.end() ‒ 1 и y.end() ‒ 1). Усло-
вот за крајот на контејнерот може да биде i < x.end() или y != y.end(). Низ
векторот може да се минува и со целобројниот бројач, од првиот елемент (z[0])
до последниот елемент (z[z.size() ‒ 1]). Функцијата size() ја дава должината на
векторот:
vector <int> :: iterator i;
cout << "\n x = { ";
for(i = x.begin(); i < x.end(); i++)
cout << *i << ' ';
vector <double> :: iterator j;
cout << "}\n y = { ";
for(j = y.begin(); j != y.end(); j++)
cout << y.at(j) << ' ';
cout << "}\n z = { ";
for(int k = 0; k < z.size(); k++)
cout << z[k] << ' ';
cout << "}\n";

279
ПРОГРАМИРАЊЕ

Векторите може да се отпечатат и со функцискиот шаблон:


template <typename T>
void pecatiVector(vector <T> &x) {
cout << " = { ";
for(auto i = x.begin(); i < x.end(); i++)
cout << *i << ' ';
cout << "}\n";
}
На пример, векторите u, v, w и t се отпечатени со наредбите:
cout << "u";
pecatiVector(u);
cout << "v";
pecatiVector(v);
cout << "w";
pecatiVector(w);
cout << "t";
pecatiVector(t);
Излезот по извршување на горните сегменти ќе биде:

Сите елементи од STL, меѓу кои и класните шаблони (како vector), имаат
цела низа од функции кои се запишани во документацијата на STL. Многу од нив
не мора да ги знаете напамет, но добро е да знаете како да ги пронајдете во до-
кументацијата, можеби да се потсетите на нивната улога или да ја осознаете нив-
ната улога и да ги искористите на вистинско место во вистинско време. На при-
мер, vector ги содржи функциите: size(), empty(), push_back(), pop_back(), front(),
back() и begin() кои имаат константна сложеност О(1) и resize(), clear(), erase(),
insert() кои имаат линеарна сложеност O(N), која зависи од бројот на елементи во
векторот или од бројот на елементи кои се внесуваат или бришат од векторот.
Дел од овие функции ќе треба правилно да ги употребите при решавањето на за-
дачите од вежбите кои следат.

Вежби

Вежба 9.7.1
Напишете програма во која внесувате низа со N елементи – цели
броеви. Потоа, ја трансформирате низата на тој начин што за секои 2 еле-
менти од оригиналната низа (прв и втор, втор и трет...) пресметувате
280
9. Динамички структури на податоци

средна вредност од двата и доколку и средната вредност е цел број го


вметнувате во низата меѓу нив.
Новодобиената низа да се отпечати на екран, да се сортира и пов-
торно да се отпечати.
Не е дозволено користење на помошни низи.
Пример:
Влез:
3
314
Објаснување: Средната вредност за 3 и 1 е 2 – значи, треба да вметнеме 2
помеѓу 3 и 1. Средната вредност за 1 и 4 е 2,5 – значи, не вметнуваме
ништо.
Излез:
3214
1234

Вежба 9.7.2
Во едно училиште има N (< 10) паралелки во прва година. Во се-
која паралелка има по одреден број ученици (< 30). За секој ученик од се-
која паралелка го знаеме моменталниот просечен успех.
Директорот одлучил најслабите ученици од секоја паралелка да
ги префрли на местото на најслабиот ученик од следната паралелка и тоа:
од првата во втората, од втората во третата... од претпоследната во пос-
ледната и од последната во првата.
Напошете програма која ќе ги внесува податоците за учениците
по паралелки и потоа на излезот ќе отпечати како изгледа просекот на
учениците по промената. За секој клас да се отпечатат просекот по уче-
ник и просекот за целата паралелка.
На крајот на внесувањето податоци за секој клас се внесува 0.
Пример:
Влез:
3
3.4 4.2 5.0 5.0 4.2 2.1 4.8 0 (овде 2.1 се менува во следниот клас)
5.0 4.7 2.3 4.0 0 (овде 2.3)
3.4 4.2 5.0 3.4 4.2 1.8 2.5 0 (овде 1.8)
Излез:
P1: 3.4 4.2 5.0 5.0 4.2 1.8 4.8
P2: 5.0 4.7 2.1 4.0
P3: 3.4 4.2 5.0 3.4 4.2 2.3 2.5
prosek na P1: 4.057
prosek na P2: 3.975
prosek na P3: 3.571
281
ПРОГРАМИРАЊЕ

9.8 Пар и мапа

Парот е комбинација од две различни вредности кои може да се и од раз-


личен тип, што се чуваат под едно заедничко име. До конкретните вредности мо-
же да се пристапи преку членовите first и second. Притоа, бидејќи е непрактично
да се иницијализираат и двата члена при самото доделување вредност на парот,
за дефинирање на одреден пар може да се искористи функцијата make_pair(val1,
val2).

За да може да се користи пар, потребно е да се вклучи соодветната дато-


тека #include <utility>. Но, како што може да забележите од примерот даден по-
горе, доколку користите некој контејнер дефиниран во стандардната библиотека
на шаблони (во нашата програма тоа е вектор), потребно е само да ја вклучите
датотеката во која е дефиниран контејнерот. Притоа, автоматски ќе биде вклуче-
на и датотеката во која е дефиниран pair.
Важно е да знаете дека за паровите се веќе имплементирани сите операто-
ри за споредба (==, !=, <, <=, >, >=). Дополнително, може да се користат и алго-
ритмите од STL за кои е потребна дефиниција за начинот на споредба, на пример
sort(pocetok, kraj). Споредбата се врши на тој начин што најпрвин се споредува
првата вредност (pair.first) и елементите се подредуваат според неа. Единствено
доколку првата вредност е еднаква, се споредува втората вредност (pair.second) и
елементите (кои имале еднаква вредност pair.first) се подредуваат според оваа
вредност.
282
9. Динамички структури на податоци

Мапа (map) претставува контејнер за чување на пар од податоци – клуч и


вредност. Да разгледаме еден пример:

При декларирање на мапите (map <string, int> m), прво го наведуваме ти-
пот на клучот (во овој случај, string), а потоа типот на вредноста (во овој случај,
int). За користење на map, потребно е вклучување на <map>.
Постојат два начини за пристапување до елемент со одреден клуч: преку
наведување на клучот во загради '[kluch]' и преку користење на функцијата find().
Притоа, функцијата find() никогаш не резултира со менување на елементите во
мапата. Од друга страна, '[kluch]' ќе креира нов пар (клуч, вредност) во мапата
доколку таков клуч не постои. Ако го користиме функцијата count(), за да
изброиме колку парови во мапата имаат клуч со одредена вредност, резултатот
ќе биде 1 (доколку постои таков клуч) или 0 (доколку не постои таков клуч).
Кај мапите применливи се функциите: size(), empty(), begin() и end() кои
имаат константна сложеност O(1), функциите insert(), erase(), find(), count(),
lower_bound() и upper_bound() кои имаат логаритамска сложеност O(logN), како и
Функцијата clear() која има линеарна сложеност O(N).

Вежби

Вежба 9.8.1
На влез во програма добиваме информација за оценката што ја
имаат сите ученици од класот по Програмирање. Да се отпечатат оценки-
те на првите тројца, според абецеден редослед.
Пример:
Влез:
5
Pero 4
Tanja 5
283
ПРОГРАМИРАЊЕ

Andrej 3
Toni 2
Ana 4
Излез:
Ana 4
Andrej 3
Pero 4

9.9 Контејнери адаптери

Ред со два краја (англ. deque) претставува STL-контејнер многу сличен на


vector. Всушност, редот со два краја ги нуди истите функции како и векторот, a
дополнително овозможува и ефикасно додавање (и бришење) на елементи од по-
четокот на редот, со функциите push_front() и pop_front() (двата се со константна
сложеност O(1)). За да користиме deque, мора во програмата да ја ставиме
директивата #include <deque>.
За разлика од векторите, во кои елементите се сместуваат како кај стан-
дардните низи, имплементацијата на редот со два краја е како линеарна поврзана
листа. Тоа значи дека неговите елементи може да бидат „расфрлени“ низ ме-
моријата, а тоа го прави управувањето со меморијата многу посложено. Поради
ова, иако и двата контејнера ги нудат истите функции со иста сложеност, докол-
ку нема потреба да додаваме или бришеме елементи од почетокот на редот,
секогаш треба да го користиме контејнерот вектор.
На следниот програмски сегмент се гледа едноставна примена на deque.
deque<int> d;
for(int i = 0; i < 3; i++)
d.push_back(i); // po zavrshuvanjeto d = {0, 1, 2}
for(int i = 0; i < 4; i++)
d.push_front(i); // po zavrshuvanjeto d = {3, 2, 1, 0,
// 0, 1, 2}
Во стандардната библиотека на шаблони, купот (stack) и редот (queue)
претставуваат контејнери адаптери, што претставуваат структури кои во позади-
на користат друг контејнер за имплементирање на потребните функции. Ако не е
поинаку дефинирано, контејнер кој е основа за овие два контејнери адаптери е
ред со два краја (deque).
Редот ги нуди функциите: empty(), size(), front (за пристап до следниот
елемент за извлекување), back() (за пристап до последниот додаден елемент),
push() (за додавање/набивање на нов елемент) и pop() (за извлекување/избивање
на следниот елемент).
Купот ги нуди функциите empty(), size(), top() (за пристап до следниот
елемент за извлекување, т. е. до последниот додаден елемент), push() (за дода-

284
9. Динамички структури на податоци

вање/набивање на нов елемент) и pop() (за извлекување/избивање на следниот


елемент).
Да не заборавиме да вклучиме <stack> и <queue> ако ги користиме овие
шаблони.

Вежби

Вежба 9.9.1
Напишете програма за инвертирање на низата [ai]n со користење
куп.

Вежба 9.9.2
Напишете алгоритам за наоѓање на спротивниот број на природ-
ниот број n со користење куп.

Вежба 9.9.3
Напишете програма во кој ќе се изврши ротација на низата од
букви [ai]n за k-места налево со користење на ред.

9.10 Алгоритми од стандардната библиотека на шаблони


на C++

Библиотеката на алгоритми од стандардната библиотека на шаблони на


C++ содржи алгоритми (функциски шаблони) за операции со контејнери со ко-
ристење итератори. При нивното користење, потребно е да се вклучи хедерот
<algorithm>.
Алгоритмите се категоризирани според примената. За секоја категорија,
ќе наведеме по неколку функциски шаблони:
 Немодификувачки алгоритми – кои не ги менуваат вредноста и
редоследот на елементите во контејнерот:
o for_each – наредба за повторување за сите елементи од контејнерот.
o foe_each_n – наредба за повторување за првите n елементи од
контејнерот.
o count, count_if – го враќа бројот на елементи кои задоволуваат
одреден услов во контејнерот.
o find, find_if, find_if_not – го наоѓа првиот елемент кој задоволува
одреден услов во даден опсег.
o find_first_of – го наоѓа првото појавување на елемент од даден опсег
во друг опсег.
o search – барање опсег од елементите во контејнерот.
o search_n – барање опсег од n елементи со иста вредност во
контејнерот.
285
ПРОГРАМИРАЊЕ

 Модификувачки алгоритми – кои ги менуваат вредноста и редоследот на


елементите во контејнерот:
o copy, copy_if – копирање опсег на елементите од контејнерот.
o copy_n – копирање на првите n елементи од контејнерот.
o move – пренесување опсег на елементите од контејнерот.
o move_backward ‒ пренесување опсег на елементите од контејнерот,
но во спротивен редослед.
o remove, remove_if – отстранување (бришење) на елементите кои
задоволуваат одреден услов од контејнерот.
o replace, replace_if – замена на вредноста на елементите, кои
задоволуваат одреден услов со друга вредност.
o swap – замена на вредностите на два објекта.
o swap_ranges – замена на два опсези на елементите.
o reverse, reverse_copy – промена на елементите од даден опсег во
спротивен редослед (и копирање).
o rotate – ротирање на елементите од даден опсег налево или надесно.
o shift_left, shift_right – поместување (шифтување) на елементите од
даден опсег налево или надесно.
o unique, unique_copy – отстранување (бришење) на дупли елементи од
даден опсег (и копирање).
 Алгоритми за поделба на елементите на контејнерот, според некој услов:
o partition, partition_copy – поделба на елементите од даден опсег на
две групи, според некој услов (и копирање).
o partition_point – одредување на точката на поделба од даден опсег на
две групи.
 Алгоритми за сортирање на елементите на контејнерот:
o is_sorted – проверка дали даден опсег од елементи е сортиран во
растечки редослед.
o is_sorted_until – наоѓање на најголемиот сортиран подопсег.
o sort – сортирање на даден опсег во растечки редослед.
o partial_sort – сортирање на првите n елементи од даден опсег.
o merge – сортирање со мешање на два сортирани опсези.
 Бинарно барање во сортиран контејнер:
o low_bound – враќа итератор на првиот елемент не помал од дадена
вредност.
o upper_bound – враќа итератор на првиот елемент поголем од
одредена вредност.
o binary_search ‒ бинарно барање елемент во контејнер.
 Алгоритми за наоѓање минимум и максимум:
o max – го враќа поголемиот од два елементи.
o min – го враќа помалиот од два елементи.
o max_element – го враќа најголемиот елемент од контејнер.
286
9. Динамички структури на податоци

o min_element – го враќа најмалиот елемент од контејнер.


o minmax – ги враќа поголемиот и помалиот од два елементи.
o minmax_element – ги враќа најголемиот и најмалиот елемент од
контејнер.
 Алгоритми за споредба:
o equal – споредба дали две множества се еднакви.
o lexicographical_compare – враќа true ако еден опсег елементи е
лексикографски помал од друг опсег.
 Нумерички алгоритми:
o iota – исполнува даден опсег елементи со последователни вредности,
почнувајќи од некоја почетна вредност.
o accumulata – ја враќа сумата на елементите од некој опсег во
контејнерот.
o inner_product – го враќа скаларниот производ на елементите од два
опсези.
o partial_sum – ја враќа сумата на елементи од некој опсег во
контејнерот.
Во С++ има и многу други библиотеки, како:
<cmath>, <numbers>, <complex>, <numeric>, <iterator> и др.
Во библиотеката <numeric> интересни се функциските шаблони4:
gcd – го дава НЗД за два броја.
lcm – го дава НЗС за два броја.
Во библиотеката <iterator> интересни се функциските шаблони:
advance – го поместува итераторот за n места понапред.
distance – го дава растојанието помеѓу два итератори.
prev, next – го дава итераторот на претходниот (следниот) еле-
мент.
Некои од наведените функции се илустрирани со следниот Пример
9.10.1.

4
За да се користат најновите измени, дополнувања и нови функции во
MSVS2019, потребно е да се селектира:
Project > Properties > C/C++ > Language > C++ Language Standard >...

287
ПРОГРАМИРАЊЕ

Пример 9.10.1
Во овој пример ќе ги користиме функциските шаблони за печатење кон-
тејнер (низа, вектор), како и функцискиот шаблон sort() од библиотеката
<algorithm>.
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <iomanip>
usingname space std;

template <typename T>


void citanjeContainer(T&);
template <typename T>
void PecatenjeContainer(T& x);

int main() {
const int n = 5;
array <int, n> a;
cout << "\nKontejner: array <int, n>" << endl;
citanjeContainer(a);
cout << "\nNesortirana niza:\t"; PecatenjeContainer(a);
sort(a.begin(), a.end());
cout << "Sortirana niza:\t\t"; PecatenjeContainer(a);

array <double, n> b;


cout << "\nKontejner: array <double, n>" << endl;
citanjeContainer(b);
cout << "\nNesortirana niza:\t"; PecatenjeContainer(b);
sort(b.rbegin(), b.rend());
cout << "Sortirana niza:\t\t"; PecatenjeContainer(b);

vector <char> c(n);


cout << "\nKontejner: vector<char>" << endl;
citanjeContainer(c);
cout << "\nNesortiran vektor:\t"; PecatenjeContainer(c);
sort(c.begin(), c.end());
cout << "Sortiran vektor:\t"; PecatenjeContainer(c);

vector <string> d(n);


cout << "\nKontejner: vector<string>" << endl;
citanjeContainer(d);
cout << "\nNesortiran vektor:\t"; PecatenjeContainer(d);
sort(d.rbegin(), d.rend());
cout << "Sortiran vektor:\t"; PecatenjeContainer(d);

288
9. Динамички структури на податоци

cout << endl;


system("Color 17");
system("pause");
return 0;
}

template <typename T>


void citanjeContainer(T& x) {
cout << "Vnesete gi elementite na kontejnerot: " << endl;
for(auto i = x.begin(); i < x.end(); i++) {
cout << "x[" << distance(x.begin(), i) << "] = ";
cin >> *i;
}
cin.ignore();
}

template <typename T>


void PecatenjeContainer(T& x) {
typename T :: iterator i;
cout << " = {";
for(auto i = x.begin(); i < x.end(); i++)
cout << setw(8) << *i;
cout << "\t}\n";
}

Вежби

Вежба 9.10.1
Одговорете на следните прашања:
1. Наведете 3 категории на алгоритми од STL.
2. Објаснете преку пример како би се употребил алгоритамот find_if().
3. Објаснете преку пример како би се употребил алгоритамот repla-
ce_if().
4. Објаснете преку пример како би се употребил алгоритамот parti-
al_sort().

289
ПРОГРАМИРАЊЕ

Резиме

 Постојата статички и динамички структури на податоци.


 Динамички структури на податоци се: динамичка низа, листа, поврзана
листа, куп, ред и дрво.
 Линеарните листи може да бидат секвенцијални (куп, ред) и поврзани.
 Елементи во купот се додаваат според стратегијата на работа наречена
„последен влезен, прв излезен“ (англ. Last In First Out ‒ LIFO).
 Елементи во редот се додаваат според стратегијата на работа наречена
„прв влезен, прв излезен“ (англ. Firs In First Out ‒ FIFO).
 Функциите кои извршуваат исти операции врз различни типови подато-
ци се нарекува функциски шаблони.
 Во стандардната библиотека на шаблони во С++ постојат четири основни
групи на шаблони: контејнери, итератори, алгоритми и функции (функто-
ри).
 Контејнер е збирка од шаблони и алгоритми кои имплементираат општи
структури на податоци.
 Користењето на контејнерите ја олеснува работата на програмерите би-
дејќи тие се добро имплементирани, брзи се и имаат општ интерфејс кој е
лесен за користење.
 Итераторите се како покажувачите и може да покажуваат (упатуваат) на
кој било елемент во еден контејнер, но не мора да се знае позицијата на
елементот.
 Најчесто користени класни шаблони се array и vector.
 Парот е комбинација од две различни вредности кои може да се и од раз-
личен тип, што се чуваат под едно заедничко име.
 Мапа претставува контејнер за чување на пар од податоци – клуч и вред-
ност.
 Библиотеката на алгоритми од стандардната библиотека на шаблони на
C++ содржи алгоритми (функциски шаблони) за операции со контејнери
со користење итератори.

290
10. Алгоритми кај низи и графови

10. АЛГОРИТМИ КАЈ НИЗИ И ГРАФОВИ

Во оваа глава ќе се запознаете со следното:

 Барање податоци во низи: секвенцијално барање, барање со чекор,


бинарно барање, интерполациско барање.
 Сортирање податоци, функција на сортирање.
 Методи за сортирање:
 сортирање со споредување,
 сортирање со наоѓање на најмалиот (или најголемиот) елемент,
 сортирање со вметнување (линеарно вметнување, бинарно
вметнување),
 сортирање со алгоритамот на Шел,
 сортирање со меурче,
 брзо сортирање.
 Графови, темиња, ребра и типови на графови.
 Претставување на граф.
 Пребарување низ граф (прво по длабочина или прво по широчина).

Клучни зборови

Барање податоци Ребро


Барање со чекор Секвенцијално барање
Бинарно барање Сортирање податоци
Брзо сортирање Сортирање со бинарно вметнување
Граф Сортирање со кофи
Дрво Сортирање со линеарно вметнување
Интерполациско барање Сортирање со меурче
Сортирање со наоѓање на најмалиот
Листа на соседство елемент
Сортирање со споредување на
Матрица на соседство елементите

Тежински граф
Неориентиран граф
Теме
Пребарување граф прво по длабочина Функција на сортирање
Пребарување граф прво по широчина
291
ПРОГРАМИРАЊЕ

10.1 Барање податоци

Честопати, во некоја датотека со податоци треба да се најде некој пода-


ток: број, збор, реченица или цел запис. За таа цел, се развиени голем број алго-
ритми за барање податоци. Нивната ефикасност се состои во брзината на наоѓање
на податоците.
Постојат повеќе алгоритми за барање кои се разликуваат по својата сло-
женост. Во овој поднаслов ќе се задржиме само на неколку од нив, а ќе ги илус-
трираме на барање податоци во низа.

10.1.1 Секвенцијално барање

Алгоритамот за секвенцијално барање (англ. Sequential search) е најчесто


користен во секојдневниот живот бидејќи вообичаено бараме последователно од
почетокот натаму. Но алгоритамот е многу неефикасен за машинско барање би-
дејќи, во најлош случај, е потребно да се извршат онолку споредби колку што
има елементи множеството во кое се бара.
Програмата е дадена на слика 10.1.1.1.

Слика 10.1.1.1
292
10. Алгоритми кај низи и графови

Слика 10.1.1.1 (продолжение)


Алгоритамот за секвенцијално барање може да се забрза со претходно
сортирање на низата. Во тој случај, алгоритамот ќе заврши со наоѓање на елемен-
тот со бараната вредност или со доаѓање до елементот чија вредност е помала од
вредноста на бараниот елемент (ако низата е сортирана во нерастечки редослед),
односно до елементот чија вредност е поголема од вредноста на бараниот еле-
мент (ако низата е сортирана во неопаднувачки редослед).
Постои уште еден начин на забрзување на секвенцијалното барање, а тоа
е кога е позната веројатноста на барање на елементите што се бараат. Да прет-
поставиме дека во множеството елементи многу почесто се бараат елементите со
одредена вредност. Во тој случај, елементите за кои веројатноста да се бараат е
најголема се поставуваат на почетокот, а целта е при следното барање на некој од
тие елементи, тој да се најде побрзо.
Еден пример од извршувањето на програмата е:

10.1.2 Барање со чекор

Алгоритамот барање со чекор (англ. Jump search) се користи за барање е-


лемент во сортирана низа. Ќе претпоставиме дека низата а[]n е сортирана во нео-
паднувачки редослед. Нека се бара елементот со вредност v. Нека чекорот на
барањето е c. Ги споредуваме елементите на позициите 1, 1 + c, 1 + 2c, 1 + 3c... со
v додека не дојдеме до елементот кој има поголема вредност од v. Да прет-
поставиме дека тоа е елементот на позиција q. Со тоа го одредуваме интервалот
293
ПРОГРАМИРАЊЕ

[q – c, q] во кој се наоѓа елементот со вредност v. За наоѓање на елементот во тој


интервал, можеме да користиме и секвенцијално барање.
На овој начин, се скратува интервалот за секвенцијално барање на c еле-
менти, што е многу побрзо отколку да се бара во сите n елементи.
Алгоритамот е даден на слика 10.1.2.1. Во него користиме подалгоритам
за секвенцијално барање во интервалот [dolna, gorna], кој ќе го наречеме Sekven-
cionalnoBaranje(dolna, gorna);. Овој подалгоритам читателот може лесно да го
направи според алгоритамот од слика 10.1.1.1.
алгоритам БарањеСоЧекор
почеток
a: низа[1..n] од реален;
печати „Внесете го бројот на елементите во низата, n = “;
читај n;
заi  1зголемувај до n
читај ai;
крај_за {i}
печати „Внесете ја вредноста на податокот што го барате, v = “;
читај v;
печати „Внесете го чекорот, c = “;
читај c;
i  –c;
повторувај
i  i + c;
додека i  n И ai < v;
dolna  i –c; {за i = 1 + c, dolna = 1, за i > 1, dolna = i – c + 1}
gorna  i;
ако dolna < 0
тогаш
dolna  0;
крај_ако {dolna < 0}
ако i > n
тогаш
gorna  n;
крај_ако {i > n}
СеквенционалноБарање(dolna, gorna);
крај {БарањеСоЧекор}
Слика 10.1.2.1
Во програмата на слика 10.1.2.2 се користат и две функции од типот void,
и тоа за читање и за печатење низа.
Бројот на споредби во алгоритамот за барање со чекорот c изнесува:

294
10. Алгоритми кај низи и графови

 n  – бројот на споредби за одредување на интервалот,


 c 
c – бројот на споредби при секвенцијалното барање.
Оптималната вредност на c  n . Барањето со овој чекор се нарекува
квадратно барање.
Ако n е многу големо, тогаш интервалот со должина c е пак голем. Затоа,
и во тој интервал може да користиме квадратно барање со чекор помал од c, т. е.
со чекорот c . Во тој случај, сложеноста на алгоритамот се намалува. Читателот
нека испита колкава ќе биде сложеноста на алгоритамот ако користиме квад-
ратно барање во секој помал интервал.

Слика 10.1.2.2
295
ПРОГРАМИРАЊЕ

Слика 10.1.2.2 (продолжение)


Еден излез од програмата е:

296
10. Алгоритми кај низи и графови

10.1.3 Бинарно барање


Алгоритамот бинарно барање (англ. Binary search) се однесува на барање
елемент со вредност v во сортирана низа. Да претпоставиме дека низата има n
елементи и дека е сортирана во неопаднувачки редослед. Прво се споредува еле-
ментот v со вредноста на средниот елемент во низата. Ако v е поголем од него,
тогаш се бара во десната половина на низата, инаку се бара во левата половина.
Постапката се повторува така што v се споредува со вредноста на средниот
елемент во десната или во левата половина, зависно од тоа каде продолжило ба-
рањето. Како резултат од второто споредување, постапката продолжува во тре-
тата или четвртата четвртина на низата или во првата или втората четвртина на
низата. Постапката завршува кога ќе го најдеме елементот со вредност v или кога
ќе дојдеме до ситуација од која ќе заклучиме дека во низата нема елемент со
вредност v.
Итеративен подалгоритам за бинарно барање е даден на слика 10.1.3.1.
подалгоритам BinarnoBaranje( a,  n,  v)
почеток
levo  1;
desno  n;
повторувај
levo + desno + 1
sredina  [ ];
2
ако asredina = v
тогаш
врати sredina;
инаку
ако v > asredina
тогаш
levo  sredina + 1;
инаку
desno  sredina – 1;
крај_ако {v > asredina}
крај_ако {asredina = v}
додека levo  desno;
крај_повторувај {levo  desno}
врати „Нема елемент со таква вредност. “;
крај {BinarnoBaranje}
Слика 10.1.3.1

297
ПРОГРАМИРАЊЕ

Пример
Во низата {4, 7, 12, 14, 16, 21, 32} го бараме елементот со вредност v = 16.
levo desno sredina a1 a2 a3 a4 a5 a6 a7
4 7 12 14 16 21 32
1 7 4 (= (1 + 7 + 1) / 2)
16 > 14 (= a4)
5 (= 4 + 1) 6 (= (5 + 7 + 1) / 2) 16 21 32
16 < 21 (= a6)
5 (= 6 – 1) 5 (= (5 + 5 + 1) / 2) 16
16 = 16 (= a5)
Програмата е дадена на слика 10.1.3.2.

Слика 10.1.3.2
298
10. Алгоритми кај низи и графови

Слика 10.1.3.2 (продолжение)


Пример за излез од програмата е:

299
ПРОГРАМИРАЊЕ

Забелешка: Во понатамошните програми, функциите citajNiza() и peca-


tiNiza() од типот void нема да ги прикажуваме.

Вежби

Вежба 10.1.1
Преработете ги претходните програми за барање елемент во низа,
со користење на вектор наместо на низа. Таму каде што е потребно низа-
та да биде сортирана искористете соодветен алгоритам од STL.

Вежба 10.1.2
Напишете програма за бинарно барање на елемент во низа.

Вежба 10.1.3
Применете го алгоритамот binary_search() на несортирана низа.
Објаснете што сте забележале.

10.2 Сортирање податоци

Сортирањето (англ. sorting) е постапка за подредување (сортирање) на


елементите на некое множество податоци во определен редослед. Секојдневно
користиме сортирани податоци, како: речници, телефонски именик, ранг-листа
итн.
Сортирањето на некое множество податоци се врши со цел да се забрза
процесот на барање податоци. При секоја обработка на податоци, потребно е
тие претходно да се најдат, а потоа врз нив да се изврши некоја операција. Кога
се работи за големо множество податоци, времето на барање одреден податок
може да биде многу долго. Со сортирање на множеството податоци во некаков
редослед, тоа време многу се скратува.
Сортирањето можеме да го дефинираме на следниов начин:
Нека се дадени множеството X = {x1,x2… xn} и функцијата f дефинирана
над множеството Х.
Под сортирање на елементите од множеството Х се подразбира нивно
подредување во одреден редослед xa,xb… xp,xq, во кој a, b... p, q се елементи од
множеството {1, 2, 3... n}, при што е исполнето едно од неравенствата:
f(xa)  f(xb) ...  f(xp)  f(xq) за неопаднувачко сортирање,
f(xa) < f(xb) <... < f(xp) < f(xq) за растечко сортирање,
f(xa)  f(xb) ...  f(xp)  f(xq) за нерастечко сортирање,
f(xa) > f(xb) >... > f(xp) > f(xq) за опаднувачко сортирање.
Функцијата f се нарекува функција на сортирање.
Сортирањето можеме да го поделиме во две основни групи, и тоа:

300
10. Алгоритми кај низи и графови

 Внатрешно сортирање (кога елементите се наоѓаат во внатрешната


меморија на компјутерот и има директен пристап до нив).
 Надворешно сортирање (кога елементите се наоѓаат на надворешната
меморија (диск, CD, DVD итн.) и пристапот до нив е секвенцијален).
Во зависност од операциите кои се извршуваат врз елементите при сорти-
рањето, тоа може да биде:
 Сортирање со споредување (кога ги користиме операторите < , > , = за
споредување на два податоци).
 Сортирање со трансформација (кога се користат аритметичките операции
врз некој податок од елементот на множеството).
Ние ќе се задржиме само на алгоритмите за сортирање со споредување.
Елементите на множеството кое се сортира може да бидат од структури-
ран или неструктуриран тип.
Елементите од неструктуриран тип имаат само еден податок и сорти-
рањето се врши по него.
Елементите од структуриран тип имаат повеќе податоци и тогаш се из-
бира еден по кој се врши сортирањето. На пример, елементите на списокот сту-
денти (индекс, име, презиме и група), можеме да ги сортираме по кој било од тие
податоци. Затоа, кога се работи за множество елементи од структуриран тип, се
избира еден од податоците и тој се нарекува клуч. Притоа, велиме дека сортира-
њето се врши по клучот.
Алгоритмите за сортирање треба да исполнуваат два главни критериуми:
а) Што помал број на споредби и размени на елементите.
б) Користење на помала дополнителна меморија.
Бидејќи денес компјутерската меморија може да се смета дека е доволно
голема, ефикасноста на алгоритмите за сортирање се одредува по првиот крите-
риум.
Кога дискутиравме за низи, веќе кажавме едноставни алгоритми за сорти-
рање на стандардна низа. Во продолжение, ќе ги наведеме поважните алгоритми
за сортирање податоци.

301
ПРОГРАМИРАЊЕ

10.2.1 Сортирање со споредување на елементите

Овој алгоритам е најмалку ефикасен бидејќи се врши споредување на сите


парови елементи од множеството. На пример, за сортирање на три броја a, b и c
во неопаднувачки редослед, дрвото на споредби изгледа како на слика 10.2.1.1.

Слика 10.2.1.1
Алгоритамот е даден на слика 10.2.1.2.
Од дрвото на споредби и од алгоритамот се гледа дека бројот на излезни
решенија е 6. Со подетална анализа, може да се заклучи дека за множество од n
елементи има вкупно n! излезни решенија. Затоа, овој алгоритам е многу неефи-
касен.
алгоритам СортирањеНаТриБроја
почеток
печати „Внесете три броја a, b и c: “;
читај a, b, c;
ако a < b
тогаш
ако b < c
тогаш
печати a, b, c
инаку
ако a < c
тогаш
печати a, c, b
инаку
печати c, a, b;
крај_ако {a < c}
крај_ако {b < c}
инаку
ако b > c
тогаш
302
10. Алгоритми кај низи и графови

печати c, b, a
инаку
ако a > c
тогаш
печати b, c, a
инаку
печати b, a, c;
крај_ако{a > c}
крај_ако {b > c}
крај_ако {a < b}
крај {СортирањеНаТриБроја}
Слика 10.2.1.2
10.2.2 Сортирање со наоѓање на најмалиот (или
најголемиот) елемент

Алгоритамот за сортирање со наоѓање на најмалиот елемент (англ. Se-


lection sort) се користи за наоѓање на најмалиот (или најголемиот) елемент во ни-
за. Ако се врши сортирање со наоѓање на најмалиот елемент, тогаш сортирањето
е во неопаднувачки редослед, а ако се врши сортирање со наоѓање на најголеми-
от елемент, сортирањето е во нерастечки редослед.
Постапката е едноставна. Прво, од сите елементи се наоѓа најмалиот
(најголемиот) и се става на првата позиција. Потоа, од останатите елементи се
наоѓа најмалиот (најголемиот) и се става на втората позиција. Постапката завр-
шува кога ќе се стави најмалиот (најголемиот) елемент од последните два на по-
зиција (n – 1).
Малку поефикасен алгоритам е кога се врши сортирање со истовремено
наоѓање на најмалиот и на најголемиот елемент од несортираната подниза.
Постапката е следна: се наоѓаат најмалиот и најголемиот елемент од елементите
од a1 до an. Најмалиот се става на прво место, а најголемиот на n-то место. Потоа,
се наоѓаат најмалиот и најголемиот елемент од елементите од a2 до an ‒ 1. Најма-
лиот се става на второ место, а најголемиот на (n – 1)-во место итн. На крајот,
најмалиот елемент од елементите од 𝑎[n] до 𝑎n − [n] + 1 се става на местото со ин-
2 2
n
декс n  , а најголемиот на местото со индекс (n − [2] + 1). Средните загради оз-
 2 
начуваат цел дел од количникот.
Овој алгоритам е даден на слика 10.2.2.1.
алгоритам СортирањеСоНаоѓањеНајголемИНајмалЕлемент
почеток
a: низа[1..n] од целоброен;
ЧитањеНиза(n, a);

303
ПРОГРАМИРАЊЕ

за i  1 зголемувај до  n 
 2 
за j  i зголемувај до n – i – 1
ако aj < ai
тогаш
aj  ai; {Razmena na sodrzinite}
крај_ако {aj < ai}
ако aj > an ‒ i ‒ 1
тогаш
aj  an ‒ i ‒ 1; {Razmena na sodrzinite}
крај_ако {aj > an ‒ i ‒ 1}
крај_за {j}
крај_за {i}
печати „Сортирана низа: “;
ПечатењеНиза(n,a);
крај {СортирањеСоНаоѓањеНајголемИНајмалЕлемент}
Слика 10.2.2.1
Функцијата за сортирање е дадена на слика 10.2.2.2. Функциите citajNi-
za() и pecatiNiza() се исти како во програмите за секвенцијално и за бинарно ба-
рање.
...

Слика 10.2.2.2
Главната функција е дадена на слика 10.2.2.3.

Слика 10.2.2.3
304
10. Алгоритми кај низи и графови

10.2.3 Сортирање со вметнување

Алгоритмите за сортирање со вметнување (англ. Insertion sort methods)


ќе ги објасниме на сортирање низа од n елементи, при што сортираните елементи
ќе ги ставаме во друга низа.
Постапката е следна. Ако сме сортирале к елементи, тогаш треба да го
вметнеме (к + 1)-виот елемент на соодветното место. Од начинот на одредување
на соодветното место за (к + 1)-виот елемент, разликуваме два случаи на сорти-
рање со вметнување:
а) Линеарно вметнување.
б) Бинарно вметнување.

10.2.3.1 Сортирање со линеарно вметнување


Во алгоритамот сортирање со линеарно вметнување (англ. Linear inser-
tion sort), местото на вметнување на (k + 1)-виот елемент се одредува со негово
споредување со веќе сортираните елементи, почнувајќи од првиот елемент. Кога
ќе се дојде до елементот кој не го задоволува критериумот за сортирање, прво
треба сите елементи од него понатаму да се поместат за едно место надесно и по-
тоа да се вметне (k + 1)-виот елемент.
Постапката е дадена како подалгоритам на слика 10.2.3.1.1. Во него,
вредноста t се вметнува во низата х која има m елементи.
подалгоритам ЛинеарноВметнување( x,  m,  t)
почеток
x: низа[1..m] од реален;
ако m = 0 ИЛИ t > xm
тогаш {Aко низата x е празна }
xm + 1  t {или се додава на крајот}
инаку
j  0; {Барање елемент поголем од t}
повторувај
j  j + 1;
до xj < t;
крај_повторувај {xj < t}
за k  m намалувај до j {Поместување на елементите}
xk + 1  xk ; {надесно од xm до xj}
крај_за {k}
xj  t; {Вметнување на t}
крај_ако {m = 0 ИЛИ t > xm }
m  m + 1; {Зголемување на димензијата за 1}
крај {ЛинеарноВметнување }
Слика 10.2.3.1.1
305
ПРОГРАМИРАЊЕ

Подалгоритамот се повикува од алгоритамот на слика 10.2.3.1.2.


алгоритам СортирањеСоЛинеарноВметнување
почеток
a: низа[1..n] од реален;
ЧитањеНиза(n, a);
m  0;
за i  1 зголемувај до n
t  ai;
ЛинеарноВметнување(a, m, t);
крај_за {i}
ПечатењеНиза(n, a);
крај {СортирањеСоЛинеарноВметнување }
Слика 10.2.3.1.2
Функцијата за линеарно вметнување е дадена на слика 10.2.3.1.3.
...

Слика 10.2.3.1.3
Главната програма е дадена на слика 10.2.3.1.4. Во неа е вклучена библи-
отеката <chrono> со #include <chrono>, која содржи функција за читање на вре-
мето now() и функција за прикажување на времетраењето (периодот) duration().
Зборот auto се користи при декларација на променлива за означување
дека таа има автоматско времетраење. На пример, знаеме дека локалните про-
менливи имаат живот од нивното декларирање до крајот на блокот или функци-
јата. За да се потенцира тоа, во постарите верзии на С++ често променлива се де-
кларира со
auto int m = 10;

306
10. Алгоритми кај низи и графови

Во поновите верзии (од С++ 11)1, зборот auto има друго значење. Тој се
користи за автоматско одредување на типот на променливата, според типот на
податокот со кој е иницијализирана. На пример, со наредбите:
auto k = 5;
auto p = 12.345;
auto s = "Makedonija e vecna";
компајлерот заклучува дека променливата k е од типот int, p е од типот double, а s
е од типот string.
Во програмата од слика 10.2.3.1.4 се користи клучниот збор auto за авто-
матско одредување на типот на променливите pocetok, kraj и vreme, според типот
на податоците со кои се иницијализираат.
Функциите citajNiza() и pecatiNiza() се исти како во програмите за секвен-
цијално и за бинарно барање.
...

Слика 10.2.3.1.4
Еден излез од извршување на програмата е:

1
Клучниот збор auto има и други намени вградени во поновите верзии С++ 11 и С++ 14.
307
ПРОГРАМИРАЊЕ

10.2.3.2 Сортирање со бинарно вметнување

Името бинарно вметнување во алгоритамот сортирање со бинарно


вметнување (англ. Binary insertion sort) доаѓа од постапката на барање на местото
на вметнување елемент во сортирана низа, позната како бинарно барање. Алго-
ритамот бинарно барање е објаснет во потточката 10.1.3 Бинарно барање.
Алгоритамот за сортирање на низата a[] со бинарно вметнување, користи
помошна низа b[] во која се сортираат елементите на низата a[]. За одредување на
местото на i-тиот елемент во веќе сортираните m елементи, се користи алгори-
тамот бинарно барање, слика 10.2.3.2.1.
алгоритам СортирањеСоБинарноВметнување
почеток
a, b: низа[1..n] од реален;
печати „Внесете го бројот на елементите во низата, n = “;
читај n;
за i 1 зголемувај до n
читај ai;
крај_за {i}
m  0;
за i  1 зголемувај до n
t  ai;
ако (m = 0) ИЛИ (t > bm)
тогаш
bm + 1  t {Првиот или последниот елемент}
308
10. Алгоритми кај низи и графови

инаку
БинарноБарањеПозиција(); {Најдена ј-та позиција}
за k  m намалувај до j
bk + 1  bk; {Поместување на елементите}
крај_за {k} {од m-та до j-та поз. за 1 место десно}
bj  t; {Вметнување на новиот елемент}
крај_ако{(m = 0) ИЛИ (t > bm)}
m  m + 1; {Зголемување на димензијата}
крај_за {i}
печати „Сортирана низа: “;
за i 1 зголемувај до m
печати bi;
крај_за {i}
крај {СортирањеСоБинарноВметнување }
Слика 10.2.3.2.1
Функцијата за бинарно вметнување е дадена на слика 10.2.3.2.2.
Останатите функции и главната функција се исти како во програмата од
потточката 10.2.3.1 Сортирање со линеарно вметнување. Во главната функција
се повикува функцијата binarnoVmetnuvanje(a, m, a[i]);
...

...
Слика 10.2.3.2.2

309
ПРОГРАМИРАЊЕ

Пример за излез од програмата е:

10.2.4 Сортирање со меурче

Алгоритамот сортирање со меурче (англ. Bubble sort) многу често се ко-


ристи при програмирањето, но за мали димензии на низите што се сортираат би-
дејќи не е многу ефикасен. Алгоритамот е популарен поради едноставноста и за
него веќе дискутиравме претходно. Овде ќе дадеме и малку повеќе детали и ќе
кажеме некои приспособувања на алгоритамот.
Сортирањето со меурче се состои во минување низ низата и замена на
местата на секој пар соседни елементи кои не се во саканиот редослед сѐ додека
не се подредат сите елементи, слика 10.2.4.1.
алгоритам СортирањеСоМеурче
почеток
a: низа[1..n] од реален;
печати „Внесете го бројот на елементите во низата, n = “;
читај n;
за i  1 зголемувај до n
читај ai;
крај_за {i}
brojac  2;
извршувај
zamena = „Не“;
за i  n намалувај до brojac
ако ai < ai ‒ 1

310
10. Алгоритми кај низи и графови

тогаш
ai  ai ‒ 1 ; (Замена на вредностите)
zamena = „Да“;
крај_ако {ai < ai ‒ 1}
крај_за {i}
brojac  brojac + 1;
додека brojac < n И zamena = „Да“;
крај_извршувај {brojac < n}
печати „Сортирана низа: “;
за i  1 зголемувај до n
печати ai;
крај_за {i}
крај {СортирањеСоМеурче}
Слика 10.2.4.1
Минувањето низ низата може да се врши од првиот до последниот
елемент или спротивно. Во алгоритамот на слика 10.2.4.1 минувањето се
врши одназад, т. е. од последниот кон првиот елемент. Со првото минува-
ње од последниот до вториот елемент, најмалиот елемент се доведува (ис-
пливува нагоре како меурче) на првата позиција. Со второто минување од
последниот до третиот елемент, вториот по големина елемент се доведува
(испливува нагоре како меурче) на втората позиција итн. На крајот се сор-
тираат последните два елементи од низата.
За забрзување на сортирањето, тоа се врши по повеќе патеки. Притоа,
бројот на патеките се намалува за половина додека не се дојде до една патека.
На пример, низата 7 1 9 8 2 4 3 може да се сортира по 3 патеки, и тоа:

патека 1: 7 х х 8 х х 3 сортирана со mеурче е: 7 х х 3 х х 8


3 х х 7 х х 8
патека 2: х 1 хх 2 хх сортирана со mеурче е: х 1 хх 2 хх
патека 3: хх 9 хх 4 х сортирана со mеурче е: хх4хх9х
Резултатот е: --------------------------------------> 3 1 4 7 2 9 8
Се преполовува бројот на патеки, т. е. 3 / 2 = 1 патека.
3 1 4 7 2 9 8 сортирана со меурче е:
Прво минување: 1 3 2 4 7 89
Второ минување: 1 2 3 4 7 89

311
ПРОГРАМИРАЊЕ

Пример 10.2.4.1
Да се сортира низа со алгоритамот сортирање со меурче по повеќе пате-
ки.

Во главната програма на слика 10.2.4.2 се повикува функцијата meurce()


за сортирањето со меурче.
...

... Слика 10.2.4.2


Еден излез по извршување на програмата е:

312
10. Алгоритми кај низи и графови

10.2.5 Сортирањето со кофи

Алгоритамот сортирање со кофи (англ. Bucket sort) се однесува на сорти-


рање еднодимензионална низа од позитивни цели броеви. На почетокот се фор-
мира дводимензионална низа од цели броеви со редици од 0 до 9 и колони од 0
до n – 1, n е бројот на елементи на низата. Секоја редица на дводимензионалната
низа се нарекува кофа.
Алгоритамот ќе го опишеме за низата: 87, 4, 102.
а) Секој елемент на еднодимензионалната низа се става во редица на
низата од кофи, зависно од цифрата на единици на елементот. На пример, 87 се
става во редица 7, 4 се става во редицата 4, а 102 се става во редица 2. Ова се на-
рекува чекор на распределба.
0
1
2 102
3
4 4
5
6
7 87
8
9
б) Се минува низ низата со кофи редица по редица и се копираат вреднос-
тите назад во оригиналната низа. Ова се нарекува чекор на прибирање. Новиот
редослед на претходните вредности во еднодимензионалната низа е 102, 4 и 87.

313
ПРОГРАМИРАЊЕ

в) Се повторува процесот за секоја наредна позиција на цифра (десетки,


стотки, илјадити делови итн.).
На второто поминување, 102 се става во редицата 0, 4 се става во редица-
та 0 (бидејќи 4 нема цифра за десетки) и 87 се става во редица 8.
0 102 4
1
2
3
4
5
6
7
8 87
9
По чекорот на прибирање, редоследот на вредностите во еднодимензио-
налната низа е 102, 4 и 87.
При третото поминување, 102 се става во редицата 1, 4 се става во реди-
цата нула и 87 се става во редицата 0 (по 4).
0 4 87
1 102
2
3
4
5
6
7
8
9
По последниот чекор на прибирање, оригиналната низа е сортирана.
Дводимензионалната низа од кофи зафаќа 10 пати поголема големина од
сортираната целобројна низа. Така, оваа техника на сортирање овозможува по-
добра изведба од сортирањето со вметнување, но бара многу повеќе меморија.
Сортирањето со вметнување бара простор само за еден дополнителен елемент.
Ова е пример за балансот простор – време: сортирањето со кофа користи повеќе
меморија отколку сортирањето со вметнување, но се извршува побрзо. Оваа вер-

314
10. Алгоритми кај низи и графови

зија на сортирањето со кофа бара копирање на сите податоци назад на оригинал-


ната низа на секое минување.
Постојат повеќе алгоритми кои може да се сметаат како варијанти на сор-
тирањето со кофи. Еден од тие е алгоритамот за сортирање со броење (англ.
Counting sort).
Исто така, од имплементацијата на сортирањето со кофи може да зависат
и неговата просторна и неговата временска сложеност. Значи, значајна улога
може да играат избраните структури на податоци во кои ќе се чуваат податоците
кои се сортираат.

Вежби

Вежба 10.2.1
Напишете функција која ќе имплементира алгоритам за сортира-
ње со наоѓање на најмалиот елемент. Искористете ја функцијата за да
сортирате низа внесена од стандарден влез.

Вежба 10.2.2
Со користење на кодот од Вежба 10.2.1, напишете функција која
ќе имплементира алгоритам за сортирање со наоѓање на најголемиот
елемент. Искористете ја функцијата за да сортирате низа која самите ќе ја
генерирате со функција за генерирање случајни броеви.

Вежба 10.2.3
Напишете програма за алгоритамот сортирање со кофи, според
објаснувањето во потточката 10.2.5.

Вежба 10.2.4
Истражете го алгоритамот Сортирање со броење (англ. Counting
sort). Напишете програма за овој алгоритам.

Вежба 10.2.5
Во една трафика се продаваат к (< 2 000) различни производи. За
секој од производите се знае неговата цена (цените се цели броеви во де-
нари и се помали од 50 000). Доаѓаат муштерии еден по еден и секој ку-
пува точно поеден производ.
Пред продавницата седи Марко и по ред ја запишува сумата која
ја плаќа секој од муштериите. На тој начин Марко формирал низа од цели
броеви. На крајот на денот, тој во низата запишал 0.
Напишете програма со која:
а) за даден број r ќе се отпечатат r највисоки цени кои се платени тој ден
од муштериите,
315
ПРОГРАМИРАЊЕ

б) за даден број s ќе се провери дали постои производ со цена ѕ.


Задачата треба да се реши со алгоритам со најниска можна сло-
женост. Во коментар на програмата напишете ја сложеноста за решавање
на проблемот до делот а) и сложеноста за решавање до делот б).
Пример:
Влез: Излез:
низа: 7 2 9 12 32 5 5 2 7 7 0 12 32
r 2 Da
s 5

10.3 Графови

Граф е математичка структура која се користи за претставување на врс-


ките/релациите помеѓу одредени објекти2. На пример, со помош на граф можеме
да претставиме како одредени лица се поврзани меѓусебно на социјалната мрежа
Фејсбук (кој е пријател со кого), како градовите се поврзани меѓусебно со патиш-
та, но и да ги претставиме врските кај електричните мрежи, водоводните мрежи
и слично. Понатаму, со помош на алгоритми кои се специјално дизајнирани за
работа со графови, нив можеме и да ги анализираме. Во продолжение, ќе се за-
познаеме со основните поими во теоријата на графови, но и со нивното претста-
вување при пишувањето на компјутерски програми.

10.3.1 Темиња, ребра и типови на графови

Во дефиницијата за граф дадена погоре, споменавме објекти кои може


меѓусебно да се поврзани со врски/релации. Графот се состои од темиња (или
јазли) и ребра (или рабови). Темињата, всушност, најчесто ги означуваат об-
јектите, а ребрата ги означуваат врските помеѓу објектите. На пример, доколку
разгледуваме пријателства помеѓу различни лица на социјалната мрежа Фејсбук
и сакаме нив да ги претставиме со помош на граф, темињата ќе бидат луѓето, а
за секое пријателство ќе нацртаме ребро од едното до другото лице. Нормално,
веројатно ќе имаме повеќе пријателства, па во графот ќе нацртаме онолку ребра
колку што има парови на лица кои се пријатели. Еден ваков пример е даден на
слика 10.3.1.1.

2
Темата за графови е една од темите во овој учебник кои се основа на понапредното
програмирање. На веб-страната mendo.mk се обработени и дополнителни теми, а е даден
поинаков поглед на некои од темите кои се обработени тука. На учениците (особено на
оние кои учествуваат на натпреварите по Информатика) им советуваме да ги користат и
тие онлајн материјали. Делови од оваа тема се базирани на материјалот објавен таму.
316
10. Алгоритми кај низи и графови

Може да се забележи дека ребрата


(линиите) помеѓу темињата немаат стрелка
(т. е. насока). За овие графови велиме дека
се неориентирани графови. Покрај вакви-
те графови, постојат и такви во кои на секое
ребро му придружуваме и насока. На при-
мер, графот за улиците во еден град ќе се
состои од темиња кои ги претставуваат рас-
крсниците и од ребра кои ги претставуваат
улиците помеѓу тие раскрсници. Притоа,
бидејќи некои улици во градовите се едно-
Слика 10.3.1.1 насочни (може да се вози само во една на-
сока), во графот ќе има и еднонасочни ли-
нии и двонасочни. За ваквите графови велиме
дека се ориентирани графови. Многу е важно
да кажеме дека помеѓу две темиња можно е да
постојат и повеќе ребра. На пример, во слу-
чајот кој го споменавме погоре, каде што збо-
рувавме за раскрсници и улици помеѓу нив,
сосема е нормално (и често), да постојат пове-
ќе улици помеѓу две раскрсници. Ова е прет-
ставено на слика 10.3.1.2.
При анализирање на различни пробле-
ми кои може да се претстават со помош на Слика 10.3.1.2
граф, може да се соочиме со ситуација во која
е потребно на самите ребра кои ги поврзуваат темињата да им придружиме
некоја вредност (тежина, далечина или нешто друго). На пример, ако зборуваме
за градови и улици, можеби ќе имаме информации за должината на самите
улици. Ваквите графови во кои за секое ребро е дефиниран и одреден реален број
кој ги означува неговата тежина, растојанието или некоја друга слична мерка се
нарекуваат тежински графови.
Сликите што ги цртаме од разни графови не мора точно да ги претста-
вуваат сите делови, насоки или вредности во графот. Имено, единственото нешто
што ни е важно при цртањето на графот е да ги обележиме сите информации кои
ќе ни бидат нам потребни за претставување или решавање на одреден проблем.
Сликите не мора да се совршени и многу често постојат повеќе начини да се на-
црта еден граф. На пример, одредено теме наместо на левата страна, може да го
нацртаме на десната страна од графот, зачувувајќи ги врските со останатите
темиња итн.

317
ПРОГРАМИРАЊЕ

Пред да продолжиме поната-


му, ќе кажеме за еден специфичен тип
графови. Дрво (слика 10.3.1.3) прет-
ставува неориентиран граф (ребрата
немаат насока), во кој темињата се ме-
ѓусебно поврзани со точно едно реб-
ро. Затоа, во дрвата не постои повеќе
од еден начин да се стигне од кое би-
ло теме до кое било друго теме. Ова
значи и дека дрвата не содржат цик-
луси, но и дека имаат точно (n – 1)
ребро, n е бројот на темиња. Имено, Слика 10.3.1.3
точно (n – 1) ребро се потребни за да
се поврзат n темиња, на начин што ќе постои точно еден пат помеѓу кои било две
темиња во графот.

10.3.2 Претставување на граф

При пишување програми кои работат со графови, ни треба начин за да ги


претставиме самите графови во компјутерската меморија. На пример, кои теми-
ња се поврзани со други темиња преку ребра. Иако постојат повеќе начини на
кои ова може да се изведе, ние ќе се фокусираме на двата најмногу споменувани
начини: користење на матрица на соседство (што може да се користи кога се
работи со графови кои имаат релативно мал број на темиња) и користење на
листи на соседство.
Прво да видиме како можеме да претставиме еден граф со помош на
матрица на соседство. Имено, да замислиме дека имаме граф со n темиња (n е
релативно мал број – на пример, до 100). Во ваков случај, можеме да направиме
матрица со големина n x n, во која секој елемент од матрицата (i, j) (i-ти ред, j-та
колона) ќе означува дали постои ребро помеѓу i-тото теме и j-тото теме. Ако се
работи за тежински граф, во матрицата се запишува тежината на реброто.
На слика 10.3.2.1 е претставен граф со 5 темиња и врските помеѓу нив:
Матрицата има големина 5 x 5 (5 редици и 5 колони) бидејќи графот е
составен од 5 темиња. Во матрицата постојат повеќе елементи еднакви на 0 (мо-
же да се користи и бројот ‒1 или нешто слично), со што означуваме дека не пос-
тои ребро помеѓу тој пар на темиња. Од друга страна, пак, да го разгледаме еле-
ментот во матрицата каде што е запишан бројот 4. Тој е тежина на реброто (3, 0).
Слично, од темето 3 постојат и две други ребра: (3, 2) и (3, 4) со тежина 7.
При решавањето на разни проблеми поврзани со графови, за означување
на темињата згодно е да се користат броеви (од 0 до n – 1 или, пак, од 1 до n). До-
колку темињата ни се дадени на некој друг начин (на пример, со имиња – "Кава-
дарци", "Мариово" итн), можеме да искористиме мапа (map <string, int>) за оз-
318
10. Алгоритми кај низи и графови

начување на имињата што се соодветни на дадените индекси, а потоа да про-


должиме со решавање на проблемот, како што е дадено погоре (со означување на
темињата со помош на броеви). Едноставно, компјутерите работат најефикасно
со помош на броеви, а и структурите на податоци кои се имплементирани рабо-
тат многу поедноставно и побрзо.

Слика 10.3.2.1
Вториот начин на кој може да се претстави еден граф е преку т.н. листи
на соседство. Замислете дека за секое теме во графот се чува по една листа во
која ни се запишани темињата до кои постои ребро. На пример, за графот со 5
темиња, тоа може да изгледа како на слика 10.3.2.2.

Слика 10.3.2.2
Со листите на соседство дадени на слика 10.3.2.2 имаме обележано дека
од темето 0 постојат ребра до темињата 2 и 3. Слично, од темето 2, постојат реб-
ра до темињата 0 и 4 итн. Од темето 1 не постојат ребра до ниту едно друго теме.
Доколку работиме со тежински графови, наместо листите да ни содржат само
броеви (како [2, 3]), тие може да се составени од пар од броеви, при што првиот
елемент ќе го означува темето до кое покажува реброто, а вториот број неговата

319
ПРОГРАМИРАЊЕ

тежина. На пример, [ (2, 5), (3, 7) ], со што имаме претставено дека од тоа теме
постои ребро до темето 2 (со тежина 5) и до темето 3 (со тежина 7). Се разбира,
како што споменавме и во претходната дискусија, тежините може да претставу-
ваат должина или некоја друга мерка. На пример, тежината може да претставува
проточност, т. е. колку литри вода може да се испраќаат по таа цевка во еден час
итн.
Во случај кога графот е неориентиран, кога ќе обележуваме дека постои
ребро од едно теме до друго (во листата), ќе запишеме и дека постои ребро од
тоа друго теме до првото. На пример, на слика 10.3.2.2, кај темето со индекс 0
имаме запишано дека од него постои ребро до темето 2, но и во листата на сосед-
ство за темето со индекс 2, ќе видиме дека постои ребро до темето 0. На овој
начин, алгоритмите кои ќе ги пишуваме ќе може едноставно да ги одредуваат
врските за да видат до кои темиња постојат ребра. За матрицата на соседство, ова
се сведува на запишување на истата вредност во елементите (i, j) и (j, i).

10.3.3 Пребарување низ граф прво по длабочина

Кога зборувавме за низи, рековме дека многу често низата треба да се


измине за да се направи некоја операција врз еден, врз дел или врз сите нејзини
елементи. Тоа беше релативно едноставно бидејќи во низата се знае кој елемент
следи по некој одреден елемент. За разлика од низите, графовите се несеквенци-
јална структура на податоци и мора да се најдат креативни начини за да го изми-
неме графот, односно да сме сигурни дека (ако треба) ќе пристапиме до секое
негово теме по еднаш.
Првиот алгоритам кој ќе го разгледаме е алгоритамот за пребарување низ
граф прво по длабочина (англ. depth-first search – DFS). Идејата е едноставна –
минување на сите темиња преку движење во „длабочина“, т. е. сè додека може да
се оди во одредена насока, а кога тоа веќе не е можно – минување по други па-
тишта, почнувајќи од истото теме. Кога и тоа веќе не е можно (сме ги пробале
сите патишта на минување од тековното теме), се враќаме наназад до темето пре-
ку кое сме дошле до сегашното и потоа ги проверуваме останатите непоминати
ребра. Ова е најлесно да се види преку пример, но и преку разгледување на код
бидејќи алгоритамот е мошне едноставен за имплементација. Овој алгоритам
може да се имплементира со помош на рекурзија или со користење на структу-
рата куп.
Овде ќе ја разгледаме имплементацијата со помош на структурата куп
која е делумно поефикасна и нема проблеми со надминување на мемориското
ограничување бидејќи не користи рекурзија. Идејата е едноставна – одбираме ед-
но теме од кое ќе почнеме да минуваме и него го ставаме на купот. Оттука, кога
ќе разгледуваме одредено теме од купот (со циклус, едно по едно, почнувајќи од
почетното), проверуваме дали тоа теме е можеби веќе посетено преку некој друг

320
10. Алгоритми кај низи и графови

пат, а ако не е, тогаш означуваме дека тоа теме сме го посетиле и на купот ги
додаваме сите негови соседни темиња (темиња до кои има ребра).
Имплементацијата на овој алгоритам е дадена со следната програма,
слика 10.3.3.1:

Слика 10.3.3.1
Да ја разгледаме програмата. Забележете дека за претставување на графот
користиме листи на соседство (и тоа, N од нив, vector <int> G[N]). Следно, дефи-
ницијата за тоа ја имаме напишано надвор од функцијата DFS(start). Ова е многу
често при пишувањето на вакви програми бидејќи многу е веројатно дека ќе
имаме повеќе функции кои ќе ги повикуваме, па не сакаме да го наведуваме гра-
фот како параметар на секоја од нив. Се разбира, наместо N, треба да ставиме
некој цел број (на пример, 100), кој ќе ни биде однапред даден при решавањето
на разни проблеми. (Во практика веќе ќе знаеме колку градови има во некоја
држава и слично). Секој елемент од G[] соодветствува на листата на соседи на
соодветното теме со тој индекс: G[0], G[1], G[2] итн. Во функцијата што ја напи-
шавме, при разгледувањето на секое теме (node), можеме да ги разгледаме сите
негови соседни темиња, користејќи for(auto next: G[node]).
Во програмата, покрај G[] што ни служи за чување на листите на сосед-
ство, имаме и stack за чување на темињата кои треба да ги посетиме, како и visi-
321
ПРОГРАМИРАЊЕ

ted[] за обележување на оние темиња кои се веќе посетени за да не ги посетуваме


по повеќе или дури и бесконечен број пати.

Пример 10.3.3.1
Дадени се бројот на неколку држави (до 100), како и листа од ребра кои
ќе означуваат дали постои гасовод помеѓу некои парови од нив. Сите гасоводи се
двонасочни (во проблемот кој ние ќе го решаваме), па графот ќе го гледаме како
да е неориентиран, т. е. како ребрата да немаат насока. Можно е да се случи овие
држави да се поделат во неколку групи кои меѓусебно не се поврзани. На при-
мер, ако дел од државите се наоѓаат на еден континент и постои гасоводен пат од
секоја држава до секоја друга, а дел од државите се на друг континент каде што
постои гасовод помеѓу нив, но не и до државите од првиот континент. За ваквите
изолирани групи ќе велиме дека се компоненти. Според терминологијата за гра-
фови, поврзана компонента е множество од темиња кои се меѓусебно поврзани,
т. е. постои пат помеѓу секои две од нив (преку едно или повеќе ребра).
Треба да се открие од колку компоненти е составен овој граф од држави.
Ова можеме да се реши со едноставно користење на функцијата DFS() од
слика 10.3.3.1. Имено, да замислиме дека сме ја повикале функцијата DFS() за
првото теме. Оваа функција, користејќи го алгоритамот, ќе ги обележи (во низата
visited[]) сите темиња кои се достапни со патишта. Ако по завршување на алго-
ритамот, откриеме теме во кое visited[i] = 0 (значи, не е посетено), ќе знаеме дека
тоа припаѓа на друга компонента, па ќе ја повикаме функцијата DFS() да ги обе-
лежи и темињата достапни оттаму. Слично, можеме со еден циклус for ова да го
направиме за сите темиња. Резултатот од алгоритамот ќе биде тоа што функци-
јата DFS() ќе ја повикаме онолку пати колку што имаме изолирани компоненти
во графот бидејќи нема да ја повикаме за некое теме што е веќе visited[i] = 1,
значи што е веќе посетено. Единствена промена што ќе треба да ја направиме во
однос на алгоритамот даден на слика 10.3.3.1, ќе биде да ја извлечеме низата
visited[N] надвор од функцијата DFS() бидејќи по нејзиното завршување ќе сака-
ме да знаеме кои темиња се веќе посетени и во функцијата main(). Комплетното
решение е дадено на слика 10.3.3.2.

... Слика 10.3.3.2


322
10. Алгоритми кај низи и графови

Слика 10.3.3.2 (продолжение)


Еден излез од извршување на програмата е:

323
ПРОГРАМИРАЊЕ

10.3.4 Пребарување низ граф прво по широчина

Тука ќе го разгледаме алгоритамот за пребарување низ граф по широчина


(англ. breadth-first search – BFS). Пребарување по широчина се спроведува на
начин што првин го разгледуваме почетното теме, па потоа сите оние темиња кои
се соседи (поврзани со ребро) со почетното теме (да ги наречеме „темиња од
ниво 1“, односно темиња до кои може да се стигне преку изминување на само 1
ребро од почетното теме). Потоа ги разгледуваме сите темиња кои се соседи
(поврзани со ребро) со темињата од ниво 1 (да ги наречеме „темиња од ниво 2“,
ова се оние темиња до кои може да се дојде преку изминување на точно две реб-
ра од почетното теме) итн. За разлика од алгоритамот за пребарување на граф по
длабочина (DFS), тука темињата ги разгледуваме последователно, во однос на
нивното растојание (како број на ребра кои треба да се изминат) од почетното те-
ме. Ова не важеше при пребарувањето по длабочина, при што од почетното теме
се движевме во одредена насока (на пример надесно, посетувајќи голем број на
темиња на разна оддалеченост), пред воопшто да разгледавме некое друго со-
седно теме на почетното.
Имплементацијата на овој алгоритам е дадена на слика 10.3.3.3.

Слика 10.3.3.3

324
10. Алгоритми кај низи и графови

Слика 10.3.3.3 (продолжение)


Овде ја користиме податочната структура queue <int> за чување на те-
мињата кои треба да се посетат. Оваа структура овозможува посетување на теми-
њата по принципот прв влегува прв излегува, односно FIFO – first-in first-out.
Дополнително, ја имаме и низата marked[], во која означуваме кои темиња ни се
веќе посетени за да не ги посетуваме повеќепати.
И двата алгоритми кои ги разгледавме (DFS и BFS), во однос на импле-
ментацијата што ние ја напишавме, имаат временска сложеност O(V + E), V е
бројот на темиња, a Е е бројот на ребра. При имплементација на овие алгоритми
на друг начин (на пример, преку претставување на графот со матрица на сосед-
ство или посетување на темињата по повеќепати и слично), тие би имале и друга
временска сложеност. Сепак, имплементациите што ние ги разгледавме се оние
што се користат најчесто и што ќе ви бидат најмногу корисни при решавањето на
разни задачи и проблеми.

Пример 10.3.4.1
Дадено е едно дрво. Да се потсетиме дека дрво е неориентиран граф во
кој кои било две темиња се поврзани со точно еден пат. Дрвата не содржат цик-
луси и за нив знаеме дека бројот на ребра е за еден помал од бројот на темиња во
дрвото.

Треба да се напише програма која, почнувајќи од едно теме во дрвото (да


го наречеме „корен“), ќе ги обележи нивоата на сите темиња. Коренот е од ниво

325
ПРОГРАМИРАЊЕ

0, сите негови директни соседи достапни преку едно ребро се од ниво 1, па сите
нивни соседи се од ниво 2 итн.
Овој проблем може едноставно да се реши со користење на алгоритамот
за пребарување по широчина (BFS) бидејќи тој ќе ги посети темињата по точниот
редослед по кој ни е нам потребно: најпрвин коренот, па сите темиња од ниво 1,
па сите темиња од ниво 2 итн. Единствено нешто на што треба да внимаваме е да
го зачуваме нивото на секое теме како што го откриваме – кога сме кај коренот,
да ги обележиме неговите соседи дека тие се од ниво 1, па кога сме кај темињата
од ниво 1 да ги обележиме нивните непосетени соседи дека тие се од ниво 2 итн.
Ова е реализирано со програмата дадена на слика 10.3.3.4.

...

Слика 10.3.3.4
326
10. Алгоритми кај низи и графови

слика 10.3.3.4 (продолжение)


Еден излез од извршување на програмата е:

Забележете дека ја ставивме директивата #include <queue> за да може да


ја користиме податочната структура queue. Слично, во алгоритамот за пребару-
вање по длабочина DFS ја ставивме директивата #include <stack>. Доколку реши-
те да ја тестирате оваа програма на Вашиот компјутер, осигурајте се дека ребрата
кои ќе ги внесете ќе претставуваат дрво, т. е. дека ќе постои пат помеѓу кои било
две темиња. На пример, ако внесете N = 5, тогаш можете да ги внесете следните
ребра "0 1", "0 2", "0 3", "2 4". Како што можете да забележите, темето 0 е
поврзано со темињата 1, 2 и 3, а постои и врска помеѓу темето 2 и темето 4. Би-
дејќи графот е неориентиран, постои пат помеѓу било кои две темиња од овој
граф. На пример, постои пат од темето 0 до темето 2, од темето 0 до темето 4
преку темето 2 итн.

Вежби

Вежба 10.3.1
Одговорете на следниве прашања:
1. Што е граф?
2. Што е теме, а што ребро во граф?
3. Која е разликата меѓу ориентиран и неориентиран граф?
4. Како може да се претстават графовите во компјутер?
Вежба 10.3.2
Разгледајте го објаснувањето поврзано со слика 10.3.2.1. Обидете
се да ги откриете и другите ребра запишани во матрицата кои не се
споменати во објаснувањето.
327
ПРОГРАМИРАЊЕ

Вежба 10.3.3
Со алгоритамот DFS да се утврди едно теме „папок“ на даден
граф. За едно теме велиме дека е „папок“ ако од него може да се стигне
до секое друго теме преку достапните ребра.

Вежба 10.2.4
Со алгоритамот DFS да се креираат матрица со димензии r x c и
даден елемент со неговите координати. Елементот да се постави на 0,
неговите соседи на 1, нивните соседи на 2 итн..
Пример:
Големина на матрицата: r = 9, c = 9.
Централни координати: (4, 4).
Излез:
444444444
433333334
432222234
432111234
432101234
432111234
432222234
433333334
444444444

Резиме

 Алгоритми за барање податоци во низа се: секвенцијално барање, барање


со чекор, бинарно барање, интерполациско барање и др.
 При секвенцијалното барање, се проверува секој елемент во низата поч-
нувајќи од првиот.
 При барање со чекор, се проверува секој к-ти елемент, к е чекорот.
 При бинарно барање, сортираната низа се дели на половина, на четвртини
итн. додека не се најде бараниот елемент или не се заклучи дека таков
елемент не постои.
 При интерполациско барање, во сортирана низа се пресметуваат позици-
јата на елементот според неговата вредност и вредностите на најмалиот и
на најголемиот елемент во интервалот.
 Сортирање на податоците во низа се врши со цел побрзо барање елемент
во неа. Постојат повеќе алгоритми за сортирање на елементите на низа, и
тоа: сортирање со споредување на елементите, сортирање со наоѓање на
најмалиот (или на најголемиот елемент), сортирање со вметнување (ли-
неарно или бинарно), сортирање со меурче, сортирање со кофи и други.

328
10. Алгоритми кај низи и графови

 Граф е математичка структура која се користи за претставување на врс-


ките/релациите помеѓу одредени објекти
 Графот се состои од темиња (или јазли) и ребра (или рабови).
 Графот може да биде неориентиран или ориентиран.
 Тежински графови се оние во кои за секое ребро е дефиниран и одреден
реален број кој ја означува неговата тежина, растојанието или некоја дру-
га слична мерка.
 Дрво претставува неориентиран граф (ребрата немаат насока), во кој
темињата се меѓусебно поврзани со точно едно ребро.
 Графот може да се претстави со матрица на соседство и со листи на со-
седство.
 Графот е несеквенцијална структура на податоци и може да се измине на
два начини: прво по длабочина или прво по широчина.
 Изолираните групи на темиња во графот се компоненти.
 Поврзана компонента е множество од темиња кои се меѓусебно поврзани,
т. е. постои пат помеѓу секои две од нив (преку едно или повеќе ребра).

329
ПРОГРАМИРАЊЕ

330
ДОДАТОК

ДОДАТОК

ОСНОВНИ ТИПОВИ НА ПОДАТОЦИ

331
ПРОГРАМИРАЊЕ

цимално ЗНАЦИ ASCII

Б
цимално

цимално

цимално
Хексаде-

Хексаде-

Хексаде-

Хексаде-
ASCII

ASCII

ASCII

ASCII
Знак

Знак

Знак

Знак
0 0 NUL 32 20 (празно) 64 40 @ 96 60 `
1 1 SOH 33 21 ! 65 41 A 97 61 a
2 2 STX 34 22 " 66 42 B 98 62 b
3 3 ETX 35 23 # 67 43 C 99 63 c
4 4 EOT 36 24 $ 68 44 D 100 64 d
5 5 ENQ 37 25 % 69 45 E 101 65 e
6 6 ACK 38 26 & 70 46 F 102 66 f
7 7 BEL 39 27 ' 71 47 G 103 67 g
8 8 BS 40 28 ( 72 48 H 104 68 h
9 9 TAB 41 29 ) 73 49 I 105 69 i
10 A LF 42 2A * 74 4A J 106 6A j
11 B VT 43 2B + 75 4B K 107 6B k
12 C FF 44 2C , 76 4C L 108 6C l
13 D CR 45 2D - 77 4D M 109 6D m
14 E SO 46 2E . 78 4E N 110 6E n
15 F SI 47 2F / 79 4F O 111 6F o
16 10 DLE 48 30 0 80 50 P 112 70 p
17 11 DC1 49 31 1 81 51 Q 113 71 q
18 12 DC2 50 32 2 82 52 R 114 72 r
19 13 DC3 51 33 3 83 53 S 115 73 s
20 14 DC4 52 34 4 84 54 T 116 74 t
21 15 NAK 53 35 5 85 55 U 117 75 u
22 16 SYN 54 36 6 86 56 V 118 76 v
23 17 ETB 55 37 7 87 57 W 119 77 w
24 18 CAN 56 38 8 88 58 X 120 78 x
25 19 EM 57 39 9 89 59 Y 121 79 y
26 1A SUB 58 3A : 90 5A Z 122 7A z
27 1B ESC 59 3B ; 91 5B [ 123 7B {
28 1C FS 60 3C < 92 5C \ 124 7C |
29 1D GS 61 3D = 93 5D ] 125 7D }
30 1E RS 62 3E > 94 5E ^ 126 7E ~
31 1F US 63 3F ? 95 5F _ 127 7F DEL

332
ДОДАТОК

ЛИТЕРАТУРА

Deitel, P., Deitel, H.: C++20 for Programmers, Pearson, 3rd edition, 2020.
Deitel, P., Deitel, H.: C++ How to Program, Pearson, 10 edition, 2017.
Eckel, B.: Thimking in C++: Introduction to Standard C++, Vol.1, Prentice Hall,
2000.
http://gocmar.mk Компјутерска литература.
Јованчевски, Ѓ.: С++ Програмирање, универзитетски учебник, Гоцмар, Скопје
2018.
Јованчевски, Ѓ., Ацковска, Н., Стојчевска, Б, Јованов, М..: С++ Збирка
алгоритми и програми, универзитетски учебник, Гоцмар, Скопје 2017, 2007.
Јованчевски, Ѓ., Ацковска, Н., Стојчевска, Б, Јованов, М..: С++ Програмирање за
почетници, Гоцмар, Скопје 2011.
Јованчевски, Ѓ., Стојова, Р.: Програмски јазици, учебник за IV година гимназиско
образование, Гоцмар, Скопје 2009, 2006, 2004;
Јованчевски, Ѓ., Лазаревска, Ж.: Програмски јазици, учебник за III година
гимназиско образование, Гоцмар, Скопје 2009, 2006;
Јованчевски, Ѓ.: Информатика, учебник за I година гимназиско образование,
Гоцмар, Скопје 2009, 2002.
Јованчевски, Ѓ., Ацковска, Н., Стојчевска, Б.: С++ Основи на програмирање,
универзитетски учебник, Гоцмар, Скопје 2007.
Јованчевски, Ѓ.: Алгоритми и програми, Гоцмар, Скопје 1993.
Knuth, D.: The Art of Computer Programming, Volumes 1-4A, 1st Ed., Addison-
Wesley Professional, 2011.
Lippman, S., Lajoie, J., Moo, B.: C++ Primer, Addison Wesley Professional, 5
edition, 2012.
http://mendo.mk/ Систем за натпревари по информатика.
Sedgewick, R.: Algorithms in C++, 3th Ed., Addison Wesley Professional, 1998.
Sedgewick, R., Wayne, K.: Algorithms, 4th Ed., Addison Wesley Professional, 2011.
Stroustrup, B: The C++ Programming Language, 4th Ed., Addison Wesley
Professional, 2013.

333
ПРОГРАМИРАЊЕ

334

You might also like