├── .gitignore ├── Additional ├── README.md ├── git(hub).md └── vs.md ├── LICENSE ├── README.md ├── Week 01 ├── Practicum.md ├── Practicum_Introduction.md ├── Practicum_Solutions.cpp ├── README.md └── Tasks.md ├── Week 02 ├── Practicum.md ├── Practicum_Solutions.cpp ├── README.md └── Tasks.md ├── Week 03 ├── Practicum.md ├── Practicum_Loops_Bonus.md ├── Practicum_Loops_Bonus_Solutions.cpp ├── Practicum_Solutions.cpp └── README.md ├── Week 04 ├── Practicum.md ├── Practicum_Solutions.cpp └── README.md ├── Week 05 ├── Practicum.md ├── Practicum_Solutions.cpp └── README.md ├── Week 06 ├── 1.Practicum.md ├── 2.Practicum_Multidimensional_Arrays.md ├── Exam_Prep.md ├── Practicum_Multidimensional_Solutions.cpp ├── Practicum_Solutions.cpp └── README.md ├── Week 07 ├── Practicum.md ├── Practicum_Bonus_Solution.cpp └── README.md ├── Week 08 ├── Practicum.md ├── README.md ├── bit_manipulation.cpp ├── bitwise_isEven.cpp ├── bitwise_powerOfTwo.cpp ├── firstMissing.cpp └── generateSubsets.cpp ├── Week 09 ├── Practicum.md ├── Practicum_Str_Functions.cpp └── README.md ├── Week 10 ├── Practicum.md ├── README.md └── SolutionsTasksPracticum.cpp ├── Week 11 ├── Practicum.md ├── README.md ├── censoreNumbers.cpp ├── examples.cpp ├── smallAndUpperStrings.cpp └── sortLower.cpp └── Week 12 ├── Practicum.md └── fibonachi_dynamic_opt.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .vs 3 | *.exe 4 | *.o 5 | *.obj 6 | *.out -------------------------------------------------------------------------------- /Additional/README.md: -------------------------------------------------------------------------------- 1 | ### Допълнителни материали 2 | 3 | - [Ръководство за работа с Visual Studio](./vs.md) 4 | - [Ръководство за работа с git и GitHub](<./git(hub).md>) -------------------------------------------------------------------------------- /Additional/git(hub).md: -------------------------------------------------------------------------------- 1 | ## Работа с git и GitHub 2 | 3 | - Инсталирайте git от официалния сайт [https://git-scm.com/downloads]() 4 | - Създайте си профил в [https://github.com/]() 5 | 6 | ### Работа през Visual Studio 7 | 8 | - Отворете Visual Studio 9 | - Изберете **Clone a repository** 10 | - Изберете **GitHub** 11 | - Добавете си акаунта 12 | - Изберете repo, което да клонирате 13 | - Когато отворите проекта, отворете прозореца **Git Changes** 14 | 15 | ##### Създаване на branch 16 | 17 | - Подсигурете се, че сте на последната версия на **main** branch-a като направите изберете **Pull from** > **Origin** от трите точки 18 | - Създайте си нов branch като отворите падащото меню, където е **main** 19 | - Напишете име на branch и натиснете **New branch** 20 | 21 | #### Качване на промени 22 | 23 | - Пишете описателно има на промените, които са направени. Обикновено за съобщение се пише в императивна форма, максимално кратко и ясно. Например **Add solution to Task01** 24 | - Натиснете **Commit All** 25 | - Изберете **Push to** > **Origin** от трите точки 26 | 27 | #### Теглене на промени 28 | 29 | - Отидете на `main` branch-a 30 | - Изберете **Pull from** > **Origin** от трите точки 31 | 32 | ### Работа през cli 33 | 34 | // TODO 35 | 36 | ### Качване на решения от самостоятелна работа 37 | 38 | 1. Отидете на [https://github.com/Tsvetilin/Introduction-To-Programming]() 39 | 2. Направете **Fork** (горе вдясно, до името на репото) 40 | 3. Клонирайте си локално fork-a 41 | 4. Създайте си нов branch с име `/week ` 42 | 5. В съответана директория за практикум добавете като отделни файлове решенията на задачите, кръстени `Task .cpp` 43 | 6. Качете промените 44 | 7. В GitHub отидете на [https://github.com/Tsvetilin/Introduction-To-Programming]() 45 | 8. Отидете на **Pull requests** 46 | 9. Създайте нов чрез **New pull request** 47 | 10. Изберете вашият branch 48 | 11. Добавете заглавие `Solutions week , , ` 49 | 12. Създайте PR 50 | 13. Преглежайте за коментари и обратна връзка 51 | 14. Последващи промени, направени локално и после качени ще бъдат отразени в Pull request-a 52 | 15. При необходимост от създаване на нов Pull request за следваща седмица, трябва да синхронизирате fork-a в GitHub (ще излезе prompt) 53 | 16. Отивате локално на `main` branch-a 54 | 17. Pull-вате промените 55 | 18. Отивате на стъпка 4 и продължавате надолу 56 | 57 | \* Навскякъде с xx e белязана текушата седмица, с fn - вашият факултетен номер, с name - вашето име 58 | 59 | \* Официална документация за работа с GitHub - [https://docs.github.com/en/get-started]() -------------------------------------------------------------------------------- /Additional/vs.md: -------------------------------------------------------------------------------- 1 | ## Работа с Visual Studio 2 | 3 | ### Инсталиране 4 | 5 | - Теглим **Visual Studio 2022 Community Edition** от официалния сайт на Microsoft - [https://visualstudio.microsoft.com/downloads/]() 6 | - Избираме **Desktop development with C++** 7 | - Инсталираме 8 | 9 | ### Създаване на проект 10 | 11 | - Отваряме Visual Studio 12 | - Избираме **Create a new project** 13 | - Филтрираме по език **C++**, платформа **Windows***, тип **Console** 14 | - Избираме **Empty project** 15 | - Избираме си име на проекта - примерно **Task 01** 16 | - Избираме име на solution-a - примерно **Week 01** 17 | - Избираме си име и локация и създаваме проекта 18 | 19 | ### Работа 20 | 21 | - Отваряме си **Solution Explorer** от менюто **View**, ако не го виждаме 22 | - С десен бутон върху solution-a (напр. **Solution 'Week 01'**) избираме **Setup Startup Projects...** 23 | - Избираме **Current Selection** и запазваме промените с **Apply** и **Ок** 24 | 25 | ##### Работа по проект/задача 26 | - В желания проект върху папката **Source files** с десен бутон избираме **Add** > **New item** 27 | - Избираме желаното от нас име. Обикновено главния файл с `main` функцията се кръщава `main.cpp` 28 | - Работим по кода 29 | 30 | ##### Изпълняване на кода 31 | - Когато сме на файла, който искаме да стартираме натискаме **Ctrl** + **F5** 32 | 33 | ##### Debugging 34 | - Слагаме breakpoint в полето до номерата на редовете на кода 35 | - Стартираме с **F5** 36 | - С **F10** се предвижваме с една стъпка напред без да влизаме в инструкцията 37 | - С **F11** се предвижваме с една стъпка напред с влизане в инструкцията, ако е възможно това 38 | 39 | ##### Създаване на проект в текущия Solution 40 | - С десен бутон върху solution-a (напр. **Solution 'Week 01'**) избираме **Add** > **New projecct** 41 | - Избираме **Empty project** 42 | - Избираме си име на проекта - примерно **Task 02** -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Tsvetilin Tsvetilov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Увод в програмирането 2 | 3 | ##### СИ, 1 курс, 6 група, Зимен семестър, 2024/2025 4 | 5 | ## Теми 6 | 7 | 8 | 9 | - [Седмица 01](<./Week 01/>) - Увод в програмирането. Типове данни, основни операции, вход и изход. 10 | - [Седмица 02](<./Week 02/>) - Условни оператори. Оператори за цикъл. 11 | - [Седмица 03](<./Week 03/>) - Условни оператори и оператори за цикъл - затвърждаване. 12 | - [Седмица 04](<./Week 04/>) - Функции. 13 | - [Седмица 05](<./Week 05/>) - Масиви. 14 | - [Седмица 06](<./Week 06/>) - Многомерни масиви. 15 | - [Седмица 07](<./Week 07/>) - Бройни системи. 16 | - [Седмица 08](<./Week 08/>) - Побитови операции. 17 | - [Седмица 09](<./Week 09/>) - Указатели и референции. Работа с масиви. Символни низове. 18 | - [Седмица 10](<./Week 10/>) - Работа с текст. 19 | - [Седмица 11](<./Week 11/>) - Динамична памет. 20 | 21 | 22 | 23 | ### Допълнителни материали 24 | 25 | 26 | 27 | - [Ръководство за работа с Visual Studio](<./Additional/vs.md>) 28 | - [Ръководство за работа с git и GitHub](<./Additional/git(hub).md>) 29 | 30 | 31 | -------------------------------------------------------------------------------- /Week 01/Practicum.md: -------------------------------------------------------------------------------- 1 | ## Примери 2 | 3 | **1.** Какво ще отпечата на екрана следният код? 4 | 5 | ```c++ 6 | #include 7 | int main() 8 | { 9 | std::cout << (((false || ((!false && true) || 0)) && false) && 1); 10 | } 11 | ``` 12 | 13 | **2.** Какво ще отпечата на екрана следният код? 14 | ```c++ 15 | #include 16 | 17 | int main() 18 | { 19 | int first = 7; 20 | int second = 2; 21 | 22 | std::cout << 2 * first / (second * (25 / 10)) << std::endl; 23 | std::cout << 2 * first / (second * 2.5) << std::endl; 24 | } 25 | 26 | ``` 27 | 28 | **3.** Какво ще отпечата на екрана следният код? 29 | 30 | ```c++ 31 | #include 32 | int main() 33 | { 34 | double a = 5.02; 35 | double b = 4.99; 36 | int c = a + b; 37 | std::cout << c; 38 | } 39 | ``` 40 | 41 | **4.** Какво ще се случи след компилиране на следния код? 42 | ```c++ 43 | #include 44 | int main() 45 | { 46 | int num = 5; 47 | std::cout << ((num == 5) && (num >= 3) || (num / !num)) << std::endl; 48 | } 49 | ``` 50 | 51 | ## Задачи 52 | 53 | **1.** Въвежда се цяло число. Отпечатайте 1, ако числото е четно и 0, ако е нечетно. 54 | 55 | **Пример** 56 | 57 | Вход: 58 | ```c++ 59 | 198 60 | ``` 61 | Изход: 62 | ```c++ 63 | 1 64 | ``` 65 | 66 | **2.** От конзолата се прочитат две цели числа и се отпечатва частното и остатъка им. 67 | 68 | **Пример** 69 | 70 | Вход: 71 | ```c++ 72 | 37 73 | 9 74 | ``` 75 | Изход: 76 | ```c++ 77 | 4 78 | 1 79 | ``` 80 | 81 | **3.** Напишете програма, която обръща подадени градуси от Целзий (C) във Фаренхайт (F)! Формулата за това е: F = (9 / 5) * C + 32. 82 | 83 | Вход: 84 | ```c++ 85 | 17 86 | ``` 87 | Изход: 88 | ```c++ 89 | 62.6 90 | ``` 91 | 92 | **4.** Да се прочетат от конзолата 2 реални числа - дължина и широчина на правоъгълник. Да се изведе периметърът и лицето. 93 | 94 | Вход: 95 | ```c++ 96 | 13 97 | 4.5 98 | ``` 99 | Изход: 100 | ```c++ 101 | 35 102 | 58.5 103 | ``` 104 | 105 | **5.** Да се напише програма, която чете от конзолата цяло число - брой секунди, и изчислява колко дни, часове, минути и секунди са. 106 | 107 | 108 | Вход: 109 | ```c++ 110 | 481 444 111 | ``` 112 | Изход: 113 | 114 | ```c++ 115 | 5 days, 13 hours, 44 minutes and 4 seconds 116 | ``` 117 | 118 | **6.** Въвежа се цяло число. Да се отпечата без последната цифра. 119 | 120 | Вход: 121 | ```c++ 122 | 6421 123 | ``` 124 | Изход: 125 | 126 | ```c++ 127 | 642 128 | ``` 129 | 130 | **7.** Въвежа се цяло число. Да се отпечата 1, ако числото е валидна оценка от училище - [2,6], a 0 - ако не е валидна. 131 | 132 | Вход: 133 | ```c++ 134 | 5 135 | ``` 136 | Изход: 137 | 138 | ```c++ 139 | 1 140 | ``` 141 | 142 | **8.** Дадени са ви 4 на брой цели числа - a, b, c, d. Да се изведе дали интервалите [a, b] и [c, d] се пресичат. 143 | 144 | Вход: 145 | ```c++ 146 | 4 9 147 | 8 23 148 | ``` 149 | Изход: 150 | 151 | ```c++ 152 | 1 153 | ``` 154 | 155 | **9.** Потребителя въвежда число n. Да се изведе сумата на числата от 1 до n 156 | 157 | Вход: 158 | ```c++ 159 | 17 160 | ``` 161 | Изход: 162 | 163 | ```c++ 164 | 153 165 | ``` 166 | 167 | **10.** Да се напише програма, която приема 4 цели числа и отпечатва 1, ако числата образуват геометрична прогресия в реда, в който са въведени, a 0 - ако съответно не образуват. 168 | 169 | Вход: 170 | ```c++ 171 | 3 9 27 81 172 | ``` 173 | Изход: 174 | 175 | ```c++ 176 | 1 177 | ``` 178 | 179 | **11.** Да се напише програма, която чете от конзолата 2 реални числа и разменя стойностите им без допълнителна промелнива. 180 | 181 | **12.** Да се напише програма, която чете от конзолата 2 числа и извежда по-голямото от тях. 182 | 183 | Вход: 184 | ```c++ 185 | 3.14 186 | 2.71 187 | ``` 188 | Изход: 189 | 190 | ```c++ 191 | 3.14 192 | ``` 193 | 194 | **13.** Напишете програма, която приема цяло число и отпечатва числото, ако е двуцифрено, или последната му цифра, ако не е. 195 | 196 | Вход: 197 | ```c++ 198 | 19 199 | ``` 200 | Изход: 201 | ```c++ 202 | 19 203 | ``` 204 | Вход: 205 | ```c++ 206 | 1985 207 | ``` 208 | Изход: 209 | ```c++ 210 | 5 211 | ``` 212 | 213 | **14.** От конзолата се въвеждат 5 цели числа. Да се изведе сумата на нечетните числа. 214 | 215 | Вход: 216 | ```c++ 217 | 4 9 19 6 5 218 | ``` 219 | Изход: 220 | ```c++ 221 | 33 222 | ``` 223 | 224 | **15.** От конзолата се четат 3 реални числа. Да се изведе дали могат да бъдат страни на триъгълник. 225 | 226 | Вход: 227 | ```c++ 228 | 20 21 29 //pythagorean triplet 229 | ``` 230 | Изход: 231 | ```c++ 232 | 1 233 | ``` 234 | 235 | 236 | 237 | ## Бонус задачи 238 | 239 | **\*** Потребителят въвежда число n. Да се изведе сборът на числата, които се делят на 3 и са по-малки или равни на n. 240 | 241 | Вход: 242 | ```c++ 243 | 15 244 | ``` 245 | Изход: 246 | ```c++ 247 | 45 248 | ``` 249 | 250 | **\*\*** Въвежда се трицифрено цяло число n. Да се отпечата числото наобратно, събрано с единица. 251 | 252 | Вход: 253 | ```c++ 254 | 735 255 | ``` 256 | Изход: 257 | ```c++ 258 | 538 259 | ``` 260 | 261 | **\*\*\*** Напишете програма, която приема цяло положително число и: 262 | 263 | * Ако то е едноциферно - да се изпечатa. 264 | * Ако то е двуцифрено - да се изпечатa последната му цифра събрана с 1. 265 | * Във всеки друг случай - да се изпечатa цялото без последната цифра. 266 | 267 | **Пример 1:** 268 | 269 | Вход: 270 | ```c++ 271 | 1234 272 | ``` 273 | 274 | Изход: 275 | ```c++ 276 | 123 277 | ``` 278 | 279 | **Пример 2:** 280 | 281 | Вход: 282 | ```c++ 283 | 18 284 | ``` 285 | 286 | Изход: 287 | ```c++ 288 | 9 289 | ``` 290 | 291 | **Пример 3:** 292 | 293 | Вход: 294 | ```c++ 295 | 6 296 | ``` 297 | 298 | Изход: 299 | ```c++ 300 | 6 301 | ``` 302 | -------------------------------------------------------------------------------- /Week 01/Practicum_Introduction.md: -------------------------------------------------------------------------------- 1 | # **Въведение в курса по УП(Практикум)** 2 | 3 | ## 1. Основни цели на курса *📚* 4 | 5 | * Въвежда студентите в програмирането 6 | * Поставя основите, които ще им служат в бъдещите курсове 7 | * Запознава ги с базови концепции и понятия, които са съществени в програмирането 8 | * Изгражда учебни и работни навици 9 | 10 | 11 | ## 2. Изисквания и структура 📜 12 | * По време на курса за решаването на поставените задачи се използва **САМО** материал, 13 | преподаден **ДОСЕГА** на **СЕМИНАРИТЕ** и **ЛЕКЦИИТЕ** 14 | 15 | * Контролни: 4 на брой 16 | 17 | * Първо контролно - отговаряне на въпроси на хартия 18 | 19 | * Второ контролно - решаване на задачи на компютър 20 | 21 | * Трето контролно - решаване на задачи на хартия + отговаряне на въпроси 22 | 23 | * Четвърто контролно - решаване на задачи на компютър - подготовка за изпит 24 | 25 | * Проект за УП Практикум 26 | 27 | * Code review: Pull request-и в github с кода от практикумите 28 | 29 | 30 | ## 3. Среда за разработка, инструменти и материали 🔧 31 | 32 | 33 | * Език за програмиране - **C++** 34 | 35 | 36 | 37 | * IDE (Integrated Development Environment) - **Visual Studio** 38 | 39 | 40 | 41 | * Канали за комуникация 42 | 43 |

44 | 45 | * Курс в **Moodle** 46 | 47 | 48 |

49 | 50 |
51 | 52 |

53 | 54 | * Студентска поща **Zimbra** 55 | 56 | 57 |

58 | 59 |
60 | 61 |

62 | 63 | * Материали в **Github** 64 | 65 | 66 |

67 | 68 | ## 4. Съвети и въпроси 🔍 69 | 70 | * Няма глупави въпроси, тук е мястото да бъркате и да питате!!! 71 | 72 | ## 5. Контакти 73 | * Юлиан Люцканов 74 | * ylyutskano@uni-sofia.bg 75 | * Георги Лазов 76 | * georgilazov04@gmail.com 77 | -------------------------------------------------------------------------------- /Week 01/Practicum_Solutions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | // Задача 1 3 | 4 | // int main() 5 | // { 6 | // int a; 7 | // std::cin >> a; 8 | // bool isTrue = (a % 2 == 0); 9 | // std::cout << isTrue; 10 | // } 11 | 12 | // Задача 2 13 | 14 | // int main() 15 | // { 16 | // int a, b; 17 | // std::cin >> a >> b; 18 | // std::cout << a / b << std::endl; 19 | // std::cout << a % b; 20 | // } 21 | 22 | // Задача 3 23 | 24 | // int main() 25 | // { 26 | // double degreesCelcius; 27 | // std::cin >> degreesCelcius; 28 | // double degreesFarenhait = (degreesCelcius * (9.0 / 5.0) + 32); 29 | // std::cout << degreesFarenhait; 30 | // } 31 | 32 | // Задача 4 33 | 34 | //int main() 35 | //{ 36 | // double length, width; 37 | // std::cin >> width >> length; 38 | // double perimeter = 2 * (width + length); 39 | // double area = length * width; 40 | // std::cout << perimeter << std::endl; 41 | // std::cout << area; 42 | //} 43 | 44 | // Задача 5 45 | 46 | //int main() 47 | //{ 48 | // int seconds, minutes, hours, days; 49 | // std::cin >> seconds; 50 | // days = seconds / (60 * 60 * 24); 51 | // seconds -= days * 60 * 60 * 24; 52 | // hours = seconds / (60 * 60); 53 | // seconds -= hours * 60 * 60; 54 | // minutes = seconds/ 60; 55 | // seconds -= minutes * 60; 56 | // std::cout << days << " days, " << hours << " hours, " << minutes << " minutes, " << seconds << " seconds"; 57 | //} 58 | 59 | // Задача 6 60 | 61 | //int main() 62 | //{ 63 | // int a; 64 | // std::cin >> a; 65 | // std::cout << a / 10; 66 | //} 67 | 68 | // Задача 7 69 | 70 | //int main() 71 | //{ 72 | // int a; 73 | // std::cin >> a; 74 | // bool is_BG_Grade = (a >= 2 && a <= 6); 75 | // std::cout << is_BG_Grade; 76 | //} 77 | 78 | // Задача 8 79 | 80 | //int main() 81 | //{ 82 | // int a, b, c, d; 83 | // std::cin >> a >> b >> c >> d; 84 | // bool intersect = (a <= d && b >= c); 85 | // //or !(a > d || b < c) the same because of de morgan rule ¬(a∨b) = ¬a∧¬b 86 | // std::cout << intersect; 87 | //} 88 | 89 | // Задача 9 90 | 91 | /*int main() 92 | { 93 | int n; 94 | std::cin >> n; 95 | std::cout << n * (n + 1) / 2; 96 | }*/ 97 | 98 | // Задача 10 99 | 100 | //int main() 101 | //{ 102 | // int a,b,c,d; 103 | // std::cin >> a>>b>>c>>d; 104 | // bool isGeometricProgression = (a * c == b * b) && (b * d == c * c); 105 | // std::cout << isGeometricProgression; 106 | //} 107 | 108 | // Задача 11 109 | 110 | //int main() 111 | //{ 112 | // double a, b; 113 | // std::cin >> a >> b; 114 | // a = a + b; 115 | // b = a - b; 116 | // a = a - b; 117 | // std::cout << a << " and " << b; 118 | //} 119 | 120 | // Задача 12 121 | 122 | //int main() 123 | //{ 124 | // double a, b; 125 | // std::cin >> a >> b; 126 | // bool isFirstLarger = a > b; 127 | // std::cout << isFirstLarger * a + !isFirstLarger * b; 128 | //} 129 | 130 | // Задача 13 131 | 132 | //int main() 133 | //{ 134 | // int a; 135 | // std::cin >> a; 136 | // bool isDoubleDigit = (a >= 10 && a <= 99) || (a <= -10 && a >= -99); 137 | // int print = isDoubleDigit * a + !isDoubleDigit * (a % 10); 138 | // std::cout << print; 139 | //} 140 | 141 | // Задача 14 142 | 143 | //int main(){ 144 | // int a, b, c, d, e; 145 | // std::cin >> a>> b>> c>> d>> e; 146 | // int sum = (a % 2) * a; 147 | // sum += (b % 2) * b; 148 | // sum += (c % 2) * c; 149 | // sum += (d % 2) * d; 150 | // sum += (e % 2) * e; 151 | // std::cout << sum; 152 | //} 153 | 154 | // Задача 15 155 | 156 | //int main() { 157 | // double a = 0, b = 0, c = 0; 158 | // std::cin >> a >> b >> c; 159 | // int isTriangle = (a + b > c) && (a + c > b) && (b + c > a); 160 | // std::cout << isTriangle; 161 | //} 162 | 163 | // Bonus 1 164 | 165 | //int main() { 166 | // int n; 167 | // std::cin >> n; // 10 168 | // int lastNumFromProgression = n / 3; //3 169 | // std::cout << 3 * lastNumFromProgression * (lastNumFromProgression + 1) / 2; // 3 + 6 + 9 = 3(1 + 2 + 3) 170 | //} 171 | 172 | //int main() { 173 | // int n = 0, a1 = 3; 174 | // std::cin >> n; 175 | // int an = n - (n % 3); 176 | // int count = n / 3; 177 | // int sum = count * (a1 + an) / 2; 178 | // std::cout << sum; 179 | //} 180 | 181 | // Bonus 2 182 | 183 | //int main() { 184 | // int n = 0; 185 | // std::cin >> n; 186 | // int reversed = (n % 10) * 100 + (n / 10 % 10) * 10 + (n / 100); 187 | // std::cout << reversed + 1; 188 | //} 189 | 190 | // Bonus 3 191 | 192 | //int main() { 193 | // int n = 0; 194 | // std::cin >> n; 195 | // int hasOneDigit = (n >= -9 && n <= 9); 196 | // int hasTwoDigits = (n >= 10 && n <= 99) || (n >= -99 && n <= -10);; 197 | // int result = hasOneDigit * n + hasTwoDigits * (n % 10 + 1) + !(hasOneDigit || hasTwoDigits) * (n / 10); 198 | // std::cout << result; 199 | //} 200 | 201 | -------------------------------------------------------------------------------- /Week 01/Tasks.md: -------------------------------------------------------------------------------- 1 | ## Задачи 2 | 3 | ### Основни задачи 4 | 5 | **Задача 1:** Въведете цяло число. Отпечатайте 1, ако числото е четно и 0, ако е нечетно. 6 | 7 | |Вход|Изход| 8 | |---|---| 9 | | 0 | 1 | 10 | | 689 | 0 | 11 | | 346 | 1 | 12 | 13 | **Задача 2:** Въведете цяло число. Отпечатайте го без последната му цифра. 14 | 15 | |Вход|Изход| 16 | |---|---| 17 | | 0 | 0 | 18 | | 689 | 68 | 19 | | 346786453 | 34678645 | 20 | 21 | **Задача 3:** Въведете цяло число. Отпечатайте последната му цифра. 22 | 23 | |Вход|Изход| 24 | |---|---| 25 | | 0 | 0 | 26 | | 689 | 9 | 27 | | 346786453 | 3 | 28 | 29 | **Задача 4:** Въведете четирицифрено число. Неговото огледално число получаваме, от цифрите на даденото, записани в обратен ред. Отпечатайте остатъка при деление на 7 на огледалното число на даденото. 30 | 31 | |Вход|Изход|Пояснения| 32 | |---|---|---| 33 | | 689 | 6 |Огледалното е $986$ и $986 \equiv 6 (mod 7)$ | 34 | | 276 | 0 |Огледалното е $672$ и $672 \equiv 0 (mod 7)$| 35 | 36 | **Задача 5:** Въведете символ. Отпечатайте 1, ако е английска съгласна буква, и 0 в противен случай. 37 | 38 | |Вход|Изход | 39 | |---|---| 40 | | a | 0 | 41 | | b | 1 | 42 | | C | 1 | 43 | 44 | **Задача 6:** Въведете две цели числа. Отпечатайте по-голямото от тях. Ако са равни, отпечатайте символа за равенство. 45 | 46 | |Вход|Изход | 47 | |---|---| 48 | | 257 257 | = | 49 | | 468 123 | 468 | 50 | | 8732 486553 | 486553 | 51 | 52 | **Задача 7:** Нека имаме две дефинирани променливи от тип `int`. Да се разменят техните стойности. 53 | 54 | *Това може да стане по няколко начина, включително с и без употреба на помощна променлива.* 55 | 56 | 57 | **Задача 8:** Въведете две числа с плаваща запетая. Проверете дали те са равни и върнете 1, ако са, и 0, ако не са. 58 | 59 | *Намерете случай, за който въведените числа са различни, но програмата казва, че са еднакви* 60 | 61 | 62 | **Задача 9:** Прочетете един символ. Преобразувайте го в цяло число и го отпечатайте. Ако символът не е число, отпечатайте `*`. 63 | 64 | **Задача 10:** Прочетете един символ - голяма латинска буква. Отпечатайте еквивалентната малка латинска буква. 65 | 66 | **Задача 11:** Променете casing-a на дадена прочетена латинска буква и отпечатайте резултата. 67 | 68 | **Задача 12:** Прочетете две числа $a$ и $b$. Изведете стойността на израза ${(a + b - 1)^3 - (b - a + 1)^2}$ 69 | 70 | **Задача 13:** Прочетете цяло число - левове. Изведете минималния брой банкноти и монети (с номинал 100, 50, 20, 10, 5, 2, 1), необходими за набавянето на тази сума. -------------------------------------------------------------------------------- /Week 02/Practicum.md: -------------------------------------------------------------------------------- 1 | ## Примери 2 | 3 | **1.** Какво ще се изведе на конзолата? 4 | ```c++ 5 | #include 6 | int main() 7 | { 8 | int a = 3; 9 | 10 | if (a < 10) 11 | std::cout << a; 12 | if (a != 10) 13 | a++; 14 | if (false, 1) 15 | std::cout << a; 16 | else 17 | a += 5; 18 | std::cout << a; 19 | } 20 | ``` 21 | **2.** Какво ще се изведе на конзолата? 22 | ```c++ 23 | #include 24 | int main() 25 | { 26 | int a = 8; 27 | if (a -= a += 8) 28 | a++; 29 | else 30 | a += 5; 31 | std::cout << a; 32 | } 33 | ``` 34 | 35 | **3.** Какво ще се изведе след изпълнение на кода? 36 | ```c++ 37 | #include 38 | 39 | int main() 40 | { 41 | int num = 25; 42 | if (num == (10, 25, 35)) 43 | { 44 | std::cout << "first"; 45 | } 46 | else if (num = !num, num += 1, (--num)++) 47 | { 48 | std::cout << "second"; 49 | } 50 | else 51 | { 52 | std::cout << "third"; 53 | } 54 | } 55 | ``` 56 | 57 | **4.** Какво ще отпечата на екрана следният код? 58 | 59 | ```c++ 60 | #include 61 | int main() 62 | { 63 | int a = 2; 64 | int b = 4; 65 | if(a, b - 2* a) 66 | std::cout << a; 67 | else 68 | std::cout << 100; 69 | } 70 | ``` 71 | 72 | **5.** Какво ще отпечата на екрана следният код? 73 | ```c++ 74 | #include 75 | int main() 76 | { 77 | 78 | int first = 37, second = 6; 79 | 80 | 81 | std::cout<< (first > second ? first : second); 82 | } 83 | ``` 84 | 85 | **6.** Ще има ли разлика след изпълнение на двете програми? 86 | 87 | **Bonus:** *А коя е по-бърза?* 88 | 89 | ```c++ 90 | int grade; 91 | std::cin >> grade; 92 | if (grade == 2) 93 | std::cout << "fail"; 94 | else if (grade <= 5) 95 | std::cout << "nice"; 96 | else if (grade == 6) 97 | std::cout << "excellent"; 98 | else 99 | std::cout << "error"; 100 | ``` 101 | 102 | ```c++ 103 | int grade; 104 | std::cin >> grade; 105 | switch(grade) 106 | { 107 | case 2: std::cout << "fail"; break; 108 | case 3: 109 | case 4: 110 | case 5: std::cout << "nice"; break; 111 | case 6: std::cout << "excellent"; break; 112 | default: std::cout << "error"; 113 | } 114 | ``` 115 | 116 | ## Задачи 117 | 118 | **1.** Въвежда се цяло число от конзолата. Изведете на кознолата дали числото е положително, отрицателно или 0. 119 | 120 | Вход: 121 | ```c++ 122 | 7 123 | ``` 124 | Изход: 125 | ```c++ 126 | Positive 127 | ``` 128 | 129 | **2.** Да се напише програма, която чете от конзолата число между 0 и 9 и отпечатва съответстващата му римска цифра. 130 | 131 | 132 | Вход: 133 | ```c++ 134 | 7 135 | ``` 136 | Изход: 137 | ```c++ 138 | VII 139 | ``` 140 | 141 | **3.** Да се прочетe от конзолата цяло число - година, и да се изведе дали годината е високосна. 142 | - година, деляща се на числото 4 без остатък, **е** високосна; 143 | - ако годината обаче също се дели без остатък на 100, то тя **не е** високосна; 144 | - но ако годината също се дели без остатък и на 400, то тя пак ще **е** високосна. 145 | 146 | 147 | Вход: 148 | ```c++ 149 | Year: 2000 150 | ``` 151 | Изход: 152 | ```c++ 153 | Leap year 154 | ``` 155 | **4.** От конзолата се въвеждат ден от седмицата под формата на цяло число от 1 до 7 (1 - Monday, 2 - Tuesday , и т.н.). Нека на конзолата се изведе кой ден от седмицата е това число с думи. 156 | 157 | *(Погрижете се и за невалидни входни данни)* 158 | 159 | 160 | Вход: 161 | ```c++ 162 | 3 163 | ``` 164 | 165 | Изход: 166 | ```c++ 167 | Wednesday 168 | ``` 169 | **5.** Използвайки тернарен оператор, изведете на конзолата кое от две въведени цели числа е по-голямо. 170 | 171 | 172 | Вход: 173 | ```c++ 174 | 9 67 175 | ``` 176 | 177 | Изход: 178 | ```c++ 179 | 67 180 | ``` 181 | 182 | **6.** Напишете програма, която чете един символ от конзолата и извежда дали той е главна или малка буква и също така дали е гласна или съгласна. Да се изведе обърнатата по капитализация буква (от главна - малка и обратното). 183 | 184 | *(При невалидни данни се извежда съобщение за грешка)* 185 | 186 | Вход: 187 | ```c++ 188 | a 189 | ``` 190 | 191 | Изход: 192 | ```c++ 193 | A 194 | Vowel 195 | ``` 196 | 197 | 198 | Вход: 199 | ```c++ 200 | ? 201 | ``` 202 | 203 | Изход: 204 | ```c++ 205 | Invalid character 206 | ``` 207 | 208 | **7.** Да се напише програма, която приема от входа 3 цели числа и ги отпечатва в сортиран вид. 209 | 210 | 211 | Вход: 212 | ```c++ 213 | 3 47 2 214 | ``` 215 | 216 | Изход: 217 | ```c++ 218 | 2 3 47 219 | ``` 220 | 221 | **8.** Да се напише програма, която при подадени радиус r и двумерна точка (х, у) проверява дали точката се намира вътре/извън или по контура на окръжност с център (0,0). 222 | 223 | *Можете да използвате фунцкията sqrt от cmath библиотеката* 224 | 225 | Вход: 226 | ```c++ 227 | 5 0 5 228 | ``` 229 | Изход: 230 | ```c++ 231 | On the circle 232 | ``` 233 | 234 | Вход: 235 | ```c++ 236 | 5 10 30 237 | ``` 238 | Изход: 239 | ```c++ 240 | Out of the circle 241 | ``` 242 | 243 | Вход: 244 | ```c++ 245 | 5 0 2 246 | ``` 247 | Изход: 248 | ```c++ 249 | In the circle 250 | ``` 251 | 252 | **9.** От конзолата се въвеждат три реални числа. Първото е ляв край на интервал, а второто десният му край. Да се провери дали третото число се съдържа в интервала и ако съвпада с единия му край да се изведе съобщение, че интервалът е затворен. Ако числото е в интервала да се изведе съобщение, че е в интервалът е отворен. Ако не се намира в интервала да се изведе подходящо съобщение. 253 | 254 | ***ВНИМАВАЙТЕ КАК СЕ СРАВНЯВАТ DOUBLE*** 255 | 256 | 257 | Вход: 258 | ```c++ 259 | 5.90 17.2 5.93 260 | ``` 261 | 262 | Изход: 263 | ```c++ 264 | The number is within the given interval. The interval is open. 265 | ``` 266 | 267 | **10.** Да се напише програма, в която се въвежда 4-цифренo естествено число *n*. От това число се формират 2 нови 2-цифрени числа. Първото число се формира от 1-вата и 4-тата цифра на *n*, а, второто - от 2-рaта и 3-тата цифра на *n*. На екрана да се изведе дали 1-то ново число e по-малко, равно или по-голямо от 2-то число. 268 | 269 | Вход: 270 | ```c++ 271 | 3483 272 | ``` 273 | 274 | Изход: 275 | ```c++ 276 | 33 < 48 277 | ``` 278 | 279 | **11.** Да се напише програма, която чете от конзолата три числа - ден, месец и година, и извежда на екрана 1, ако трите числа оформят валидна дата, и 0 в противен случай. 280 | 281 | Вход: 282 | ```c++ 283 | 12 1 1989 284 | ``` 285 | Изход: 286 | ```c++ 287 | 1 288 | ``` 289 | Вход: 290 | ```c++ 291 | 12 13 0 292 | ``` 293 | Изход: 294 | ```c++ 295 | 0 296 | ``` 297 | 298 | **12.** Ще бъдат въведени две срещуположни точки за сформиране на правоъгълник.(x,y координати) Приемаме, че той не е завъртян, а е ориентиран успоредно на координатната система. При въвеждане на още една точка установете дали тя се намира вътре, по контура или отвън спрямо правоъгълника. 299 | 300 | Вход: 301 | ```c++ 302 | 2 4 8 8 4 3 303 | ``` 304 | Изход: 305 | ```c++ 306 | 0 307 | ``` 308 | 309 | Вход: 310 | ```c++ 311 | 2 4 8 8 4 6 312 | ``` 313 | Изход: 314 | ```c++ 315 | 1 316 | ``` 317 | 318 | **13.** Въвеждат се целите числа a,b,c , които са съответно коефициентите в уравнението a*x2+ b*x +c = 0. 319 | Да се изведе колко на брой *реални* корени има това уравнение. 320 | 321 | Вход: 322 | ```c++ 323 | 1 5 6 324 | ``` 325 | Изход: 326 | ```c++ 327 | 2 328 | ``` 329 | 330 | Вход: 331 | ```c++ 332 | 5 2 7 333 | ``` 334 | Изход: 335 | ```c++ 336 | 0 337 | ``` 338 | 339 | **14.** Да се напише програма, която получава 5 латински букви. Първите две от тях са главни и образуват множеството A, където A съдържа всички букви между въпросните две букви, включително самите тях. Вторите две букви са малки и образуват множеството B, където B съдържа всички букви между тях, включително самите тях. 340 | 341 | Четем 5-та буква (case insensitive). Да се изведе: 342 | 343 | * Дали 5-тата буква принадлежи на обединението на A и B. 344 | * Дали 5-тата буква принадлежи на сечението на A и B. 345 | * Дали 5-тата буква принадлежи на разликата на A с B. 346 | * Без да използвате допълнителни проверки (освен резултатите от предните три условия) определете дали 5-тата буква принадлежи само и единствено в някое от множествата A или B. 347 | 348 | *(Да се похвалите после по ДСТР, че сте решили последната подточка* 😎 *)* //shoutout to Ivan Makaveev 349 | 350 | **Пример:** 351 | 352 | Вход: 353 | ```c++ 354 | A E c e e 355 | ``` 356 | 357 | Изход: 358 | ```c++ 359 | true, true, false, false 360 | ``` 361 | -------------------------------------------------------------------------------- /Week 02/Practicum_Solutions.cpp: -------------------------------------------------------------------------------- 1 | //Task 1 2 | int number; 3 | std::cout << "Enter a number: "; 4 | std::cin >> number; 5 | if (!std::cin) { 6 | std::cout << "Invalid input!" << std::endl; 7 | return -1; 8 | } 9 | 10 | if (number > 0) { 11 | std::cout << number << " is positive." << std::endl; 12 | } 13 | else if (number < 0) { 14 | std::cout << number << " is negative." << std::endl; 15 | } 16 | else { 17 | std::cout << "The number is 0." << std::endl; 18 | } 19 | 20 | //Task 2 21 | int number; 22 | std::cout << "Enter a number: "; 23 | std::cin >> number; 24 | if (!std::cin) { 25 | std::cout << "Invalid input!" << std::endl; 26 | return -1; 27 | } 28 | 29 | switch (number) { 30 | case 1: 31 | std::cout << "I" << std::endl; 32 | break; 33 | case 2: 34 | std::cout << "II" << std::endl; 35 | break; 36 | case 3: 37 | std::cout << "III" << std::endl; 38 | break; 39 | case 4: 40 | std::cout << "IV" << std::endl; 41 | break; 42 | case 5: 43 | std::cout << "V" << std::endl; 44 | break; 45 | case 6: 46 | std::cout << "VI" << std::endl; 47 | break; 48 | case 7: 49 | std::cout << "VII" << std::endl; 50 | break; 51 | case 8: 52 | std::cout << "VIII" << std::endl; 53 | break; 54 | case 9: 55 | std::cout << "IX" << std::endl; 56 | break; 57 | default: 58 | std::cout << "You must enter a number between 1 and 9!" << std::endl; 59 | break; 60 | } 61 | 62 | //Task 3 63 | int year; 64 | std::cout << "Enter a year: "; 65 | std::cin >> year; 66 | if (!std::cin) { 67 | std::cout << "Invalid input!" << std::endl; 68 | return -1; 69 | } 70 | 71 | if (year % 4 == 0 && ((year % 100 != 0) || year % 400 == 0)) { 72 | std::cout << year << " is a leap year!" << std::endl; 73 | } 74 | else { 75 | std::cout << year << " is not a leap year!" << std::endl; 76 | } 77 | 78 | //Task 4 79 | int day; 80 | std::cout << "Enter a number between 1 and 7: "; 81 | std::cin >> day; 82 | if (!std::cin) { 83 | std::cout << "Invalid input!" << std::endl; 84 | return -1; 85 | } 86 | 87 | switch (day) { 88 | case 1: 89 | std::cout << day << " is Monday." << std::endl; 90 | break; 91 | case 2: 92 | std::cout << day << " is Tuesday." << std::endl; 93 | break; 94 | case 3: 95 | std::cout << day << " is Wednesday." << std::endl; 96 | break; 97 | case 4: 98 | std::cout << day << " is Thursday." << std::endl; 99 | break; 100 | case 5: 101 | std::cout << day << " is Friday." << std::endl; 102 | break; 103 | case 6: 104 | std::cout << day << " is Saturday." << std::endl; 105 | break; 106 | case 7: 107 | std::cout << day << " is Sunday." << std::endl; 108 | break; 109 | default: 110 | std::cout << "You have entered an incorrect number!" << std::endl; 111 | break; 112 | } 113 | 114 | //Task 5 115 | int num1, num2; 116 | std::cout << "Enter 2 numbers: "; 117 | std::cin >> num1 >> num2; 118 | 119 | int biggerNumber = (num1 > num2) ? num1 : num2; 120 | std::cout << "The biggest number out of " << num1 << " and " << num2 << " is " << biggerNumber << "." << std::endl; 121 | 122 | //zad.6 123 | char ch; 124 | std::cout << "Enter a character: "; 125 | std::cin >> ch; 126 | 127 | if (ch >= 'a' && ch <= 'z') 128 | std::cout << std::endl << ch << " is small letter and "; 129 | else if(ch >= 'A' && ch <= 'Z') 130 | std::cout << std::endl << ch << " is big letter and "; 131 | else 132 | return -1; 133 | 134 | bool isVowel = false; 135 | switch(ch) { 136 | case 'a': 137 | case 'i': 138 | case 'o': 139 | case 'u': 140 | case 'e': 141 | case 'A': 142 | case 'I': 143 | case 'O': 144 | case 'U': 145 | case 'E': std::cout << "vowel letter." << std::endl; break; 146 | default: std::cout << "consonant letter." << std::endl; 147 | 148 | if (ch >= 'a' && ch <= 'z') { 149 | std::cout << "Reversed lettter: " << (char)(ch - 'a' + 'A') << std::endl; 150 | } 151 | else if (ch >= 'A' && ch <= 'Z') { 152 | std::cout << "Reversed letter: " << (char)(ch - 'A' + 'a') << std::endl; 153 | } 154 | 155 | //Task 7 156 | int a, b, c; 157 | std::cout << "Enter the value of 3 numbers: "; 158 | std::cin >> a >> b >> c; 159 | 160 | if (a > b) { 161 | int temp = a; 162 | a = b; 163 | b = temp; 164 | } 165 | if (b > c) { 166 | int temp = b; 167 | b = c; 168 | c = temp; 169 | } //the biggest is pushed behind 170 | if (a > b) { 171 | int temp = b; 172 | b = a; 173 | a = temp; 174 | } 175 | 176 | std::cout << a << ", " << b << ", " << c << std::endl; 177 | 178 | //Task 8 179 | int dx, dy; 180 | std::cout << "Enter the coordinates of your point:"; 181 | std::cin >> dx >> dy; 182 | 183 | int r; 184 | std::cout << "Enter the radius of the circle: "; 185 | std::cin >> r; 186 | if (r <= 0) { 187 | std::cout << "Invalid input!" << std::endl; 188 | return -1; 189 | } 190 | 191 | int squaredLen = dx * dx + dy * dy; 192 | int squaredRadius = r * r; 193 | if (squaredLen == squaredRadius) { 194 | std::cout << "Point (" << dx << "," << dy << ") is on the circle." << std::endl; 195 | } 196 | else if (squaredLen < squaredRadius) { 197 | std::cout << "Point (" << dx << "," << dy << ") is inside the circle." << std::endl; 198 | } 199 | else { 200 | std::cout << "Point (" << dx << "," << dy << ") is outside the circle." << std::endl; 201 | } 202 | 203 | //Task 9 204 | const double EPSILON = 0.000001; 205 | double lowerBound, upperBound, num; 206 | std::cin >> lowerBound >> upperBound >> num; 207 | if(lowerBound > upperBound) { 208 | double temp = lowerBound; 209 | lowerBound = upperBound; 210 | upperBound = temp; 211 | } 212 | if (num > lowerBound && num < upperBound) 213 | { 214 | std::cout << "The number is within the given interval. The interval is open."; 215 | } 216 | else if (lowerBound - num < EPSILON || num - upperBound < EPSILON) 217 | { 218 | std::cout << "The number is within the given interval. The interval is closed."; 219 | } 220 | else 221 | { 222 | std::cout << "The number is not within the given interval."; 223 | } 224 | 225 | //Task 10 226 | int n; 227 | std::cin >> n; 228 | int d1 = n / 1000; 229 | int d2 = n / 100 % 10; 230 | int d3 = n / 10 % 10; 231 | int d4 = n % 10; 232 | int firstNum = d1 * 10 + d4; 233 | int secondNum = d2 * 10 + d3; 234 | char sign = (firstNum < secondNum) ? '<' : ((firstNum > secondNum) ? '>' : '='); 235 | std::cout << firstNum << " " << sign << " " << secondNum; 236 | 237 | //Task 11 238 | int day, month, year; 239 | std::cin >> day >> month >> year; 240 | bool isLeapYear = (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0); 241 | bool validDate = year >= 0; 242 | switch (month) 243 | { 244 | case 1: 245 | case 3: 246 | case 5: 247 | case 7: 248 | case 8: 249 | case 10: 250 | case 12: 251 | validDate = validDate && day >= 1 && day <= 31; 252 | break; 253 | case 2: 254 | validDate = validDate && day >= 1 && (day <= (isLeapYear ? 29 : 28)); 255 | break; 256 | case 4: 257 | case 6: 258 | case 9: 259 | case 11: 260 | validDate = validDate && day >= 1 && day <= 30; 261 | break; 262 | default: validDate = false; 263 | } 264 | std::cout << validDate; 265 | 266 | //Task 12 267 | int x1, y1, x2, y2, x3, y3, minX, minY, maxX, maxY; 268 | std::cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3; 269 | // намираме минималните и максималните координати от двете дадени точки 270 | if (x1 > x2) 271 | { 272 | maxX = x1; 273 | minX = x2; 274 | } 275 | else 276 | { 277 | maxX = x2; 278 | minX = x1; 279 | } 280 | if (y1 > y2) 281 | { 282 | maxY = y1; 283 | minY = y2; 284 | } 285 | else 286 | { 287 | maxY = y2; 288 | minY = y1; 289 | } 290 | 291 | bool isOnLowerOrUpperLine = (y3 == minY || y3 == maxY) && (x3 >= minX && x3 <= maxX); 292 | bool isOnLeftOrRightLine = (x3 == minX || x3 == maxX) && (y3 >= minY && y3 <= maxY); 293 | 294 | if (x3 > minX && x3 < maxX && y3 > minY && y3 < maxY) 295 | { 296 | std::cout << "In the rectangle"; 297 | } 298 | else if (isOnLowerOrUpperLine || isOnLeftOrRightLine) 299 | { 300 | std::cout << "On the rectangle"; 301 | } 302 | else 303 | { 304 | std::cout << "Outside the rectangle"; 305 | } 306 | 307 | //Task 13 308 | double a, b, c; 309 | std::cout << "You are given the equation ax^2 + bx + c = 0." << std::endl; 310 | std::cout << "Enter the value of coef. a, b and c: "; 311 | std::cin >> a >> b >> c; 312 | 313 | if (a == 0) { 314 | if (b != 0) { 315 | std::cout << "The equation " << b << "x + " << c << " = 0 has 1 root." << std::endl; 316 | } 317 | else if (c == 0) { 318 | std::cout << "The equation has infinitely many solutions." << std::endl; 319 | } 320 | else { 321 | std::cout << "The equation has no solution." << std::endl; 322 | } 323 | } 324 | 325 | double d = b * b - 4 * a * c; 326 | 327 | if (d > 0) { 328 | std::cout << "The equation has two real roots." << std::endl; 329 | } 330 | else if (d == 0) { 331 | std::cout << "The equation has one real double root." << std::endl; 332 | } 333 | else { 334 | std::cout << "The equation has zero real roots." << std::endl; 335 | } 336 | 337 | //Task 14 338 | const int LETTER_DIFF = 'a' - 'A'; 339 | char lowerBoundA, upperBoundA, lowerBoundB, upperBoundB, letter; 340 | std::cin >> lowerBoundA >> upperBoundA >> lowerBoundB >> upperBoundB >> letter; 341 | char swappedCaseLetter = (letter >= 'A' && letter <= 'Z') ? letter + LETTER_DIFF : letter - LETTER_DIFF; 342 | bool belongsToA = (letter >= lowerBoundA && letter <= upperBoundA) 343 | || (swappedCaseLetter >= lowerBoundA && swappedCaseLetter <= upperBoundA); 344 | bool belongsToB = (letter >= lowerBoundB && letter <= upperBoundB) 345 | || (swappedCaseLetter >= lowerBoundB && swappedCaseLetter <= upperBoundB); 346 | bool belongsToUnion = belongsToA || belongsToB; 347 | bool belongsToIntersection = belongsToA && belongsToB; 348 | bool belongsToDifference = belongsToA && !belongsToB; 349 | bool belongsToOnlyOne = belongsToUnion && !belongsToIntersection; 350 | 351 | std::cout << "(Union, Intersection, Difference, Only one) : " 352 | << (belongsToUnion ? "true" : "false") << ", " 353 | << (belongsToIntersection ? "true" : "false") << ", " 354 | << (belongsToDifference ? "true" : "false") << ", " 355 | << (belongsToOnlyOne ? "true" : "false"); 356 | 357 | -------------------------------------------------------------------------------- /Week 02/README.md: -------------------------------------------------------------------------------- 1 | # Условни оператори.
Оператори за цикъл 2 | 3 | 4 | 5 | ## Условни оператори 6 | 7 | - Предоставят разклонение в логиката на програмата 8 | - Винаги оценяваме дадено булево условие 9 | 10 | ```cpp 11 | if() 12 | ``` 13 | 14 | ```cpp 15 | int x = 42; 16 | if(x % 2 == 0) std::cout << "x is even"; 17 | ``` 18 | 19 | 20 | 21 | - Може да добавяме и какво да се случи ако не влезем в това разклонение 22 | 23 | ```cpp 24 | if() 25 | else 26 | ``` 27 | 28 | ```cpp 29 | int x = 42; 30 | if(x % 2 == 0) std::cout << "x is even"; 31 | else std::cout << "x is odd"; 32 | ``` 33 | 34 | > [!NOTE] 35 | > Влизаме или само в операция 1 или само в операция 2 36 | 37 | 38 | 39 | - Може да добавяме и множество разклонения 40 | 41 | ```cpp 42 | if() 43 | else if() 44 | ... 45 | else if() 46 | else 47 | ``` 48 | 49 | ```cpp 50 | int x = 42; 51 | if(x > 0) std::cout << "x is positive"; 52 | else if(x < 0) std::cout << "x is negative"; 53 | else std::cout << "x is zero"; 54 | ``` 55 | 56 | > [!NOTE] 57 | > Винаги влизаме само в едно разклонение и надолу проверките спират, ако все още има такива 58 | 59 | 60 | 61 | - Операцията може да бъде цял блок, обособяващ в себе си и повече от една операция 62 | 63 | ```cpp 64 | int x = 42; 65 | int result; 66 | if(x > 0) 67 | { 68 | std::cout << "x is positive"; 69 | result = 2; 70 | } 71 | else if(x < 0) 72 | { 73 | std::cout << "x is negative"; 74 | result = 1; 75 | } 76 | else 77 | { 78 | std::cout << "x is zero"; 79 | result = 0; 80 | } 81 | ``` 82 | 83 | > [!NOTE] 84 | > Обикновено, дори да имаме само 1 операция, винаги създаваме scope за условия оператор, за по-голяма четимост 85 | 86 | 87 | 88 | - Когато имаме по-сложна логика на програмата можем да правим и вложени проверки 89 | 90 | ```cpp 91 | int x = 42; 92 | if(x > 0) 93 | { 94 | if(x%2==0) std::cout << "x is positive and even"; 95 | else std::cout << "x is positive and odd"; 96 | } 97 | else if(x < 0) 98 | { 99 | if(x%2==0) std::cout << "x is negative and even"; 100 | else std::cout << "x is negative and odd"; 101 | } 102 | else 103 | { 104 | std::cout << "x is zero"; 105 | } 106 | ``` 107 | 108 | > [!IMPORTANT] 109 | > Трето ниво на влагане на проверки обикновено означава недобре структуриран код 110 | 111 | 112 | 113 | ### switch-case 114 | 115 | - Подобно на `if`, можем да правим проверки, но за дадени стойности 116 | - Имаме експлицитно ограничение стойностите на кои типове можем да сравняваме - `int`, `char`, `bool`, `enum`(??) 117 | - Използваме оператор `break` за прекъсване на изпълнението на оператора, ако намерим попадение 118 | - Използваме ключовата дума `default` за случай, в който не намерим попадение преди това 119 | 120 | ```cpp 121 | switch() 122 | { 123 | case : break; 124 | case : break; 125 | // ... 126 | case : break; 127 | default: break; 128 | } 129 | ``` 130 | 131 | 132 | 133 | - По принцип подреждаме по вероятност на случаите стойностите за проверка 134 | - Ако не ползваме `break`, то ще пропаднем надолу по случаите, дори без да има попадение 135 | - `default` случаят се разглежда последен винаги, независимо от позицията си в тялото на `switch`. За четимост винаги го пишем последен! 136 | - След последния случай в тялото може да не пишем оператор `break`, понеже няма накъде да пропаднем повече. За четимост може да го пишем! 137 | - Операциите на случаите може да са цели блокове 138 | 139 | > [!WARNING] 140 | > Ако искаме да декларираме променливи в даден случай, задължително ни трябва нов block scope. Изключение е, ако случаят е последен. Защо? 141 | 142 | 143 | 144 | - Switch vs if 145 | 146 | ```cpp 147 | int x = 42; 148 | 149 | switch(x) 150 | { 151 | case 1 : std::cout<<"one"; break; 152 | case 2 : std::cout<<"two"; break; 153 | case 3 : std::cout<<"three"; break; 154 | case 4 : std::cout<<"four"; break; 155 | default : std::cout<<"idk"; break; 156 | } 157 | 158 | if(x==1) std::cout<<"one"; 159 | else if(x==2) std::cout<<"two"; 160 | else if(x==3) std::cout<<"three"; 161 | else if(x==4) std::cout<<"four"; 162 | else std::cout<<"idk"; 163 | ``` 164 | 165 | - Компилаторът прави оптимизация, генерирайки jump tree за `switch`, което предполага по-бързо изпълнение. Това в днешно време не е задължително да е предимство пред `if`, понеже различните компилатори на различен код правят различни оптимизации и е възможно `if` да се справя дори по-добре. 166 | - `switch` е подходящ, когато проверяваме за конкретни стойности на променлива, в случаите когато са повече от 2 възможни разклонения. Във всички останали случаи предпочитаме `if`. 167 | 168 | 169 | 170 | - Пример за пропадане 171 | 172 | ```cpp 173 | switch(x) 174 | { 175 | case 1 : std::cout<<"one"; 176 | case 5 : std::cout<<"five"; 177 | case 3 : std::cout<<"three"; break; 178 | case 2 : std::cout<<"two"; 179 | case 4 : std::cout<<"four"; break; 180 | case 6 : std::cout<<"three"; 181 | default : std::cout<<"idk"; break; 182 | } 183 | ``` 184 | 185 | - Пример за декларация на променлива 186 | 187 | ```cpp 188 | int y = 24; 189 | switch(x) 190 | { 191 | // case 3 : int y = 42; std::cout<<"three"; break; 192 | case 3 : { int y = 42; std::cout<<"three"; break; } 193 | case 4 : std::cout<<"four"; break; 194 | default : int y = 42; std::cout<<"idk"; break; 195 | } 196 | ``` 197 | 198 | 199 | 200 | > [!IMPORTANT] 201 | > Тялото на произволна клауза може да е празно. Това на практика не се ползва. 202 | 203 | ```cpp 204 | int x = 42; 205 | if(x==0); 206 | else if(x==5) std::cout<<"five"; 207 | else if(x==10); 208 | else; 209 | ``` 210 | 211 | ```cpp 212 | int x = 42; 213 | switch(x) 214 | { 215 | case 1 : break; 216 | case 2 : ; 217 | case 3 : std::cout<<"three"; 218 | case 4 : ; 219 | default : std::cout<<"idk" break; 220 | } 221 | ``` 222 | 223 | 224 | 225 | - Разлики с тернарен оператор 226 | - Връщане на стойност 227 | - Изпълнение на множество инструкции 228 | 229 | ```cpp 230 | if(x % 2 == 0) std::cout << "even\n"; 231 | else std::cout << "odd\n"; 232 | 233 | std::cout << (x % 2 == 0 ? "even" : "odd") << "\n"; 234 | ``` 235 | 236 | ```cpp 237 | int x = 42, y = 42; 238 | double z = 5; 239 | if(x%2 == 0) y+=2; 240 | else z+=1; 241 | 242 | x%2 == 0 ? y+=2 : z+= 1; 243 | ``` 244 | 245 | > [!WARNING] 246 | > Тернарен оператор ползваме, когато искаме да върнем стойност 247 | 248 | 249 | 250 | > [!CAUTION] 251 | > Всяка програма, която ползва множество `if` проверки, може да се представи като програма, която използва множество `switch` проверки. Това е важно едниствено с цел за разбирането на принципа на работа на условните оператори, не е от практическо значение. Възможно е и представянето на програмата единствено с тернарни оператори, като това изкривява тотално смисъла на операторите. 252 | 253 | 254 | 255 | ## Оператори за цикъл 256 | 257 | - Цикълът е процес, представляващ многократното изпълнение на дадена последователност от операции с определени данни 258 | - В общия смикъл е операция, която се изпълнява определен брой пъти 259 | - Цикличния процес може да **ИМА** предварително известен брой повторения - тогава той е **индуктивен** процес 260 | - Цикличния процес може да **НЯМА** предварително известен брой повторения - тогава той е **итеративен** процес 261 | 262 | 263 | 264 | ### Оператор while 265 | 266 | ```cpp 267 | while() 268 | ``` 269 | 270 | - Изпълнява операцията, докато булевото условие е истина 271 | - Операцията в общия случай трябва да променя някакви данни, за да може условието в даден момент да стане лъжа 272 | - Може операцията да е цял блок, представялващ нов scope. За прегледност винаги пишем блок! 273 | - Оценява се условието, изпълнява се тялото, оценява се условието, изъплянава се тялото, оценява се условието, ..., оценява се условието 274 | - Можем да създаваме и безкрайни цикли, което не е приложимо в практиката... 275 | 276 | 277 | 278 | ```cpp 279 | while(true) std::cout << "Infinite loop"; 280 | 281 | int i = 0; 282 | while(i <= 100) 283 | { 284 | std::cout << i << std::endl; 285 | ++i; 286 | } 287 | ``` 288 | 289 | 290 | 291 | > [!IMPORTANT] 292 | > По принцип префиксната инкрементация е по-оптимална от постфиксната и може да направи някаква оптимизация. Защо? 293 | 294 | 295 | 296 | - Поведението на цикъла може да се контролира и от оператор `break` - когато го използваме някъде в тялото на цикъла изпълнението спира до този ред и условието повече не се оценява 297 | - Друг оператор е `continue` - при него спираме изпълнението на тялото на цикъла и отиваме директно на следващата оценка на условието 298 | 299 | > [!NOTE] 300 | > Когато имаме цикли, които имат по-сложни условия за финал (които по-лесно могат да се оценят в тялото на цикъла) обикновено правим безкраен цикъл и в тялото ползваме `break` 301 | 302 | 303 | 304 | ```cpp 305 | int i = 0; 306 | 307 | while(true) 308 | { 309 | std::cout << i << std::endl; 310 | if(i==100) break; 311 | ++i; 312 | } 313 | ``` 314 | 315 | ```cpp 316 | int i = 0; 317 | 318 | while(true) 319 | { 320 | if(i==101) break; 321 | ++i; 322 | if(i%2==1) continue; 323 | std::cout << i << std::endl; 324 | } 325 | ``` 326 | 327 | > [!CAUTION] 328 | > От съществено значение е мястото, на което ползваме `break` и `continue` 329 | 330 | 331 | 332 | ### Оператор do-while 333 | 334 | - Различава се от оператор `while` с това, че **тялото се изпълнява поне веднъж** 335 | 336 | ```cpp 337 | do while(); 338 | ``` 339 | 340 | - Операцията може и трябва да е отделен блок 341 | - Изпълнява се тялото, оценява се условието, изъплянава се тялото, оценява се условието, ..., оценява се условието 342 | 343 | ```cpp 344 | 345 | int i = 0; 346 | do 347 | { 348 | std::cout << i << std::endl; 349 | } 350 | while(i <= 10); 351 | 352 | ``` 353 | 354 | 355 | 356 | ### Оператор for 357 | 358 | ```cpp 359 | for(; ; ) 360 | ``` 361 | 362 | - Улеснява рабоата, еквивалентен на 363 | 364 | ```cpp 365 | { 366 | ; 367 | while() 368 | { 369 | ; 370 | ; 371 | } 372 | } 373 | ``` 374 | 375 | - Инициализация, условие, тяло, инкрементация, условие, тяло, инкрементация, условие, тяло, инкрементация, ..., условие 376 | 377 | 378 | 379 | ```cpp 380 | for(;;); // Infinite loop 381 | ``` 382 | 383 | ```cpp 384 | for(int i = 0; i <= 100; ++i) 385 | { 386 | std::cout << i << std::end; 387 | } 388 | ``` 389 | 390 | ```cpp 391 | for(int i = 0; i <= 100; i+=2) 392 | { 393 | std::cout << i << std::end; 394 | } 395 | ``` 396 | 397 | ```cpp 398 | int i = 0; 399 | 400 | for (std::cout << "initialize\n"; ((std::cout << "checking i=" << i << std::endl), i <= 5); std::cout<<"incrementing\n", i+=2 ) 401 | { 402 | std::cout< 407 | 408 | > [!IMPORTANT] 409 | > Всички оператори за цикли са взаимно заменяеми. Всеки трябва да може да пише еквивалентния код с друг оператор. 410 | 411 | > [!IMPORTANT] 412 | > Обикновено ползваме `for` за индуктивни процеси, `while` за итеративни, а `do-while` не ползваме. 413 | > Важно е да напишем цикъла по разбираем и подходящ начин. 414 | 415 | > [!IMPORTANT] 416 | > Когато имаме повторение на код, трябва или да изнесем общата логика от разклоненията, или да направим цикъл. По-нататък ще разберем и други възможности за справяне с този проблем. 417 | 418 | > [!NOTE] 419 | > Въпроси? 420 | -------------------------------------------------------------------------------- /Week 02/Tasks.md: -------------------------------------------------------------------------------- 1 | # Задачи 2 | 3 | ## Основни задачи 4 | 5 | **Задача 1:** Да се напише програма, която прочита цяло число и проверява дали е в интервалите $A = (0,50]$, $B = (50,100)$, $C = [100,200]$ или не е в никое от тях, като извежда подходящо съощение. 6 | 7 | **Задача 2:** Да се напише програма, която прочита цяло число и проверява дали е валиден ден от седмицата (1-7) и извежда подходящо съобщение за деня. 8 | 9 | **Задача 3:** Да се напише програма, която въвежда размерите на геометрична фигура и пресмята лицето й. Фигурите са четири вида: квадрат (s), правоъгълник (r), кръг (c) и триъгълник (triangle). На първия ред на входа се чете вида на фигурата (square, rectangle, circle или triangle). Ако фигурата е квадрат, на следващия ред се чете едно число – дължина на страната му. Ако фигурата е правоъгълник, на следващите два реда четат две числа – дължините на страните му. Ако фигурата е кръг, на следващия ред чете едно число – радиусът на кръга. Ако фигурата е триъгълник, на следващите два реда четат две числа – дължината на страната му и дължината на височината към нея. 10 | 11 | **Задача 4:** Да се напише програма, която при подадени радиус $r$ и двумерна точка $(х, у)$ проверява дали точката се намира вътре/извън или по контура на окръжност с център $(0,0)$. 12 | -------------------------------------------------------------------------------- /Week 03/Practicum.md: -------------------------------------------------------------------------------- 1 | ## Примери ## 2 | ### **1.** Какво ще отпечата на екрана следният код? 3 | ```c++ 4 | #include 5 | int main() 6 | { 7 | const int ALPHABET_LETTER_COUNT = 26; 8 | 9 | char currentLetter; 10 | for (int i = 0; i < ALPHABET_LETTER_COUNT; i++) 11 | { 12 | currentLetter = 'a' + i; 13 | std::cout << currentLetter; 14 | } 15 | } 16 | 17 | //cons: big logic, hard to follow, currentLetter initialization is at risk of having undefined value 18 | ``` 19 | ### **2** Какво ще се случи след изпълнение на следния код? (Да анализираме различни варианти) 20 | ```c++ 21 | #include 22 | int main() 23 | { 24 | const int ALPHABET_LETTER_COUNT = 26; 25 | 26 | for (int i = 0, char currentLetter = 'a' ; i < ALPHABET_LETTER_COUNT; i++, currentLetter++) 27 | { 28 | std::cout << currentLetter; 29 | } 30 | } 31 | ``` 32 | ### **3** Какво е хубавото в тази интерпретация и какво не е наред? 33 | ```c++ 34 | #include 35 | int main() 36 | { 37 | const int ALPHABET_LETTER_COUNT = 26; 38 | 39 | char currentLetter = 'a'; 40 | for (int i = 0; i < ALPHABET_LETTER_COUNT; i++, currentLetter++) 41 | { 42 | std::cout << currentLetter; 43 | } 44 | } 45 | //pros: +readable 46 | // +All changes of counterlogic are in 1 place 47 | //cons: 48 | // -variable currentLetter stays in the stack after the loop 49 | // -2 variables in counter updation part 50 | ``` 51 | ### **4** Какво е хубавото в тази интерпретация и какво не е наред? 52 | ```c++ 53 | #include 54 | int main() 55 | { 56 | const int ALPHABET_LETTER_COUNT = 26; 57 | 58 | for (int i = 0; i < ALPHABET_LETTER_COUNT; i++) 59 | { 60 | char currentLetter = 'a' + i; 61 | std::cout << currentLetter; 62 | } 63 | } 64 | //pros: readable and the logic in the for loop stays there 65 | //(i and currentLetter are removed from the stack after the loop) 66 | 67 | //cons: maybe the slowest, because of the initialization of currentLetter 68 | ``` 69 | ### **5** Without extra variable 70 | ```c++ 71 | #include 72 | int main() 73 | { 74 | const int ALPHABET_LETTER_COUNT = 26; 75 | const char FIRST_ALPHABET_LETTER = 'a'; 76 | 77 | for (int i = 0; i < ALPHABET_LETTER_COUNT; i++) 78 | { 79 | std::cout << (char)(FIRST_ALPHABET_LETTER + i); 80 | } 81 | } 82 | //pros: no extra data in stack 83 | //cons: not very readable, casting is slowing the program 84 | ``` 85 | ```c++ 86 | #include 87 | int main() 88 | { 89 | const int ALPHABET_LETTER_COUNT = 26; 90 | for (int i = 0; i < ALPHABET_LETTER_COUNT; i++) 91 | { 92 | std::cout << (char)('a' + i); 93 | } 94 | } 95 | ``` 96 | ### **6** Best scenario for the task 97 | ```c++ 98 | #include 99 | int main() 100 | { 101 | const int ALPHABET_LETTER_COUNT = 26; 102 | 103 | char currentLetter = 'a'; 104 | for (int i = 0; i < ALPHABET_LETTER_COUNT; i++) 105 | { 106 | std::cout << currentLetter++; 107 | } 108 | } 109 | //only 4 bites more but very readable 110 | ``` 111 | ### **7** Another good 112 | ```c++ 113 | #include 114 | int main() 115 | { 116 | for (char i = 'a'; i <= 'z'; i++) 117 | { 118 | std::cout << i; 119 | } 120 | } 121 | //the best : with no additional memory and the fastest with least operations (+,-,++,--,=...), readable, but breaks the logic behind the counter i. 122 | ``` 123 | ### **8.** Същия "код" ли е като предните? 124 | ```c++ 125 | #include 126 | 127 | const int ALPHABET_LETTER_COUNT = 26; 128 | const char FIRST_ALPHABET_LETTER = 'a'; 129 | 130 | int main() 131 | { 132 | int i = 0; 133 | while (i < ALPHABET_LETTER_COUNT) 134 | { 135 | std::cout << (char)(FIRST_ALPHABET_LETTER + i++); 136 | } 137 | } 138 | ``` 139 | ### **9.** Какво ще отпечата на екрана следният код? 140 | ```c++ 141 | #include 142 | int main() 143 | { 144 | int a = 10; 145 | while (a) 146 | { 147 | a++; 148 | std::cout << a--; 149 | a--; 150 | } 151 | } 152 | ``` 153 | 154 | ## Задачи 155 | ### **1.** Да се напише програма, която чете от конзолата 2 цели числа n и m в интервала [0, 256] и изписва символите на всички ASCII кодове в интервала [n, m] 156 | 157 | **Пример:** 158 | 159 | Вход: 160 | ```c++ 161 | Start: 65 162 | End: 75 163 | ``` 164 | Изход: 165 | ```c++ 166 | 65 --> A 167 | 66 --> B 168 | 67 --> C 169 | 68 --> D 170 | 69 --> E 171 | 70 --> F 172 | 71 --> G 173 | 72 --> H 174 | 73 --> I 175 | 74 --> J 176 | 75 --> K 177 | ``` 178 | Вход: 179 | ```c++ 180 | Start: 300 181 | End: 350 182 | ``` 183 | Изход: 184 | ```c++ 185 | Invalid codes! 186 | ``` 187 | ### **2.** Да се прочетe от конзолата естествено число и да се намери факториелът му. 188 | 189 | **Пример:** 190 | 191 | Вход: 192 | ```c++ 193 | 5 194 | ``` 195 | Изход: 196 | ```c++ 197 | Factorial: 120 198 | ``` 199 | ### **3.** Да се напише програма, която прочита естествено число N и пресмята сборът 1 + (1 + 2) + (1 + 2 + 3) + ... + (1 + 2 + ... + N). 200 | 201 | **Пример:** 202 | 203 | Вход: 204 | ```c++ 205 | 5 206 | ``` 207 | Изход: 208 | ```c++ 209 | 35 210 | ``` 211 | 212 | ### **4.** Да се напише програма, която приема естествено число "n" и изкарва на конзолата всички негови делители. 213 | 214 | **Пример:** 215 | 216 | Вход: 217 | ```c++ 218 | 10 219 | ``` 220 | Изход: 221 | ```c++ 222 | 1 2 5 223 | ``` 224 | 225 | ### **5.** Да се напише програма, която чете от конзолата число N и извежда първите N числа от редицата на Фибоначи. Редицата на Фибоначи се състои от числа, всяко от които е сбора на предишните 2. Първите 2 числа в редицата са 0 и 1. 226 | 227 | **Пример:** 228 | 229 | Вход: 230 | ```c++ 231 | 10 232 | ``` 233 | Изход: 234 | ```c++ 235 | 0 1 1 2 3 5 8 13 21 34 236 | //0+1=1 1+1=2 1+2=3 2+3=5 3+5=8 5+8=13 ... 237 | ``` 238 | ### **6.** Да се напише програма, която приема естествено число n и след това се приема неопределен брой цели числа от стандартния вход. Въвеждането да спре при въвеждане на числото -1. Да се отпечата сборът на всички числа от въведените, които са по-малки от n и са четни. 239 | 240 | **Пример:** 241 | 242 | Вход: 243 | ```c++ 244 | 15 245 | 1 4 5 6 19 22 24 90 124 8 -1 246 | ``` 247 | Изход: 248 | ```c++ 249 | 18 250 | ``` 251 | Вход: 252 | ```c++ 253 | 4 254 | 12 12 12 -1 255 | ``` 256 | Изход: 257 | ```c++ 258 | 0 259 | ``` 260 | ### **7.** Да се напише програма, която чете от конзолата 2 естествени числа m и n и извежда всички перфектни числа в интервала [m, n]. Перфектно е такова число N, което е равно на сумата от своите по-малки делители (т.е. различни от самото число). 261 | 262 | **Пример:** 263 | 264 | Вход: 265 | ```c++ 266 | 1 500 267 | ``` 268 | 269 | Изход: 270 | ```c++ 271 | 6 // 6 се дели на 1, 2, 3; 1+2+3=6 272 | 28 // 28 се дели на 1, 2, 4, 7, 14; 1+2+4+7+14=28 273 | 496 274 | ``` 275 | 276 | ### **8.** Въвеждат се две естествени числа "*n*" и "*m*". Да се изкара координатната им матрица. 277 | 278 | Вход: 279 | 280 | ``` 281 | 4 3 282 | ``` 283 | 284 | Изход: 285 | 286 | ``` 287 | (1, 1) (1, 2) (1, 3) 288 | (2, 1) (2, 2) (2, 3) 289 | (3, 1) (3, 2) (3, 3) 290 | (4, 1) (4, 2) (4, 3) 291 | 292 | ``` 293 | 294 | -------------------------------------------------------------------------------- /Week 03/Practicum_Loops_Bonus.md: -------------------------------------------------------------------------------- 1 | ### **1.** Какво ще отпечата на екрана следният код? 2 | ```c++ 3 | #include 4 | int main() 5 | { 6 | while(true) 7 | { 8 | int i = 10; 9 | while (i = 6 || i = 10) 10 | { 11 | if (i == 0) 12 | break; 13 | if (i == 10) 14 | continue; 15 | std::cout << i-- << std::endl; 16 | std::cout << --i << std::endl; 17 | } 18 | 19 | break; 20 | } 21 | } 22 | ``` 23 | ### Таблица с приоритет на операторите: https://pvs-studio.com/en/blog/terms/0064/ 24 | ### **1.2.** Какво ще отпечата на екрана следният код? 25 | ```c++ 26 | #include 27 | int main() 28 | { 29 | while(true) 30 | { 31 | int i = 10; 32 | while ((i = 6) || (i = 10)) 33 | { 34 | if (i == 0) 35 | break; 36 | if (i == 10) 37 | continue; 38 | std::cout << i-- << std::endl; 39 | std::cout << --i << std::endl; 40 | } 41 | 42 | break; 43 | } 44 | } 45 | ``` 46 | ### **1.3.** Какво ще отпечата на екрана следният код? 47 | ```c++ 48 | #include 49 | int main() 50 | { 51 | while(true) 52 | { 53 | int i = 10; 54 | while ((i == 6) || (i == 10)) 55 | { 56 | if (i == 0) 57 | break; 58 | if (i == 10) 59 | continue; 60 | std::cout << i-- << std::endl; 61 | std::cout << --i << std::endl; 62 | } 63 | 64 | break; 65 | } 66 | } 67 | ``` 68 | ### **1.4.** Какво ще отпечата на екрана следният код? 69 | ```c++ 70 | #include 71 | int main() 72 | { 73 | while (true) 74 | { 75 | unsigned short i = 10; //2B <=> 16b : [0,2^16) 76 | while ((i == 6) || (i != 6)) 77 | { 78 | if (i == 11) 79 | break; 80 | if (i == 10) 81 | i++; 82 | std::cout << i-- << std::endl; 83 | std::cout << --i << std::endl; 84 | } 85 | 86 | break; 87 | } 88 | } 89 | ``` 90 | ### **2.** Какво ще отпечата на екрана следният код? 91 | ```c++ 92 | #include 93 | int main() 94 | { 95 | for (unsigned i = 10; i >= 0; i--) 96 | { 97 | std::cout << i; 98 | } 99 | } 100 | ``` 101 | ### **3.** Каквa е разликата между двата фрагмента код? (while / do-while) 102 | ```c++ 103 | #include 104 | int main() 105 | { 106 | int a = 0; 107 | while (a) 108 | { 109 | std::cout << 'a'; 110 | std::cout << " abc"; 111 | } 112 | } 113 | ``` 114 | ```c++ 115 | #include 116 | int main() 117 | { 118 | int a = 0; 119 | do 120 | { 121 | std::cout << 'a'; 122 | std::cout << " abc"; 123 | } while(a); 124 | } 125 | ``` 126 | ### **4.** Какво ще се случи след изпълнение на кода? 127 | 128 | ```c++ 129 | for(int i=0; i<10 ; ) { 130 | i = i++; 131 | std::cout<<"Hello World"; 132 | } 133 | ``` 134 | 135 | ### **5.** Какво ще се случи след изпълнение на кода? 136 | 137 | ```c++ 138 | do { 139 | int y = 1; 140 | std::cout << y++ << " "; 141 | } while (y <= 10); 142 | 143 | ``` 144 | ## Задачи 145 | ### **1.** Да се прочете от конзолата естествено число N и да се изведе дали може да се представи като сума на 2 прости числа. 146 | 147 | **Пример:** 148 | 149 | Вход: 150 | ```c++ 151 | 20 152 | ``` 153 | Изход: 154 | ```c++ 155 | 20 = 3 + 17 156 | 157 | 20 = 7 + 13 158 | ``` 159 | ### **2.** Нека числовата редица { an }n=1 е зададена по следният начин: 160 | 161 | * a0 = 1/2 162 | * an+1 = (an2 + 1) / 2 163 | 164 | При прочитане на число n от конзолата, изведете стойността на елемента an от редицата. Ако сте работили вярно, ще забележите, че редицата клони към 1. 165 | 166 | **Пример:** 167 | 168 | Вход: 169 | ```c++ 170 | n = 1 171 | ``` 172 | 173 | Изход: 174 | ```c++ 175 | a_n = 0,625 176 | ``` 177 | ## 2. Задачи за рисуване по конзолата 178 | 179 | ### **3.** Да се напише програма, която приема цяло положително число n и отпечатва следната пирамида от доларчета. 180 | 181 | **Пример:** 182 | 183 | ![enter image description here](https://i.ibb.co/SNqW5YF/Capture.png) 184 | 185 | ### **4.** Да се напише програма, която приема цяло положително число **n** и отпечатва следната рамка: 186 | 187 | **Пример:** 188 | 189 | ![enter image description here](https://i.ibb.co/vBjhsTj/Capture2.png) 190 | 191 | ### **5.** Да се напише програма, която приема цяло положително число **n** и отпечатва следната папионка: 192 | 193 | **Пример:** 194 | 195 | ![enter image description here](https://i.ibb.co/NKSPm4z/ddz.png) 196 | 197 | ### **6.** Да се напише програма, която приема цяло положително число **n** и отпечатва следния килим: 198 | 199 | **Пример:** 200 | 201 | ![enter image description here](https://i.ibb.co/c2w8Gwt/kilim.png) 202 | 203 | ### **7** Да се напише програма, която приема цяло положително число n и отпечатва числата от 1 до n*n в спираловиден вид. 204 | 205 | **Пример:** 206 | 207 | ![enter image description here](https://i.ibb.co/KF7TcH6/Capture6.png) 208 | 209 | ### **8** Да се напише програма, която приема цяло положително число n и отпечатва числата от 1 до n*n в спираловиден вид. 210 | 211 | **Пример:** 212 | 213 | ![enter image description here](https://i.ibb.co/hg0268B/Capture7.png) 214 | -------------------------------------------------------------------------------- /Week 03/Practicum_Loops_Bonus_Solutions.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //__________________________________________________// 5 | //Task 1 with functions 6 | 7 | bool isPrime(unsigned num) { 8 | if (num <= 1) 9 | { 10 | return false; 11 | } 12 | unsigned sqrt = std::sqrt(num); //don't need the decimal part 13 | for (size_t i = 2; i <= sqrt; i++) 14 | { 15 | if (num % i == 0) 16 | { 17 | return false; 18 | } 19 | } 20 | return true; 21 | } 22 | 23 | void printPrimeSum(unsigned equalsNumber) { 24 | int middle = equalsNumber / 2; //middle to not include the both cases where 20 = 3 + 17 and 20 = 17 + 3 25 | for (unsigned i = 2; i <= middle; i++) 26 | { 27 | if (isPrime(i)) 28 | { 29 | unsigned filler = equalsNumber - i; 30 | if (isPrime(filler)) 31 | { 32 | std::cout << equalsNumber << " = " << i << " + " << filler << std::endl; 33 | } 34 | } 35 | } 36 | } 37 | 38 | int main() 39 | { 40 | unsigned n; 41 | std::cin >> n; 42 | printPrimeSum(n); 43 | } 44 | 45 | //__________________________________________________// 46 | 47 | int main() 48 | { 49 | //Exercise 1 50 | 51 | int number; 52 | std::cout << "Enter a positive number: "; 53 | std::cin >> number; 54 | if (!std::cin || number < 0) { 55 | std::cout << "You should enter a positive number!" << std::endl; 56 | return 1; 57 | } 58 | 59 | for (int i = 2; i < number; ++i) { 60 | bool isPrimeI = true; 61 | for (int k = 2; k <= std::sqrt(i); ++k) { 62 | if (i % k == 0) { 63 | isPrimeI = false; 64 | break; 65 | } 66 | } 67 | 68 | if (!isPrimeI) continue; 69 | 70 | for (int j = 2; j < number; ++j) { 71 | bool isPrimeJ = true; 72 | int check = j / 2; 73 | for (int k = 2; k <= check; ++k) { 74 | if (j % k == 0) { 75 | isPrimeJ = false; 76 | break; 77 | } 78 | } 79 | 80 | if (isPrimeJ && i + j == number) { 81 | std::cout << i << " + " << j << " = " << number << std::endl; 82 | } 83 | } 84 | } 85 | 86 | //Exercise 2 87 | 88 | int number; 89 | std::cout << "Enter a number bigger than 0: "; 90 | std::cin >> number; 91 | if (!std::cout || number < 1) { 92 | std::cerr << "You should enter a number bigger than!" << std::endl; 93 | return 1; 94 | } 95 | double currentNumber = 0, previousNumber = (double)(1 / 2); 96 | 97 | for (size_t i = 0; i <= number; ++i) { 98 | currentNumber = (previousNumber * previousNumber + 1) / 2; 99 | previousNumber = currentNumber; 100 | } 101 | 102 | std::cout << "a_n = " << (double)previousNumber << std::endl; 103 | 104 | //Exercise 3 105 | 106 | int number; 107 | std::cout << "Enter a number bigger than 0: "; 108 | std::cin >> number; 109 | if (!std::cin || number < 0) { 110 | std::cerr << "You should enter a positive number bigger than 0!" << std::endl; 111 | return 1; 112 | } 113 | 114 | const char ch = '$'; 115 | 116 | for (size_t i = 1; i <= number; ++i) { 117 | for (size_t j = 1; j <= i; ++j) { 118 | std::cout << ch; 119 | } 120 | std::cout << std::endl; 121 | } 122 | 123 | //Exercise 4 124 | 125 | int number; 126 | std::cout << "Enter the dimentions of the frame: "; 127 | std::cin >> number; 128 | if (!std::cin || number < 1) { 129 | std::cerr << "You should enter a positive number bigger than 0!" << std::endl; 130 | return 1; 131 | } 132 | 133 | if (number == 1) { 134 | std::cout << "+" << std::endl; 135 | return 0; 136 | } 137 | 138 | std::cout << "+"; 139 | for (size_t i = 1; i < number - 1; ++i) { 140 | std::cout << "-"; 141 | } 142 | std::cout << "+" << std::endl; 143 | 144 | for (size_t k = 1; k < number - 1; ++k) { 145 | std::cout << '|'; 146 | for (size_t f = 1; f < number - 1; ++f) { 147 | std::cout << '-'; 148 | } 149 | std::cout << '|' << std::endl; 150 | } 151 | 152 | std::cout << "+"; 153 | for (size_t i = 1; i < number - 1; ++i) { 154 | std::cout << "-"; 155 | } 156 | std::cout << "+" << std::endl; 157 | 158 | //Exercise 5 159 | 160 | int number; 161 | std::cout << "Enter the length of your bow tie: "; 162 | std::cin >> number; 163 | if (!std::cin || number < 1) { 164 | std::cerr << "You should enter a positive number bigger than 0!" << std::endl; 165 | return 1; 166 | } 167 | 168 | if (number == 1) { 169 | std::cout << "1 - 1" << std::endl; 170 | return 0; 171 | } 172 | 173 | std::cout << "1"; 174 | for (size_t i = 1; i < number * 3 - 1; ++i) { 175 | std::cout << " "; 176 | } 177 | std::cout << "1" << std::endl; 178 | 179 | for (size_t j = 1; j < number; ++j) { 180 | // Left side (1 to j) 181 | for (size_t k = 1; k <= j; ++k) { 182 | std::cout << k; 183 | } 184 | 185 | for (size_t f = 1; f <= (number * 3 - 2 - j * 2); ++f) { 186 | std::cout << " "; 187 | } 188 | 189 | for (size_t l = j; l >= 1; --l) { 190 | std::cout << l; 191 | } 192 | 193 | std::cout << std::endl; 194 | } 195 | 196 | for (size_t k = 1; k <= number; ++k) { 197 | std::cout << k; 198 | } 199 | for (size_t f = 0; f < number; ++f) { 200 | std::cout << "-"; 201 | } 202 | for (size_t l = number; l >= 1; --l) { 203 | std::cout << l; 204 | } 205 | std::cout << std::endl; 206 | 207 | for (size_t j = number - 1; j >= 1; --j) { 208 | for (size_t k = 1; k <= j; ++k) { 209 | std::cout << k; 210 | } 211 | 212 | for (size_t f = 1; f <= (number * 3 - 2 - j * 2); ++f) { 213 | std::cout << " "; 214 | } 215 | 216 | for (size_t l = j; l >= 1; --l) { 217 | std::cout << l; 218 | } 219 | 220 | std::cout << std::endl; 221 | } 222 | 223 | //Exercise 6 224 | 225 | int n; 226 | std::cout << "Enter a positive number: "; 227 | std::cin >> n; 228 | 229 | if (!std::cin || n < 1) { 230 | std::cerr << "You should enter a positive number bigger than 0!" << std::endl; 231 | return 1; 232 | } 233 | 234 | for (int i = 0; i < n + 2; ++i) { 235 | std::cout << "#"; 236 | } 237 | std::cout << std::endl; 238 | 239 | for (int i = 0; i < n; ++i) { 240 | std::cout << "#"; 241 | 242 | for (int j = 0; j < n; ++j) { 243 | std::cout << (i + j) % n + 1; 244 | } 245 | 246 | std::cout << "#"; 247 | std::cout << std::endl; 248 | } 249 | 250 | std::cout << "#"; 251 | if (n % 2 == 0) { 252 | for (int i = 0; i < n / 2 - 1; ++i) { 253 | std::cout << " "; 254 | } 255 | std::cout << "xx"; 256 | for (size_t i = n / 2; i < n - 1; ++i) { 257 | std::cout << " "; 258 | } 259 | } 260 | else { 261 | for (int i = 0; i < n / 2 - 1; ++i) { 262 | std::cout << " "; 263 | } 264 | std::cout << " x "; 265 | for (size_t i = n / 2; i < n - 2; ++i) { 266 | std::cout << " "; 267 | } 268 | } 269 | std::cout << "#" << std::endl; 270 | 271 | for (int i = n - 1; i >= 0; --i) { 272 | std::cout << "#"; 273 | 274 | for (int j = 0; j < n; ++j) { 275 | std::cout << (i + j) % n + 1; 276 | } 277 | 278 | std::cout << "#"; 279 | std::cout << std::endl; 280 | } 281 | 282 | for (int i = 0; i < n + 2; ++i) { 283 | std::cout << "#"; 284 | } 285 | std::cout << std::endl; 286 | 287 | //Exercise 8 288 | 289 | int size; 290 | std::cout << "Enter the size of the matrix: "; 291 | std::cin >> size; 292 | 293 | if (size < 1) { 294 | std::cerr << "You should enter a positive number bigger than 0!" << std::endl; 295 | return 1; 296 | } 297 | 298 | int currentNumber = 1; 299 | 300 | for (int i = 1; i <= size; ++i) { 301 | if (i % 2 != 0) { 302 | for (int j = 1; j <= size; ++j) { 303 | std::cout << currentNumber << " "; 304 | ++currentNumber; 305 | } 306 | } 307 | else { 308 | int end = currentNumber + size - 1; 309 | for (int j = end; j >= currentNumber; --j) { 310 | std::cout << j << " "; 311 | } 312 | currentNumber += size; 313 | } 314 | std::cout << std::endl; 315 | } 316 | 317 | return 0; 318 | } 319 | -------------------------------------------------------------------------------- /Week 03/Practicum_Solutions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | //Exercise 1 6 | int n, m; 7 | std::cout << "Enter the values of N and M: "; 8 | std::cin >> n >> m; 9 | if (!std::cin || n < 0 || n > 256 || m < 0 || m > 256) { 10 | std::cerr << "You should enter two positive numbers in the interval [0, 256]!" << std::endl; 11 | return 1; 12 | } 13 | 14 | if (n > m) { 15 | int temp = n; 16 | n = m; 17 | m = temp; 18 | } 19 | 20 | for (size_t i = n; i < m; ++i) { 21 | std::cout << i << " -> " << (char)i << std::endl; 22 | } 23 | 24 | 25 | //Exercise 2 26 | int number; 27 | std::cout << "Enter a positive number: "; 28 | std::cin >> number; 29 | if (!std::cin || number < 0) { 30 | std::cerr << "You should enter a positive number!" << std::endl; 31 | return 1; 32 | } 33 | 34 | if (number == 0) { 35 | std::cout << 1 << std::endl; 36 | } 37 | 38 | int product = 1; 39 | 40 | for (size_t i = number; i > 0; --i) { 41 | product *= i; 42 | } 43 | 44 | std::cout << "The factoriel of " << number << " is: " << product << std::endl; 45 | 46 | 47 | //Exercise 3 48 | int number; 49 | std::cout << "Enter a positive number bigger than 0: "; 50 | std::cin >> number; 51 | if (!std::cin || number <= 0) { 52 | std::cerr << "You should enter a positive number bigger than 0!" << std::endl; 53 | return 1; 54 | } 55 | 56 | if (number == 1) { 57 | std::cout << "The sum is 1." << std::endl; 58 | } 59 | 60 | int sumParts = 0, sumWhole = 0; 61 | for (int i = 1; i <= number; ++i) { 62 | sumParts = 0; 63 | for (int j = 1; j <= i; ++j) { 64 | sumParts += j; 65 | } 66 | sumWhole += sumParts; 67 | } 68 | 69 | std::cout << "The sum for the first " << number << " numbers is: " << sumWhole << std::endl; 70 | 71 | 72 | //Exercise 4 73 | int number; 74 | std::cout << "Enter a number: "; 75 | std::cin >> number; 76 | if (!std::cin) { 77 | std::cerr << "You should enter a number!" << std::endl; 78 | return 1; 79 | } 80 | int check = number / 2; //There is no need to check after that 81 | for (size_t i = 1; i <= check; ++i) { 82 | if (number % i == 0) { 83 | std::cout << i << " "; 84 | } 85 | } 86 | 87 | std::cout << std::endl; 88 | 89 | 90 | //Exercise 5 91 | int number; 92 | std::cout << "Enter a positive number: "; 93 | std::cin >> number; 94 | if (!std::cin || number <= 0) { 95 | std::cerr << "You should enter a positive number!" << std::endl; 96 | return 1; 97 | } 98 | 99 | int fibbNumber; 100 | 101 | if (number == 1) { 102 | std::cout << 0 << std::endl; 103 | } 104 | else if (number == 2) { 105 | std::cout << 0 << " " << 1 << " "; 106 | } 107 | else { 108 | int first = 0, second = 1, fibbNumber; 109 | 110 | std::cout << first << " " << second << " "; 111 | 112 | for (size_t i = 3; i <= number; ++i) { 113 | fibbNumber = first + second; 114 | std::cout << fibbNumber << " "; 115 | first = second; 116 | second = fibbNumber; 117 | } 118 | 119 | std::cout << std::endl; 120 | } 121 | 122 | std::cout << std::endl; 123 | 124 | 125 | //Exercise 6 126 | int number; 127 | std::cout << "Enter a number: "; 128 | std::cin >> number; 129 | if (!std::cin) { 130 | std::cerr << "You should enter a number!" << std::endl; 131 | return 1; 132 | } 133 | 134 | int newNum, sum = 0; 135 | std::cout << "Now, enter a row of numbers: "; 136 | while (std::cin) { 137 | std::cin >> newNum; 138 | if (newNum % 2 == 0 && newNum < number) { 139 | sum += newNum; 140 | } 141 | if (newNum == -1) { 142 | break; 143 | } 144 | } 145 | 146 | std::cout << sum << std::endl; 147 | 148 | 149 | //Exercise 7 150 | int m, n; 151 | std::cout << "Enter two positive numbers: "; 152 | std::cin >> m >> n; 153 | if (!std::cin || m < 0 || n < 0) { 154 | std::cerr << "You should enter two positive numbers!" << std::endl; 155 | } 156 | 157 | if (m > n) { 158 | int temp = m; 159 | m = n; 160 | n = temp; 161 | } 162 | 163 | int sum; 164 | for (size_t i = m; i <= n; ++i) { 165 | sum = 0; 166 | int check = i / 2; 167 | for (size_t j = 1; j <= check; ++j) { 168 | if (i % j == 0) { 169 | sum += j; 170 | } 171 | } 172 | if (sum == i) { 173 | std::cout << i << " "; 174 | } 175 | } 176 | 177 | 178 | //Exercise 8 179 | int n, m; 180 | std::cout << "Enter two positive numbers bigger than 1: "; 181 | std::cin >> n >> m; 182 | if (!std::cin || n <= 0 || m <= 0) { 183 | std::cerr << "You should enter two positive numbers!" << std::endl; 184 | return 1; 185 | } 186 | 187 | for (size_t i = 1; i <= n; ++i) { 188 | for (size_t j = 1; j <= m; ++j) { 189 | std::cout << "(" << i << ", " << j << ") "; 190 | } 191 | std::cout << std::endl; 192 | } 193 | 194 | return 0; 195 | } 196 | -------------------------------------------------------------------------------- /Week 03/README.md: -------------------------------------------------------------------------------- 1 | # Условни оператори и оператори за цикъл - затвърждаване.
Основни принципи при работа 2 | 3 | 4 | 5 | ### Валидиране на входа 6 | 7 | - При некоректни входни данни можем да изпишем грешка на `std::cerr` 8 | - Можем да проверяваме състоянието на потока за четене, за да сме сигурни дали операцията е завършила успешно 9 | - `std::cin.fail()` - булева стойност, показваща дали последната операция е завършила с грешка 10 | - `std::cin.good()` - булева стойност показваща дали последната операцията е завършила с успех 11 | - `std::cin.bad()` - булева стойност, показваща дали някоя операция е завършила с грешка 12 | - `std::cin.clear()` - изчиства състоянието на потока 13 | - `!std::cin` - имплицитно се преобразува към тип `bool`, еквивалентно на `std::cin.fail()`, също на `!std::good()` 14 | 15 | 16 | 17 | - При наличие на некоректни данни може да приключим програмата преждевременно с `return ;`. Кодовете за изход са: 18 | - `0` - за успех, стандартно така завършва `main` функцията 19 | - Всеки друг положителен код означава, че програмата завършва с грешка 20 | - За семантично различни грешки се ползват обикновено различни кодове 21 | - Ако искаме програмата да приклячи успешно и просто да принтира грешката на стандартния изход (не на изхода за грешки), то това е валиден случай, всичко зависи от контекста 22 | 23 | 24 | 25 | - Guard clause - проверка с обърнато условие, която предотвратява нататъчното изпълнение на кода (Защо обърнато условие?) 26 | 27 | ```cpp 28 | const int MIN_VALUE = 5; 29 | const int MAX_VALUE = 10; 30 | int number; 31 | std::cin >> number; 32 | if (!std::cin) 33 | { 34 | std::cerr << "You should enter a number" << std::endl; 35 | return 1; 36 | } 37 | 38 | if(x < MIN_VALUE || x > MAX_VALUE) 39 | { 40 | std::cerr << "The number must be between "<< MIN_VALUE<< " and "<< MAX_VALUE << std::endl; 41 | return 2; 42 | } 43 | 44 | // More code 45 | ``` 46 | 47 | 48 | 49 | ### Оптимизация на дървото на разклоненията 50 | 51 | - Случаите, които водят до еднакъв резултат, при нормални обстоятелства, искаме да са събрани заедно, за да избегнем повторението на код 52 | 53 | ```cpp 54 | // Code breaking guides 55 | int year; 56 | std::cin >> year; 57 | if (year % 4 == 0) 58 | { 59 | if (year % 100 == 0) 60 | { 61 | if (year % 400 == 0) 62 | { 63 | cout << "Leap Year"; 64 | } 65 | else 66 | { 67 | cout << "Normal Year"; 68 | } 69 | } 70 | else 71 | { 72 | cout << "Leap Year"; 73 | } 74 | } 75 | else 76 | { 77 | cout << "Normal Year"; 78 | } 79 | ``` 80 | 81 | ```cpp 82 | // Code following guides 83 | int year; 84 | std::cin >> year; 85 | if (year % 4 == 0 && ((year % 100 != 0) || year % 400 == 0)) 86 | { 87 | cout << "Leap Year"; 88 | } 89 | else 90 | { 91 | cout << "Normal Year"; 92 | } 93 | ``` 94 | 95 | 96 | 97 | ### Магически числа и преобразуване на символи 98 | 99 | - Всяко число различно то `0` и `1` трябва да бъде изнесено като константа 100 | - Когато правим проверки за символи, никога не ползваме техните числени стойности от ASCII таблицата, а ползваме символните литерали - така избягваме нуждата от константи 101 | - За преобразуване от малка в голяма буква и обратно, както и от символ цифра в числена стойност, е необходимо да приложим правилата за mapping на интервал в друг (от математиката): 102 | - От малка в голяма буква: `c + 'A' - 'a'` 103 | - От голяма в малка буква: `c + 'a' - 'A'` 104 | - От цифра в числена стойност: `c - '0'` 105 | - От числена стойност в цифра: `c + '0'` 106 | 107 | 108 | 109 | ```cpp 110 | // Code breaking guides 111 | char character; 112 | std::cin >> character; 113 | if (character >= 65 && character <= 90) 114 | { 115 | if (character == 'A' || character == 'E' || character == 'U' || character == 'O' || character == 'Y') 116 | { 117 | std::cout << "Vowel" << endl; 118 | } 119 | else 120 | { 121 | std::cout << "Not Vowel" << endl; 122 | } 123 | std::cout << "Capital Letter" << endl; 124 | char newCharacter = character + 32; 125 | std::cout << newCharacter; 126 | } 127 | ``` 128 | 129 | 130 | 131 | ### Използване на имена от `std` 132 | 133 | - Не е добра практика да ползваме `using namespace std;` от към качество на кода 134 | - От тук нататък този ред е забранен 135 | - Стараем се да пишем винаги `std::cin`, `std::cout`, ... 136 | 137 | 138 | 139 | ### Използване на правилен тип данни 140 | 141 | - Трябва винаги да внимаване дали използваме правилен тип данни спрямо контекста на задачата 142 | 143 | ```cpp 144 | // Code breaking guides 145 | std::cin >> a >> b >> c; 146 | int D = b * b - 4 * a * c; 147 | if (D > 0) 148 | cout << "2 roots"; 149 | else if (D == 0) 150 | cout << "1 doubled root"; 151 | else 152 | cout << "0 roots"; 153 | ``` 154 | 155 | 156 | 157 | ### Сравняване на дробни числа 158 | 159 | - Когато искаме да ползваме дробни числа, винаги предпочитаме `double` 160 | - Винаги когато сравняваме дробни числа, използваме някаква фиксирана грешка и **НИКОГА** `==` 161 | 162 | ```cpp 163 | const double EPSILON = 1e-9; 164 | double x = 0.1 + 0.2; 165 | double y = 0.3; 166 | std::cout << x << std::endl; // 0.3 167 | std::cout << y << std::endl; // 0.3 168 | std::cout << (x == y) << std::endl; // false 169 | std::cout << (x - y) << std::endl; // 5.55112e-17 170 | std::cout << (x < y ? y - x < EPSILON : y - x < EPSILON) << std::endl; // true 171 | ``` 172 | 173 | 174 | 175 | ```cpp 176 | // Code breaking guides 177 | double a, b, c; 178 | std::cin >> a >> b >> c; 179 | if (c < b && c > a) 180 | std::cout << "in the interval"; 181 | if (c == a || c == b) 182 | std::cout << "in the closed interval"; 183 | else 184 | std::cout << "not in the interval"; 185 | ``` 186 | 187 | 188 | 189 | ### Четене от стандартния вход 190 | 191 | - Може да имаме случай на четене от стандартния вход на неизвестен брой данни 192 | - Ако искаме да прочетем всички данни до тяхното изчерпване: 193 | 194 | ```cpp 195 | int num; 196 | int sum = 0; 197 | while(std::cin >> num) 198 | { 199 | sum += num; 200 | } 201 | 202 | std::cout << sum; 203 | ``` 204 | 205 | - Това е удобно при четене от поток при пренасочване, например от файл 206 | - Ако искаме да тестваме от входа от конзолата, то за да подадем сигнал за край на входа може да ползваме `Ctrl + Z` 207 | 208 | 209 | 210 | ### Операции с цифрите на число 211 | 212 | - Когато имаме дадено цяло число, можем да правим всякакви операции с цифрите му, например: 213 | - Да търсим сума или произведение 214 | - Да търсим цифри на определени позиции 215 | - Да търсим числото с обърнати цифри 216 | - Да търсим брой срещания 217 | - Много други... 218 | 219 | - Основна операция е взимането на $k$-тата поредна цифра отпред и отзад на числото $x$, което е $n$-цифрено 220 | - `x / pow(10,n - k) % 10` - отпред назад 221 | - `x / pow(10,k - 1) % 10` - отзад напред 222 | 223 | 224 | 225 | - Може итеративно да обхождаме цифрите отзад напред - най-честия случай 226 | 227 | ```cpp 228 | int n; 229 | std::cin >> n; 230 | while(n != 0) 231 | { 232 | int d = n % 10; 233 | // ... operation with digit d 234 | n /= 10; 235 | } 236 | ``` 237 | 238 | - Mutate vs non-mutable n 239 | 240 | 241 | 242 | ### Подходящ оператор за цикъл 243 | 244 | - Ако проверяваме за зависими помежду си стойности в определен диапазон - `for` 245 | - Ако знаем само как да конструираме условие за финал - `while` 246 | - Ако не знаем нищо - `while` 247 | 248 | 249 | 250 | ### Процеси, основани на циклични проверки 251 | 252 | - Проверка за просто число 253 | - Проверка за НОК и НОД 254 | - Разлагане на число на множители 255 | - Факториел 256 | - Парциални суми 257 | - Ред на Фибоначи 258 | 259 | 260 | 261 | ### Вложени цикли 262 | - Геометрични фигури 263 | - Декартово произведение 264 | - Матрици 265 | -------------------------------------------------------------------------------- /Week 04/Practicum.md: -------------------------------------------------------------------------------- 1 | ## Примери 2 | **1.** **Какво ще отпечата на екрана следният код?** 3 | ```c++ 4 | #include 5 | int main() 6 | { 7 | int i = 9; 8 | while (i = 12) 9 | { 10 | if (i == 0) 11 | break; 12 | if (i == 9) 13 | continue; 14 | i--; 15 | std::cout << i << std::endl; 16 | } 17 | } 18 | ``` 19 | 20 | **2.** **Какво ще се случи при изпълнение на следния код?** 21 | ```c++ 22 | #include 23 | int main() 24 | { 25 | while () 26 | { 27 | std::cout << 3; 28 | } 29 | } 30 | ``` 31 | **А тук?** 32 | 33 | ```c++ 34 | #include 35 | int main() 36 | { 37 | for( ; ; ) 38 | { 39 | std::cout << 3; 40 | } 41 | } 42 | ``` 43 | 44 | **3.** **Какво ще отпечата на екрана следният код?** 45 | ```c++ 46 | for(int i = 5, j = 21; j - i > 6 ; j--, ++i){ 47 | std::cout<< i << ' ' << j << std::endl; 48 | } 49 | ``` 50 | 51 | **4.** Каквa е разликата между двата фрагмента код? 52 | ```c++ 53 | #include 54 | int main() 55 | { 56 | int a = 0; 57 | while (a) 58 | { 59 | std::cout << "a"; 60 | } 61 | } 62 | ``` 63 | ```c++ 64 | #include 65 | int main() 66 | { 67 | int a = 0; 68 | do 69 | { 70 | std::cout << "a"; 71 | } while(a); 72 | } 73 | ``` 74 | 75 | ## Задачи 76 | ### **1.** Да се прочете от конзолата естествено число и да се изведе дали е просто. 77 | 78 | **Пример:** 79 | 80 | Вход: 81 | ```c++ 82 | 23 83 | ``` 84 | Изход: 85 | ```c++ 86 | 1 87 | ``` 88 | ### **2.** Да се прочетат от конзолата естествено число(unsigned int / unsigned) и цифра и да се изведе колко пъти цифрата се среща в даденото число. 89 | 90 | 91 | **Пример:** 92 | 93 | Вход: 94 | ```c++ 95 | 823475897 7 96 | ``` 97 | 98 | Изход: 99 | ```c++ 100 | 2 101 | ``` 102 | 103 | 104 | ### **3.** Да се напише програма, която приема естествено число и отпечатва ново число, съставено от сортираните му във възходящ ред цифри. (ако съдържа нули да се пропуснат) 105 | 106 | **Пример:** 107 | 108 | Вход: 109 | ```c++ 110 | 72341142 111 | ``` 112 | 113 | Изход: 114 | ```c++ 115 | 11223447 116 | ``` 117 | 118 | ### **4.** Да се напише програма, която приема естествено число и го отпечатва наобратно: (ако има водещи нули да се пропуснат) 119 | 120 | **Пример:** 121 | 122 | Вход: 123 | ```c++ 124 | 957254 125 | ``` 126 | 127 | Изход: 128 | ```c++ 129 | 452759 130 | ``` 131 | 132 | ### **5.** Създайте програма, която чете цяло положително число K и интервал [N, M]. Да се изведат всички специални числа в интервала спрямо въведеното K. Специално число е такова чисо, за което K се дели без остатък на всяка негова цифра. (Примерно 2418 е специално спрямо K = 16, защото 16 се дели на 2, 4, 1 и 8). 133 | 134 | Вход: 135 | ```c++ 136 | 3 137 | 1111 9999 138 | ``` 139 | 140 | Изход: 141 | ```c++ 142 | 1111 1113 1131 1133 1311 1313 1331 1333 3111 3113 3131 3133 3311 3313 3331 3333 143 | ``` 144 | 145 | ### **6\*(по желание).** Да се напише програма, която приема число и премахва среднaта цифра , ако числото има нечетен брой цифри или премахва средните две цифри, ако числото има четен брой цифри. След това да се отпечата числото увеличено с 1-ца. 146 | 147 | Вход: 148 | ```c++ 149 | 1234 150 | ``` 151 | 152 | Изход: 153 | ```c++ 154 | 14 15 155 | ``` 156 | 157 | Вход: 158 | ```c++ 159 | 51234 160 | ``` 161 | 162 | Изход: 163 | ```c++ 164 | 5134 5135 165 | ``` 166 | 167 | 168 | ## Примери за *ФУНКЦИИ* 169 | **1.** Какво бихте променили в следния код? 170 | ```c++ 171 | #include 172 | void printPrimeDivs(int num) 173 | { 174 | if (num == 0) 175 | return; 176 | for (int i = 2; i <= num; i++) 177 | { 178 | if (num % i == 0) 179 | { 180 | bool isPrimeDiv = true; 181 | for (int j = 2; j <= sqrt(i); j++) 182 | { 183 | if (i % j == 0) 184 | { 185 | isPrimeDiv = false; 186 | break; 187 | } 188 | } 189 | if (isPrimeDiv) 190 | std::cout << i << " "; 191 | } 192 | } 193 | } 194 | ``` 195 | 196 | **2.** Какво ще отпечата на екрана следният код? 197 | ```c++ 198 | #include 199 | bool f() { 200 | std::cout << 5; 201 | return false; 202 | } 203 | bool g() { 204 | std::cout << 123; 205 | return true; 206 | } 207 | bool h() { 208 | std::cout << 0; 209 | return true; 210 | } 211 | void k() 212 | { 213 | std::cout << (h() || g() || f()) << std::endl; 214 | std::cout << (g() && f() && h()) << std::endl; 215 | } 216 | ``` 217 | 218 | ## Задачи за *ФУНКЦИИ* 219 | ### Да се реализират следните функции: 220 | 221 | ```c++ 222 | 223 | int absoluteValue(int number); //връща | number | 224 | 225 | bool isDigit(char symbol); //връща дали символът е цифра 226 | 227 | char toUpper(char symbol); // ако буквата е малка връща съответната и главна 228 | 229 | char toLower(char symbol); //ако буквата е главна връща съответната и малка 230 | 231 | int toNumber(char symbol); //конвертира от символ в цифра 232 | 233 | char toCharacter(int number); //конвертира от цифра в символ 234 | 235 | int power(int base, unsigned int exponent); // връща base^exponent 236 | 237 | bool isPrime(unsigned int number); //проверява дали дадено число е просто 238 | 239 | short getLength(int number); //връща колко цифри има даденото число 240 | 241 | // да се напишат функции с подходящи сигнатури за задачи 2., 3. и 4. 242 | ``` 243 | 244 | ### **1.** Да се напише функция, която да проверява дали едно число е пермутация на друго. 245 | 246 | Пример: 247 | ```c++ 248 | isPermutation(352953,295335); // true 249 | isPermutation(123,234) // false 250 | ``` 251 | 252 | 253 | ### **2.** Да се напише функция, която да проверява дали число е палиндром.(да е еднакво отляво-надясно и отдясно-наляво) 254 | 255 | Подсказка: *Използвайте функцията за задача 4.* 256 | 257 | Пример: 258 | ```c++ 259 | isPalindrome(1234); // false 260 | isPalindrome(1267621) // true 261 | ``` 262 | -------------------------------------------------------------------------------- /Week 04/Practicum_Solutions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // FUNCTIONS 4 | bool invalidInput(int n) { 5 | return !std::cin || n < 0; 6 | } 7 | 8 | int absoluteValue(int number) { 9 | return number < 0 ? -number : number; 10 | } 11 | 12 | bool isDigit(char symbol) { 13 | return symbol >= '0' && symbol <= '9'; 14 | } 15 | 16 | char toUpper(char symbol) { 17 | if (symbol >= 'a' && symbol <= 'z') { 18 | return symbol + 'A' - 'a'; 19 | } 20 | return symbol; 21 | } 22 | 23 | char toLower(char symbol) { 24 | if (symbol >= 'A' && symbol <= 'Z') { 25 | return symbol + 'a' - 'A'; 26 | } 27 | return symbol; 28 | } 29 | 30 | int toNumber(char symbol) { 31 | if (isDigit(symbol)) { 32 | return symbol - '0'; 33 | } 34 | return -1; 35 | } 36 | 37 | char toCharacter(int number) { 38 | return number + '0'; 39 | } 40 | 41 | int power(int base, unsigned int exponent) { 42 | int result = 1; 43 | for (int i = 0; i < exponent; i++) { 44 | result *= base; 45 | } 46 | return result; 47 | } 48 | 49 | bool isPrime(unsigned int number) { 50 | int nSquared = sqrt(number); 51 | for (int i = 2; i <= nSquared; i++) { 52 | if (number % i == 0) { 53 | return false; 54 | } 55 | } 56 | return true; 57 | } 58 | 59 | short getLength(int number) { 60 | short digits = 0; 61 | while (number) { 62 | digits++; 63 | number /= 10; 64 | } 65 | return digits; 66 | } 67 | 68 | unsigned getDigitOccurences(unsigned number, int digit) { 69 | int occurences = 0; 70 | while (number) { 71 | if (number % 10 == digit) { 72 | occurences++; 73 | } 74 | number /= 10; 75 | } 76 | return occurences; 77 | } 78 | 79 | unsigned toSorted(unsigned n) { 80 | unsigned sorted = 0; 81 | for (int digit = 1; digit <= 9; digit++) { 82 | unsigned occur = getDigitOccurences(n, digit); 83 | for (size_t i = 0; i < occur; i++) { 84 | sorted = sorted * 10 + digit; 85 | } 86 | } 87 | return sorted; 88 | } 89 | 90 | int toReversed(int n) { 91 | int reversed = 0; 92 | while (n) { 93 | reversed = reversed * 10 + n % 10; 94 | n /= 10; 95 | } 96 | return reversed; 97 | } 98 | 99 | bool isPermutation(int first, int second) { 100 | for (int i = 0; i <= 9; i++) { 101 | if (getDigitOccurences(first, i) != getDigitOccurences(second, i)) { 102 | return false; 103 | } 104 | } 105 | return true; 106 | } 107 | 108 | bool isPalindrome(int n) { 109 | return n == toReversed(n); 110 | } 111 | 112 | -------------------------------------------------------------------------------- /Week 04/README.md: -------------------------------------------------------------------------------- 1 | # Функции 2 | 3 | 4 | 5 | ## Същност 6 | 7 | - Код, който има определен семантично завършен смисъл 8 | - Позволява многократната употреба и извикване на кода 9 | - Повишава значително качеството на кода, заради въвеждането на абстракция 10 | - Може да връща даден резултат 11 | 12 | 13 | 14 | ## Декларирация на функция 15 | 16 | ```cpp 17 | [] ([[ ]...]) 18 | { 19 | 20 | 21 | return []; 22 | } 23 | ``` 24 | - `return` прекратява изпълнението на функцията и връща указания резултат 25 | - `void` означава, че функцията не връща стойност. Тогава може да ползваме `return` без да подаваме стойност. Може да не извикаме `return` нито веднъж 26 | - Параметрите са незадължителни 27 | 28 | 29 | 30 | > [!NOTE] 31 | > Когато изтървем типа на връщане, се подразбира тип `int`. Това никога и по никакъв повод не го правим! 32 | 33 | > [!CAUTION] 34 | > Когато функцията има тип на връщане, трябва задължително **ВСЕКИ КЛОН** на програмата да връща стойност 35 | 36 | > [!IMPORTANT] 37 | > **СИГНАТУРА** на функция е последователността от тип на връщане, име на функцията и броя и типа на подадените параметри. Имената на параметрите **НЕ СА** част от сигнатурата на функцията. 38 | 39 | 40 | 41 | ## Формални параметри 42 | 43 | - Параметрите при декларация на функция се наричат формални 44 | - Това са променливите, с които се изпълнява функцията 45 | - Те са само нови имена 46 | - Реалните стойности идват при извикването на функцията 47 | - Фактическите параметри живеят в новия function scope 48 | - Може дадена функция да няма параметри 49 | 50 | 51 | 52 | ## Фактически параметри 53 | 54 | - Параметрите с които извикваме функцията 55 | - Реалните стойности, които се подават на формалните параметри 56 | - Възможно е да се случи имплицитно преобразуване на типовете, реално при извикване се случва присвояване на фактическия параметър на формалния 57 | 58 | ```cpp 59 | // int x = 42.0 - implicit casting on invocation 60 | int func(int x) 61 | { 62 | return x + 1; 63 | } 64 | 65 | int main() 66 | { 67 | std::cout << func(42.0); 68 | } 69 | ``` 70 | 71 | 72 | 73 | ## Малко подробности 74 | 75 | - Подредбата на параметрите е важна, те са позиционни 76 | - При предаване на параметър на функция, се създава копие на оригиналния параметър, не се правят промени по оригиналните променливи 77 | - Добре е даден параметър да е константа, ако няма да се променя 78 | 79 | > [!IMPORTANT] 80 | > Фактическият и формалният параметър са две отделни променливи, които имат еднакви стойности в началото 81 | 82 | 83 | 84 | ## Декларация и дефиниция 85 | - Forward declaration, прототип, декларация - изписване на сигнатурата на функцията 86 | - Не можем в кода да ползваме дадена функция, ако преди това не е декларирана или дефинирана на по-горен ред 87 | - Дефиницията може да е на по-късен етап 88 | - Може да има най-много една дефиниция 89 | - Ако ползваме функция, която е единствено декларирана, без да е дефинирана - грешка 90 | 91 | 92 | 93 | ## Overloading 94 | - Може да имаме повече от една функция с дадено име. Тези функции обаче трябва да са с различни сигнатури, изразяващи се в различни параметри 95 | - Не бива да правим функции, различаващи се само по типа на връщане - грешки по двусмислие 96 | 97 | ```cpp 98 | int f() {return 0;} 99 | int f(int x) {return x;} 100 | int f(int x, int y) {return x + y;} 101 | ``` 102 | 103 | 104 | 105 | ## Параметри по подразбиране 106 | - Параметрите може да имат стойност по подразбиране 107 | - Само последните параметри може да имат стойност по подразбиране 108 | - Това е така, понеже параметрите са позиционни за функцията и няма нужда да подаване параметър, който има стойност по подразбиране, ако тя ни устройва 109 | 110 | ```cpp 111 | // void printLetter(bool capitalize = true, char c) - wrong 112 | void printLetter(char c, bool capitalize = true) 113 | { 114 | std::cout << (capitalize ? c + 'A' - 'a' : c); 115 | } 116 | 117 | int main() 118 | { 119 | printLetter('a'); 120 | printLetter('a', false); 121 | printLetter('a', true); 122 | } 123 | ``` 124 | 125 | 126 | 127 | ## Pure functions 128 | - Чиста функция е такава, която не променя външното състояние на програмата, а просто връща резултат от някакви действия над входа си 129 | - Четенето от и писането на конзолата не са чисти операции 130 | - Трябва да се стремим да пишем чисти функции 131 | - Това очевидно не е възможно винаги, но трябва да отделяме логиката така, че да разграничим чистите операции от тези, мутиращи състоянието 132 | 133 | > [!CAUTION] 134 | > Една функция трябва да отговаря за едно нещо и в никакъв случай да не смесваме чисти операции с мутиращи състоянието 135 | 136 | > [!IMPORTANT] 137 | > Всяка функция трябва да извършва точно едно нещо 138 | 139 | 140 | 141 | ```cpp 142 | // pure function 143 | bool isCapitalLetter(char c) 144 | { 145 | return 'A' <= c && c <= 'Z'; 146 | } 147 | ``` 148 | 149 | ```cpp 150 | // separate function for writing (or reading) 151 | bool printLetter(char c) 152 | { 153 | std::cout << c; 154 | } 155 | ``` 156 | 157 | ```cpp 158 | // incorrect use of non-pure function with composite logic 159 | bool printCapitalLetter() 160 | { 161 | char c; 162 | std::cin >> a; 163 | std::cout << c + 'A' - 'a'; 164 | } 165 | ``` 166 | 167 | 168 | 169 | ## Разделяне на кода 170 | - В големи проекти отделяме дефинициите от декларациите 171 | - Декларациите се правят в хедърни файлове (`.hpp`) 172 | - Тези хедърни файлове се `include`-ват при нужда от употреба на функцията 173 | - За всеки хедърен файл съществува един `.cpp` файл, в който са имплементациите - дефинициите 174 | 175 | > [!NOTE] 176 | > Това води освен до подобряване на качеството на кода, така и до оптимизация на процеса на компенсация 177 | 178 | 179 | 180 | ## Често срещани проблеми 181 | 182 | ```cpp 183 | // Never use if-else to return true or false value of function 184 | bool isCapitalLetter(char c) 185 | { 186 | if('A' <= c && c <= 'Z') 187 | return true; 188 | else 189 | return false; 190 | 191 | // return 'A' <= c && c <= 'Z'; 192 | } 193 | ``` 194 | 195 | ```cpp 196 | // Never use branching when you can skip 197 | bool isPrime(int x) 198 | { 199 | if(x <= 0) 200 | { 201 | return 0; 202 | } 203 | else 204 | { 205 | for (int i = 2; i < a; i++) 206 | { 207 | if (x % i == 0) return false; 208 | } 209 | return true; 210 | } 211 | } 212 | ``` 213 | 214 | 215 | 216 | 217 | ```cpp 218 | // Missing return value of the last branch 219 | int getValue(char c, int x) 220 | { 221 | if('A' <= c && c <= 'Z') 222 | return c - 'A'; 223 | else if(0 <= x && x <= 10) 224 | return x + 50; 225 | 226 | // return 0; 227 | } 228 | ``` 229 | 230 | ```cpp 231 | bool isValidData(int a) 232 | { 233 | if (a >= 1000) 234 | { 235 | return true; 236 | } 237 | if (a % 2 != 0) 238 | { 239 | return false; 240 | } 241 | } 242 | ``` 243 | 244 | 245 | 246 | ## Добри практики 247 | - Употреба на guard clause 248 | 249 | ```cpp 250 | bool IsPrime(const int a) 251 | { 252 | if (a < 2) return false; 253 | if (a == 2) return true; 254 | 255 | for (int i = 3; i * i < a; i += 2) 256 | { 257 | if (a % i == 0) return false; 258 | } 259 | 260 | return true; 261 | } 262 | ``` 263 | 264 | 265 | 266 | ## Копиране на стойността на параметъра 267 | 268 | ```cpp 269 | int increment(int x) 270 | { 271 | x++; 272 | } 273 | 274 | int main() 275 | { 276 | int x = 7; 277 | increment(x); 278 | std::cout << x; // 7 279 | } 280 | ``` 281 | 282 | 283 | 284 | ## Други начини за предаване на параметър 285 | - Когато предаваме параметър по показаните начини досега, ние предаваме копие на стойността на параметъра 286 | - Може да предаваме и действителната променлива, като така всяка промяна ще се отразява и на нея 287 | 288 | - Ползване на референция - след типа на променливата слагаме `&` 289 | 290 | ```cpp 291 | int increment(int& x) 292 | { 293 | x++; 294 | } 295 | 296 | int main() 297 | { 298 | int x = 7; 299 | increment(x); 300 | std::cout << x; // 8 301 | } 302 | ``` 303 | 304 | 305 | 306 | ## Малко повече за референциите 307 | - Трябва да се инициализират при декларация 308 | - След като веднъж е била инициализирана, повече не може да се променя 309 | 310 | ```cpp 311 | // Променливите x и y сочат на едно и също място в паметта 312 | // Aналогично е когато се ползва и във функция 313 | // - формалният параметър сочи същата памет като фактическия 314 | int x = 42; 315 | int& y = x; 316 | y++; 317 | std::cout << x << " " << y; //43 43 318 | 319 | // Тук за променливата b се заделя нова памет и се копира стойността на a 320 | int a = 42; 321 | int b = a; 322 | ``` 323 | 324 | 325 | 326 | ## Указатели 327 | - Указателят е променлива, която пази адрес от паметта - шестнадесетично число, пазещо поредния номер в паметта на първата клетка от променливата 328 | - Създаваме указател от даден тип като след типа сложим `*` 329 | 330 | ```cpp 331 | int* pointer = 0x123; 332 | ``` 333 | 334 | - Префиксен оператор `&`, приложен на променлива - връща нейния адрес 335 | - Префиксен оператор `*`, приложен на променлива-указател - връща стойността, намираща се на този адрес, като взима предвид типа на указателя(колко байта да прочете) - операцита се нарича дереференсиране на указател 336 | 337 | ```cpp 338 | int x = 42; 339 | int* xAddress = &x; //0x... 340 | int xValue = *xAddress; // 42 341 | ``` 342 | 343 | 344 | 345 | ```cpp 346 | // Променливата y има за стойност някакво число - адрес 347 | // Стойността на y е адресът на променливата x 348 | int x = 42; 349 | int* y = &x; 350 | (*y)++; 351 | std::cout << x << " " << (*y); //43 43 352 | ``` 353 | 354 | ```cpp 355 | int increment(int* x) 356 | { 357 | (*x)++; 358 | } 359 | 360 | int main() 361 | { 362 | int x = 7; 363 | increment(&x); 364 | std::cout << x; // 8 365 | } 366 | ``` 367 | 368 | 369 | 370 | > [!IMPORTANT] 371 | > Указателите са изключително важни, защото ни предоставят възможност за "пряк достъп" до паметта! Оттук нататък те ще са основа при работата с масиви и при въвеждането на обектно-ориентираното програмиране. 372 | 373 | > [!CAUTION] 374 | > Указателите позволяват много гъвкавост. Когато може да не ползваме указател, няма нужда да го правим. 375 | > В случаите, в които е неизбежна употребата, трябва да се прави с много внимание и разбиране. 376 | > От указателите не може да се избяга. Трябва да се разбират! 377 | 378 | 379 | 380 | ## Стекова рамка 381 | - Извикването на функции става веднага при достигането на инструкцията 382 | - Инструкциите след функцията продължават след извикването на функцията 383 | - Може да викаме функции във функции 384 | - Стековата рамка запазва последователните извиквания при влизане във функцията и когато функция свърши я маха от стековата рамка (последното извикване се маха) 385 | - Стекът е структура от данни (Повече подробности?) 386 | - Извикване на функция от функция (Рекурсия?) 387 | -------------------------------------------------------------------------------- /Week 05/Practicum.md: -------------------------------------------------------------------------------- 1 | 2 | ## Примери 3 | **1.** Какво ще върне следната функция? 4 | ```c++ 5 | #include 6 | double f() 7 | { 8 | double num1 = 4; 9 | double num2 = 4 / 7; 10 | return (num2-- = ++num1 + 2); 11 | } 12 | ``` 13 | 14 | **2.** Какво ще се изпечата? 15 | ```c++ 16 | #include 17 | 18 | void f(int num){ 19 | num+=7; 20 | } 21 | 22 | void g(int& num){ 23 | num+=7; 24 | } 25 | 26 | int main(){ 27 | int num = 3; 28 | f(num); 29 | std::cout< 39 | 40 | int num1 = 3; 41 | 42 | int foo1(int num2) { 43 | std::cout << num2; 44 | return 4 * num1; 45 | } 46 | 47 | int main() { 48 | int num1 = 1; int num2 = 1; 49 | std::cout << num1 << std::endl << foo1(num1); 50 | } 51 | ``` 52 | 53 | **4.** Какво ще се изпечата? 54 | ```c++ 55 | #include 56 | 57 | 58 | int main() { 59 | for (int i = 0; i <= 20; i*=2, std::cout << ++i << " " << std::endl); 60 | } 61 | ``` 62 | ## 1. Базови задачи 63 | **Задача 1:** Да се напише функция `swap`, която приема две числa и разменя стойностите им. Създайте *overload*-и на тази функция, така че тя да работи за `int`, `double` (добавете и още типове, ако желаете). 64 | 65 | **Пример:** 66 | ```c++ 67 | 5 10 68 | ``` 69 | ```c++ 70 | 10 5 71 | ``` 72 | 73 | **Задача 2:** Създайте фунция, която приема 2 цели числа - числител и знаменател, и съкращава дробта. 74 | 75 | **Бонус:** Напишете програма, която извежда сбора на 2 такива дробни числа. 76 | 77 | **Пример:** 78 | ```c++ 79 | 16 20 80 | ``` 81 | ```c++ 82 | 4 5 83 | ``` 84 | 85 | **Задача 3:** Да се напише функция, която приема число *n* и индекс на цифра *k* и премахва *k*-тата цифра на *n*. 86 | 87 | **Пример:** 88 | ```c++ 89 | 12345 3 90 | ``` 91 | ```c++ 92 | 1245 93 | ``` 94 | 95 | **Задача 4:** Да се напише функция, която приема число и го разделя на две числа, съставени съответно от цифрите му на четна позиция и цифрите му на нечетна. 96 | 97 | **Пример:** 98 | ```c++ 99 | 1234567 100 | ``` 101 | ```c++ 102 | 246 1357 103 | ``` 104 | 105 | **Задача 5:** Да се напише функция, която приема число *n* и индекси на цифри в него - *i* и *j* *(i <= j)*. Програмата да променя *n* така, че накрая да е съставено само от цифрите от *i*-та до *j*-та позиция включително. 106 | 107 | **Пример:** 108 | ```c++ 109 | 1234567 2 5 110 | ``` 111 | ```c++ 112 | 2345 113 | ``` 114 | 115 | **Задача 6:** Да се напише функция, която по дадени 3 числа - *n, m, k* разменя *k*-тите цифри на *m* и *n*. 116 | 117 | **Пример:** 118 | ```c++ 119 | 1234 567 2 120 | ``` 121 | ```c++ 122 | 1634 527 123 | ``` 124 | 125 | **Задача 7:** Да се напише функция `gcd(int first, int second)`, която връща най-големият общ делител на две числа. 126 | 127 | **Пример:** 128 | ```c++ 129 | cout << gcd(15, 25) << endl; 130 | ``` 131 | ```c++ 132 | 5 133 | ``` 134 | 135 | **Задача 8:** Да се напише функция `lcm(int first, int second)`, която връща най-малкото общо кратно на две числа. 136 | 137 | **Пример:** 138 | ```c++ 139 | cout << lcm(6, 9) << endl; 140 | ``` 141 | ```c++ 142 | 18 143 | ``` 144 | 145 | **Задача 9:** Напишете функция `concat(unsigned int first, unsigned int second)`, която връща число, получено при конкатенация (долепяне) на first и second. 146 | **Пример:** 147 | ```c++ 148 | cout << concat(123, 456) << endl; 149 | ``` 150 | ```c++ 151 | 123456 152 | ``` 153 | ## 2. Задачи за практикум 154 | 155 | ### Задача 1: 156 | 157 | Дата представяме като три числа от тип unsigned. Примерно (4, 11, 2022) е валидна дата. Напшиете функция, която приема дата, представена като три числа, и намира следващия ден. От вас се очаква да проверите дали датата е валидна. 158 | 159 | Високосна година (leap year) е календарна година, която съдържа един ден повече. Годината е високосна ако: 160 | * Се дели на 400 (2000 година е високосна) 161 | * Ако не се дели на 100 (2100 година не е високосна) 162 | * Ако се дели на 4 (2004 година е високосна) 163 | * В противен случай не е високосна (2005 не е високосна) 164 | 165 | Да се напише програма която намира коя ще е датата след n дена. 166 | 167 |
168 | 169 | ### Задача 2: 170 | 171 | Да се въведе от потребителя число n. Нека се създаде функция, която приема n . След това потребителя въведе две бинарни числа (само от 0ли и 1ци) с дължина n. Ако двете числа са различни нека програмата изведе колко най-малко swap-a трябва да се направят от първото да се получи второто. 172 | 173 | **Пример 1:** 174 | ```c++ 175 | 5 176 | 11001 177 | 10101 178 | ``` 179 | ```c++ 180 | 1 181 | ``` 182 | 183 | **Пример 2:** 184 | ```c++ 185 | 6 186 | 110110 187 | 011011 188 | ``` 189 | ```c++ 190 | 2 191 | ``` 192 | 193 | **Пример 3:** 194 | ```c++ 195 | 20 196 | 10011011101110001010 197 | 01101000111111001001 198 | ``` 199 | ```c++ 200 | 5 201 | ``` 202 | 203 | **Пример 3:** 204 | ```c++ 205 | 7 206 | 0010111 207 | 1111110 208 | ``` 209 | ```c++ 210 | Invalid numbers - The first number cannot be transformed into the second! 211 | ``` 212 | -------------------------------------------------------------------------------- /Week 05/Practicum_Solutions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //1 5 | void swap(int& first, int& second) { 6 | int temp = first; 7 | first = second; 8 | second = temp; 9 | } 10 | 11 | void swap(double& first, double& second) { 12 | double temp = first; 13 | first = second; 14 | second = temp; 15 | } 16 | 17 | 18 | void swap(char& first, char& second) { 19 | char temp = first; 20 | first = second; 21 | second = temp; 22 | } 23 | 24 | void swap(unsigned& first, unsigned& second) { 25 | unsigned temp = first; 26 | first = second; 27 | second = temp; 28 | } 29 | 30 | 31 | 32 | //7 33 | int gcd(unsigned first, unsigned second) { 34 | 35 | if (first < second) { // we want the larger number to be first and the smaller - second 36 | swap(first, second); 37 | } 38 | 39 | unsigned rest = first;//search euclidian algorithm 40 | 41 | while (rest) { 42 | rest = first % second; 43 | first = second; 44 | second = rest; 45 | } 46 | 47 | return first; 48 | } 49 | 50 | //2 51 | void simplify(unsigned& nominator, unsigned& denominator) { 52 | 53 | int commonDivisor = gcd(nominator, denominator); 54 | nominator /= commonDivisor; 55 | denominator /= commonDivisor; 56 | } 57 | 58 | 59 | unsigned reverse(unsigned num) { 60 | int res = 0; 61 | while (num) { 62 | res *= 10; 63 | res += (num % 10); 64 | num /= 10; 65 | } 66 | 67 | return res; 68 | } 69 | 70 | unsigned countDigits(unsigned num) { 71 | if (num == 0) 72 | return 1; 73 | 74 | int res = 0; 75 | 76 | while (num) { 77 | num /= 10; 78 | res++; 79 | } 80 | 81 | return res; 82 | } 83 | 84 | unsigned pow(unsigned base, unsigned exponent) { 85 | if (base == 0) 86 | return 0; 87 | unsigned res = 1; 88 | 89 | for (size_t i = 0; i < exponent; i++) 90 | { 91 | res *= base; 92 | } 93 | return res; 94 | } 95 | 96 | //9 97 | unsigned concat(unsigned first, unsigned second) { 98 | int secondDigitsCount = countDigits(second); 99 | 100 | return first * pow(10, secondDigitsCount) + second; 101 | } 102 | 103 | //3 104 | unsigned removeKthDigit(unsigned num, unsigned short k) { 105 | unsigned short powerOf10 = 1; 106 | unsigned rightSideOfNum = 0; 107 | 108 | for (unsigned short i = 0; i < k - 1; i++) //take the last k - 1 digits 109 | { 110 | rightSideOfNum *= 10; 111 | rightSideOfNum += (num % 10); 112 | num /= 10; 113 | } 114 | num /= 10; // remove the kth digit 115 | 116 | rightSideOfNum = reverse(rightSideOfNum); 117 | 118 | 119 | return concat(num, rightSideOfNum); 120 | //if the indexation is for front to back 121 | //reverse the number at the start and reverse it again at the end 122 | 123 | } 124 | //4 125 | void split(unsigned num, unsigned& even, unsigned& odd) { 126 | 127 | even = odd = 0; 128 | unsigned short counter = 1; 129 | 130 | while (num) { 131 | if (counter % 2 == 0) { //evens 132 | even *= 10; 133 | even += (num % 10); 134 | } 135 | else { //odds 136 | odd *= 10; 137 | odd += (num % 10); 138 | } 139 | 140 | num /= 10; 141 | counter++; 142 | } 143 | 144 | even = reverse(even); 145 | odd = reverse(odd); 146 | 147 | } 148 | 149 | //5 150 | unsigned trim(unsigned num, unsigned i, unsigned j) { 151 | unsigned digitsCount = countDigits(num); 152 | unsigned digitsToTrimFront = i - 1; 153 | unsigned digitsToTrimBack = digitsCount - j; 154 | 155 | for (size_t i = 0; i < digitsToTrimBack; i++) //trim back 156 | num /= 10; 157 | 158 | num = reverse(num); 159 | 160 | for (size_t i = 0; i < digitsToTrimFront; i++) //trim front 161 | num /= 10; 162 | 163 | 164 | return reverse(num); 165 | 166 | } 167 | 168 | //6 169 | 170 | void changeDigits(unsigned& n, unsigned& m, unsigned k) { 171 | n = reverse(n); 172 | m = reverse(m); 173 | unsigned leftEndN = 0; 174 | unsigned leftEndM = 0; 175 | 176 | for (size_t i = 0; i < k - 1; n /= 10, m /= 10, i++) 177 | { 178 | leftEndN *= 10; 179 | leftEndN += (n % 10); 180 | leftEndM *= 10; 181 | leftEndM += (m % 10); 182 | } 183 | 184 | unsigned digitN = (n % 10); 185 | unsigned digitM = (m % 10); 186 | 187 | n -= digitN; 188 | n += digitM; 189 | m -= digitM; 190 | m += digitN; 191 | n = concat(leftEndN, reverse(n)); 192 | m = concat(leftEndM, reverse(m)); 193 | 194 | } 195 | 196 | //8 197 | unsigned lcm(unsigned first, unsigned second) { 198 | 199 | return (first * second) / gcd(first, second); 200 | } 201 | 202 | 203 | int main() { 204 | } 205 | -------------------------------------------------------------------------------- /Week 05/README.md: -------------------------------------------------------------------------------- 1 | # Масиви 2 | 3 | 4 | 5 | ## Същност 6 | - Съставен тип данни 7 | - Последователност от елементи от един и същ тип 8 | - Предоставят начин за организация на данните 9 | - Линейна структура от данни 10 | 11 | 12 | 13 | ## Декларация на масив 14 | 15 | ```cpp 16 | []; 17 | ``` 18 | 19 | ```cpp 20 | const int ARRAY_SIZE = 10; 21 | int arr[ARRAY_SIZE]; 22 | ``` 23 | 24 | - Създаваме масив с фиксиран размер - статичен масив - броят на елементите му не може да се променя 25 | 26 | > [!CAUTION] 27 | > Когато декларираме масив, задължително указваме размера му, за да знае компилатора колко място да задели 28 | 29 | > [!WARNING] 30 | > Размера на масива задължително е константа - без магически числа 31 | 32 | > [!IMPORTANT] 33 | > Не може за размер на масив да ползваме променлива. Компилаторът трябва да знае преди компилацията размера на масива 34 | 35 | 36 | 37 | ## Дефиниция на масив 38 | 39 | ```cpp 40 | [[]] = {[...]}; 41 | ``` 42 | - Използваме инициализиращ списък 43 | - Това не е нов scope, а семантично различна структура, използвана за даване на стойност при инициализация на съставни типове данни 44 | 45 | ```cpp 46 | const int ARRAY_SIZE = 5; 47 | int arr[ARRAY_SIZE] = { 4, 2 }; // 4 2 0 0 0 48 | int arr[ARRAY_SIZE] = { }; // 0 0 0 0 0 49 | 50 | // undefined values 51 | // (leftover from previous user of the memory) 52 | int arr[ARRAY_SIZE]; 53 | 54 | // int arr[ARRAY_SIZE] = { 1, 2, 3, 4, 5, 6}; - Error 55 | 56 | ``` 57 | 58 | > [!CAUTION] 59 | > Когато дефинираме масив може да му укажем размер и да сложим стойности на първите n на брой елемента. Останалите елементи накрая ще бъдат със стойността по подразбиране за типа (за простите типове досега - 0, за сложни типове - по-нататък) 60 | 61 | 62 | 63 | ```cpp 64 | int arr[] = {1, 2, 3}; // 1 2 3 65 | ``` 66 | 67 | > [!IMPORTANT] 68 | > Може да изпуснем размера на масива. В такъв случай големината му се подразбира от броя елементи в инициализиращия списък 69 | 70 | 71 | 72 | ## Достъп до елементите на масив 73 | 74 | - Елементите на масива се индексират с цели числа от 0 нататък 75 | - Първият елемент е с индекс `0`, а последният елемент е с индекс `n-1`, ако масива е с `n` елемента 76 | - Оператор `[]` ни дава достъп до определен индексиран елемент на масива 77 | 78 | ```cpp 79 | int ARRAY_SIZE = 10; 80 | int arr[ARRAY_SIZE] = {1,2,3,4,5}; 81 | 82 | std::cout << arr[3]; 83 | std::cout << arr[5]; 84 | std::cin >> arr[5]; 85 | std::cout << arr[5]; 86 | ``` 87 | 88 | > [!CAUTION] 89 | > Достъпването на индекс, който не принадлежи на елемент на масива е груба грешка. Дори компилаторът да го позволи, това не трябва да се ползва по никакъв повод. Индексацията с отрицателни индекси - аналогично. 90 | 91 | 92 | 93 | ## Какво всъщност е масив 94 | - Компилаторът заделя определен блок памет, който ще се използва за масива 95 | - Количеството задалена памет се определя като умножим големината на типа на елементите на масива с броя на елементите в масива 96 | 97 | ```cpp 98 | const int ARRAY_SIZE = 10; 99 | int arr[ARRAY_SIZE] = {}; 100 | 101 | std::cout << sizeof(int) * ARRAY_SIZE; // 40 102 | std::cout << sizeof(arr); // 40 103 | ``` 104 | 105 | > [!IMPORTANT] 106 | > Ако имаме даден масив винаги може да намерим броя на елементите му по горните правила 107 | 108 | 109 | 110 | - Самата променлива обаче, с която работим е указател 111 | - Този указател сочи към първият елемент на масива 112 | - И по-точно има стойността на адреса на първия байт на първия елемент на масива 113 | - Този указател не може да бъде променян 114 | 115 | 116 | 117 | ## Оператори, приложени над "масиви" 118 | - Ние няма как да приложим оператор над масив 119 | - Оператор може да приложим единствено над указателя, който имаме при създаване на масива 120 | - Това означава, че оператор `=` за присвояване на стойност на масив не можем да ползваме 121 | - Не можем да четем или пишем цял масив от и на стандартния вход, като използваме единствено променливата 122 | - Не може да извършваме логически операции, например за сравнение на два масива дали са равни с оператор `==` 123 | 124 | > [!IMPORTANT] 125 | > В случаят с инициализиращия списък, въпреки че се използва символа `=`, това не е оператор `=` за присвояване. Аналогично е и при инициализацията на всяка променлива. Ако даваме начална стойност, това не е оператора `=`. 126 | 127 | 128 | 129 | ```cpp 130 | int arr1[5] = {1, 2, 3, 4, 5}; 131 | int arr2[5] = {1, 2, 3, 4, 5}; 132 | std::cout << arr1 << std::endl; // 0xdd61fff970 133 | std::cout << arr2 << std::endl; // 0xdd61fff950 134 | std::cout << (arr1 == arr2) << std::endl; // false 135 | 136 | // arr2 = arr1; - Error: arr2 is not modifiable lvalue 137 | 138 | int* pointer1 = arr1; // modify pointer and elements 139 | const int* pointer2 = arr1; // modify pointer only 140 | int*const pointer3 = arr1; // modify elements only 141 | const int* const pointer4 = arr1; // modify nothing 142 | // arr1 -> similar to int* const 143 | ``` 144 | 145 | > [!NOTE] 146 | > Адресна аритметика, работа с указатели и подробности за работата на масивите по-нататък 147 | 148 | 149 | 150 | ## Операции с масиви 151 | 152 | - Достъп 153 | - Пряк - по индекс 154 | - Обхождане 155 | - Извеждане на масив (писане) 156 | - Търсене на елемент 157 | - Мутация - чрез пряк достъп по индекс 158 | - Въвеждане на масив (четене) 159 | - Сортиране 160 | - Други основни задачи 161 | - Reverse an array 162 | - Equal arrays 163 | - Counting sort basics 164 | 165 | 166 | 167 | ```cpp 168 | const size_t ARRAY_SIZE = 1024; 169 | int arr[ARRAY_SIZE]; 170 | 171 | size_t n; 172 | std::cout << "Enter number of elements: "; 173 | std::cin >> n; 174 | 175 | if (!std::cin) 176 | { 177 | std::cerr << "Could not read number of elements."; 178 | return 1; 179 | } 180 | 181 | if (n > ARRAY_SIZE) 182 | { 183 | std::cerr << "Invalid number of elements. Max number of elements is " << ARRAY_SIZE; 184 | return 2; 185 | } 186 | 187 | std::cout << "Enter the elements: "; 188 | for (size_t i = 0; i < n; i++) 189 | { 190 | std::cin >> arr[i]; 191 | } 192 | 193 | if (std::cin.bad()) 194 | { 195 | std::cerr << "Could not read elements of array."; 196 | return 3; 197 | } 198 | 199 | int search; 200 | std::cout << "Enter element to search: "; 201 | std::cin >> search; 202 | 203 | if (!std::cin) 204 | { 205 | std::cerr << "Could not read the searched number."; 206 | return 4; 207 | } 208 | 209 | int sum = 0; 210 | size_t indexFound = ARRAY_SIZE; 211 | for (size_t i = 0; i < n; i++) 212 | { 213 | sum += arr[i]; 214 | if (indexFound == ARRAY_SIZE && arr[i] == search) 215 | { 216 | indexFound = i; 217 | } 218 | } 219 | 220 | std::cout << "Sum of elements: " << sum << std::endl; 221 | if (indexFound != ARRAY_SIZE) 222 | { 223 | std::cout << "The element " << search << " is at index " << indexFound << std::endl; 224 | } 225 | else 226 | { 227 | std::cout << "The element " << search << " is not in the array" << std::endl; 228 | } 229 | 230 | int reversedArray[ARRAY_SIZE]; 231 | for (size_t i = 0; i < n; i++) 232 | { 233 | reversedArray[i] = arr[n - i - 1]; 234 | } 235 | 236 | std::cout << "The reversed array is: "; 237 | for (size_t i = 0; i < n; i++) 238 | { 239 | std::cout << reversedArray[i] << " "; 240 | } 241 | std::cout << std::endl; 242 | 243 | bool areArraysPalindrome = true; 244 | for (size_t i = 0; i < n; i++) 245 | { 246 | if (reversedArray[i] != arr[i]) 247 | { 248 | areArraysPalindrome = false; 249 | break; 250 | } 251 | } 252 | 253 | // Couting sort / histogram -> only works for positive numbers 254 | const size_t COUNTER_SIZE = 1e6; // max expected element in the array 255 | size_t counter[COUNTER_SIZE] = {}; // could cause stack overflow if too large 256 | for (size_t i = 0; i < n; i++) 257 | { 258 | counter[arr[i]]++; 259 | } 260 | 261 | for (size_t i = 0; i < COUNTER_SIZE; i++) 262 | { 263 | if (counter[i] > 0) 264 | { 265 | std::cout << "The number " << i << " is in the array " << counter[i] << " times" << std::endl;; 266 | } 267 | } 268 | 269 | // Bubble sort 270 | for (size_t i = 0; i < n - 1; i++) 271 | { 272 | bool swapped = false; 273 | for (size_t j = 0; j < n - i - 1; j++) 274 | { 275 | if (arr[j] > arr[j + 1]) 276 | { 277 | std::swap(arr[j], arr[j + 1]); // own swap function here 278 | swapped = true; 279 | } 280 | } 281 | 282 | if (!swapped) 283 | { 284 | break; 285 | } 286 | } 287 | 288 | // Selection sort 289 | for (size_t i = 0; i < n - 1; i++) 290 | { 291 | size_t minIndex = i; 292 | for (size_t j = i + 1; j < n; j++) 293 | { 294 | if (arr[j] < arr[minIndex]) 295 | { 296 | minIndex = j; 297 | } 298 | } 299 | 300 | std::swap(arr[i], arr[minIndex]); // own swap function here 301 | } 302 | ``` 303 | 304 | > [!NOTE] 305 | > Оттук нататък за цели положителни числа използваме типа `size_t`, който отговаря на `unsigned long long int`. По дефиниция това е типа, който може да съдържа всеки възможен индекс на масив. При обхождане на масив, за итерарищата променлива за индекс, отново използваме този тип. 306 | 307 | > [!IMPORTANT] 308 | > Ако решавате задача на контролно или изпит и пише "Да се изведе съобщение за грешка и програмата да приключи успешно", може да се тълкува като да пишем грешките на `std::cout` и да връщаме винаги `return 0;`. Ако в условието пише, че се очаква валиден вход, то не е необходимо да се правят допълнителни проверки. 309 | 310 | 311 | 312 | ## Масиви и функции 313 | 314 | - Подаване на масив като параметър на функция 315 | 316 | > [!IMPORTANT] 317 | > Навсякъде в контекста на функции `size_t size = sizeof(arr) / sizeof(int);` връща `2`, понеже вече работим с променлива произволен указател, която няма информация за първоначалния масив 318 | 319 | ```cpp 320 | void set(int arr[], size_t ind, int value) 321 | { 322 | size_t size = sizeof(arr) / sizeof(int); // 2 323 | if(ind < size) 324 | { 325 | arr[ind] = value; 326 | } 327 | } 328 | 329 | void set(int* arr, size_t ind, int value) 330 | { 331 | size_t size = sizeof(arr) / sizeof(int); // 2 332 | if(ind < size) 333 | { 334 | arr[ind] = value; 335 | } 336 | 337 | arr = &value; 338 | arr[0] = 7; // value = 7; 339 | } 340 | 341 | void set(int* const arr, size_t ind, int value) 342 | { 343 | size_t size = sizeof(arr) / sizeof(int); // 2 344 | if(ind < size) 345 | { 346 | arr[ind] = value; 347 | } 348 | 349 | // arr = &value; - Error: Pointer is constant 350 | } 351 | 352 | void set(const int* arr, size_t ind, int value) 353 | { 354 | size_t size = sizeof(arr) / sizeof(int); // 2 355 | if(ind < size) 356 | { 357 | // arr[ind] = value; - Error: values are constant 358 | } 359 | 360 | arr = &value; 361 | // arr[0] = 7; - Error: values are constant 362 | } 363 | 364 | void set(const int* const arr, size_t ind, int value) 365 | { 366 | size_t size = sizeof(arr) / sizeof(int); // 2 367 | if(ind < size) 368 | { 369 | // arr[ind] = value; - Error: values are constant 370 | } 371 | 372 | // arr = &value; - Error: Pointer is constant 373 | // arr[0] = 7; - Error: values are constant 374 | } 375 | ``` 376 | 377 | 378 | 379 | - Връщане на масив - не може да връщаме статични масиви (тоест указатели към такива). Това е така защото статичните променливи живеят само в scope-a, в който са дефинирани. Повече подробности по-нататък. 380 | 381 | ```cpp 382 | int* getArr(int num) 383 | { 384 | const size_t ARRAY_SIZE = 10; 385 | int arr[ARRAY_SIZE]; 386 | 387 | arr[0] = num; 388 | 389 | return arr; // warning or error (depends on compiler) 390 | } 391 | 392 | // when called - runtime error 393 | ``` 394 | 395 | 396 | 397 | ## За самостоятелна работа 398 | 399 | ***Срок: до 09.11.2024*** 400 | 401 | Въвеждат се две числа от стандартния вход - брой елементи на масиви. Прочетете двата масива от стандартния вход. За двата масива се знае, че са сортирани. Слейте ги в нов сортиран масив. Отпечатайте на стандартния изход новия масив. При нарушаване на някои от условията или възникване на грешка, приключете програмата по подходящ начин. 402 | 403 | > [!IMPORTANT] 404 | > За домашни и контролни не е позволено ползването на вградени функции. Изключения се правят след изрично посочена функция или запитване -------------------------------------------------------------------------------- /Week 06/1.Practicum.md: -------------------------------------------------------------------------------- 1 | # Видове сортиране - https://visualgo.net/en/sorting?slide=1-1 2 | 3 | - Bubble sort 4 | - Selection sort 5 | - Insertion sort 6 | 7 | # Търсене на елемент в сортиран масив 8 | 9 | - Binary search 10 | 11 | ### Bubble sort 12 | 13 | ```c++ 14 | void bubbleSort(int arr[], int n) 15 | { 16 | int i, j; 17 | for (i = 0; i < n - 1; i++) { 18 | for (j = 0; j < n - i - 1; j++) { 19 | if (arr[j] > arr[j + 1]) { 20 | swap(arr[j], arr[j + 1]); 21 | } 22 | } 23 | } 24 | } 25 | ``` 26 | 27 | ### Selection sort 28 | 29 | ```c++ 30 | void selectionSort(int arr[], int n) 31 | { 32 | int i, j, min_idx; 33 | 34 | for (i = 0; i < n - 1; i++) { 35 | 36 | min_idx = i; 37 | for (j = i + 1; j < n; j++) { 38 | if (arr[j] < arr[min_idx]) 39 | min_idx = j; 40 | } 41 | 42 | if (min_idx != i) 43 | swap(arr[min_idx], arr[i]); 44 | } 45 | } 46 | ``` 47 | 48 | ### Insertion sort 49 | 50 | ```c++ 51 | void insertionSort(int arr[], int n) 52 | { 53 | int i, key, j; 54 | for (i = 1; i < n; i++) { 55 | key = arr[i]; 56 | j = i - 1; 57 | 58 | while (j >= 0 && arr[j] > key) { 59 | arr[j + 1] = arr[j]; 60 | j = j - 1; 61 | } 62 | arr[j + 1] = key; 63 | } 64 | } 65 | ``` 66 | 67 | ### Binary search 68 | 69 | ```c++ 70 | int binarySearch(int arr[], int l, int r, int x) 71 | { 72 | while (l <= r) { 73 | int m = l + (r - l) / 2; 74 | 75 | // Check if x is present at mid 76 | if (arr[m] == x) 77 | return m; 78 | 79 | // If x greater, ignore left half 80 | if (arr[m] < x) 81 | l = m + 1; 82 | 83 | // If x is smaller, ignore right half 84 | else 85 | r = m - 1; 86 | } 87 | 88 | // If we reach here, then element was not present 89 | return -1; 90 | } 91 | ``` 92 | 93 | # Задачи, максималният размер да е 1000 94 | 95 | ### **1.** Напишете функция, която приема масив от цели числа и индекс и премахва числото, което се намира на този индекс. 96 | 97 | Вход: 98 | 99 | ``` 100 | [33 1 23 8 54 5 1 6] 3 101 | ``` 102 | 103 | Изход: 104 | 105 | ``` 106 | [33 1 23 54 5 1 6] 107 | ``` 108 | 109 | ### **2.** Напишете функция, която приема 2 масива от цели числа **arr** и **result** (който е празен), 2 числа **a** и **b** и пълни масива **result** с всички числа от **arr**, които са в интервала **[a, b]** . 110 | 111 | Вход: 112 | 113 | ``` 114 | [5 7 1 4 3 9 10] 115 | 2 8 116 | ``` 117 | 118 | Изход: 119 | 120 | ``` 121 | [1 4 3 9 10] 122 | ``` 123 | 124 | ### **3.** Да се напише функция, която приема масив от цели числа и връща дали е симетричен. 125 | 126 | Вход: 127 | 128 | ``` 129 | [1 2 3 2 1] 130 | ``` 131 | 132 | Изход: 133 | 134 | ``` 135 | yes 136 | ``` 137 | 138 | Вход: 139 | 140 | ``` 141 | [1 2 3 4 1] 142 | ``` 143 | 144 | Изход: 145 | 146 | ``` 147 | no 148 | ``` 149 | 150 | ### **4.** Да се напише функция, която приема масив от цели числа и връща дължината на най-дългата редица от еднакви числа. 151 | 152 | **Пример:** 153 | 154 | Вход: 155 | 156 | ```c++ 157 | [3 3 2 2 2 5 2 2 3 3 3] 158 | ``` 159 | 160 | Изход: 161 | 162 | ```c++ 163 | 3 164 | ``` 165 | ### **5.** Напишете функция, която приема масив от цели числа и филтрира отрицателните елементи от масива, като ги премахва. 166 | 167 | **Пример:** 168 | ```c++ 169 | [1, -4, 4, -5, -9, 2, 10] 170 | ``` 171 | ```c++ 172 | [1, 4, 2, 10] 173 | ``` 174 | 175 | 176 | ### **6.** Напишете функция, която приема два масива от цели числа и размерите им, и проверява дали вторият масив е подмасив на първия. 177 | 178 | Вход: 179 | ```c++ 180 | [1, 4, 4, 0, 4, 2] 181 | [4, 0, 4] 182 | ``` 183 | 184 | Изход: 185 | ```c++ 186 | true 187 | ``` 188 | 189 | Вход: 190 | ```c++ 191 | [1, 4, 9, 8, 4, 2] 192 | [4, 9, 2] 193 | ``` 194 | 195 | Изход: 196 | ```c++ 197 | false 198 | ``` 199 | 200 | ### **7.** Да се напише функция, която приема 3 масива от цели числа - arr1, arr2 и result (който е празен), като arr1 и arr2 са сортирани във възходящ ред. В края на функцията result трябва представлява обединение на 2-та масива и е сортиран във възходящ ред. 201 | 202 | **Пример:** 203 | ```c++ 204 | [1, 5, 7, 8] 205 | [2, 3, 9] 206 | ``` 207 | ```c++ 208 | [1, 2, 3, 5, 7, 8, 9] 209 | ``` 210 | 211 | ### **8.** Да се напишат функции, които приемат 3 масива от цели числа - **arr1**, **arr2** и **result** (който е празен) и пълнят третия съответно с обединението на **arr1** и **arr2**. **result** да е сортиран във възходящ ред. 212 | Вход: 213 | 214 | ``` 215 | [2 4 1 7 8] 216 | [1 2 3 5] 217 | ``` 218 | 219 | Изход: 220 | 221 | ``` 222 | [ 1 2 3 4 5 7 8 ] 223 | 224 | ``` 225 | 226 | ### **9.** Да се напише функция, която приема 3 масива от цели числа - **arr1**, **arr2** и **result** (който е празен). В края на функцията **result** представлява сечението на 2-та масива и е сортиран във възходящ ред. 227 | 228 | **Пример:** 229 | 230 | Вход: 231 | 232 | ``` 233 | [2 4 1 3 7 8] 234 | [1 2 3 5] 235 | ``` 236 | 237 | Изход: 238 | 239 | ``` 240 | [ 1 2 3 ] 241 | ``` 242 | -------------------------------------------------------------------------------- /Week 06/2.Practicum_Multidimensional_Arrays.md: -------------------------------------------------------------------------------- 1 | ## Задачи за матрици 2 | 3 | **Задача 1:** Да се напише функция, която приема матрица и връща най-малкия й елемент. 4 | 5 | **Пример:** 6 | ```c++ 7 | 3 5 1 8 | 6 2 4 9 | 9 0 8 10 | ``` 11 | ```c++ 12 | 0 13 | ``` 14 | 15 | **Задача 2:** Да се напише функция, която приема квадратна матрица с **n** на **n** елемента отпечатва главния диагонал, след това и второстепенния. 16 | 17 | **Пример:** 18 | ```c++ 19 | 1 2 3 20 | 4 5 6 21 | 7 8 9 22 | ``` 23 | ```c++ 24 | 1 5 9 25 | 3 5 7 26 | ``` 27 | 28 | **Задача 3:** Да се напише функция, която по даден матрица отпечатва елементите ѝ на зиг-заг (първи ред отляво надясно, втори ред отдясно наляво и т.н.) 29 | 30 | **Пример:** 31 | ```c++ 32 | 1 2 3 33 | 4 5 6 34 | 7 8 9 35 | ``` 36 | ```c++ 37 | 1 2 3 38 | 6 5 4 39 | 7 8 9 40 | ``` 41 | 42 | **Задача 4:** Да се напише функция, която приема квадратна матрица с **n** на **n** елемента и връща дали матрицата е триъгълна, т.е. под главния диагонал има само нули. 43 | 44 | **Пример 1:** 45 | ```c++ 46 | 5 1 5 47 | 0 5 9 48 | 0 6 7 49 | ``` 50 | ```c++ 51 | 0 52 | ``` 53 | 54 | **Пример 2:** 55 | ```c++ 56 | 5 1 5 57 | 0 5 9 58 | 0 0 7 59 | ``` 60 | ```c++ 61 | 1 62 | ``` 63 | 64 | **Задача 5:** Да се напише функция, която транспонира квадратна матрица с **n** на **n** елемента. 65 | 66 | **Пример:** 67 | ```c++ 68 | 1 2 3 69 | 4 5 6 70 | 7 8 9 71 | ``` 72 | ```c++ 73 | 1 4 7 74 | 2 5 8 75 | 3 6 9 76 | ``` 77 | 78 | **Задача 6:** Една квадратна матрица от числа се нарича магически квадрат, когато всички суми, получени поотделно от сбора на елементите по всеки ред/всеки стълб/всеки от двата диагонала са равни. Да се състави функция, която приема квадратна матрица и определя дали образува магически квадрат. 79 | 80 | **Пример:** 81 | ```c++ 82 | 16 3 2 13 83 | 5 10 11 8 84 | 9 6 7 12 85 | 4 15 14 1 86 | ``` 87 | ```c++ 88 | 1 //sum = 34 89 | ``` 90 | 91 | **Задача 7:** Да се напише функция, която: 92 | - събира 2 матрици 93 | - умножава матрица с число 94 | 95 | **Пример (събиране):** 96 | ```c++ 97 | 1 2 3 98 | 4 5 6 99 | 100 | 5 6 7 101 | 8 9 10 102 | ``` 103 | ```c++ 104 | 6 8 10 105 | 12 14 16 106 | ``` 107 | 108 | **Пример (скаларно умножение):** 109 | 110 | ```c++ 111 | 1 2 3 112 | 4 5 6 113 | 114 | 3 115 | ``` 116 | ```c++ 117 | 3 6 9 118 | 12 15 18 119 | ``` 120 | 121 | **Задача 8:** Да се напише функция, която умножава 2 матрици. 122 | 123 | **Пример:** 124 | ```c++ 125 | 1 2 126 | 8 9 127 | 10 0 128 | 1 0 129 | 2 2 130 | 131 | 1 2 3 132 | 4 5 2 133 | ``` 134 | ```c++ 135 | 9 12 15 136 | 44 61 78 137 | 10 20 30 138 | 1 2 3 139 | 10 14 18 140 | ``` 141 | 142 | **Задача 9:** Да се напише функция, която приема матрица и принтира елементите й спираловидно, отвън навътре. 143 | 144 | **Пример:** 145 | ```c++ 146 | 1 2 3 147 | 4 5 6 148 | 7 8 9 149 | ``` 150 | ```c++ 151 | 1 2 3 6 9 8 7 4 5 152 | ``` 153 | 154 | **Задача 10:** Да се напише функция, която приема матрица и я обръща надясно. 155 | 156 | **Пример:** 157 | ```c++ 158 | 1 2 3 159 | 4 5 6 160 | 7 8 9 161 | ``` 162 | ```c++ 163 | 7 4 1 164 | 8 5 2 165 | 9 6 3 166 | ``` 167 | 168 | -------------------------------------------------------------------------------- /Week 06/Exam_Prep.md: -------------------------------------------------------------------------------- 1 | # Подготовка за контролно 2 | 3 | ### **1.** Да се напише програма, която приема двумерна матрица (MxN) с M редове и N колони (0 <= M, N <= 100), размери на двумерна подматрица квадрат (QxQ) (Q <= M и Q <= N). Да се изведе на конзолата най-малката сума на подматрица и съответващия му индекс. 4 | **Пример:** 5 | Вход: 6 | ```c++ 7 | 4 3 8 | 16 3 2 9 | 5 10 11 10 | 9 6 7 11 | 4 15 14 12 | 2 13 | ``` 14 | Изход: 15 | ```c++ 16 | 26 (0,1) 17 | ``` 18 | Пояснение: (0,1) е елемента 3. 3 + 2 + 10 + 11 = 26 19 | 20 |

21 | ### **2.** Да се напише програма, която приема двумерна матрица (MxN) с M редове и N колони, (0<=M,N<=100). Да се изведат на конзолата координатите на тези стойности, които са най-малки спрямо колоната и реда си. 22 | **Пример:** 23 | Вход: 24 | ```c++ 25 | 4 3 26 | 3 4 1 27 | 10 2 8 28 | 6 7 12 29 | 1 11 2 30 | ``` 31 | Изход: 32 | ```c++ 33 | (3,0), (1,1), (0,2) 34 | ``` 35 | Пояснение: (3,0) на 3-ти ред и 0-ва колона е елемента 1. По ред 3 {1, 11, 2}: 1 e най-малкият елемент. По колона 0 {3, 10, 6, 1}: 1 също е най-малката стойност за реда си => Точка с координати (3,0) е търсена координата. Аналогично за (1,1) и (0,2). 36 | 37 | -------------------------------------------------------------------------------- /Week 06/Practicum_Multidimensional_Solutions.cpp: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Week 06/Practicum_Solutions.cpp: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Week 06/README.md: -------------------------------------------------------------------------------- 1 | # Многомерни масиви 2 | 3 | 4 | 5 | ### Същност 6 | - Подобно на едномерните масиви, представляват хиперкуб с елементи 7 | - Данните представляват множество от множество от ... множество от елементи 8 | - Масиви с размерност повече от 3 практически са неприложими, освен за моделиране на големи данни и невронни мрежи 9 | - Най-лесната аналогия на двумерен масив е таблицата (матрица от алгебрата) 10 | - В курса многомерен масив с размерност над 3 няма да е необходим 11 | 12 | 13 | 14 | ### Декларация на двумерен масив 15 | 16 | ```cpp 17 | // 2d array 18 | [][]; 19 | ``` 20 | 21 | ```cpp 22 | int arr1[4][3]; 23 | int arr2[][2] = {{1,2},{5,6},{7,8}} 24 | std::cout << arr2[0][1]; 25 | ``` 26 | 27 | > [!NOTE] 28 | > Може да пропуснем размера само на първото измерение. Това е така защото компилатора трябва да знае колко място да задели за останалите елементи и е необходимо за да изчислява мястото в паметта 29 | 30 | > [!IMPORTANT] 31 | > За размерност на масивите отново се ползват само константи 32 | 33 | 34 | 35 | 36 | ### Принцип на работа 37 | 38 | - Двумерните масиви в паметта са разполагат като едномерни масиви. Благодарение на размерността при инициализация, компилаторът изчислява как да си достъпи адреса в паметта. 39 | - На практика ако имаме двумерен масив `arr`, то `arr[0]` ни връща указател към масива, представляващ второто измерение за конкретната стойност от първото измерение 40 | - Може да си го мислим като масив от масиви 41 | - На практика в паметта се разлога като една последователност и липсва тази концепция за разграничаване на отделните масиви (това е вярно само за статичните масиви) 42 | 43 | > [!NOTE] 44 | > `arr[i][j]` е същото като да достъпим `arr[i * n + j]` 45 | 46 | 47 | 48 | ### Многомерен масив 49 | 50 | ```cpp 51 | int logicalTwist[2][3][4][5][6]; 52 | int arr[3][4][5]; 53 | int arr2[][2][2] = { {{1,2},{3,4}}, {{5,6},{7,8}} }; 54 | arr2[0][1][0] = 42; 55 | ``` 56 | 57 | 58 | 59 | ### Работа с двумерен масив 60 | 61 | Всички операции с двумерни масиви се основават на обхаждането на матрицата. Това носи и своите особености 62 | - Обхождане по редове 63 | - Обхождане по колони 64 | - Обхождане по диагонали 65 | ```cpp 66 | // Обхождане на диагонал, успореден на главия, 67 | // минаващ през елемент matrix[startRow][startCol] 68 | for(size_t i = startRow, j = startCol; i <= n && j <= m; i++; j++){ } 69 | 70 | // Обхождане на диагонал, успореден на втория диагонал, 71 | // минаващ през елемент matrix[startRow][startCol], 72 | // отдолу нагоре 73 | for(int i = startRow, j = startCol; i >= 0 && j <= m; i--; j++){ } 74 | ``` 75 | - Обхождане по спирала 76 | 77 | 78 | 79 | Подаване на двумерен масив във функци - с особеностите на декларацията - може да пропуснем само първата размерност 80 | 81 | > [!IMPORTANT] 82 | > Когато обхождаме масив отзад напред, трябва променливата да е от тип със знак, защото операция -- приложена над елемент от тип size_t със стойност 0 ни дава отново положително цяло число 83 | 84 | 85 | 86 | ### Ефективност на алгоритмите 87 | - За да може да избираме един алгоритъм пред друг, ни трябва някаква мярка 88 | - Пример за такава мярка може да е дали алгоритамът винаги завършва, дали винаги намира решение, дали винаги намира оптимално решение и т.н. 89 | - Като за начало може да въведем понятието сложност на алгоритъм - броят операции, необходими за завършването на алгоритъма 90 | - Тази метрика има своите нюанси, но нека разгледаме сложност в най-лошия случай, тоест броят операции, необходими за изпълнение на алгоритъма при възможно най-неприятни за него входни данни - това може да значи например масив сортиран точно наобратно 91 | - Нотацията за сложност на алгоритъм ползва като параметър `N` - големината на входните данни - може да си го мислим като броя елементи в масива 92 | - Тогава ако искаме да обходим един масив, то ще имаме условно `N` елемента над които да минем 93 | - Като търсим елемент в едномерен масив сложността на алгоритъма ще казваме, че е в най-лошия случай `N`, понеже трябва да обходим целия масив с `N` елемента, ако търсения е последен 94 | - Аналогично ако искаме да обходим квадратна матрица, ще имаме сложност `N*N`, ако `N` е размерността ѝ 95 | - Big O notation? 96 | 97 | 98 | 99 | ### Основна задача 100 | Да се провери дали даден масив е трион - тоест всеки негов елемент е по-малък(или равен) или по-голям(или равен) едновременно от двамата си съседи (`arr[k] <= arr[k+1] <= arr[k+2]` или `arr[k] >= arr[k+1] >= arr[k+2]` за произволно `k`) 101 | 102 | 103 | 104 | ### Сложна задача за упражнение 105 | Дадено е число $n \in [3,10]$ - брой на числата $x_i$. Всяко число $x_i$ има минимум 1 и максимум 10 цифри. Създаваме нулева квадратна матрица, която попълваме по следните правила: 106 | 107 | - Ако цифрите на числото $x_i$ образуват трион, слагаме числото на ред $i$, подравнено вляво, като всяка цифра е отделен елемент 108 | - Ако горното условие не е изпълнено, но четните цифри на числото $x_i$образуват трион, слагаме числото на ред $i$, подравнено вляво, като всяка цифра е отделен елемент 109 | - Ако горните условия не са изпълнени, слагаме числото, получено от текущото като напишем цифрите му в обратен ред, на ред $i$, подравнено вляво, като всяка цифра е отделен елемент 110 | 111 | За така получената матрица образуваме ново число, получено по следните правила: 112 | - Обхождаме матрицата спираловидно по посока на часовниковата стрелка отвън навътре 113 | - Ако предходната цифра от обхождането е нечетна, добавяме текущата цифра към новото число отзад 114 | - Ако предходната цифра от обхождането е четна, то ако сумата на елементите от диагонала, успореден на главния, който минава през текущия елемент, е нечетна, то добавяме текущата цифра към новото число 115 | - Ако новото число надвиши 10 цифри, махаме цифра от началото на числото 116 | 117 | Да се отпечата новополученото число, ако се прочитат от конзолата $n$ и $x_i$. 118 | -------------------------------------------------------------------------------- /Week 07/Practicum.md: -------------------------------------------------------------------------------- 1 | ## Задачи 2 | 3 | **1.** Да се напише функция, която приема масив от символи, големината му и число K. Масивът от символи е число в K-ична бройна система. 4 | Функцията трябва да увеличава числото с 1 (приемаме, че в масива има достатъчно място). 5 | 6 | **Пример:** 7 | 8 | Вход: 9 | ```c++ 10 | ['0', '1', '1'] 3 2 11 | ``` 12 | 13 | Изход: 14 | ```c++ 15 | ['1', '0', '0'] 16 | ``` 17 | 18 | **2.** Да се напише функция, която приема масив от символи, големината му и число K. Масивът от символи е число в K-ична бройна система. 19 | Функцията трябва да намалява числото с 1. 20 | 21 | **Пример:** 22 | 23 | Вход: 24 | ```c++ 25 | ['1', '0', '0'] 3 2 26 | ``` 27 | 28 | Изход: 29 | ```c++ 30 | ['0', '1', '1'] 31 | ``` 32 | 33 | **3.** Напишете функция, която приема два масива от символи, големината им (която е еднаква), число K и празен масив res заедно с големината му. Масивите от символи са числа в K-ична бройна система. 34 | Функцията трябва да прибавя второто към първото и да попълни резултата в res. 35 | 36 | **Пример:** 37 | 38 | Вход: 39 | ```c++ 40 | ['1', '7', '5'] 41 | ['5', '3', '7'] 42 | 3 8 43 | [] 44 | ``` 45 | 46 | Изход: 47 | ```c++ 48 | ['7', '3', '4'] 49 | ``` 50 | 51 | 52 | **4.** Да се напише функция, която приема число от тип **unsigned int** (32 бита) и **K** - бройна система (<= 16-ична). Функцията да връща дали числото е палиндром в дадената бройна система. 53 | 54 | **Пример:** 55 | 56 | Вход: 57 | ```c++ 58 | 7 2 59 | ``` 60 | 61 | Изход: 62 | ```c++ 63 | true 64 | //7 = 111 in binary 65 | ``` 66 | 67 | **5.** Да се напише функция, която приема два масива от символи, големината им и числа К и N. Масивите са съответно две числа - първото в К-ична, второто в N-ична бройна система. Функцията да връща дали числата са равни. 68 | 69 | **Пример:** 70 | 71 | Вход: 72 | ```c++ 73 | ['3', '4', '5'] 3 8 74 | ['E', '5'] 2 16 75 | ``` 76 | 77 | Изход: 78 | ```c++ 79 | true 80 | //345(8) = 229(10) = E5(16) 81 | ``` 82 | 83 | **\*Bonus. LIVE DEMO** Да се напише функция, която приема масив от символи - число в К-ична бройна система - и размера му, К и N, и да върне като резултат нов масив, съдържащ числото преобразувано в N-ична бройна система. 84 | 85 | **Пример:** 86 | 87 | Вход: 88 | 89 | ```c++ 90 | ['9', 'C', 'A'] 3 91 | 13 --> 7 92 | ``` 93 | 94 | Изход: 95 | ```c++ 96 | ['4', '6', '3','0'] 97 | ``` 98 | -------------------------------------------------------------------------------- /Week 07/Practicum_Bonus_Solution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | const int SIZE = 1000; 5 | 6 | int countDigitsInKSystem(int num, int k) { 7 | int counter = 0; 8 | while (num > 0) 9 | { 10 | counter++; 11 | num /= k; 12 | } 13 | return counter; 14 | } 15 | 16 | char convert(int num) { 17 | if (0 <= num && num <= 9) 18 | { 19 | return num + '0'; 20 | } 21 | return num - 10 + 'A'; 22 | } 23 | 24 | int extract(char num) { 25 | if ('0' <= num && num <= '9') 26 | { 27 | return num - '0'; 28 | } 29 | return num - 'A' + 10; 30 | } 31 | 32 | int fromKto10(char kSystem[], int kArrSize, int k) { 33 | int result = 0; 34 | size_t counter = 1; 35 | for (size_t i = 0; i < kArrSize; i++) 36 | { 37 | result *= k; 38 | result += extract(kSystem[i]); 39 | } 40 | return result; 41 | } 42 | 43 | void from10toN(int num, char result[], int& nArrSize, int n) { 44 | nArrSize = countDigitsInKSystem(num, n); 45 | for (long long i = nArrSize - 1; i >= 0; i--) 46 | { 47 | result[i] = convert(num % n); 48 | num /= n; 49 | } 50 | } 51 | 52 | void fromKtoN(char kSystem[], int kSize, int k, char nSystem[], int& nSize, int n) { //defined with convertions between 2 and 36 counting systems 53 | from10toN(fromKto10(kSystem, kSize, k), nSystem, nSize, n); 54 | } 55 | 56 | int main() 57 | { 58 | char arr[] = { 'A', 'B', 'C' }; 59 | int sizeArr = 0; 60 | char result[SIZE]; 61 | fromKtoN(arr, 3, 13, result, sizeArr, 36); 62 | for (size_t i = 0; i < sizeArr; i++) 63 | { 64 | std::cout << result[i]; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Week 07/README.md: -------------------------------------------------------------------------------- 1 | # Бройни системи 2 | 3 | 4 | 5 | - Начин за представяне на числата - количествена характеристика - брой 6 | - Има позиционни бройни системи, които имат теглова стойност за всяка цифра от числото в последователността, а при непозиционните има други правила например за последователността на цифрите като при римската бройна система 7 | - Всяка бройна система се характеризира с основа - броят унакилани символи, с които се записват числата - още азбука на бройната система 8 | - Приемаме че бройната система има за основа естествено ненулево число, въпреки че има и изключения 9 | - Най-разпространени по различни причини са бройните системи с основа 2,8,10,16,20,60,64 10 | - Азбуката на бройната система може да е произволна 11 | 12 | 13 | 14 | - При позиционните бройни системи обкновено отляво надясно цифрите на всяка позиция се умножават с тегло $n^p$, където $n$ e основата на системата, а $p$ е текущата цифра отдясно наляво, индексирана от 0 15 | - Тоест числото $a = a_ka_{k-1} \cdots a_1a_0$ в n-ична бройна система ще има стойност в десетична $\sum_{j=0}^k f(a_j) \cdot n^j$, където $f(x)$ e десетичната стойност на цифрата x от дадената бройна система 16 | - Наример за работа с позиционна бройна система с основа 3 и азбука `'A', 'K', '7'` - семантично означаващи стойности в 10-тична система 0,1,2 - числото `7A` преобразуване към десетична система ще има стойност `6 = 2*3^1 + 0*3^0`. Как образуваме последователни числа? - Когато за дадена позици сме обходили всички възможни цифрени стойности, започваме следващата цифрена стойност, като за една нейна итерация обхождаме всички възможни цифрени стойности на всички предходни позиции 17 | 18 | 19 | 20 | | Десетична (decimal) | Двоична (binary) | осмична (octal) | Шестнайсетична (hexadecimal) | 21 | | ------------------- | ---------------- | --------------- | ---------------------------- | 22 | | 0-9 | 0-1 | 0-7 | 0-F (0-9 & A-F) | 23 | | 00 | 00000 | 00 | 00 | 24 | | 01 | 00001 | 01 | 01 | 25 | | 02 | 00010 | 02 | 02 | 26 | | 03 | 00011 | 03 | 03 | 27 | | 04 | 00100 | 04 | 04 | 28 | | 05 | 00101 | 05 | 05 | 29 | | 06 | 00110 | 06 | 06 | 30 | | 07 | 00111 | 07 | 07 | 31 | | 08 | 01000 | 10 | 08 | 32 | | 09 | 01001 | 11 | 09 | 33 | | 10 | 01010 | 12 | 0A | 34 | | 11 | 01011 | 13 | 0B | 35 | | 12 | 01100 | 14 | 0C | 36 | | 13 | 01101 | 15 | 0D | 37 | 38 | 39 | 40 | - За преобразуване от система в система винаги делим целочислено числото до достигане на нула на число със стойност равна на основана на новата система и взимаме остатъците в обратен ред 41 | - За удобство ако искаме да сметнем десетичната стойност на дадено число може да умножим всяка позиция по 42 | 43 | - За работа при преобразуване между произволни бройни системи е удобно да се ползва преминаване между десетична бройна система 44 | 45 | - Операциите по делене, умножение, изваждане и събиране могат да са объркващи ако искаме да ги приложим над две произволни системи директно, но в общия случай правилата са еднакви 46 | 47 | - Например $2143_5 = 640_7$, понеже $7 = 12_5$ и имаме 48 | - $2143_5 / 12_5 = 132_5 (4_5 = 4_7)$ 49 | - $132_5 / 12_5 = 11_5 (0_5 = 0_7)$ 50 | - $11_5 / 12_5 = 0_5 (11_5 = 6_7)$ 51 | 52 | 53 | 54 | ```cpp 55 | // TODO: there are no validations in this example! 56 | 57 | const size_t MAX_DIGITS = 1024; 58 | 59 | void swap(char& x, char& y) 60 | { 61 | char temp = x; 62 | x = y; 63 | y = temp; 64 | } 65 | 66 | int indexOf(char c, char arr[], size_t count) 67 | { 68 | for (size_t i = 0; i < count; i++) 69 | { 70 | if (arr[i] == c) 71 | { 72 | return i; 73 | } 74 | } 75 | 76 | return -1; 77 | } 78 | 79 | void reverseArray(char arr[], size_t count) 80 | { 81 | for (size_t i = 0; i < count / 2; i++) 82 | { 83 | swap(arr[i], arr[count - i - 1]); 84 | } 85 | } 86 | 87 | int fromNto10(char number[], int digitsCount, int n, char nAlphabet[]) { 88 | int result = 0; 89 | for (size_t i = 0; i < digitsCount; i++) 90 | { 91 | result *= n; 92 | result += indexOf(number[i], nAlphabet, n); 93 | } 94 | return result; 95 | } 96 | 97 | size_t from10toN(int number, int n, char nAlphabet[], char result[]) { 98 | 99 | size_t digitsCount = 0; 100 | while (number) 101 | { 102 | result[digitsCount++] = nAlphabet[number % n]; 103 | number /= n; 104 | } 105 | 106 | reverseArray(result, digitsCount); 107 | return digitsCount; 108 | } 109 | 110 | size_t convertNBaseToKBase(char number[], size_t digitsCount, char result[], size_t n, char nAlphabet[], size_t k, char kAlphabet[]) 111 | { 112 | return from10toN(fromNto10(number, digitsCount, n, nAlphabet), k, kAlphabet, result); 113 | } 114 | ``` 115 | 116 | 117 | 118 | - Представяне на отрицателни числа 119 | - 1's compliment: flip the number (e.g. 1011 -> 0100) - flaw: zero = 00...000 = 11...111 120 | - 2's compliment: flip the number and add 1 (e.g. 1011 -> 0100 -> 0101) - zero = 00...000 121 | - Когато използваме 2's compliment печелим едно допълнително отрицателно число (11...111) -------------------------------------------------------------------------------- /Week 08/Practicum.md: -------------------------------------------------------------------------------- 1 | # Побитови операции 2 | Прилагат се върху един бит или набор от повече отделни битове на двоични числа. 3 | 4 | - Побитово И (**&**) 5 | - Побитово ИЛИ (**|**) 6 | - Побитово ИЗКЛЮЧВАЩО ИЛИ (**^**) 7 | - Побитово отместване (**<<**) (**>>**) 8 | 9 | | | | 10 | |--------|-----------| 11 | | a | 101010100 | 12 | | b | 100101110 | 13 | | a&b | 100000100 | 14 | | a \| b | 101111110 | 15 | | a^b | 001111010 | 16 | | a << 2 | 101010000 | 17 | | a >> 2 | 001010101 | 18 | 19 | 20 | Примери: 21 | 22 | - Функция, която с побитови операции проверява дали число е четно 23 | - Функция, която с побитови операции повдига 2 на степен k. 24 | - Връщане на стойност на бит 25 | - Изчистване на бит (да стане 0) 26 | - Вдигане на бит (да стане 1) 27 | - Обръщане на бит(toggleBit) 28 | - Слагане на подадена стойност на бит. 29 | 30 | 31 | ## Задачи 32 | 33 | **1.** Да се напише функция, която приема 3 цели числа **x**, **m** и **n** и връща числото, което се получава, ако от **x** се вземат **n** бита, започвайки от позиция **m**. 34 | 35 | **Пример:** 36 | 37 | Вход: 38 | ```c++ 39 | 16 4 3 40 | ``` 41 | 42 | Изход: 43 | ```c++ 44 | 4 //*100*00 45 | ``` 46 | 47 | **2.** Напишете функция, която приема цяло число и връща броя на 1-ците в двоичния му запис. 48 | 49 | *Вход: 189, Изход: 6* 50 | 51 | **3.** Напишете функция, която по подадено цяло число n и цяло число k и връща числото, което е "закодирано" в последните k бита на n. 52 | 53 | *Вход: 15 2, Изход: 3* 54 | 55 | *Вход: 189 3, Изход: 5* 56 | 57 | *Вход: 189 4, Изход: 13* 58 | 59 | 60 | **4.** Да се напише функция swap, която приема 2 цели числа **a** и **b** и разменя стойностите им без допълнителна променлива с побитови операции. 61 | 62 | **Пример:** 63 | 64 | Вход: 65 | ```c++ 66 | 120 2 67 | ``` 68 | 69 | Изход: 70 | ```c++ 71 | 2 120 72 | ``` 73 | 74 | **5.** Да се напише функция, която приема 3 цели числа **n**, **p** - позиция и бит **b** - 0 или 1 и сменя бита на **n** на позиция **p** с бита **b**. 75 | 76 | **Пример:** 77 | 78 | Вход: 79 | ```c++ 80 | 120 2 1 81 | ``` 82 | 83 | Изход: 84 | ```c++ 85 | 124 86 | ``` 87 | Вход: 88 | ```c++ 89 | 120 4 0 90 | ``` 91 | 92 | Изход: 93 | ```c++ 94 | 104 95 | ``` 96 | 97 | **6.** Да се напише функция, която приема 2 цели числа **a** и **b** и проверява дали битовете на a са пермутация на битовете на b. 98 | 99 | **Пример:** 100 | 101 | Вход: 102 | ```c++ 103 | 7 11 104 | ``` 105 | 106 | Изход: 107 | ```c++ 108 | 1 109 | ``` 110 | 111 | ## Бонус задачи 112 | 113 | **Задача 1:** Да се напише функция, която приема масив, в който всяко число се среща 2 пъти с изключение на едно число, което се среща веднъж. 114 | Напишете функция, която приема такъв масив и връща кое е това число. 115 | (Подсказка: използвайте побитови операции, за да постигнете линейно решение) 116 | 117 | *Вход: [9 18 9 12 18 15 12], Изход: 15* 118 | 119 | 120 | **Задача 2:** Напишете функция, която приема масив(разглеждаме го като множество) и отпечатва всички негови подмножества(без значение е редът на отпечатване). 121 | 122 | *Вход: [1, 2, 3], Изход: [], [1], [2], [3], [1,2], [2,3], [1,3], [1,2,3]* 123 | 124 | *Вход: [5, 3] Изход: [], [5], [3], [5, 3]* 125 | -------------------------------------------------------------------------------- /Week 08/README.md: -------------------------------------------------------------------------------- 1 | # Побитови операции 2 | 3 | | Оператор | Значение | Тип | 4 | | :---: | :---: | :---: | 5 | | `&` | Побитово **и** | инфиксен, бинарен| 6 | | `\|` | Побитово **или** | инфиксен, бинарен| 7 | | `~` | Побитово **не** | префиксен, унарен| 8 | | `<<` | Побитове отместване наляво | инфиксен, бинарен| 9 | | `>>` | Логическо отместване надясно | инфиксен, бинарен| 10 | 11 | 12 | ```cpp 13 | int x = 7; // 0b110 14 | int y = 5; // 0b101 15 | int op1 = x&y; // 0b100 16 | int op2 = x|y; // 0b111 17 | int op3 = ~x; // 0b001 18 | int op4 = x<<2;// 0b11000 19 | int op5 = x>>2;// 0b1__ 20 | ``` 21 | 22 | 23 | - Основни побитови операции 24 | - Проверка дали число е четно 25 | - Пресмянане 2 на степен k 26 | - Взимане на стойност на бит 27 | - Задаване на стойлност на бит 28 | - Toggle на бит 29 | 30 | 31 | 32 | - Основни приложения 33 | - Четност на срещане на число (свойство на XOR) 34 | - Подмножества - генериране на индикаторна функция (свойство на последователните двоични числа) 35 | - Оптимизация на мястото за съхранение - напр. съхранение на булева информация 36 | -------------------------------------------------------------------------------- /Week 08/bit_manipulation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | bool checkBit(unsigned int n, unsigned ind) 5 | { 6 | unsigned int mask = 1; 7 | mask <<= ind; 8 | return (mask & n) == mask; 9 | } 10 | 11 | unsigned makeBitZero(unsigned int n, unsigned int ind) //clear bit 12 | { 13 | unsigned int mask = 1; 14 | mask <<= ind; 15 | 16 | mask = ~mask; 17 | 18 | return n & mask; 19 | } 20 | 21 | unsigned makeBitOne(unsigned int n, unsigned int ind) //set bit 22 | { 23 | unsigned int mask = 1; 24 | mask <<= ind; 25 | 26 | return n | mask; 27 | } 28 | 29 | 30 | unsigned toggleBitOne(unsigned int n, unsigned int ind) 31 | { 32 | unsigned int mask = 1; 33 | mask <<= ind; 34 | 35 | return n ^ mask; 36 | } 37 | 38 | int main() 39 | { 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Week 08/bitwise_isEven.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | bool isEven(int n) 5 | { 6 | int mask = 1; 7 | return !(n & mask); 8 | } 9 | int main() 10 | { 11 | cout << isEven(30) << endl; 12 | } 13 | -------------------------------------------------------------------------------- /Week 08/bitwise_powerOfTwo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | //Зад. Вход N. Да пресметнете 2^n 6 | 7 | unsigned int powerOfTwo(unsigned int n) 8 | { 9 | if(n > 31) 10 | return 0; //error 11 | 12 | return 1 << n; 13 | } 14 | 15 | 16 | int main() 17 | { 18 | cout << powerOfTwo(8); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Week 08/firstMissing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int getMissing(const int arr[], size_t size) 5 | { 6 | int result = 0; 7 | for(unsigned i = 0; i < size; i++) 8 | result ^= arr[i]; 9 | return result; 10 | } 11 | int main() 12 | { 13 | constexpr size_t size = 7; 14 | int arr[] = {5, 1, 5, 6, 1, 7, 6}; 15 | 16 | cout << getMissing(arr, 7); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /Week 08/generateSubsets.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | void printSubset(const int arr[], size_t size, unsigned mask) 5 | { 6 | cout << "{ "; 7 | for (int i = size - 1; i >= 0; i--) 8 | { 9 | if (mask % 2 != 0) 10 | cout << arr[i] << " "; 11 | mask /= 2; 12 | } 13 | cout << "} " << endl; 14 | 15 | } 16 | 17 | unsigned powerOfTwo(unsigned n) 18 | { 19 | return 1 << n; 20 | } 21 | void generateSubsets(const int arr[], size_t size) 22 | { 23 | //size <= 32 24 | unsigned pt = powerOfTwo(size); 25 | for (unsigned i = 0; i < pt; i++) 26 | printSubset(arr, size, i); 27 | } 28 | int main() 29 | { 30 | constexpr size_t SIZE = 5; 31 | int arr[SIZE] = { 1,2,3,4,5 }; 32 | 33 | generateSubsets(arr, SIZE); 34 | } 35 | -------------------------------------------------------------------------------- /Week 09/Practicum.md: -------------------------------------------------------------------------------- 1 | # Указатели. Символни низове. 2 | 3 | ## Въведение в указателите. 4 | Оператор **&** 5 | 6 | - Приема променлива от тип Т. 7 | 8 | - Връща указател от тип T*. 9 | 10 | 11 | ```c++ 12 | int number = 10; 13 | int* ptr = &number; 14 | ``` 15 | 16 | 17 | Оператор * (дерефериране) 18 | - Приема указaтел от тип Т* 19 | - Връща променлива от тип Т 20 | 21 | 22 | ```c++ 23 | int number = 10; 24 | int* ptr = &number; 25 | int result = *ptr; 26 | cout << result; //10 27 | ``` 28 | 29 | Разлика между указател и референция? 30 | 31 | - Указателят може да се "re-assign"-ва. Може да приема нови стойност 32 | - Референцията трябва да се инициализира при създаването. 33 | - Указателят има неутрална стойност (nullptr), а референцията няма. 34 | - Може да се направи масив от указатели, но не и масив от референции. 35 | 36 | ```c++ 37 | int arr[] = {1, 2, 3}; 38 | int* ptr = arr; 39 | ``` 40 | 41 | ![enter image description here](https://i.ibb.co/cDcX8st/Untitled-Diagram-drawio-3.png) 42 | 43 | 44 | ```c++ 45 | ptr++; 46 | cout << ptr[0]; //2; 47 | cout << ptr[1]; //3; 48 | ``` 49 | 50 | ![enter image description here](https://i.ibb.co/xLLsVK5/Untitled-Diagram-drawio-4.png) 51 | 52 | ```c++ 53 | int number = 10; 54 | int* ptrNumber = &number; 55 | 56 | int copy = *ptrNumber; 57 | copy++; 58 | cout << copy << endl; //11 59 | cout << number << endl; //10 60 | 61 | (*ptrNumber)++; 62 | cout << number << endl; //11 63 | cout << *ptrNumber << endl; //11 64 | cout << ptrNumber << endl; //The adress of number 65 | 66 | int& refNumber = *ptrNumber; 67 | refNumber++; 68 | cout << refNumber << endl; //12 69 | cout << number << endl; //12 70 | cout << &refNumber << ' ' << ptrNumber << endl; //same adress 71 | 72 | const int& constRefNumber = number; //always pointing at the same adress of number 73 | number++; //fine 74 | constRefNumber++; //not fine 75 | cout << constRefNumber << ' ' << number; 76 | 77 | int otherVar = 7; 78 | const int* constNumberPtr = &number; 79 | constNumberPtr = &otherVar; //fine 80 | (*constNumberPtr)++; //not fine 81 | 82 | int* const constPtrNumber = &number; 83 | constPtrNumber = &otherVar; //not fine 84 | (*constPtrNumber)++; //fine 85 | 86 | const int* const constPtrConstNumber = &number; 87 | constPtrConstNumber = &otherVar; //not fine 88 | (*constPtrConstNumber)++; //not fine 89 | ``` 90 | 91 | Какво ще стане, ако дереферираме Nullptr? 92 | 93 | ```c++ 94 | int a = 5; 95 | int* ptrA = &a; 96 | cout << ptrA[0] << endl; //used only with arrays but still works - syntactic sugar 97 | cout << ptrA[1] << endl; //still works but undefined behaviour 98 | 99 | int arr[] = { 1, 2 ,3 }; 100 | int* ptrArr = arr; 101 | cout << ptrArr[0] << endl; 102 | cout << ptrArr[3] << endl; //still works but undefined behaviour 103 | 104 | int* nullPointer = nullptr; 105 | cout << *nullPointer; 106 | ``` 107 | 108 | ## Въведение в символните низове (стрингове). 109 | 110 | ```c++ 111 | char str[] = {'t', 'e', 's', 't', '\0'}; 112 | char str2[] = "test"; //equivalent to str 113 | char str3[7] = "test"; 114 | ``` 115 | 116 | ![enter image description here](https://i.ibb.co/ZmRwt6R/Untitled-Diagram-drawio-5.png) 117 | 118 | Примерна имплементация на: 119 | 120 |

Live:

121 | - strlen (намиране на дължина на стринг)

122 | - strcpy (копиране на стринг)

123 | - strcat (конкатениране на стрингове)

124 | - strcmp (лексикографско сравнение на стрингове)

125 | 126 |

В задачите:

127 | - търсене в текст

128 | - броене на срещанията на конкретен символ в текст

129 | - заместване в стринг.

130 | 131 |

Задачи

132 | 133 | **Задача 1:** Да се напише функция, която приема стринг с произволна дължина **text**, символ **symbol**. Функцията да обработва **text** така, че да не съдържа **symbol** . 134 | 135 | **Пример:** 136 | ```c++ 137 | Hello, my friend! 138 | e 139 | ``` 140 | ```c++ 141 | Hllo, my frind! 142 | ``` 143 | **Задача 2:** Напишете функция, която приема 3 стринга - text, where и what и земства в text всяко срещане на where с what. 144 | 145 | *Да се реши без допълнителна памет (in-place).* 146 | 147 | *Вход: "I am the worst of the worst", "worst" , "best" , Изход: "I am the best of the best"* 148 | 149 | **Задача 3** Напишете функции toUpper и toLower, които приемат стринг и променят всички главни букви в малки/всички малки букви в главни. 150 | 151 | **Задача 4:** Да се напише функция, която приема стринг с произволна дължина от цифри, и стринг **result**. Функцията да обработва **result** така, че да предтсавлява стринг, в който пише коя цифра колко пъти се среща. 152 | 153 | **Пример:** 154 | ```c++ 155 | 4231148 156 | ``` 157 | ```c++ 158 | 2x1,1x2,1x3,2x4,1x8 159 | ``` 160 | 161 | **Задача 5:** Да се напише функция, която приема стринг и го обработва така, че всяка нова дума (в началото на текста или след интервал) да започва с главна буква. 162 | 163 | **Пример:** 164 | ```c++ 165 | hello, my friend! 166 | ``` 167 | ```c++ 168 | Hello, My Friend! 169 | ``` 170 | **Задача 6:** Да се напише функция, която приема стринг **input** и стринг **result**. Функцията да обработва **result** тала, че в него да е записана последната дума от подадения **input**. 171 | 172 | **Пример:** 173 | ```c++ 174 | What is your name 175 | ``` 176 | ```c++ 177 | name 178 | ``` 179 | 180 | **Задача 7** Напишете функция, която приема стринг и връща броя на думите в него. (Думите са разделени с произволен брой интервали, табулации и препинателни знаци) 181 | 182 | *Вход: "Me? Why always me?, Изход: 4* 183 | 184 | 185 | **Задача 8** Напишете функция, която приема стринг и връща най-често срещаната дума.(Думите са разделени с произволен брой интервали, табулации и препинателни знаци). Игнорираме разликата между главни и малки букви за задачата. 186 | 187 | *Вход: "Me? Why always me?, Изход: me* 188 | 189 | **Задача 9** Напишете функция, която приема стринг и връща лексикографско най-малка дума. 190 | 191 | *Вход: "Me? Why always me?, Изход: always* 192 | -------------------------------------------------------------------------------- /Week 09/Practicum_Str_Functions.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace std; 4 | #pragma warning (disable: 4996) 5 | 6 | int myStrLen(const char* str) { 7 | if (str == nullptr) { 8 | return -1; 9 | } 10 | int counter = 0; 11 | while (*str) { 12 | counter++; 13 | str++; 14 | } 15 | return counter; 16 | } 17 | 18 | //copy the source to destination. 19 | //We assume that in dest the are enough cells. 20 | void myStrCpy(const char* source, char* dest) { 21 | if (!source || !dest) 22 | { 23 | return; 24 | } 25 | while (*source) { 26 | *dest = *source; 27 | dest++; 28 | source++; 29 | } 30 | *dest = '\0'; 31 | } 32 | 33 | // - first < second 34 | // 0 first == second 35 | // + first > second 36 | int myStrCmp(const char* str1, const char* str2) { 37 | if (!str1 || !str2) { 38 | return 128; 39 | } 40 | while ((*str1) == (*str2) && (*str1)) { 41 | str1++; 42 | str2++; 43 | } 44 | return (*str1 - *str2); 45 | } 46 | 47 | void myStrcat(char* first, const char* second) { 48 | if (!first || second == nullptr) 49 | return; 50 | 51 | size_t firstLen = myStrLen(first); // abc0 52 | first += firstLen; 53 | myStrCpy(second, first); 54 | } 55 | 56 | 57 | int main() 58 | { 59 | 60 | char str[100] = "ABC"; 61 | char str2[100] = "ABC"; 62 | 63 | cout << myStrCmp(str, str2); 64 | } 65 | -------------------------------------------------------------------------------- /Week 09/README.md: -------------------------------------------------------------------------------- 1 | # Указатели и референции. Работа с масиви. Символни низове. 2 | 3 | 4 | 5 | ## Референции 6 | - Трябва да се инициализират при декларация 7 | - След като веднъж е била инициализирана, повече не може да се променя 8 | 9 | ```cpp 10 | // Променливите x и y сочат на едно и също място в паметта 11 | int x = 42; 12 | int& y = x; 13 | y++; 14 | std::cout << x << " " << y; //43 43 15 | 16 | // int& z; - Error 17 | 18 | // Тук за променливата b се заделя нова памет и се копира стойността на a 19 | int a = 42; 20 | int b = a; 21 | ``` 22 | 23 | - Референции като аргументи на функции 24 | - Референции като резултат на функция - само ако знаем, че променливата е жива след функцията 25 | 26 | 27 | 28 | ## Указатели 29 | - Указателят е променлива, която пази адрес от паметта - шестнадесетично число, пазещо поредния номер в паметта на първата клетка от променливата 30 | - Създаваме указател от даден тип като след типа сложим `*` 31 | 32 | ```cpp 33 | int* pointer = 0x123; 34 | ``` 35 | 36 | - Префиксен оператор `&`, приложен на променлива - връща нейния адрес 37 | - Префиксен оператор `*`, приложен на променлива-указател - връща стойността, намираща се на този адрес, като взима предвид типа на указателя(колко байта да прочете) - операцита се нарича дереференсиране на указател 38 | 39 | ```cpp 40 | int x = 42; 41 | int* xAddress = &x; //0x... 42 | int xValue = *xAddress; // 42 43 | ``` 44 | 45 | 46 | 47 | ```cpp 48 | // Променливата y има за стойност някакво число - адрес 49 | // Стойността на y е адресът на променливата x 50 | int x = 42; 51 | int* y = &x; 52 | (*y)++; 53 | std::cout << x << " " << (*y); //43 43 54 | ``` 55 | 56 | 57 | 58 | - Указател може да има стойност `nullptr` (предефинирана константа от тип указател) - това е нулевият адрес в паметта, който не пренадлежи на никоя програма - използва се за невалидна стойност на указател 59 | 60 | ```cpp 61 | int temp = 0; 62 | int x = 42; 63 | 64 | int *x1 = &x; 65 | *x1 = 7; 66 | x1 = &temp; 67 | 68 | const int *x2 = &x; // same as int const *x1 69 | // *x2 = 7; 70 | x2 = &temp; 71 | 72 | int *const x3 = &x; 73 | *x3 = 7; 74 | // x3 = &temp; 75 | 76 | const int *const x4 = &x; 77 | // *x4 = 7; 78 | // x4 = &temp; 79 | ``` 80 | 81 | 82 | - `void*` - пойнтър без тип - пази само адреса, не може да се ползва за нищо без да се кастне 83 | - Защо всъщност указателите имат тип, ако сам пазят адрес? - За да може да извършваме адресна аритметика 84 | 85 | ```cpp 86 | int x = 42; 87 | 88 | int* xAddress = &x; // address n 89 | xAddress++; // address n + sizeof(int) 90 | ``` 91 | 92 | 93 | 94 | ## Указатели и масиви 95 | - Когато имаме масив, ние имаме указател към първия елемент от масива 96 | - Масивът е последователност в паметта 97 | - Следователно можем с адресна аритметика да достъпваме елементите на масива - така работи оператор `[]` 98 | 99 | ```cpp 100 | int arr[10] = {1,2,3}; 101 | arr[0] = 7; 102 | std:: cout << arr[0]; // 7 103 | 104 | *arr = 8; 105 | std::cout << *arr; // 8 106 | 107 | *(arr + 1) = 9; 108 | std::cout << *(arr + 1); // 9 109 | 110 | // 8 9 3 111 | ``` 112 | 113 | 114 | 115 | `arr[n] = *(arr + n)` 116 | 117 | > [!IMPORTANT] 118 | > Оператор `[]` ни позволява да достъпваме паметта с отместване и нищо повече. Когато имаме масив го интерпретираме като индекс на масива. Ако го прилагаме над произволна променлива, то се случва същото като при масива - отиваме надясно, просто паметта вече не знаем каква е. 119 | 120 | 121 | 122 | - Указател към указател - това е сценарият при матриците. По ООП се ползва и с други цели 123 | 124 | ```cpp 125 | int x = 42; 126 | int* xp = &x; 127 | int** ptr = &xp; 128 | (**xp)++; // x = 43 129 | (*xp)++; // xp value changed 130 | 131 | // Матрицата в паметта е разгърната като една последователност 132 | int matrix[5][5]; 133 | int* const* const mAddress = matrix; 134 | int* arrM = matrix[1]; 135 | ``` 136 | 137 | 138 | 139 | ## Символни низове 140 | 141 | - Символният низ е последователност от символи 142 | - Низът задължително завършва с един допълнителен символ - терминираща нула `'\0'` 143 | - Последователност от 0 символа (без терминираща нула) наричаме празен низ 144 | - Терминиращата нула е отделен символ и заема място, въпреки, че не я считаме за част от самото съдържание на низа 145 | - Низовите константи (напр. `"Hello"`) представляват масив от символи завършващ с терминираща нула 146 | - Терминиращата нула ни показва края на низа 147 | 148 | ```cpp 149 | char word[] = { 'H', 'e', 'l', 'l', 'o', '\0' }; 150 | char word[6] = { 'H', 'e', 'l', 'l', 'o' }; //обикновен масив от символи 151 | char word[5] = { 'H', 'e', 'l', 'l', 'o' }; //обикновен масив от символи 152 | char word[100] = "Hello"; 153 | char word[5] = "Hello"; //невалидно, понеже " "включват в себе си '\0' 154 | char word[6] = "Hello"; 155 | char word[6]= {'H', 'e', 'l', 'l','\0', 'o'}; //символният низ е "Hell" 156 | ``` 157 | 158 | > [!IMPORTANT] 159 | > Символният низ е интерпретация на масива от символи. Ако в даден символен масив имаме терминираща нула, от нас зависи дали го интерпретираме като низ или като последователност от символи. Терминираща нула може да има на средата на масив. 160 | 161 | 162 | 163 | - При работа с низове не е необходимо да знаем размера на масива, понеже интерпретацията на низ задължава съществуването на терминираща нула и съответно знаем кой е последният символ на низа 164 | - По тази логика работи и `std::cout` - спира итерирането през символния масив когато стигне терминиращата нула на низа. Такава ТРЯБВА да има ако е низ! 165 | - `std::cin` чете символен низ до срещане на табулация, интервал, символ за нов ред или край на потока 166 | - Автоматично се добавя терминираща нула при четене 167 | 168 | ```cpp 169 | int main() { 170 | char buffer[24]; 171 | std::cin >> buffer; // Hello, world! 172 | std::cout << buffer << std::endl; // Hello, 173 | } 174 | ``` 175 | 176 | 177 | 178 | - Ако искаме да имаме по-голям контрол над четенето, ползваме `std::cin.getline(char buffer[], size_t count, char delimiter = '\n')`; 179 | - Буферът трябва да е предварително заделен и да укажем неговият размер. Може да използваме и различен символ за спиране на четенето 180 | - Автоматично се добавя терминираща нула при четене 181 | 182 | ```cpp 183 | #include 184 | // 13 characters + 1 for '\0' character 185 | const int BUFFER_SIZE = 13 + 1; 186 | 187 | int main() { 188 | char buffer[BUFFER_SIZE]; 189 | std::cin.getline(buffer, BUFFER_SIZE); // Hello, world! 190 | std::cout << buffer << std::endl; // Hello, world! 191 | } 192 | ``` 193 | 194 | > [!NOTE] 195 | > Максималния брой символи които ефективно може да прочетем са винаги с един по-малко от размера на масива 196 | 197 | ```cpp 198 | char text[4]; 199 | std::cin.getline(text,4); // test 200 | std::cout << text; // tes 201 | ``` -------------------------------------------------------------------------------- /Week 10/Practicum.md: -------------------------------------------------------------------------------- 1 | 2 | **Задача 1:** Да се напише функция myReverse, която да приема символен низ и да го обръща наобратно. 3 | 4 | **Пример:** 5 | 6 | ```c++ 7 | "abcdef" 8 | ``` 9 | 10 | ```c++ 11 | "fedcba" 12 | ``` 13 | **Задача 2:** Да се напише функция ,която да приема символен низ и да превръща всички гласни в главни, а всички съгласни в малки букви. 14 | 15 | 16 | **Пример:** 17 | 18 | ```c++ 19 | "heLlo worldD123" 20 | ``` 21 | 22 | ```c++ 23 | "hEllO wOrld123" 24 | ``` 25 | 26 | 27 | **Задача 3:** Да се напише функция ,която да приема символен низ и го преобразува така, че всички числа от подадения стринг са цензурирани. 28 | 29 | **Пример:** 30 | 31 | ```c++ 32 | "abcd1234fsdfb43kdajdf4n" 33 | ``` 34 | 35 | ```c++ 36 | "abcd*fsdfb*kdajdf*n" 37 | ``` 38 | **Задача 4:** Да се напише функция `void sortCharacters(const char* str, char* result)`. Нека функцията превръща всички главни букви в малки и подрежда всички символи в низа във възходящ ред. 39 | 40 | **Пример:** 41 | 42 | ```c++ 43 | "Hello world" 44 | ``` 45 | 46 | ```c++ 47 | " dehllloorw" 48 | ``` 49 | 50 | **Задача 5:** Да се напише функция `void swap(int*& a, int*& b)`, която разменя стойностите на два указателя, които сочат към целочислени числа 51 | 52 | **Пример:** 53 | 54 | ```c++ 55 | 21 37 56 | ``` 57 | 58 | ```c++ 59 | 37 21 60 | ``` 61 | 62 | **Задача 6:** Да се напише функция, която приема символен низ с максимална дължина 10 000 и матрица от символи. Нека в редовете на матрицата да се запазят всички думи от низа. 63 | - Всяка дума няма да надвишава 1024 символа; 64 | - Гарантирано е, че има най-много 100 думи; 65 | - Гарантирано е, че всички думи са разделени с произволен брой интервали; 66 | 67 | **Пример:** 68 | 69 | ```c++ 70 | "Hi my name is Gosho" 71 | ``` 72 | 73 | ```c++ 74 | ["Hi"] 75 | ["my"] 76 | ["name"] 77 | ["is"] 78 | ["Gosho"] 79 | ``` 80 | -------------------------------------------------------------------------------- /Week 10/README.md: -------------------------------------------------------------------------------- 1 | # Работа с текст 2 | 3 | - Дължина на низ 4 | - Лексикографско сравнение на низове 5 | - Копиране на низ 6 | - Конкатенация на низове 7 | - Проверка дали даден низ съдържа друг 8 | - Замяна на подниз 9 | - Брой срещания на подниз 10 | - Валидация на формат на низ 11 | - Преобразуване на низ в число и обратно -------------------------------------------------------------------------------- /Week 10/SolutionsTasksPracticum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | constexpr int ROWS = 100; 4 | constexpr int MAX_WORD_LEN = 512; 5 | 6 | 7 | void myStrCpy(const char* source, char* dest) { 8 | if (!source || !dest) 9 | { 10 | return; 11 | } 12 | while (*source) { 13 | *dest = *source; 14 | dest++; 15 | source++; 16 | } 17 | *dest = '\0'; 18 | } 19 | 20 | void fillWords(const char* str, char words[][MAX_WORD_LEN], int& wordsCount) { 21 | if (str == nullptr) 22 | return; 23 | 24 | wordsCount = 0; 25 | 26 | char curWord[MAX_WORD_LEN]{}; 27 | int curWordIndx = 0; 28 | int curChar = *str; 29 | 30 | while (curChar) { 31 | 32 | if (curChar == ' ') { 33 | if (curWordIndx == 0) { //skip the consecutive spaces 34 | str++; 35 | curChar = *str; 36 | continue; 37 | } 38 | curWord[curWordIndx] = '\0'; //finish the curWord with terminating zero, otherwise it won't be a valid string 39 | curWordIndx = 0; 40 | 41 | myStrCpy(curWord, words[wordsCount]); //fill the whole word on the next line 42 | wordsCount++; 43 | 44 | } 45 | else { 46 | curWord[curWordIndx] = curChar; 47 | curWordIndx++; 48 | } 49 | 50 | str++; 51 | curChar = *str; 52 | } 53 | 54 | 55 | //fill the last word 56 | if (curWordIndx == 0) { 57 | return; 58 | } 59 | curWord[curWordIndx] = '\0'; 60 | 61 | myStrCpy(curWord, words[wordsCount]); 62 | wordsCount++; 63 | 64 | } 65 | 66 | void mySwap(char& ch1, char& ch2) { 67 | char temp = ch1; 68 | ch1 = ch2; 69 | ch2 = temp; 70 | } 71 | 72 | char toUpper(char ch) { 73 | if ('a' <= ch && ch <= 'z') 74 | { 75 | return ch - 'a' + 'A'; 76 | } 77 | return ch; 78 | } 79 | 80 | char toLower(char ch) { 81 | if ('A' <= ch && ch <= 'Z') 82 | { 83 | return ch - 'A' + 'a'; 84 | } 85 | return ch; 86 | } 87 | 88 | bool vowel(char ch) { 89 | char toCheck = toLower(ch); 90 | switch (toCheck) { 91 | case 'a': 92 | case 'o': 93 | case 'u': 94 | case 'i': 95 | case 'e': 96 | case 'y': 97 | return true; 98 | default: 99 | return false; 100 | } 101 | } 102 | 103 | bool consonant(char ch) { 104 | return !vowel(ch); 105 | } 106 | 107 | void magic(char* str) { 108 | if (!str) 109 | { 110 | return; 111 | } 112 | while (*str) { 113 | if (vowel(*str)) 114 | { 115 | *str = toUpper(*str); 116 | } 117 | else { 118 | *str = toLower(*str); 119 | } 120 | str++; 121 | } 122 | } 123 | bool isNumber(char ch) { 124 | return ('1' <= ch && ch <= '9'); 125 | } 126 | 127 | void censor(char* str) { 128 | if (!str) 129 | { 130 | return; 131 | } 132 | bool flag = false; 133 | int put = 0; 134 | int get = 0; 135 | while (str[get]) { 136 | if (isNumber(str[get])) { 137 | flag = true; 138 | } 139 | else { 140 | if (flag) 141 | { 142 | flag = false; 143 | str[put++] = '*'; 144 | } 145 | str[put++] = str[get]; 146 | } 147 | 148 | get++; 149 | } 150 | if (flag) 151 | { 152 | str[put++] = '*'; 153 | } 154 | str[put] = '\0'; 155 | } 156 | 157 | void myReverse(char* str) { 158 | int size = strlen(str); 159 | int halfSize = size/2; 160 | for (size_t i = 0; i < halfSize; i++) 161 | { 162 | mySwap(str[i], str[size - i - 1]); 163 | } 164 | } 165 | int main() 166 | { 167 | 168 | char str[] = "abcd1234fsdfb43kdajdf4n"; 169 | censor(str); 170 | std::cout << str; 171 | } 172 | -------------------------------------------------------------------------------- /Week 11/Practicum.md: -------------------------------------------------------------------------------- 1 | ## Динамична памет 2 | **stack** 3 | - паметта се заделя ПО ВРЕМЕ на компилация на програмата. 4 | - паметта се освобождава/трие/маркира като свободна автоматично - при излизането от scope-а, в който е дефинирана. 5 | 6 | Искаме памет по време на изпълнението на програмта? 7 | 8 | **heap** 9 | - Масиви и обекти без предварително да е известна големината. 10 | 11 | 12 | Оператор **new** 13 | 14 | - Връща указтел към началото на паметта 15 | 16 | ```c++ 17 | new int[n]; n НЕ е задължително да е константа! 18 | ``` 19 | 20 | Заделянето на динамична памет е много "бавна" операция!! 21 | 22 | Динамична памет НЕ се трие автоматично. 23 | 24 | Оператор delete[] - освобождава/маркира като свободна динамична памет! 25 | 26 | 27 | ```c++ 28 | void f() 29 | { 30 | int x = 40; 31 | char ch[2] = {'a', 'b'}; 32 | int* ptr = new int[3]; 33 | } 34 | ``` 35 | 36 | ![enter image description here](https://i.ibb.co/vYdR6Zj/dyn-mem.png) 37 | 38 | След приключването на функцията ще се изчисти паметта в стека, но НЕ и паметта в heap-а. 39 | 40 | За това ние трябва ръчно да я маркираме като свободна. 41 | 42 | ```c++ 43 | void f() 44 | { 45 | int x = 40; 46 | char ch[2] = {'a', 'b'}; 47 | int* ptr = new int[3]; 48 | delete[] ptr; //!!!!!!! 49 | } 50 | ``` 51 | 52 | Примери: 53 | 54 | - Да се напише функция, която приема стринг и връща нов стринг с ТОЧНА ГОЛЕМИНА, в който всички числа са цензурирани. (Всяко число е заменено с '*') 55 | - Да се напише функция, която приема стринг и връща два стринга с ТОЧНА големина. Първият да бъде съставен само от малките букви, а другият да бъде съставен само от главните букви. 56 | - Да се напише функция, която приема стринг и връща нов стринг с точна големина, който е съставен от малките латински букви на подадения, но в сортиран вид. 57 | 58 | ## Задачи 59 | 60 | 61 | **1.** Да се напише програма, която прочита от стандартния вход число N и след него N на брой цели числа. Програмата да отпечатва числата в обратен на въвеждането им ред. 62 | 63 | **Пример:** 64 | 65 | Вход: 66 | ```c++ 67 | 5 68 | 1 2 3 4 5 69 | ``` 70 | 71 | Изход: 72 | ```c++ 73 | 5 4 3 2 1 74 | ``` 75 | 76 | **2.** Да се напише функция, която приема 2 масива от цели числа и големината им(вече като аргумент), както и число К. Програмата да връща нов масив, за който е заделено точно количество памет, който да е съставен само от числата, съдържащи се в двата масива, които се делят на К. 77 | 78 | **Пример:** 79 | 80 | Вход: 81 | ```c++ 82 | [2 4 5 8] 4 83 | [3 16 7 9 10] 5 84 | 2 85 | ``` 86 | 87 | Изход: 88 | ```c++ 89 | [2 4 8 16 10] 90 | ``` 91 | 92 | **3.** Да се напише функция, която приема масив и дължина(като аргумент) и цяло число K и връща нов масив, за който е заделено точно количество памет, в който всички елементи са изместени циклично K позиции надясно. 93 | 94 | **Пример:** 95 | 96 | Вход: 97 | ```c++ 98 | [1 2 3 4 5] 5 99 | 2 100 | ``` 101 | Изход: 102 | ```c++ 103 | [4 5 1 2 3] 104 | ``` 105 | 106 | **4.** Да се напише функция, която приема масив с дължината му и връща нов масив, за който е заделено точно количество памет, който е съставен само от елементите, които се делят на поне 1 от съседите си. 107 | 108 | **Пример:** 109 | 110 | Вход: 111 | ```c++ 112 | [5 10 20 4 2 7] 6 113 | ``` 114 | Изход: 115 | ```c++ 116 | [10 20 4] 117 | ``` 118 | 119 | **5.** Да се напише функция, която приема 2 символни низа и връща нов символен низ, за който е заделено точно количество памет, който представлява конкатенация на малките букви в първия с главните във втория. 120 | 121 | **Пример:** 122 | 123 | Вход: 124 | ```c++ 125 | abcAGHp 126 | mnAHGT5saP 127 | ``` 128 | Изход: 129 | ```c++ 130 | abcpAHGTP 131 | ``` 132 | 133 | **6.** Да се напише функция, която приема стринг с произволна дължина и връща като резултат нов стринг, за който е заделено точно количество памет, представляващ конкатенацията на първата и последната дума от подадения, като двете думи да са разделени с интервал. 134 | 135 | **Пример:** 136 | 137 | Вход: 138 | ```c++ 139 | Hello hi hey 140 | ``` 141 | Изход: 142 | ```c++ 143 | Hello hey 144 | ``` 145 | 146 | **7.** Да се напише функция, която приема символен низ, масив от цели числа с подадена дължина, представляващи позиции в символния низ, и символ S. Функцията да връща нов символен низ, за който е заделено точно количество памет, в който на всяка една от дадените позиции е вмъкнат символът S. 147 | 148 | **Пример:** 149 | 150 | Вход: 151 | ```c++ 152 | Hi here nice o mee you. 153 | [3 13 18] 3 154 | t 155 | ``` 156 | Изход: 157 | ```c++ 158 | Hi there nice to meet you. 159 | ``` 160 | 161 | 162 | **8.** Напишете функция, която приема масив и връща масив от масиви, на който елементите му са всички непразни подмасиви на дадения. 163 | 164 | *Вход: [1, 2, 3]* 165 | 166 | *Изход: [1], [2], [3], [1, 2], [2, 3], [1, 3], [1, 2, 3]* 167 | -------------------------------------------------------------------------------- /Week 11/README.md: -------------------------------------------------------------------------------- 1 | # Динамична памет 2 | 3 | 4 | 5 | ## Стекова памет / Stack memory 6 | - Стековата памет е тази, която се заделя по време на компилация на програмата 7 | - Всяка програма има фиксиран размер на стековата памет - може да не успеем да заделим паметта, която искаме в даден момент 8 | - Тук паметта се освобождава автоматично от компилатора, когато излезем от блока, в който е дефинирана променливата, използваща паметта 9 | - При създаването на статични масиви в стековата памет е необходимо размера им да е константен, точно заради особеностите по заделянето на паметта 10 | 11 | 12 | 13 | ## Динамична памет / Heap memory 14 | - Динамимчната памет се заделя по време на изпълнение на програмата 15 | - Динамичната памет не се освобождава автоматично, трябва програмата сама да си я освободи 16 | - При създаването на данамични масиви, може да използваме произволен неконстантен размер, заради начина на заделяне на паметта 17 | 18 | > [!IMPORTANT] 19 | > Заделянето на динамична памет е по-бавна операция, както и достъпването ѝ. Когато може да се избягва, е препоръчително. 20 | 21 | > [!IMPORTANT] 22 | > Когато е заделена динамична памет, трябва винаги да се освободи! 23 | 24 | 25 | 26 | ## Заделяне и освобождаване на динамична памет 27 | - Памет се заделя с оператор `new`, следван от типа на променливата 28 | - Оператор `new` връща указател към първия байт от заделената памет, от типа на променливата 29 | - Паметта се освобождава с оператор `delete`, на който се подава указател от типа на променливата, сочещ паметта, която да се освободи 30 | 31 | ```cpp 32 | // on the stack 33 | int sValue = 5; 34 | int* sPtr = &sValue; 35 | 36 | // on the heap 37 | int* hValue = new int; // the pointer is allocated on the stack 38 | *hValue = 5; 39 | delete hValue; 40 | ``` 41 | 42 | 43 | 44 | ## Създаване на динамични масиви 45 | 46 | - При заделяне на памет за масив, след типа указваме броя елементи 47 | - Когато заделяме паметта, не е необходимо да се ползва константа 48 | - За да се освободи памет, заделена за масив - `delete[]` 49 | 50 | ```cpp 51 | size_t count = 42; 52 | int* arr = new int[count]; 53 | delete[] arr; 54 | ``` 55 | 56 | 57 | 58 | - `delete` над `nullptr` не прави нищо 59 | 60 | > [!IMPORTANT] 61 | > Всяка функция трябва да се грижи за проверката дали даден указател е nullptr 62 | 63 | ```cpp 64 | size_t strLen(const char* str) 65 | { 66 | if(str == nullptr) 67 | { 68 | return 0; 69 | } 70 | 71 | size_t count = 0; 72 | while(*str) 73 | { 74 | count++; 75 | str++; 76 | } 77 | 78 | return count; 79 | } 80 | ``` 81 | 82 | 83 | 84 | ## Как работят всъщност new и delete 85 | 86 | `malloc` заделя определен брой байтове и връща `void*` указател, който сочи първия байт. За да можем ефективно да използваме този указател, трябва да го кастнем към указател към даден тип. Това по никакъв начин не ни гарантира, че паметта която е заделена, отговаря на типа, към който сме кастнали ние пойнтъра 87 | 88 | ```cpp 89 | size_t count = 42; 90 | int* arr = (int*)malloc(count * sizeof(int)); 91 | free(arr); 92 | ``` 93 | 94 | 95 | 96 | ## Масиви от указатели 97 | 98 | - Статичен масив от указатели към динамични масиви 99 | 100 | ```cpp 101 | const size_t ROWS_COUNT = 20; 102 | 103 | size_t elementsPerRow; 104 | std::cin >> elementsPerRow; 105 | 106 | int* matrix[ROWS_COUNT]; 107 | for(size_t i = 0; i < ROWS_COUNT; i++) 108 | { 109 | matrix[i] = new int[elementsPerRow]; 110 | } 111 | 112 | for(size_t i = 0; i < ROWS_COUNT; i++) 113 | { 114 | delete[] matrix[i]; 115 | } 116 | ``` 117 | 118 | 119 | 120 | - Статичен масив от указатели 121 | 122 | ```cpp 123 | const size_t ARR_SIZE = 10; 124 | 125 | int arr[ARR_SIZE] = {1,2,3,4,5,6,7,8,9,10}; 126 | int* ptrs[ARR_SIZE]; 127 | for(size_t i = 0; i < ROWS_COUNT; i++) 128 | { 129 | ptrs[i] = arr + ARR_SIZE - i - 1; 130 | } 131 | ``` 132 | 133 | 134 | 135 | - Данимичен масив от указатели към елементи 136 | 137 | ```cpp 138 | const size_t ARR_SIZE = 10; 139 | 140 | int** ptrs = new int*[ARR_SIZE]; 141 | for(size_t i = 0; i < ROWS_COUNT; i++) 142 | { 143 | ptrs[i] = new int(i); 144 | } 145 | 146 | for(size_t i = 0; i < ROWS_COUNT; i++) 147 | { 148 | delete ptrs[i]; 149 | } 150 | 151 | delete[] ptrs; 152 | ``` 153 | 154 | 155 | 156 | - Динамичен масив с указатели към масиви (matrix / jagged array) 157 | 158 | ```cpp 159 | const size_t ARR_SIZE = 10; 160 | 161 | int** ptrs = new int*[ARR_SIZE]; 162 | for(size_t i = 0; i < ROWS_COUNT; i++) 163 | { 164 | ptrs[i] = new int[i]; 165 | } 166 | 167 | for(size_t i = 0; i < ROWS_COUNT; i++) 168 | { 169 | delete[] ptrs[i]; 170 | } 171 | 172 | delete[] ptrs; 173 | ``` 174 | 175 | 176 | 177 | ## Работа с данимични масиви 178 | 179 | Динамичните масиви позволяват да бъдат връщани като резултат на функция (или поне указател към първия елемент на масива). Като това е най-удобно за низове, ако не знаем броя елементи на масива, или за произволни масиви, ако знаем броя на елементите. Всички функции, които работят с низове и не целят inplace операции, могат да връщат нов динамичен низ. Динамичните низове позволяват заделяне на точното количество памет за низа. 180 | 181 | ```cpp 182 | int* createArray(size_t size) 183 | { 184 | return new int[size]; 185 | } 186 | 187 | int** createMatrix(size_t n, size_t m) 188 | { 189 | int** matrix = new int*[n]; 190 | for(size_t i = 0; i < n; i++) 191 | { 192 | matrix[i] = createArray(m); 193 | } 194 | } 195 | 196 | void readMatrix(int** matrix, size_t n, size_t m) 197 | { 198 | for(size_t i = 0; i < n; i++) 199 | { 200 | for(size_t j = 0; j < n; j++) 201 | { 202 | std::cin >> matrix[i][j]; 203 | } 204 | } 205 | } 206 | 207 | void printMatrix(int** matrix, size_t n, size_t m) 208 | { 209 | if(matrix == nullptr) 210 | { 211 | return; 212 | } 213 | 214 | for(size_t i = 0; i < n; i++) 215 | { 216 | // if matrix[i] is nullptr ? 217 | for(size_t j = 0; j < n; j++) 218 | { 219 | std::cout << matrix[i][j]; 220 | } 221 | } 222 | } 223 | 224 | void freeMatrix(int** matrix, size_t n) 225 | { 226 | if(matrix == nullptr) 227 | { 228 | return; 229 | } 230 | 231 | for(size_t i = 0; i < n; i++) 232 | { 233 | // it's ok to delete nullptr 234 | delete[] matrix[i]; 235 | } 236 | 237 | delete[] matrix; 238 | } 239 | 240 | char* readString() 241 | { 242 | const size_t BUFFER_SIZE = 1024 + 1; 243 | char buffer[BUFFER_SIZE]; 244 | 245 | std::cin.getline(buffer, BUFFER_SIZE); 246 | 247 | char* result = new char[strlen(buffer) + 1]; 248 | strcpy(buffer, result); 249 | 250 | return result; 251 | } 252 | 253 | int main() 254 | { 255 | char* str = readString(); 256 | std::cout << str; 257 | delete[] str; 258 | 259 | size_t n, m; 260 | std::cin >> n >> m; 261 | int** matrix = createMatrix(n, m); 262 | readMatrix(matrix, n, m); 263 | printMatrix(matrix, n, m); 264 | freeMatrix(matrix, n, m); 265 | } 266 | ``` 267 | 268 | 269 | 270 | ## Основни задачи 271 | - Всички подмножества / подредици на дадена 272 | - string split by separators list 273 | - string manipulations - concat, replace, etc. 274 | 275 | 276 | 277 | ## Други задачи 278 | 279 | Нека от конзолата се прочат две естествени числа: n - брой на редовете, които да се прочетат от конзолата и k - номер на бит. На следващите n реда се въвежда първо естествено число - големината на последващия низ и след това низ, представящ математическа операция за калкулатор във вида 280 | `7add8multiply9divide2subtract10`, където операциите са изписани с думи и се извършват последователно, без да се взима предвид приоритета им. След това се чете още един низ, съставен от n-1 операции, например `addsubtractdivideadd`. Да се изчислят стойностите за всеки от първоначалните n операции, като за всеки резултат да се обърне k-тия бит отдясно наляно на полученото число. След това тези резултати се използват за аргументи на последната операция без числени аргументи. Да се изведе резултатът от последното изчисление. 281 | 282 | Вход: 283 | ``` 284 | 3 285 | 1add2add3 286 | 7multuply10 287 | 10divide2add8 288 | addmultiply 289 | ``` 290 | 291 | Изход: 292 | ``` 293 | 4416 294 | ``` 295 | -------------------------------------------------------------------------------- /Week 11/censoreNumbers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | unsigned myStrlen(const char* str) 5 | { 6 | if (!str) 7 | return 0; 8 | 9 | unsigned result = 0; 10 | while (*str) 11 | { 12 | result++; 13 | str++; 14 | } 15 | return result; 16 | } 17 | 18 | bool isDigit(char ch) 19 | { 20 | return ch >= '0' && ch <= '9'; 21 | } 22 | unsigned getDigitsCount(const char* str) 23 | { 24 | if (!str) 25 | return 0; 26 | unsigned count = 0; 27 | 28 | while (*str) 29 | { 30 | if (isDigit(*str)) 31 | count++; 32 | str++; 33 | } 34 | return count; 35 | } 36 | 37 | unsigned getNumbersCount(const char* str) 38 | { 39 | if (!str) 40 | return 0; 41 | unsigned count = 0; 42 | while (*str) 43 | { 44 | if (isDigit(*str) && !isDigit(*(str + 1))) //we count the end of the numbers. Str + 1 is allowed, because we have a terminating zero (which is not a digit) at the end (we won't go out of bounds) 45 | count++; 46 | str++; 47 | } 48 | return count; 49 | } 50 | 51 | char* censoreNumbers(const char* str) 52 | { 53 | if (!str) 54 | return nullptr; 55 | 56 | size_t resultSize = myStrlen(str) 57 | - getDigitsCount(str) 58 | + getNumbersCount(str); 59 | 60 | char* result = new char[resultSize + 1]; //!!!!! '\0' 61 | unsigned resultIndex = 0; 62 | 63 | while (*str) 64 | { 65 | if (!isDigit(*str)) 66 | result[resultIndex++] = *str; 67 | else if(!isDigit(*(str + 1))) 68 | result[resultIndex++] = '*'; 69 | str++; 70 | } 71 | 72 | result[resultSize] = '\0'; 73 | return result; 74 | } 75 | int main () 76 | { 77 | char* str = censoreNumbers("abc1234dgg4fsdg5"); 78 | cout << str; 79 | 80 | delete[] str;//!!!!! 81 | } 82 | -------------------------------------------------------------------------------- /Week 11/examples.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const size_t RESIZE_FACTOR = 2; 4 | 5 | size_t strLen(const char* str) 6 | { 7 | if (str == nullptr) 8 | { 9 | return 0; 10 | } 11 | 12 | size_t count = 0; 13 | 14 | while (*str) 15 | { 16 | str++; 17 | count++; 18 | } 19 | 20 | return count; 21 | } 22 | 23 | char* strCopy(const char* str) 24 | { 25 | if (str == nullptr) 26 | { 27 | return nullptr; 28 | } 29 | 30 | size_t lenStr = strLen(str); 31 | char* result = new char[lenStr + 1]; 32 | 33 | for (size_t i = 0; i < lenStr; i++) 34 | { 35 | result[i] = str[i]; 36 | } 37 | 38 | result[lenStr] = '\0'; 39 | 40 | return result; 41 | } 42 | 43 | char* readString() 44 | { 45 | const size_t STR_SIZE = 1024 + 1; 46 | char str[STR_SIZE]; 47 | std::cin.getline(str, STR_SIZE); 48 | return strCopy(str); 49 | } 50 | 51 | int** createMatrix(size_t n, size_t m) 52 | { 53 | int** matrix = new int* [n]; 54 | for (size_t i = 0; i < n; i++) 55 | { 56 | matrix[i] = new int[m]; 57 | } 58 | return matrix; 59 | } 60 | 61 | void readMatrix(int* const* const matrix, size_t n, size_t m) 62 | { 63 | if (matrix == nullptr) 64 | { 65 | return; 66 | } 67 | 68 | for (size_t i = 0; i < n; i++) 69 | { 70 | for (size_t j = 0; j < m; j++) 71 | { 72 | std::cin >> matrix[i][j]; 73 | } 74 | } 75 | } 76 | 77 | void printMatrix(int** matrix, size_t n, size_t m) 78 | { 79 | if (matrix == nullptr) 80 | { 81 | return; 82 | } 83 | 84 | for (size_t i = 0; i < n; i++) 85 | { 86 | // if matrix[i] is nullptr ? 87 | for (size_t j = 0; j < m; j++) 88 | { 89 | std::cout << matrix[i][j] << " "; 90 | } 91 | std::cout << std::endl; 92 | } 93 | } 94 | 95 | void freeMatrix(int** matrix, size_t n) 96 | { 97 | if (matrix == nullptr) 98 | { 99 | return; 100 | } 101 | 102 | for (size_t i = 0; i < n; i++) 103 | { 104 | delete[] matrix[i]; 105 | } 106 | 107 | delete[] matrix; 108 | } 109 | 110 | void transposeMatrix(int**& matrix, int n, int m) 111 | { 112 | if (matrix == nullptr) 113 | { 114 | return; 115 | } 116 | 117 | int** newMatrix = createMatrix(m, n); 118 | 119 | for (size_t i = 0; i < n; i++) 120 | { 121 | for (size_t j = 0; j < m; j++) 122 | { 123 | newMatrix[j][i] = matrix[i][j]; 124 | } 125 | } 126 | 127 | freeMatrix(matrix, n); 128 | matrix = newMatrix; 129 | } 130 | 131 | int* readArray(size_t n) 132 | { 133 | int* result = new int[n]; 134 | 135 | for (size_t i = 0; i < n; i++) 136 | { 137 | std::cin >> result[i]; 138 | } 139 | 140 | return result; 141 | } 142 | 143 | int** getAllSubsequences(const int* arr, size_t n, size_t k, size_t& resultCount) 144 | { 145 | if (k > n || arr == nullptr) 146 | { 147 | return nullptr; 148 | } 149 | 150 | const size_t seqCount = n + 1 - k; 151 | 152 | int** subseqs = new int* [seqCount]; 153 | for (size_t i = 0; i < seqCount; i++) 154 | { 155 | subseqs[i] = new int[k]; 156 | for (size_t j = 0; j < k; j++) 157 | { 158 | subseqs[i][j] = arr[i + j]; 159 | } 160 | } 161 | 162 | resultCount = seqCount; 163 | return subseqs; 164 | } 165 | 166 | void resizeIfNecessary(int**& arr, size_t count, size_t& size) 167 | { 168 | if (count != size) 169 | { 170 | return; 171 | } 172 | 173 | size *= RESIZE_FACTOR; 174 | int** newArr = new int* [size]; 175 | for (size_t i = 0; i < count; i++) 176 | { 177 | newArr[i] = arr[i]; 178 | } 179 | 180 | delete[] arr; 181 | arr = newArr; 182 | } 183 | 184 | void resizeIfNecessary(char**& arr, size_t count, size_t& size) 185 | { 186 | if (count != size) 187 | { 188 | return; 189 | } 190 | 191 | size *= RESIZE_FACTOR; 192 | char** newArr = new char* [size]; 193 | for (size_t i = 0; i < count; i++) 194 | { 195 | newArr[i] = arr[i]; 196 | } 197 | 198 | delete[] arr; 199 | arr = newArr; 200 | } 201 | 202 | // TODO: maybe not working in all cases 203 | int** getAllSubsequencesWithSumK(const int* arr, size_t n, size_t k, size_t& resultCount) 204 | { 205 | if (k > n || arr == nullptr) 206 | { 207 | return nullptr; 208 | } 209 | 210 | size_t currentSize = 10; 211 | size_t currentCount = 0; 212 | int** subseqs = new int* [currentSize]; 213 | 214 | for (size_t i = 0; i < n; i++) 215 | { 216 | size_t currentSum = 0; 217 | size_t j = 0; 218 | for (; j < n - i; j++) 219 | { 220 | currentSum += arr[i + j]; 221 | if (currentSum > k) 222 | { 223 | break; 224 | } 225 | } 226 | 227 | if (currentSum <= k) 228 | { 229 | currentCount++; 230 | resizeIfNecessary(subseqs, currentCount, currentSize); 231 | subseqs[currentCount - 1] = new int[j + 1]; 232 | subseqs[currentCount - 1][0] = j; 233 | for (size_t p = 0; p < j; p++) 234 | { 235 | subseqs[currentCount - 1][p + 1] = arr[i + p]; 236 | } 237 | } 238 | } 239 | 240 | resultCount = currentCount; 241 | return subseqs; 242 | } 243 | 244 | size_t countOneBits(size_t num) 245 | { 246 | size_t count = 0; 247 | while (num) 248 | { 249 | count += num & 1; 250 | num = (num >> 1); 251 | } 252 | 253 | return count; 254 | } 255 | 256 | int** getAllSubsets(const int* arr, size_t n, size_t& resultCount) 257 | { 258 | if ( arr == nullptr) 259 | { 260 | return nullptr; 261 | } 262 | 263 | const size_t subsetsCount = 1 << n; 264 | 265 | int** subsets = new int* [subsetsCount]; 266 | 267 | for (size_t currentSubsetMask = 0; currentSubsetMask < subsetsCount; currentSubsetMask++) 268 | { 269 | size_t currentSetSize = countOneBits(currentSubsetMask); 270 | subsets[currentSubsetMask] = new int[currentSetSize + 1]; 271 | subsets[currentSubsetMask][0] = currentSetSize; 272 | 273 | // TODO: Add elements to the subset (subsets[currentSubsetMask] elements) 274 | } 275 | 276 | resultCount = subsetsCount; 277 | return subsets; 278 | } 279 | 280 | bool contains(const char* str, char c) 281 | { 282 | while (*str) 283 | { 284 | if (*str == c) 285 | { 286 | return true; 287 | } 288 | str++; 289 | } 290 | 291 | return false; 292 | } 293 | 294 | char* substring(const char* str, size_t startIndex, size_t count) 295 | { 296 | if (str == nullptr) 297 | { 298 | return nullptr; 299 | } 300 | 301 | size_t ogStringLen = strLen(str); 302 | 303 | if (startIndex + count > ogStringLen) 304 | { 305 | return nullptr; 306 | } 307 | 308 | char* result = new char[count + 1]; 309 | 310 | for (size_t i = 0; i < count; i++) 311 | { 312 | result[i] = str[i + startIndex]; 313 | } 314 | result[count] = '\0'; 315 | 316 | return result; 317 | } 318 | 319 | char** split(const char* str, const char* separators, bool removeEmptyEntries = false) 320 | { 321 | if (str == nullptr || separators == nullptr) 322 | { 323 | return nullptr; 324 | } 325 | 326 | size_t lenStr = strLen(str); 327 | 328 | size_t currentSize = 10; 329 | size_t currentCount = 0; 330 | char** splits = new char* [currentSize]; 331 | 332 | int lastSeparatorIndex = -1; 333 | for (size_t i = 0; i < lenStr + 1; i++) 334 | { 335 | if (contains(separators, str[i]) || i == lenStr) 336 | { 337 | char* current = substring(str, lastSeparatorIndex + 1, i - lastSeparatorIndex - 1); 338 | 339 | lastSeparatorIndex = i; 340 | 341 | if (removeEmptyEntries && strLen(current) == 0) 342 | { 343 | delete[] current; 344 | continue; 345 | } 346 | 347 | currentCount++; 348 | resizeIfNecessary(splits, currentCount, currentSize); 349 | splits[currentCount - 1] = current; 350 | } 351 | } 352 | 353 | currentCount++; 354 | resizeIfNecessary(splits, currentCount, currentSize); 355 | splits[currentCount - 1] = nullptr; 356 | 357 | return splits; 358 | } 359 | 360 | int main() 361 | { 362 | //char* str = readString(); 363 | //std::cout << str; 364 | //delete[] str; 365 | 366 | 367 | //size_t n, m; 368 | //std::cin >> n >> m; 369 | //int** matrix = createMatrix(n, m); 370 | //readMatrix(matrix, n, m); 371 | //transposeMatrix(matrix, n, m); 372 | //printMatrix(matrix, m, n); 373 | //freeMatrix(matrix, m); 374 | 375 | 376 | //size_t n; 377 | //std::cin >> n; 378 | //int* arr = readArray(n); 379 | // 380 | //size_t k; 381 | //std::cin >> k; 382 | // 383 | //size_t subseqCount; 384 | //int** subseqs = getAllSubsequences(arr, n, k, subseqCount); 385 | 386 | 387 | char* str = readString(); 388 | char** splits = split(str, " ", true); 389 | while (*splits != nullptr) 390 | { 391 | std::cout << *splits << std::endl; 392 | splits++; 393 | } 394 | 395 | delete[] str; 396 | 397 | while (*splits) 398 | { 399 | delete[] *splits; 400 | splits++; 401 | } 402 | 403 | delete[] splits; 404 | } -------------------------------------------------------------------------------- /Week 11/smallAndUpperStrings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | bool isLower(char ch) 6 | { 7 | return ch >= 'a' && ch <= 'z'; 8 | } 9 | bool isUpper(char ch) 10 | { 11 | return ch >= 'A' && ch <= 'Z'; 12 | } 13 | void getLowerAndUpperCount(const char* str, unsigned& lowerCount, unsigned& upperCount) 14 | { 15 | upperCount = lowerCount = 0; 16 | if (!str) 17 | return; 18 | 19 | while (*str) 20 | { 21 | if (isLower(*str)) 22 | lowerCount++; 23 | else if (isUpper(*str)) 24 | upperCount++; 25 | str++; 26 | } 27 | } 28 | void getLowerAndUpperStrings(const char* str, char*& lower, char*& upper) 29 | { 30 | if (!str) 31 | return; 32 | unsigned lowerCount = 0, upperCount = 0; 33 | getLowerAndUpperCount(str, lowerCount, upperCount); 34 | lower = new char[lowerCount + 1]; 35 | upper = new char[upperCount + 1]; 36 | lower[lowerCount] = upper[upperCount] = '\0'; 37 | 38 | unsigned lowerIndex = 0, upperIndex = 0; 39 | while (*str) 40 | { 41 | if (isLower(*str)) 42 | lower[lowerIndex++] = *str; 43 | else if (isUpper(*str)) 44 | upper[upperIndex++] = *str; 45 | str++; 46 | } 47 | } 48 | 49 | 50 | int main() 51 | { 52 | char* lower = nullptr; 53 | char* upper = nullptr; 54 | getLowerAndUpperStrings("AAqew12423BBq", lower, upper); 55 | 56 | cout << lower << endl << upper << endl; 57 | delete[] lower; 58 | delete[] upper; 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /Week 11/sortLower.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | bool isLower(char ch) 5 | { 6 | return ch >= 'a' && ch <= 'z'; 7 | } 8 | 9 | unsigned getLowerCount(const char* str) 10 | { 11 | if(!str) 12 | return 0; 13 | 14 | unsigned count = 0; 15 | while(*str) 16 | { 17 | if(isLower(*str)) 18 | count++; 19 | 20 | str++; 21 | } 22 | return count; 23 | } 24 | 25 | void concatLettersAtBack(char* str, unsigned firstIndex, char ch, unsigned count) 26 | { 27 | for(int i = 0; i < count; i++) 28 | str[firstIndex + i] = ch; 29 | } 30 | 31 | char* sortLower(const char* str) 32 | { 33 | unsigned lower = getLowerCount(str); 34 | char* result = new char[lower + 1]; 35 | 36 | constexpr unsigned alphabet_size = 26; 37 | constexpr char first_letter = 'a'; 38 | 39 | result[lower] = '\0'; 40 | 41 | unsigned resultIndex = 0; 42 | int countLower[alphabet_size]{ 0 }; 43 | while (*str) 44 | { 45 | if (isLower(*str)) 46 | countLower[*str - 'a']++; 47 | str++; 48 | } 49 | for (int i = 0; i < alphabet_size; i++) 50 | { 51 | concatLettersAtBack(result, resultIndex, first_letter + i, countLower[i]); 52 | resultIndex += countLower[i]; //maybe this should be in the function 53 | } 54 | 55 | return result; 56 | } 57 | 58 | int main() 59 | { 60 | char* str = sortLower("zAzAbbzazQc"); 61 | 62 | cout << str; 63 | delete[] str; 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /Week 12/Practicum.md: -------------------------------------------------------------------------------- 1 | # УП - Практикум 13.01.2025 Седмица 12 2 | 3 | # Задачи с функция от по-висок ред 4 | 5 | **Задача 1.** 6 | Напишете функция countCharsApplicableTo, която приема символен низ и предикатна функция (от тип bool и приема точно един параметър от тип char), и да връща колко от символите отговарят на условието от предиката. 7 | ### Пример: 8 | Вход: " I am a Businessman 123 " , 9 | (Function: How many chars are capital letter) 10 | (Function: How many chars are digits) 11 | (Function: How many chars are whitespace) 12 | 13 | Изход: 14 | 2 15 | 3 16 | 6 17 | 18 | # Задачи с рекурсия 19 | **Задача 1.** 20 | Напишете рекурсивна функция, която приема цяло число n и връща масив от първите n числа на Фибоначи. 21 | 22 | ### Пример: 23 | Вход: 6 24 | Изход: 1 1 2 3 5 8 25 | 26 | **Задача 2.** 27 | Напишете рекурсивна функция, която приема цяло число n и връща масив от първите n числа на Фибоначи, която работи за n = [1, 100] за по-малко от 1 секунда. 28 | 29 | ![image](https://github.com/user-attachments/assets/12563a36-f86c-4687-84e5-6bc820e3d6b5) 30 | 31 | **Задача 3.** 32 | Напишете рекурсивна функция за корен квадратен с помощта на формулата: 33 | 34 | ![image](https://github.com/user-attachments/assets/0f14869f-65aa-4e4c-9c26-fddfcd2649bc) 35 | 36 | **Задача 4.** 37 | Напишете рекурсивна функция, която пресмята броя срещания на символ c в низ str. 38 | 39 | ### Пример: 40 | Вход: alabala a 41 | Изход: 4 42 | 43 | **Задача 5.** 44 | Даден е лабиринт под формата на матрица с размер n x m, където свободно квадратче се отбелязва с 1, а стена – с 0. Намерете има ли път от позиция (0,0) до позиция (n-1, m-1), движейки се в четирите основни посоки и само през свободни квадратчета. 45 | 46 | **Задача 6.** 47 | Напишете рекурсивна фунцкия за двоично търсене. 48 | И решете следната задача: 49 | 50 | # Задачи с Алгоритми 51 | 52 | **Задача 1. - Напишете най-оптимално решение, използвайки BS** 53 | Имате булева квадратна матрица (NxN пълна само с 0 или 1), за която знаете, че със сигурност: поне един от ъглите на матрицата е със стойност 1 и поне един от ъглите е със стойност 0. 54 | Напишете функция, която приема такава матрица, и връща наредена двойка (x, y), които представляват координатите на матрица 2x2, в която: 55 | поне един от ъглите на матрицата е със стойност 1 и поне един от ъглите е със стойност 0 56 | 57 | **Задача 2. - Задача с дървета** 58 | Напишете функция, която приема масив от цели положителни числа и да върне дължината на най-дългата нарастваща редица от числа. 59 | 60 | ### Пример: 61 | Вход : [3, 6, 2, 7, 4, 8, 3, 2, 11, 7] 62 | Процес: [{3}, {6}, 2, {7}, 4, {8}, 3, 2, {11}, 7] 63 | Изход : 5 64 | 65 | **Задача BONUS.** 66 | Дадена е шахматна дъска 8x8. Да се напише ф-ция, която приема начална позиция m(xm, ym) и крайна позиция n(xn, yn) на кон и връща колко най-малко хода трябва да направи коня от позиция m до n. 67 | -------------------------------------------------------------------------------- /Week 12/fibonachi_dynamic_opt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | long long* arr = nullptr; 3 | const int MAX_ARR_LEN = 10000; 4 | long long* getDinamicOptArr() { 5 | if (!arr) { 6 | arr = new long long[MAX_ARR_LEN]; 7 | for (int i = 0; i < MAX_ARR_LEN; ++i) { 8 | arr[i] = -1; 9 | } 10 | } 11 | return arr; 12 | } 13 | long long fib(int n) { 14 | if (n == 1) { 15 | return 0; 16 | } 17 | if (n == 2) { 18 | return 1; 19 | } 20 | return fib(n - 1) + fib(n - 2); 21 | } 22 | 23 | long long dinamicOptFib(int n) { 24 | long long* arrDinamic = getDinamicOptArr(); 25 | if (arrDinamic[n] == -1) 26 | { 27 | long long toSet; 28 | if (n == 1) { 29 | toSet = 0; 30 | } 31 | else if (n == 2) { 32 | toSet = 1; 33 | } 34 | else { 35 | toSet = dinamicOptFib(n - 1) + dinamicOptFib(n - 2); 36 | } 37 | arrDinamic[n] = toSet; 38 | } 39 | return arrDinamic[n]; 40 | } 41 | 42 | int main() 43 | { 44 | for (int i = 1; i < 100; ++i) { 45 | std::cout << dinamicOptFib(i) << '\n'; 46 | } 47 | for (int i = 1; i < 100; ++i) { 48 | std::cout << fib(i) << '\n'; 49 | } 50 | } 51 | --------------------------------------------------------------------------------