├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── README.md ├── en ├── 00_introduction │ ├── github_pack.md │ └── resources.md ├── 01_computer_architecture │ └── doc.md ├── 02_fundamental_concepts │ ├── file_system.md │ └── interfaces_abstraction.md ├── 03_command_line │ └── doc.md ├── 04_compiler_and_ide │ ├── cpp_extension.png │ ├── doc.md │ ├── path_variable.png │ └── stub.md ├── 05_programming_fundamentals │ ├── doc.md │ ├── function_example_1 │ │ └── main.cpp │ ├── linker_examples │ │ ├── README.md │ │ ├── linker_1 │ │ │ ├── diagram.drawio │ │ │ ├── f.cpp │ │ │ ├── f.h │ │ │ └── main.cpp │ │ ├── linker_2 │ │ │ ├── f.cpp │ │ │ └── main.cpp │ │ ├── linker_3 │ │ │ ├── f.cpp │ │ │ └── main.cpp │ │ ├── linker_4 │ │ │ ├── diagram.drawio │ │ │ ├── f.cpp │ │ │ └── main.cpp │ │ ├── wrong_1 │ │ │ ├── f.cpp │ │ │ ├── linker_error.drawio │ │ │ └── main.cpp │ │ └── wrong_2 │ │ │ ├── linker_error.drawio │ │ │ └── main.cpp │ ├── memory_example_1 │ │ ├── example.cpp │ │ └── example_memory.xlsx │ ├── memory_example_2 │ │ ├── example.cpp │ │ └── example_memory.xlsx │ ├── memory_example_3 │ │ ├── heap_1.cpp │ │ ├── heap_2.cpp │ │ ├── stack_1.cpp │ │ ├── stack_2.cpp │ │ ├── stack_2.xlsx │ │ ├── static_1.cpp │ │ └── static_2.cpp │ ├── memory_example_4 │ │ ├── example_memory.xlsx │ │ └── recursion.cpp │ ├── snake │ │ ├── common │ │ │ ├── common.cpp │ │ │ ├── common.h │ │ │ ├── logic.cpp │ │ │ └── logic.h │ │ ├── console │ │ │ ├── Makefile │ │ │ ├── controller.cpp │ │ │ ├── controller.h │ │ │ ├── graphic.cpp │ │ │ ├── graphic.h │ │ │ └── main.cpp │ │ └── raylib-example │ │ │ ├── .gitignore │ │ │ ├── .vscode │ │ │ ├── launch.json │ │ │ ├── settings.json │ │ │ └── tasks.json │ │ │ ├── README.md │ │ │ ├── build-MinGW-W64.bat │ │ │ ├── build-VisualStudio2022.bat │ │ │ ├── build │ │ │ └── premake5.lua │ │ │ ├── include │ │ │ └── .keep │ │ │ └── src │ │ │ └── main.cpp │ ├── stub.md │ └── tictactoe │ │ └── main.cpp ├── 05a_programming_fundamentals │ ├── 01_oop_primitives.md │ ├── 02_RAII.md │ ├── 03_operators.md │ ├── 04_enum.md │ ├── 05_module.md │ ├── 06_namespace.md │ ├── 07_template.md │ ├── 08_strings.md │ ├── 09_iterator.md │ ├── 10_other.md │ ├── 11_polymorphism.md │ ├── README.md │ ├── enums │ │ ├── enum_class.cpp │ │ ├── global_const_list.cpp │ │ └── namespaced_enum.cpp │ ├── headers │ │ ├── example_1 │ │ │ ├── compile.bat │ │ │ ├── f.cpp │ │ │ ├── main.cpp │ │ │ └── other_file.cpp │ │ ├── example_2 │ │ │ ├── compile.bat │ │ │ ├── f.cpp │ │ │ ├── f.h │ │ │ ├── main.cpp │ │ │ ├── other_file.cpp │ │ │ └── other_file.h │ │ └── example_3 │ │ │ ├── f.h │ │ │ ├── main.cpp │ │ │ └── other_file.h │ ├── iterator │ │ ├── graph.h │ │ ├── graph_1.cpp │ │ ├── graph_manual_iterator.cpp │ │ ├── graph_range_for.cpp │ │ ├── graph_standard.cpp │ │ ├── run.sh │ │ ├── standard_impl.cpp │ │ └── video.cpp │ ├── polymorphism │ │ ├── abstract_base_class.cpp │ │ ├── button_func_pointer_decentralized.cpp │ │ ├── button_func_pointer_example.cpp │ │ ├── fat_pointer.cpp │ │ ├── func_void_pointer_context.cpp │ │ ├── func_with_context.cpp │ │ ├── functor.cpp │ │ ├── functor_custom_name.cpp │ │ ├── lambda_1_void.cpp │ │ ├── lambda_2_context_copy.cpp │ │ ├── lambda_3_shared_context.cpp │ │ ├── lambda_4_functor_sizes.cpp │ │ ├── multiple_vtables_cpp_approach.cpp │ │ ├── pointer_value_union_small_example.cpp │ │ ├── std_function.cpp │ │ └── strategy_func_pointer.cpp │ ├── procedural │ │ └── shop.cpp │ ├── stub.md │ ├── template │ │ ├── example_1 │ │ │ └── main.cpp │ │ ├── example_2 │ │ │ ├── compile.bat │ │ │ ├── f.cpp │ │ │ ├── main.cpp │ │ │ └── template.h │ │ ├── example_3 │ │ │ └── main.cpp │ │ ├── example_4 │ │ │ ├── compile.bat │ │ │ ├── f.cpp │ │ │ ├── main.cpp │ │ │ └── two_values.h │ │ ├── example_5 │ │ │ ├── compile.bat │ │ │ ├── f.cpp │ │ │ ├── f.h │ │ │ └── main.cpp │ │ └── example_6 │ │ │ ├── compile.bat │ │ │ ├── f.cpp │ │ │ ├── f.h │ │ │ └── main.cpp │ └── vector │ │ ├── README.md │ │ ├── mutation.cpp │ │ ├── operator.cpp │ │ └── procedural.cpp ├── 06_arrays │ ├── array.cpp │ ├── doc.md │ ├── std_array.cpp │ ├── std_span.cpp │ ├── stub.md │ └── t.cpp ├── 07_serialization │ ├── doc.md │ ├── stub.md │ └── validation │ │ ├── 01_bool_example.cpp │ │ ├── 02_string_example.cpp │ │ ├── 03_string_multiple_example.cpp │ │ ├── 04_enum_example.cpp │ │ ├── 05_enum_flags_example.cpp │ │ ├── 06_tagged_union_example.cpp │ │ ├── 07_exception_usage_example.cpp │ │ └── common.h ├── 08_searching_algorithms │ ├── binarySearch.cpp │ ├── binarySearchTree.cpp │ ├── binarySearchTreeArray.cpp │ ├── binarySearchTreeArrayIndices.cpp │ ├── binarySearchTreeRecursive.cpp │ ├── linearSearch.cpp │ ├── stub.md │ └── waves_algorithm │ │ ├── README.md │ │ ├── example.maze │ │ ├── excel_water.xlsx │ │ ├── level_by_level.cpp │ │ ├── maze.maze │ │ ├── minecraft │ │ ├── README.md │ │ ├── map.rar │ │ └── mods │ │ │ ├── fabric-carpet-1.20-1.4.112v230608.jar │ │ │ └── subtick-mc1.20.1-v1.0.15.jar │ │ ├── rewritten_for_video.cpp │ │ ├── single_queue.cpp │ │ └── walls.maze ├── 09_generic_data_structures │ ├── associative_array.cpp │ ├── associative_array_linear.cpp │ ├── buffer_without_abstraction.cpp │ ├── doubly_linked_list.cpp │ ├── dynamic_array.cpp │ ├── dynamic_buffer.cpp │ ├── graph.cpp │ ├── graph_searches.cpp │ ├── graphs_search_video_ro.cpp │ ├── images │ │ ├── buffer_example.png │ │ ├── buffer_example_1.png │ │ ├── doubly_linked_list_memory.png │ │ ├── graph1.png │ │ ├── linked_list.png │ │ ├── linked_list_memory.png │ │ ├── linked_list_memory_1.png │ │ ├── quene.png │ │ ├── queue2.png │ │ └── stack.png │ ├── linked_list.cpp │ ├── linked_list_impl.cpp │ ├── queue.cpp │ ├── queue_ring_buffer.cpp │ ├── stack.cpp │ ├── stack_video.cpp │ ├── static_buffer.cpp │ └── stub.md ├── 10_sorting │ ├── examples │ │ ├── 01_selection_sort.cpp │ │ ├── 01_selection_sort_pointers.cpp │ │ ├── 01_selection_sort_video.cpp │ │ ├── 02_insertion_sort.cpp │ │ ├── 02_insertion_sort_two_steps.cpp │ │ ├── 03_bubble_sort.cpp │ │ ├── 03_bubble_sort_recursive.cpp │ │ ├── 04_merge_sort.cpp │ │ ├── 04_merge_sort_video.cpp │ │ ├── 05_quick_sort.cpp │ │ ├── 05_quick_sort_video.cpp │ │ ├── 06_heap_sort.cpp │ │ ├── common.h │ │ ├── merge_sort_complexity.png │ │ └── readme.md │ └── stub.md └── 11_multidimensional_arrays │ ├── iliffe.cpp │ ├── linear.cpp │ └── stub.md ├── ru └── labs │ ├── algoritms │ ├── 01_git.md │ ├── 02_searching_algorithms.md │ ├── 03_linked_lists.md │ ├── 04_graphs.md │ ├── 05_stack_queue.md │ ├── 06_hash_table.md │ ├── 07_sorting_algorithms.md │ └── 08_multidimensional_array.md │ ├── common │ ├── 01_computer_architecture.md │ ├── 02_number_systems.md │ ├── 03_numbers.md │ ├── 04_algorithm.md │ ├── 05_function_execution.md │ ├── 06_compiler_install.md │ └── 07_git.md │ └── cpp │ ├── 01_basics.md │ ├── 02_struct.md │ ├── 03_object.md │ ├── 04_bool.md │ ├── 05_string_basic.md │ ├── 06_linker.md │ ├── 07_oop_syntax.md │ ├── 08_raii.md │ ├── 09_enum.md │ ├── 10_operators.md │ ├── 11_iterator.md │ ├── 12_dynamic_array.md │ ├── 13_events.md │ └── README.md ├── tests └── main.cpp └── workspace.tmux /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.pdb 3 | *.lib 4 | ~$*.xlsx 5 | .idea 6 | .vs 7 | *.ilk 8 | *.o 9 | test.md 10 | test*.cpp 11 | Tests 12 | *.out 13 | 14 | *.html 15 | *.pdf 16 | 17 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Default", 5 | "cppStandard": "c++20", 6 | } 7 | ], 8 | "version": 4 9 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch codelldb", 9 | "type": "codelldb", 10 | "request": "launch", 11 | "program": "${fileBasenameNoExtension}", 12 | "args": [ 13 | ], 14 | "stopAtEntry": false, 15 | "cwd": "${fileDirname}", 16 | "environment": [], 17 | "console": "integratedTerminal", 18 | "preLaunchTask": "zig_cpp_current_file" 19 | }, 20 | { 21 | "name": "(Windows) Launch", 22 | "type": "cppvsdbg", 23 | "request": "launch", 24 | "program": "${fileBasenameNoExtension}", 25 | "args": [ 26 | 27 | ], 28 | "stopAtEntry": false, 29 | "cwd": "${fileDirname}", 30 | "environment": [], 31 | "console": "integratedTerminal", 32 | "preLaunchTask": "zig_cpp_current_file" 33 | }, 34 | { 35 | "name": "(gdb) Launch", 36 | "type": "cppdbg", 37 | "request": "launch", 38 | "program": "${fileDirname}/${fileBasenameNoExtension}.exe", 39 | "cwd": "${fileDirname}", 40 | "MIMode": "gdb", 41 | "setupCommands": [ 42 | { 43 | "description": "Enable pretty-printing for gdb", 44 | "text": "-enable-pretty-printing", 45 | "ignoreFailures": true 46 | }, 47 | { 48 | "description": "Set Disassembly Flavor to Intel", 49 | "text": "-gdb-set disassembly-flavor intel", 50 | "ignoreFailures": true 51 | } 52 | ], 53 | "preLaunchTask": "gcc_cpp_current_file" 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.uxml": "xml", 4 | "*.meta": "yaml", 5 | "*.uss": "css", 6 | "*.tt": "t4", 7 | "*.prefab": "yaml", 8 | "*.asset": "yaml", 9 | "*.dwlt": "yaml", 10 | "*.json": "jsonc", 11 | "array": "cpp", 12 | "atomic": "cpp", 13 | "bit": "cpp", 14 | "cctype": "cpp", 15 | "charconv": "cpp", 16 | "clocale": "cpp", 17 | "cmath": "cpp", 18 | "compare": "cpp", 19 | "concepts": "cpp", 20 | "cstddef": "cpp", 21 | "cstdint": "cpp", 22 | "cstdio": "cpp", 23 | "cstdlib": "cpp", 24 | "cstring": "cpp", 25 | "ctime": "cpp", 26 | "cwchar": "cpp", 27 | "exception": "cpp", 28 | "format": "cpp", 29 | "functional": "cpp", 30 | "initializer_list": "cpp", 31 | "ios": "cpp", 32 | "iosfwd": "cpp", 33 | "iostream": "cpp", 34 | "istream": "cpp", 35 | "iterator": "cpp", 36 | "limits": "cpp", 37 | "list": "cpp", 38 | "locale": "cpp", 39 | "memory": "cpp", 40 | "mutex": "cpp", 41 | "new": "cpp", 42 | "ostream": "cpp", 43 | "ratio": "cpp", 44 | "span": "cpp", 45 | "stdexcept": "cpp", 46 | "stop_token": "cpp", 47 | "streambuf": "cpp", 48 | "system_error": "cpp", 49 | "thread": "cpp", 50 | "tuple": "cpp", 51 | "type_traits": "cpp", 52 | "typeinfo": "cpp", 53 | "unordered_map": "cpp", 54 | "utility": "cpp", 55 | "vector": "cpp", 56 | "xfacet": "cpp", 57 | "xhash": "cpp", 58 | "xiosbase": "cpp", 59 | "xlocale": "cpp", 60 | "xlocbuf": "cpp", 61 | "xlocinfo": "cpp", 62 | "xlocmes": "cpp", 63 | "xlocmon": "cpp", 64 | "xlocnum": "cpp", 65 | "xloctime": "cpp", 66 | "xmemory": "cpp", 67 | "xstring": "cpp", 68 | "xtr1common": "cpp", 69 | "xutility": "cpp", 70 | "fstream": "cpp", 71 | "string": "cpp", 72 | "algorithm": "cpp", 73 | "chrono": "cpp", 74 | "iomanip": "cpp", 75 | "optional": "cpp", 76 | "bitset": "cpp" 77 | }, 78 | "cmake.configureOnOpen": true 79 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "shell", 6 | "label": "zig_cpp_current_file", 7 | "command": "zig", 8 | "args": [ 9 | "c++", 10 | "${file}", 11 | "-o", 12 | "${fileBasenameNoExtension}.exe", 13 | "-Werror", 14 | "-Wall", 15 | "-std=c++20", 16 | ], 17 | "options": { 18 | "cwd": "${fileDirname}" 19 | }, 20 | "problemMatcher": [ 21 | "$gcc" 22 | ], 23 | "group": { 24 | "kind": "build", 25 | "isDefault": true 26 | } 27 | }, 28 | { 29 | "type": "shell", 30 | "label": "gcc_cpp_current_file", 31 | "command": "g++", 32 | "args": [ 33 | "${file}", 34 | "-o", 35 | "${fileBasenameNoExtension}.exe", 36 | // "-Werror", 37 | "-Wall", 38 | "-std=c++20", 39 | "-ggdb", 40 | // "-O1" 41 | ], 42 | "options": { 43 | "cwd": "${fileDirname}" 44 | }, 45 | "problemMatcher": [ 46 | "$gcc" 47 | ], 48 | "group": { 49 | "kind": "build", 50 | "isDefault": true 51 | } 52 | }, 53 | ] 54 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Anton Curmanschii 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 | Playlists with video content accompanying the lessons: 2 | - [ru](https://www.youtube.com/playlist?list=PL4sUOB8DjVlXtWZJKdJdTeT9i4q3mNEsm), 3 | - [ro](https://www.youtube.com/playlist?list=PL4sUOB8DjVlX_9_rQXhOS6WiCkE8SFc7F). 4 | 5 | [C++ (ru) Playlist](https://youtube.com/playlist?list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&si=4nQMQ-X6wVKpuQzi) 6 | 7 | 8 | Find the lab tasks in `ru/labs`. 9 | -------------------------------------------------------------------------------- /en/00_introduction/github_pack.md: -------------------------------------------------------------------------------- 1 | # How to get free stuff from GitHub 2 | 3 | If you've got a university email, you can get free stuff by applying for 4 | [GitHub Students Developer Pack](https://education.github.com/pack). 5 | 6 | Note that the email you get from university is a Microsoft email, and to access it you need to go to 7 | [e.g. office.com](https://www.office.com/), provide your credentials, 8 | and then select [the outlook app](https://outlook.office.com/mail/). 9 | You'll see your new emails here. 10 | It also comes with the office applications which you can install. 11 | 12 | Beside the university email, you need a confirmation that you actually are a student. 13 | You can get that in the management office at university (decanat). 14 | Just enter there and ask for a document that confirms you are a student. 15 | Take a picture of it, you'll need it later for your application. 16 | 17 | You will also need a github account, which you can create by 18 | [this link](https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F&source=header-home). 19 | You may use any email to sign up, you will be able to attach your university email to your account after signing up. 20 | 21 | If you have an account already, or you've just created one and haven't attached your univesity email to it yet, 22 | you can do it by using the UI on [this page](https://github.com/settings/emails). 23 | After you type in the email, you'll have to confirm it. 24 | 25 | Once you have the confirmation document, you can apply online via 26 | [this link](https://education.github.com/discount_requests/application). 27 | 28 | After some time, maybe a few days, you should get a confirmation letter from GitHub, 29 | with which you'll get access to all services they give away, like a Rider license or access to GitHub Copilot. 30 | 31 | While you're still a student, you can refresh this thing every year, regaining access to all of the goodies. -------------------------------------------------------------------------------- /en/00_introduction/resources.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | I have a lot of example university projects on my github which can be used as reference when doing them youself. 4 | Most of them are here listed in the `uni_` projects [here](https://github.com/AntonC9018?tab=projects&type=classic). 5 | Almost all of the projects, except [FP](https://github.com/AntonC9018/FP) and [graphs](https://github.com/AntonC9018/graphs) 6 | have `uni_` in their name, so that they are easily found by searching repositories with `uni_` in the name in my github. 7 | 8 | Here's my google meet link: [https://meet.google.com/trr-gkmj-cxz](https://meet.google.com/trr-gkmj-cxz). 9 | 10 | Here's my google drive link, which contains rendered completed university assignments, 11 | and example test answers, grouped by semester, as well as some books I read when learning: 12 | [https://drive.google.com/drive/u/0/folders/1Rs0-qy6ivSDuHh5JadrP4Ta4YDhuVRiC](https://drive.google.com/drive/u/0/folders/1Rs0-qy6ivSDuHh5JadrP4Ta4YDhuVRiC) 13 | 14 | 15 | **Good YouTube videos and channels for learning programming:** 16 | 17 | - [Casey Muratori at Molly Rocket](https://www.youtube.com/@MollyRocket). 18 | This is just a very smart guy who has an immense experience in the industry. You should watch all his lectures. 19 | 20 | - [Code Aesthetic](https://www.youtube.com/@CodeAesthetic), 21 | who has awesome visual videos for understanding intermediate-advanced programming concepts. 22 | 23 | - [Simon Dev's video on floating point numbers](https://www.youtube.com/watch?v=Oo89kOv9pVk). 24 | I probably won't be covering this in the course, so you may want to learn it on your own. 25 | 26 | - [Essense of Linear Algebra](https://www.youtube.com/watch?v=fNk_zzaMoSs&list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab). 27 | This topic is very important to understand for game development and graphics, and it's best understood visually in my opinion. 28 | There's no better source for learning this than these series. 29 | 30 | - [Essense of Calculus](https://www.youtube.com/watch?v=WUvTyaaNkzM&list=PLZHQObOWTQDMsr9K-rj53DwVRMYO3t5Yr). 31 | This is to understand derivatives and integrals, which are occasionally useful in game development. 32 | 33 | - [Associativity](https://www.youtube.com/watch?v=Oq71Ev9-aQE). 34 | You really want to understand this if you study abstract algebra. 35 | It will really help you big time in realizing what's going on in the lectures. 36 | Probably not relevant for this course though. 37 | 38 | - [OOP is bad](https://www.youtube.com/watch?v=QM1iUe6IofM). This video explains why. 39 | 40 | 41 | **Some articles:** 42 | 43 | - [Zig compiler](https://ziglang.org/), which I'll use to compile C and C++ (it bundles Clang). 44 | 45 | - [Virtual multiple inheritance in C++](https://www.cnblogs.com/yetanghanCpp/p/9288708.html). 46 | I will cover this in a future lesson and move the link, but for now, I'll keep it here. 47 | 48 | 49 | **Precausions:** 50 | 51 | - Don't EVER under any circumstances use pirated software, like [monkrus'](https://w14.monkrus.ws/). 52 | ALWAYS install the official bloated Windows 10 version from the official site and 53 | ALWAYS be sure to install office tools from official installation files 54 | (you get the license from the university too!), which come with telemetry to make the services better. -------------------------------------------------------------------------------- /en/02_fundamental_concepts/file_system.md: -------------------------------------------------------------------------------- 1 | **Be sure to know these concepts, learn at your own pace**: 2 | 3 | - File System Entries (File, Directory/Folder) 4 | - Disk 5 | - Path (Absolute, Relative) 6 | - The explorer application 7 | 8 | You can use e.g. this [link](https://docs.oracle.com/cd/E19253-01/806-4743/filemanager-3/index.html). 9 | You should really knows this at this point, so I won't explain it. 10 | 11 | **Knowing these would be great, but it's not required**: 12 | 13 | - File System Tree (the idea of organizing file system entries in a tree) 14 | - Symbolic Links (Junctions) 15 | 16 | **Learn these if you're interested**: 17 | 18 | - File system formats (FAT32, NTFS, etc.) 19 | - Permissions in NTFS 20 | - Formatting drives 21 | - Fragmentation 22 | - Storage media (HDD, SSD, tape, etc.) 23 | - Backupping -------------------------------------------------------------------------------- /en/04_compiler_and_ide/cpp_extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/04_compiler_and_ide/cpp_extension.png -------------------------------------------------------------------------------- /en/04_compiler_and_ide/path_variable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/04_compiler_and_ide/path_variable.png -------------------------------------------------------------------------------- /en/04_compiler_and_ide/stub.md: -------------------------------------------------------------------------------- 1 | **What's a compiler?** 2 | 3 | Read [this blogpost](https://www.scaler.com/topics/c/compilation-process-in-c/), it has pretty good wording in my opinion. 4 | You may watch [this video](https://www.youtube.com/watch?v=QXjU9qTsYCc) as well, for a general understanding. 5 | 6 | - Preprocessor (#include, #define) 7 | - Object files 8 | - Linking 9 | 10 | **Practical tool understanding** 11 | 12 | - Installing a compiler manually (zig C++) 13 | - Compiling manually 14 | 15 | **IDE usage** 16 | 17 | - Installing like visual studio (but use anything you want, I don't care) 18 | - Using a debugger 19 | 20 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/function_example_1/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | void a() 3 | { 4 | int i = 5; 5 | i = i + 5; 6 | // return; 7 | } 8 | /* 9 | - Allocate space for `i` on the stack. 10 | - Write 5 to `i`. 11 | - Add 5 to `i`. 12 | - Return (to address of `return;` stored by b). 13 | */ 14 | 15 | void b() 16 | { 17 | a(); 18 | return; 19 | } 20 | 21 | /* 22 | - Allocate space for the next instruction on the stack. 23 | - Save address of `return;` on the stack. 24 | - Jump to first instruction of `a`. 25 | - Return (to address of `return 0;` in main). 26 | */ 27 | 28 | int main() 29 | { 30 | b(); 31 | return 0; 32 | } 33 | 34 | /* 35 | - Allocate space for the next instruction on the stack. 36 | - Save address of `return 0;` on the stack. 37 | - Just to first instruction of b. 38 | - return 0; 39 | */ -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/README.md: -------------------------------------------------------------------------------- 1 | Compile the examples by using e.g.: 2 | 3 | ``` 4 | zig c++ main.cpp f.cpp 5 | ``` 6 | 7 | View the diagrams here: https://app.diagrams.net/ -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_1/f.cpp: -------------------------------------------------------------------------------- 1 | // Definitions of the functions visible to the linker. 2 | #include "f.h" 3 | 4 | int f(int a) 5 | { 6 | return a; 7 | } 8 | 9 | float b(float b) 10 | { 11 | return b * 2; 12 | } 13 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_1/f.h: -------------------------------------------------------------------------------- 1 | int f(int a); 2 | float b(float b); -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_1/main.cpp: -------------------------------------------------------------------------------- 1 | // View the diagram file here https://app.diagrams.net/ 2 | // Remember that include pastes the contents of the file. 3 | // So this will just insert the two declaration as text, replacing the #include. 4 | #include "f.h" 5 | 6 | int main() 7 | { 8 | f(1); 9 | b(2.0f); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_2/f.cpp: -------------------------------------------------------------------------------- 1 | // Global non-static variable *definition*. 2 | // Defining it again in another file will give a linker error 3 | // (due to multiple definitions). 4 | int a; 5 | 6 | // This one exists only in this compilation unit / object file. 7 | static int b; -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_2/main.cpp: -------------------------------------------------------------------------------- 1 | // Bind `a` to the global `a` using the linker. 2 | extern int a; 3 | 4 | int main() 5 | { 6 | a = 5; 7 | return 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_3/f.cpp: -------------------------------------------------------------------------------- 1 | // This function appears literally nowhere in the compiled executable. 2 | // It doesn't participate in linking, which means you can put them in header files. 3 | // It's better to also make them static to avoid confusing the linker. 4 | static inline int sum() 5 | { 6 | return 1; 7 | } 8 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_3/main.cpp: -------------------------------------------------------------------------------- 1 | // Macros work at TEXT level (they do textual substitution 2 | // as a separate pass before actual compilation). 3 | #define SUM(a, b) ((a) + (b)) 4 | 5 | // Inline functions work at instruction level 6 | // (the instructions of the function are pasted in place of the function call). 7 | inline int sum(int a, int b) 8 | { 9 | return a + b; 10 | } 11 | 12 | int main() 13 | { 14 | // Gets LITERALLY replaced with, before the actual compiling starts: 15 | // int s1 = ((4) + (5)); 16 | int s1 = SUM(4, 5); 17 | 18 | // The instructions that would be executed when calling sum 19 | // will be placed directly in place of the function call. 20 | // This can be useful for functions that do very little work: 21 | // using these adds to the size of the executable, but it can speed up 22 | // the program when the cost of invoking the function 23 | // (as in, storing the next instruction address, 24 | // jumping to the function address, returning from it) 25 | // is high enough compared to the actual work that the function does. 26 | int s2 = sum(4, 5); 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_4/f.cpp: -------------------------------------------------------------------------------- 1 | static int sum(int a, int b) 2 | { 3 | return 1; 4 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/linker_4/main.cpp: -------------------------------------------------------------------------------- 1 | static int sum(int a, int b) 2 | { 3 | return a + b; 4 | } 5 | 6 | int main() 7 | { 8 | int c = sum(4, 5); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/wrong_1/f.cpp: -------------------------------------------------------------------------------- 1 | // Linker error: duplicate definition. 2 | int f(int a) 3 | { 4 | return a; 5 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/wrong_1/main.cpp: -------------------------------------------------------------------------------- 1 | int f(int a); 2 | 3 | int main() 4 | { 5 | f(1); 6 | return 0; 7 | } 8 | 9 | int f(int a) 10 | { 11 | return a; 12 | } 13 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/linker_examples/wrong_2/main.cpp: -------------------------------------------------------------------------------- 1 | // Declaration without definition 2 | int f(int a); 3 | 4 | int main() 5 | { 6 | f(1); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_1/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | // TODO: Show this memory on a picture, people don't understand it as comments. 7 | 8 | // 0 0 0 69 9 | int i = 69; 10 | // 0 0 0 5 11 | // 0 0 2 1 12 | // 0 0 0 0 13 | // 0 0 0 0 14 | // 0 0 0 0 15 | // 0 0 0 0 16 | int arr[6] = { }; 17 | arr[0] = 5; 18 | arr[1] = 513; 19 | 20 | // 0 0 0 0 0 0 0 36 21 | int* iPointer = &i; // make sure people understand what & does 22 | // 0 0 0 0 0 0 0 36 23 | uintptr_t iPointerAsNumber = (uintptr_t) iPointer; 24 | 25 | std::cout << iPointerAsNumber << std::endl; 26 | std::cout << (*iPointer) << std::endl; 27 | 28 | // 0 0 0 0 0 0 0 44 29 | int* arr1Pointer = iPointer + 2; // explain pointer arithmetic, with pictures 30 | std::cout << *arr1Pointer; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_1/example_memory.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/05_programming_fundamentals/memory_example_1/example_memory.xlsx -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_2/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct TwoInts 5 | { 6 | int a; 7 | int b; 8 | }; 9 | 10 | struct StructWithArray 11 | { 12 | int arr[4]; 13 | int* someNumber; 14 | }; 15 | 16 | int main() 17 | { 18 | TwoInts i2 = { }; 19 | i2.a = 5; 20 | i2.b = 7; 21 | 22 | std::cout << i2.a << std::endl; 23 | std::cout << i2.b << std::endl; 24 | 25 | StructWithArray s = { }; 26 | s.arr[0] = 10; 27 | 28 | StructWithArray s1 = { }; 29 | s1.arr[0] = 15; 30 | 31 | StructWithArray* sPointer = &s; 32 | sPointer->arr[0] = 20; 33 | 34 | std::cout << s.arr[0] << std::endl; 35 | s.arr[0] = 25; 36 | std::cout << s.arr[0] << std::endl; 37 | sPointer->arr[0] = 30; 38 | std::cout << s.arr[0] << std::endl; 39 | 40 | sPointer = &s1; 41 | sPointer->arr[0] = 35; 42 | std::cout << s.arr[0] << std::endl; 43 | std::cout << s1.arr[0] << std::endl; 44 | 45 | StructWithArray structArray[2] = { }; 46 | structArray[0].arr[3] = 77; 47 | structArray[1].someNumber = &structArray[0].arr[3]; 48 | 49 | sPointer = &s; 50 | int* pointer = &sPointer->arr[3]; 51 | s.arr[3] = 72; 52 | std::cout << *pointer; 53 | 54 | StructWithArray memory; 55 | memset(&memory, 0, sizeof(StructWithArray)); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_2/example_memory.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/05_programming_fundamentals/memory_example_2/example_memory.xlsx -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/heap_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int* heapMemory() 4 | { 5 | int* a = new int{}; 6 | std::cout << "a: " << *a << std::endl; 7 | // assign to memory at address stored in a = deference a + 1 8 | *a = *a + 1; 9 | return a; 10 | } 11 | 12 | int main() 13 | { 14 | int* a = heapMemory(); // prints 0 15 | int* b = heapMemory(); // prints 0 16 | 17 | // The addresses won't be equal, every new invocation gets a new `a`. 18 | bool areAddressesEqual = ((uintptr_t) a == (uintptr_t) b); 19 | std::cout << "are addresses equal: " << (areAddressesEqual ? "yes" : "no") << std::endl; 20 | 21 | // The values will! 22 | bool areValuesEqual = (*a == *b); 23 | std::cout << "are values equal: " << (areValuesEqual ? "yes" : "no") << std::endl; 24 | 25 | // And it's legal to use them again, even outside `heapMemory`'s stack frame. 26 | *a = 5; 27 | *b = 10; 28 | // Prints -5. 29 | std::cout << (*a - *b) << std::endl; 30 | 31 | // Don't forget to reclaim the memory. 32 | // Forgetting to do this is called a memory leak. 33 | // Practically, you should always do this, even though all memory 34 | // is reclaimed automatically when the program exits. 35 | // Especially in long-lived applications. 36 | delete a; 37 | delete b; 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/heap_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // This is the same example, but with the malloc() function, 5 | // it uses the C heap instead of the C++ heap. 6 | 7 | int* heapMemory() 8 | { 9 | void* memory = malloc(sizeof(int)); 10 | int* a = static_cast(memory); 11 | *a = 0; 12 | std::cout << "a: " << *a << std::endl; 13 | *a = *a + 1; 14 | return a; 15 | } 16 | 17 | int main() 18 | { 19 | int* a = heapMemory(); // prints 0 20 | int* b = heapMemory(); // prints 0 21 | 22 | // no 23 | bool areAddressesEqual = ((uintptr_t) a == (uintptr_t) b); 24 | std::cout << "are addresses equal: " << (areAddressesEqual ? "yes" : "no") << std::endl; 25 | 26 | // yes 27 | bool areValuesEqual = (*a == *b); 28 | std::cout << "are values equal: " << (areValuesEqual ? "yes" : "no") << std::endl; 29 | 30 | *a = 5; 31 | *b = 10; 32 | // Prints -5. 33 | std::cout << (*a - *b) << std::endl; 34 | 35 | free(a); 36 | free(b); 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/stack_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void stackMemory() 4 | { 5 | int a = 0; 6 | std::cout << "a: " << a << std::endl; 7 | a += 1; 8 | } 9 | 10 | int main() 11 | { 12 | stackMemory(); // prints 0 13 | stackMemory(); // prints 0 14 | stackMemory(); // prints 0 15 | return 0; 16 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/stack_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // This program was designed to show you how the stack works. 5 | // You shouldn't dereference pointers which are no longer in scope. 6 | // Never do that, it's undefined behavior (anything can happen). 7 | 8 | // Note that this program may break if you use optimizations. 9 | // Also, I have only tried it on Zig C++ (Clang) on Windows. 10 | 11 | // Also note, that this produces a warning on Zig C++ (Clang), which is expected. 12 | 13 | // See the excel file for a visualization of the stack. 14 | 15 | int* stackMemory1() 16 | { 17 | int a = 1; 18 | return &a; 19 | } 20 | 21 | int* stackMemory2() 22 | { 23 | int b = 2; 24 | return &b; 25 | } 26 | 27 | int main() 28 | { 29 | int* b = stackMemory1(); 30 | int a1 = *b; // 1 31 | int* c = stackMemory2(); 32 | int a2 = *c; // 2 33 | int a3 = *b; // 2 34 | 35 | std::cout << a1 << std::endl; // prints 1 36 | std::cout << a2 << std::endl; // prints 2 37 | std::cout << a3 << std::endl; // prints 2 38 | std::cout << ((std::byte*) b - (std::byte*) c) << std::endl; // prints 0, pointers are equal 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/stack_2.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/05_programming_fundamentals/memory_example_3/stack_2.xlsx -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/static_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void staticMemory() 4 | { 5 | static int a = 0; 6 | std::cout << "a: " << a << std::endl; 7 | a += 1; 8 | } 9 | 10 | int main() 11 | { 12 | staticMemory(); // prints 0 13 | staticMemory(); // prints 1 14 | staticMemory(); // prints 2 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_3/static_2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int a = 0; 4 | 5 | void staticMemory() 6 | { 7 | std::cout << "a: " << a << std::endl; 8 | a += 1; 9 | } 10 | 11 | int main() 12 | { 13 | std::cout << a; 14 | staticMemory(); // prints 0 15 | staticMemory(); // prints 1 16 | staticMemory(); // prints 2 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/memory_example_4/example_memory.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/05_programming_fundamentals/memory_example_4/example_memory.xlsx -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/common/common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "common.h" 4 | 5 | Direction getOppositeDirection(Direction d) 6 | { 7 | return (d + 2) % directionCount; 8 | } 9 | 10 | Vector getDirectionAsVector(Direction d) 11 | { 12 | switch (d) 13 | { 14 | case UP: 15 | { 16 | return { 17 | .x = 0, 18 | .y = -1, 19 | }; 20 | } 21 | case RIGHT: 22 | { 23 | return { 24 | .x = 1, 25 | .y = 0, 26 | }; 27 | } 28 | case LEFT: 29 | { 30 | return { 31 | .x = -1, 32 | .y = 0, 33 | }; 34 | } 35 | case DOWN: 36 | { 37 | return { 38 | .x = 0, 39 | .y = 1, 40 | }; 41 | } 42 | default: 43 | { 44 | assert(false); 45 | } 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/common/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct Vector 5 | { 6 | int x; 7 | int y; 8 | }; 9 | 10 | struct BoardDimensions 11 | { 12 | size_t col; 13 | size_t row; 14 | size_t totalCells; 15 | }; 16 | 17 | inline bool areVectorsEqual(Vector a, Vector b) 18 | { 19 | return a.x == b.x && a.y == b.y; 20 | } 21 | 22 | inline BoardDimensions createBoardDimensions(size_t col, size_t row) 23 | { 24 | return { 25 | .col = col, 26 | .row = row, 27 | .totalCells = col * row, 28 | }; 29 | } 30 | 31 | using Direction = int; 32 | static inline const Direction UP = 0; 33 | static inline const Direction RIGHT = 1; 34 | static inline const Direction DOWN = 2; 35 | static inline const Direction LEFT = 3; 36 | static inline const Direction INVALID_DIRECTION = -1; 37 | static inline const int directionCount = 4; 38 | 39 | Direction getOppositeDirection(Direction d); 40 | Vector getDirectionAsVector(Direction d); 41 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/common/logic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "common.h" 6 | 7 | struct SnakePositionsStorage 8 | { 9 | std::span bodyPositions; 10 | size_t headIndex; 11 | size_t snakeLength; 12 | }; 13 | 14 | using RNGState = std::mt19937; 15 | 16 | SnakePositionsStorage createSnakePositionStorage(const BoardDimensions& dimensions); 17 | void freeSnakePositionStorage(SnakePositionsStorage& snake); 18 | 19 | bool existsSnakeBodyAt( 20 | const SnakePositionsStorage& snake, 21 | Vector randomPosition, 22 | bool includeLast = true); 23 | 24 | Direction getNextDirection( 25 | Direction currentDirection, 26 | Direction desiredDirection); 27 | 28 | inline Vector& getHeadPosition(SnakePositionsStorage& snake) 29 | { 30 | return snake.bodyPositions[snake.headIndex]; 31 | } 32 | 33 | void moveHead(SnakePositionsStorage& snake); 34 | 35 | struct GameState 36 | { 37 | SnakePositionsStorage snakePositions; 38 | Direction snakeDirection; 39 | Vector applePosition; 40 | RNGState rngState; 41 | }; 42 | 43 | bool doGameLogic( 44 | const BoardDimensions& dimensions, 45 | GameState& state); 46 | GameState createInitialGameState(const BoardDimensions& dimensions); 47 | void freeGameState(GameState& state); 48 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/console/Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-Wall -Werror -Wconversion -Wextra -std=c++20 2 | 3 | snake.out: main.o ../common/common.o graphic.o ../common/logic.o controller.o 4 | g++ -o snake.out main.o ../common/common.o graphic.o ../common/logic.o controller.o $(CPPFLAGS) 5 | 6 | main.o: main.cpp ../common/common.h graphic.h ../common/logic.h 7 | g++ -c main.cpp $(CPPFLAGS) 8 | 9 | graphic.o: graphic.cpp graphic.h ../common/logic.h ../common/common.h 10 | g++ -c graphic.cpp $(CPPFLAGS) 11 | 12 | controller.o: controller.cpp controller.h ../common/common.h 13 | g++ -c controller.cpp $(CPPFLAGS) 14 | 15 | ../common.o: ../common/common.cpp ../common/common.h 16 | cd ../common; g++ -c common.cpp $(CPPFLAGS) 17 | 18 | ../logic.o: ../common/logic.cpp ../common/logic.h ../common/common.h 19 | cd ../common; g++ -c logic.cpp $(CPPFLAGS) 20 | 21 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/console/controller.cpp: -------------------------------------------------------------------------------- 1 | #include "controller.h" 2 | #include 3 | 4 | Direction getDirectionFromKey(char ch) 5 | { 6 | switch (ch) 7 | { 8 | case 'W': 9 | case 'w': 10 | { 11 | return UP; 12 | } 13 | case 'S': 14 | case 's': 15 | { 16 | return DOWN; 17 | } 18 | case 'A': 19 | case 'a': 20 | { 21 | return LEFT; 22 | } 23 | case 'D': 24 | case 'd': 25 | { 26 | return RIGHT; 27 | } 28 | default: 29 | { 30 | return INVALID_DIRECTION; 31 | } 32 | } 33 | } 34 | 35 | // raylib 36 | char getPressedSymbol() 37 | { 38 | int ch = std::cin.get(); 39 | const int asciiMask = 0x7F; 40 | if ((ch & asciiMask) == ch) 41 | { 42 | return static_cast(ch); 43 | } 44 | else 45 | { 46 | return 0; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/console/controller.h: -------------------------------------------------------------------------------- 1 | #include "../common/common.h" 2 | 3 | Direction getDirectionFromKey(char ch); 4 | 5 | // raylib 6 | char getPressedSymbol(); 7 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/console/graphic.cpp: -------------------------------------------------------------------------------- 1 | #include "graphic.h" 2 | 3 | #include 4 | 5 | static size_t getBoardTextIndexFromPosition(Vector position, size_t boardTextRowLen) 6 | { 7 | size_t textIndex = static_cast(position.x) 8 | + static_cast(position.y) * boardTextRowLen; 9 | return textIndex; 10 | } 11 | 12 | void printBoard( 13 | BoardText& boardText, 14 | GameState& state) 15 | { 16 | // memset(boardText, '_', boardTextSize); 17 | for (size_t i = 0; i < boardText.span.size(); i++) 18 | { 19 | boardText.span[i] = '_'; 20 | } 21 | for (size_t i = boardText.rowLen - 1; i < boardText.span.size(); i += boardText.rowLen) 22 | { 23 | boardText.span[i] = '\n'; 24 | } 25 | 26 | SnakePositionsStorage& snake = state.snakePositions; 27 | for (size_t offset = 1; offset < snake.snakeLength; offset += 1) 28 | { 29 | size_t m = snake.bodyPositions.size(); 30 | size_t bodyPartIndex = (snake.headIndex + m - offset) % m; 31 | Vector snakePosition = snake.bodyPositions[bodyPartIndex]; 32 | size_t textIndex = getBoardTextIndexFromPosition(snakePosition, boardText.rowLen); 33 | boardText.span[textIndex] = '*'; 34 | } 35 | 36 | { 37 | Vector headPosition = getHeadPosition(snake); 38 | size_t textIndex = getBoardTextIndexFromPosition(headPosition, boardText.rowLen); 39 | boardText.span[textIndex] = '@'; 40 | } 41 | 42 | { 43 | size_t textIndex = getBoardTextIndexFromPosition( 44 | state.applePosition, 45 | boardText.rowLen); 46 | boardText.span[textIndex] = 'o'; 47 | } 48 | 49 | std::string_view s{ 50 | boardText.span.data(), 51 | boardText.span.size(), 52 | }; 53 | std::cout << s << std::endl; 54 | } 55 | 56 | BoardText createBoardText( 57 | const BoardDimensions& dimensions) 58 | { 59 | size_t boardTextRowLen = dimensions.col + 1; 60 | size_t boardTextSize = boardTextRowLen * dimensions.row; 61 | char* boardText = new char[boardTextSize]; 62 | std::span boardSpan = { boardText, boardTextSize }; 63 | return { 64 | .span = boardSpan, 65 | .rowLen = boardTextRowLen, 66 | }; 67 | } 68 | 69 | void freeBoardText(BoardText& boardText) 70 | { 71 | delete[] boardText.span.data(); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/console/graphic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../common/common.h" 4 | #include "../common/logic.h" 5 | #include 6 | 7 | struct BoardText 8 | { 9 | std::span span; 10 | size_t rowLen; 11 | }; 12 | 13 | void printBoard(BoardText& boardText, GameState& state); 14 | BoardText createBoardText(const BoardDimensions& dimensions); 15 | void freeBoardText(BoardText& boardText); 16 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/console/main.cpp: -------------------------------------------------------------------------------- 1 | #include "graphic.h" 2 | #include "controller.h" 3 | #include "../common/logic.h" 4 | 5 | int main() 6 | { 7 | const BoardDimensions dimensions = createBoardDimensions(5, 5); 8 | GameState state = createInitialGameState(dimensions); 9 | BoardText boardText = createBoardText(dimensions); 10 | 11 | printBoard(boardText, state); 12 | 13 | while (true) 14 | { 15 | { 16 | char key = getPressedSymbol(); 17 | if (key == 10) 18 | { 19 | continue; 20 | } 21 | 22 | Direction desiredDirection = getDirectionFromKey(key); 23 | if (desiredDirection != INVALID_DIRECTION) 24 | { 25 | state.snakeDirection = getNextDirection( 26 | state.snakeDirection, 27 | desiredDirection); 28 | } 29 | } 30 | 31 | const bool isGameOver = doGameLogic(dimensions, state); 32 | 33 | printBoard(boardText, state); 34 | 35 | if (isGameOver) 36 | { 37 | break; 38 | } 39 | } 40 | 41 | freeBoardText(boardText); 42 | freeGameState(state); 43 | } 44 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/raylib-example/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}.exe", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": false 23 | } 24 | ], 25 | "windows": { 26 | "miDebuggerPath": "gdb.exe", 27 | }, 28 | "osx": { 29 | "program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}", 30 | "MIMode": "lldb" 31 | }, 32 | "linux": { 33 | "program": "${workspaceFolder}/bin/Debug/${workspaceFolderBasename}", 34 | "miDebuggerPath": "/usr/bin/gdb", 35 | }, 36 | "preLaunchTask": "build debug" 37 | }, 38 | { 39 | "name": "Run", 40 | "type": "cppdbg", 41 | "request": "launch", 42 | "args": [], 43 | "stopAtEntry": false, 44 | "cwd": "${workspaceFolder}", 45 | "environment": [], 46 | "externalConsole": false, 47 | "program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}.exe", 48 | "MIMode": "gdb", 49 | "windows": { 50 | "program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}.exe", 51 | "miDebuggerPath": "gdb.exe" 52 | }, 53 | "osx": { 54 | "program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}", 55 | "MIMode": "lldb" 56 | }, 57 | "linux": { 58 | "program": "${workspaceFolder}/bin/Release/${workspaceFolderBasename}", 59 | "miDebuggerPath": "/usr/bin/gdb" 60 | }, 61 | "preLaunchTask": "build release", 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/raylib-example/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/.svn": true, 5 | "**/.hg": true, 6 | "**/CVS": true, 7 | "**/.DS_Store": true, 8 | "**/*.o": true, 9 | "**/*.exe": true, 10 | } 11 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/raylib-example/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build debug", 8 | "type": "process", 9 | "command": "make", 10 | "windows": { 11 | "command": "mingw32-make.exe", 12 | "args": [ 13 | "SHELL=cmd" 14 | ], 15 | }, 16 | "group": { 17 | "kind": "build", 18 | "isDefault": true 19 | }, 20 | "problemMatcher": [ 21 | "$gcc" 22 | ], 23 | "dependsOn":["UpdateMake"] 24 | }, 25 | { 26 | "label": "build release", 27 | "type": "process", 28 | "command": "make", 29 | "windows": { 30 | "command": "mingw32-make.exe", 31 | "args": [ 32 | "SHELL=cmd", 33 | "config=release_x64" 34 | ], 35 | }, 36 | "linux": { 37 | "args": [ 38 | "config=release_x64" 39 | ], 40 | }, 41 | "osx": { 42 | "args": [ 43 | "config=release_ARM64" 44 | ], 45 | }, 46 | "group": "build", 47 | "problemMatcher": [ 48 | "$gcc" 49 | ], 50 | "dependsOn":["UpdateMake"] 51 | }, 52 | { 53 | "label": "Clean", 54 | "type": "process", 55 | "command": "make", 56 | "windows": { 57 | "command": "mingw32-make.exe", 58 | "args": [ 59 | "SHELL=cmd", 60 | "clean" 61 | ], 62 | }, 63 | "linux": { 64 | "args": [ 65 | "clean" 66 | ], 67 | }, 68 | "osx": { 69 | "args": [ 70 | "clean" 71 | ], 72 | }, 73 | "group": "build", 74 | "problemMatcher": [ 75 | "$gcc" 76 | ], 77 | "dependsOn":["UpdateMake"] 78 | }, 79 | { 80 | "label": "UpdateMake", 81 | "type": "process", 82 | "command": "./premake5", 83 | "options": { 84 | "cwd": "${workspaceFolder}/build/" 85 | }, 86 | "args": [ 87 | "gmake2" 88 | ], 89 | "windows": { 90 | "command": "./premake5.exe" 91 | }, 92 | "linux": { 93 | "command": "./premake5" 94 | }, 95 | "osx": { 96 | "command": "premake5.osx" 97 | }, 98 | "group": "build" 99 | } 100 | ] 101 | } -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/raylib-example/build-MinGW-W64.bat: -------------------------------------------------------------------------------- 1 | cd build 2 | premake5.exe gmake2 3 | cd .. 4 | make SHELL=CMD clean 5 | pause -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/raylib-example/build-VisualStudio2022.bat: -------------------------------------------------------------------------------- 1 | cd build 2 | premake5.exe vs2022 || pause 3 | cd ../ -------------------------------------------------------------------------------- /en/05_programming_fundamentals/snake/raylib-example/include/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/05_programming_fundamentals/snake/raylib-example/include/.keep -------------------------------------------------------------------------------- /en/05_programming_fundamentals/stub.md: -------------------------------------------------------------------------------- 1 | - Variables 2 | - Functions 3 | - `std::cin` and `std::cout` 4 | - Pointers, pointer arithmetic, `void*`, `&` 5 | - C arrays 6 | - `for` and `while` loops 7 | - `struct`, `.` and `->` 8 | - `auto`?? 9 | - C++ references -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/README.md: -------------------------------------------------------------------------------- 1 | **IMPORTANT!** 2 | 3 | **This topic is only required for those who want to use standard containers 4 | (`std::vector`, `std::unordered_map`) and `std::string`, and those who have been 5 | explicitly told to study this or just want to learn more.** 6 | 7 | This topic is an extension of the previous topic of programming fundamentals, focusing 8 | on RAII, move semantics, some OOP elements and other C++ features. 9 | 10 | Concepts covered: 11 | - References (`&`) 12 | - Methods, `this` 13 | - `static` class members 14 | - Scopes, destructors 15 | - Ownership of memory -- the idea of RAII 16 | - `std::unique_ptr` and `std::shared_ptr` 17 | - Custom `std::vector` implementation with RAII 18 | - `const` parameters and `const` methods 19 | - Constructors, copy constructors 20 | - lvalues and rvalues 21 | - Move semantics (rvalue references `&&`, `std::move`, move constructors) 22 | - Basic templating 23 | - Strings: C strings, `std::string`, `std::string_view` 24 | - Function pointers, `typedef`, `auto`, `decltype` 25 | - Storing data together with functions to implement delegates, `std::function` -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/enums/enum_class.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum class TrafficLightColor 5 | { 6 | RED = 0, 7 | YELLOW = 1, 8 | GREEN = 2, 9 | }; 10 | 11 | void writeLightColor(TrafficLightColor color) 12 | { 13 | switch (color) 14 | { 15 | case TrafficLightColor::RED: 16 | { 17 | std::cout << "red"; 18 | break; 19 | } 20 | case TrafficLightColor::YELLOW: 21 | { 22 | std::cout << "yellow"; 23 | break; 24 | } 25 | case TrafficLightColor::GREEN: 26 | { 27 | std::cout << "green"; 28 | break; 29 | } 30 | default: 31 | { 32 | assert(false); 33 | } 34 | } 35 | } 36 | 37 | int main() 38 | { 39 | writeLightColor(TrafficLightColor::RED); 40 | writeLightColor(TrafficLightColor::YELLOW); 41 | writeLightColor(static_cast(1)); // have to cast instead 42 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/enums/global_const_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static inline const int RED = 0; 5 | static inline const int YELLOW = 1; 6 | static inline const int GREEN = 2; 7 | 8 | void writeColorName(int color) 9 | { 10 | switch (color) 11 | { 12 | case RED: 13 | { 14 | std::cout << "red"; 15 | break; 16 | } 17 | case YELLOW: 18 | { 19 | std::cout << "yellow"; 20 | break; 21 | } 22 | case GREEN: 23 | { 24 | std::cout << "green"; 25 | break; 26 | } 27 | default: 28 | { 29 | assert(false); // shouldn't happen. 30 | } 31 | } 32 | } 33 | 34 | int main() 35 | { 36 | std::cout << "Please input a color: "; 37 | const int numColors = 3; 38 | { 39 | std::cout << "0 - "; 40 | writeColorName(0); 41 | } 42 | for (int i = 1; i < numColors; i++) 43 | { 44 | std::cout << i << " - "; 45 | writeColorName(i); 46 | } 47 | 48 | int color; 49 | do 50 | { 51 | std::cin >> color; 52 | } 53 | while (!std::cin.good()); // while not parsed 54 | 55 | switch (color) 56 | { 57 | case RED: 58 | { 59 | std::cout << "Stop"; 60 | break; 61 | } 62 | case YELLOW: 63 | { 64 | std::cout << "Get ready"; 65 | break; 66 | } 67 | case GREEN: 68 | { 69 | std::cout << "Go"; 70 | break; 71 | } 72 | } 73 | 74 | return 0; 75 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/enums/namespaced_enum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace TrafficLightColor 5 | { 6 | struct Type 7 | { 8 | int value; 9 | 10 | // Make sure the constructor is never called implicilty. 11 | // We could even make this private so that people can only use the constants, 12 | // but being able to convert from an int is useful. 13 | constexpr explicit Type(int value) : value(value) {} 14 | }; 15 | 16 | inline static constexpr Type RED{0}; 17 | inline static constexpr Type YELLOW{1}; 18 | inline static constexpr Type GREEN{2}; 19 | }; 20 | 21 | using TrafficLightColorT = TrafficLightColor::Type; 22 | 23 | void writeLightColor(TrafficLightColorT color) 24 | { 25 | switch (color.value) 26 | { 27 | case TrafficLightColor::RED.value: 28 | { 29 | std::cout << "red"; 30 | break; 31 | } 32 | case TrafficLightColor::YELLOW.value: 33 | { 34 | std::cout << "yellow"; 35 | break; 36 | } 37 | case TrafficLightColor::GREEN.value: 38 | { 39 | std::cout << "green"; 40 | break; 41 | } 42 | default: 43 | { 44 | assert(false); 45 | } 46 | } 47 | } 48 | 49 | int main() 50 | { 51 | writeLightColor(TrafficLightColor::RED); 52 | writeLightColor(TrafficLightColor::YELLOW); 53 | // writeLightColor(1); // doesn't work, because the constructor is explicit 54 | writeLightColor(TrafficLightColorT{1}); // converts to TrafficLightColor using the constructor 55 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_1/compile.bat: -------------------------------------------------------------------------------- 1 | zig c++ main.cpp f.cpp other_file.cpp -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_1/f.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void f(int a) 4 | { 5 | std::cout << a; 6 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_1/main.cpp: -------------------------------------------------------------------------------- 1 | void f(int a); 2 | void otherFunc(); 3 | 4 | int main() 5 | { 6 | f(10); 7 | otherFunc(); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_1/other_file.cpp: -------------------------------------------------------------------------------- 1 | void f(int a); 2 | 3 | void otherFunc() 4 | { 5 | f(15); 6 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_2/compile.bat: -------------------------------------------------------------------------------- 1 | zig c++ main.cpp f.cpp other_file.cpp -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_2/f.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "f.h" 3 | 4 | void f(int a) 5 | { 6 | std::cout << a; 7 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_2/f.h: -------------------------------------------------------------------------------- 1 | void f(int a); -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_2/main.cpp: -------------------------------------------------------------------------------- 1 | #include "f.h" 2 | #include "other_file.h" 3 | 4 | int main() 5 | { 6 | f(10); 7 | otherFunc(); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_2/other_file.cpp: -------------------------------------------------------------------------------- 1 | #include "f.h" 2 | #include "other_file.h" 3 | 4 | void otherFunc() 5 | { 6 | f(15); 7 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_2/other_file.h: -------------------------------------------------------------------------------- 1 | void otherFunc(); -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_3/f.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void f(int a) 5 | { 6 | std::cout << a; 7 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_3/main.cpp: -------------------------------------------------------------------------------- 1 | #include "f.h" 2 | #include "other_file.h" 3 | 4 | int main() 5 | { 6 | f(10); 7 | otherFunc(); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/headers/example_3/other_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "f.h" 3 | 4 | void otherFunc() 5 | { 6 | f(11); 7 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/graph.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | std::vector children; 8 | 9 | // NOTE: This leaks the nodes 10 | }; 11 | 12 | static std::unique_ptr createGraph() 13 | { 14 | std::unique_ptr root{new Node{1}}; 15 | 16 | Node* a = new Node{2}; 17 | Node* b = new Node{3}; 18 | Node* c = new Node{4}; 19 | Node* d = new Node{5}; 20 | Node* e = new Node{6}; 21 | Node* f = new Node{7}; 22 | 23 | root->children.push_back(a); 24 | root->children.push_back(b); 25 | root->children.push_back(c); 26 | 27 | a->children.push_back(e); 28 | a->children.push_back(d); 29 | 30 | e->children.push_back(f); 31 | 32 | return root; 33 | } 34 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/graph_1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "graph.h" 5 | 6 | void printDFS(const Node* node) 7 | { 8 | std::cout << node->value << std::endl; 9 | for (size_t i = 0; i < node->children.size(); i++) 10 | printDFS(node->children[i]); 11 | } 12 | 13 | int main() 14 | { 15 | const std::unique_ptr root = createGraph(); 16 | printDFS(root.get()); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/graph_manual_iterator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "graph.h" 5 | 6 | class IteratorDFS 7 | { 8 | std::vector stack; 9 | std::vector ownIndexInParentStack; 10 | 11 | public: 12 | IteratorDFS(const Node* root) 13 | { 14 | this->stack.push_back(root); 15 | } 16 | 17 | IteratorDFS(const IteratorDFS& other) : 18 | stack(other.stack), 19 | ownIndexInParentStack(other.ownIndexInParentStack) 20 | { 21 | } 22 | 23 | bool empty() const 24 | { 25 | return this->stack.empty(); 26 | } 27 | 28 | int value() const 29 | { 30 | return this->stack.back()->value; 31 | } 32 | 33 | void advance() 34 | { 35 | const Node* node = this->stack.back(); 36 | if (node->children.size() > 0) 37 | { 38 | this->stack.push_back(node->children[0]); 39 | this->ownIndexInParentStack.push_back(0); 40 | return; 41 | } 42 | 43 | while (true) 44 | { 45 | this->stack.pop_back(); 46 | if (this->stack.empty()) 47 | return; 48 | 49 | const Node *parent = this->stack.back(); 50 | 51 | size_t ownIndex = this->ownIndexInParentStack.back(); 52 | this->ownIndexInParentStack.pop_back(); 53 | 54 | size_t nextNodeIndex = ownIndex + 1; 55 | 56 | if (nextNodeIndex < parent->children.size()) 57 | { 58 | this->stack.push_back(parent->children[nextNodeIndex]); 59 | this->ownIndexInParentStack.push_back(nextNodeIndex); 60 | return; 61 | } 62 | 63 | // Finished with the parent, keep walking up the stack. 64 | } 65 | } 66 | }; 67 | 68 | int main() 69 | { 70 | const std::unique_ptr root = createGraph(); 71 | 72 | // if (false) 73 | { 74 | IteratorDFS it{root.get()}; 75 | 76 | while (!it.empty()) 77 | { 78 | std::cout << it.value() << std::endl; 79 | it.advance(); 80 | } 81 | } 82 | 83 | // Could iterate two graphs in lockstep now. 84 | // if (false) 85 | { 86 | IteratorDFS it1{root.get()}; 87 | IteratorDFS it2{root.get()}; // imagine this was a different graph 88 | 89 | int result = 0; 90 | while (!it1.empty() && !it2.empty()) 91 | { 92 | result += it1.value() + it2.value(); 93 | it1.advance(); 94 | it2.advance(); 95 | } 96 | } 97 | 98 | // Can store the state to resume later. 99 | { 100 | IteratorDFS it{root.get()}; 101 | 102 | // Just skip 3 elements. 103 | for (int i = 0; i < 3; i++) 104 | it.advance(); 105 | 106 | // Copy the state 107 | IteratorDFS it2{it}; 108 | 109 | // Finish executing the first iterator 110 | while (!it.empty()) 111 | { 112 | std::cout << it.value() << std::endl; 113 | it.advance(); 114 | } 115 | 116 | std::cout << "Iterator 1 finished" << std::endl; 117 | 118 | // Now count the sum with the second iterator 119 | int result = 0; 120 | while (!it2.empty()) 121 | { 122 | result += it2.value(); 123 | it2.advance(); 124 | } 125 | 126 | std::cout << "Iterator 2 computed the sum: " << result << std::endl; 127 | } 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/graph_range_for.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "standard_impl.cpp" 3 | 4 | class DFSRange 5 | { 6 | const Node* root; 7 | 8 | public: 9 | DFSRange(const Node* root) : root(root) 10 | { 11 | } 12 | 13 | IteratorDFS begin() const 14 | { 15 | return IteratorDFS{this->root}; 16 | } 17 | 18 | IteratorDFS end() const 19 | { 20 | return IteratorDFS{}; 21 | } 22 | }; 23 | 24 | int main() 25 | { 26 | const std::unique_ptr root = createGraph(); 27 | const DFSRange range = DFSRange{root.get()}; 28 | 29 | for (int value : range) 30 | std::cout << value << std::endl; 31 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/graph_standard.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "standard_impl.cpp" // see this file 3 | 4 | int main() 5 | { 6 | const std::unique_ptr root = createGraph(); 7 | const IteratorDFS end{}; 8 | 9 | // if (false) 10 | { 11 | IteratorDFS it{root.get()}; 12 | 13 | while (it != end) 14 | { 15 | std::cout << *it << std::endl; 16 | ++it; 17 | } 18 | } 19 | 20 | // Could iterate two graphs in lockstep now. 21 | // if (false) 22 | { 23 | IteratorDFS it1{root.get()}; 24 | IteratorDFS it2{root.get()}; // imagine this was a different graph 25 | 26 | int result = 0; 27 | while (it1 != end && it2 != end) 28 | { 29 | result += *it1 + *it2; 30 | ++it1; 31 | ++it2; 32 | } 33 | } 34 | 35 | // Can store the state to resume later. 36 | { 37 | IteratorDFS it{root.get()}; 38 | 39 | // Just skip 3 elements. 40 | for (int i = 0; i < 3; i++) 41 | ++it; 42 | 43 | // Copy the state 44 | IteratorDFS it2{it}; 45 | 46 | // Finish executing the first iterator 47 | while (it != end) 48 | { 49 | std::cout << *it << std::endl; 50 | ++it; 51 | } 52 | 53 | std::cout << "Iterator 1 finished" << std::endl; 54 | 55 | // Now count the sum with the second iterator 56 | int result = 0; 57 | while (it2 != end) 58 | { 59 | result += *it2; 60 | ++it2; 61 | } 62 | 63 | std::cout << "Iterator 2 computed the sum: " << result << std::endl; 64 | } 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/run.sh: -------------------------------------------------------------------------------- 1 | g++ graph_1.cpp -Werror -Wall -std=c++20 2 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/iterator/standard_impl.cpp: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | #include 3 | #include 4 | 5 | class IteratorDFS 6 | { 7 | std::vector stack; 8 | std::vector ownIndexInParentStack; 9 | 10 | public: 11 | IteratorDFS() 12 | { 13 | } 14 | 15 | IteratorDFS(const Node* root) 16 | { 17 | this->stack.push_back(root); 18 | } 19 | 20 | IteratorDFS(const IteratorDFS& other) : 21 | stack(other.stack), 22 | ownIndexInParentStack(other.ownIndexInParentStack) 23 | { 24 | } 25 | 26 | bool operator==(const IteratorDFS& other) const 27 | { 28 | return this->stack == other.stack && 29 | this->ownIndexInParentStack == other.ownIndexInParentStack; 30 | } 31 | // operator!= added automatically: !(this == other) 32 | 33 | int operator*() const 34 | { 35 | return this->stack.back()->value; 36 | } 37 | 38 | IteratorDFS& operator++() // ++i 39 | { 40 | this->advance(); 41 | return *this; 42 | } 43 | 44 | private: 45 | void advance() 46 | { 47 | const Node* node = this->stack.back(); 48 | if (node->children.size() > 0) 49 | { 50 | this->stack.push_back(node->children[0]); 51 | this->ownIndexInParentStack.push_back(0); 52 | return; 53 | } 54 | 55 | while (true) 56 | { 57 | this->stack.pop_back(); 58 | if (this->stack.empty()) 59 | return; 60 | 61 | const Node *parent = this->stack.back(); 62 | 63 | size_t ownIndex = this->ownIndexInParentStack.back(); 64 | this->ownIndexInParentStack.pop_back(); 65 | 66 | size_t nextNodeIndex = ownIndex + 1; 67 | 68 | if (nextNodeIndex < parent->children.size()) 69 | { 70 | this->stack.push_back(parent->children[nextNodeIndex]); 71 | this->ownIndexInParentStack.push_back(nextNodeIndex); 72 | return; 73 | } 74 | 75 | // Finished with the parent, keep walking up the stack. 76 | } 77 | } 78 | }; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/abstract_base_class.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class GreetingAbstractBase 5 | { 6 | public: 7 | virtual void introduceSelf() = 0; 8 | virtual void excuseSelf() = 0; 9 | }; 10 | 11 | class QuestionAbstractBase 12 | { 13 | public: 14 | virtual int computeSum(int a, int b) = 0; 15 | virtual void writeCppProgram(std::ostream& out) = 0; 16 | }; 17 | 18 | enum ProgrammingLanguage 19 | { 20 | None, 21 | Cpp, 22 | CSharp, 23 | Java, 24 | }; 25 | 26 | class Person : 27 | public GreetingAbstractBase, 28 | public QuestionAbstractBase 29 | { 30 | std::string name; 31 | std::string excuse; 32 | ProgrammingLanguage languageCanProgram; 33 | int maxNumberCanHoldInHead; 34 | 35 | public: 36 | Person( 37 | std::string&& name, 38 | std::string&& excuse, 39 | ProgrammingLanguage languageCanProgram, 40 | int maxNumberCanHoldInHead) 41 | 42 | : name(std::move(name)) 43 | , excuse(std::move(excuse)) 44 | , languageCanProgram(languageCanProgram) 45 | , maxNumberCanHoldInHead(maxNumberCanHoldInHead) 46 | { 47 | } 48 | 49 | void introduceSelf() override 50 | { 51 | std::cout << "Hi. My name is "; 52 | std::cout << name << std::endl; 53 | } 54 | 55 | void excuseSelf() override 56 | { 57 | std::cout << excuse << std::endl; 58 | } 59 | 60 | int computeSum(int a, int b) override 61 | { 62 | int result = a + b; 63 | return std::min(result, maxNumberCanHoldInHead); 64 | } 65 | 66 | void writeCppProgram(std::ostream& out) override 67 | { 68 | if (languageCanProgram == Cpp) 69 | { 70 | out << "int main() { return 0; }" << std::endl; 71 | } 72 | } 73 | }; 74 | 75 | class Dog : 76 | public QuestionAbstractBase 77 | { 78 | int favoriteNumber; 79 | 80 | public: 81 | Dog(int favoriteNumber) 82 | : favoriteNumber(favoriteNumber) 83 | { 84 | } 85 | 86 | int computeSum(int, int) override 87 | { 88 | return favoriteNumber; 89 | } 90 | 91 | void writeCppProgram(std::ostream& out) override 92 | { 93 | } 94 | }; 95 | 96 | void enterAndThenLeave(GreetingAbstractBase* object) 97 | { 98 | object->introduceSelf(); 99 | object->excuseSelf(); 100 | } 101 | 102 | void quiz(QuestionAbstractBase* object) 103 | { 104 | std::cout << "Question 1: What is 5 + 6?" << std::endl; 105 | std::cout << "Answer: " << object->computeSum(5, 6) << std::endl; 106 | 107 | std::cout << "Question 2: What is 10 + 20?" << std::endl; 108 | std::cout << "Answer: " << object->computeSum(10, 20) << std::endl; 109 | 110 | std::cout << "Question 3: Write a C++ program" << std::endl; 111 | object->writeCppProgram(std::cout); 112 | } 113 | 114 | int main() 115 | { 116 | Person john{"John", "I'm not feeling well", Cpp, 30}; 117 | Person jane{"Jane", "I gotta go", Java, 20}; 118 | 119 | Dog husky{11}; 120 | 121 | std::vector objects{ 122 | &john, 123 | &jane, 124 | &husky, 125 | }; 126 | for (auto object : objects) 127 | { 128 | quiz(object); 129 | } 130 | 131 | std::vector greetingsObjects{ 132 | &john, 133 | &jane, 134 | }; 135 | for (auto object : greetingsObjects) 136 | { 137 | enterAndThenLeave(object); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/button_func_pointer_decentralized.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using ButtonFunc = void(*)(); 6 | struct FuncOption 7 | { 8 | std::string name; 9 | ButtonFunc func; 10 | }; 11 | 12 | void printHello(); 13 | void greetUser(); 14 | 15 | void addTextOptions(std::vector &allFunctions) 16 | { 17 | allFunctions.push_back({"print \"Hello\"", printHello}); 18 | allFunctions.push_back({"greet the user", greetUser}); 19 | } 20 | 21 | void addTwoValues(); 22 | void subtractTwoValues(); 23 | 24 | void addCalculatorOptions(std::vector &allFunctions) 25 | { 26 | allFunctions.push_back({"add two values", addTwoValues}); 27 | allFunctions.push_back({"subtract two values", subtractTwoValues}); 28 | } 29 | 30 | int main() 31 | { 32 | std::vector allFunctions; 33 | addTextOptions(allFunctions); 34 | addCalculatorOptions(allFunctions); 35 | 36 | size_t functionChoice; 37 | while (true) 38 | { 39 | std::cout << "Select a function to be executed ("; 40 | for (size_t i = 0; i < allFunctions.size(); i++) 41 | { 42 | std::cout << i << " - " << allFunctions[i].name << ", "; 43 | } 44 | std::cout << "): "; 45 | 46 | std::cin >> functionChoice; 47 | 48 | if (!std::cin.good()) 49 | continue; 50 | if (functionChoice >= allFunctions.size()) 51 | continue; 52 | break; 53 | } 54 | 55 | allFunctions[functionChoice].func(); 56 | return 0; 57 | } 58 | 59 | 60 | void greetUser() 61 | { 62 | std::string userName; 63 | std::cout << "Enter your name: "; 64 | std::cin >> userName; 65 | std::cout << "Hello, " << userName << "!" << std::endl; 66 | } 67 | 68 | void printHello() 69 | { 70 | std::cout << "Hello!" << std::endl; 71 | } 72 | 73 | std::array readTwoValues() 74 | { 75 | std::array result; 76 | 77 | std::cout << "Enter a: "; 78 | std::cin >> result[0]; 79 | 80 | std::cout << "Enter b: "; 81 | std::cin >> result[1]; 82 | 83 | return result; 84 | } 85 | 86 | void addTwoValues() 87 | { 88 | std::array values = readTwoValues(); 89 | float result = values[0] + values[1]; 90 | std::cout 91 | << values[0] 92 | << " + " 93 | << values[1] 94 | << " = " 95 | << result 96 | << std::endl; 97 | } 98 | 99 | void subtractTwoValues() 100 | { 101 | std::array values = readTwoValues(); 102 | float result = values[0] - values[1]; 103 | std::cout 104 | << values[0] 105 | << " - " 106 | << values[1] 107 | << " = " 108 | << result 109 | << std::endl; 110 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/button_func_pointer_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using ButtonFunc = void(*)(); 5 | 6 | void printHello() 7 | { 8 | std::cout << "Hello!" << std::endl; 9 | } 10 | 11 | void greetUser() 12 | { 13 | std::string userName; 14 | std::cout << "Enter your name:"; 15 | std::cin >> userName; 16 | std::cout << "Hello, " << userName << "!" << std::endl; 17 | } 18 | 19 | int main() 20 | { 21 | std::array allFunctions{ 22 | printHello, 23 | greetUser, 24 | }; 25 | 26 | size_t functionChoice; 27 | while (true) 28 | { 29 | std::cout << "Select a function to be executed:"; 30 | std::cin >> functionChoice; 31 | if (!std::cin.good()) 32 | continue; 33 | if (functionChoice >= allFunctions.size()) 34 | continue; 35 | break; 36 | } 37 | 38 | ButtonFunc selectedFunc = allFunctions[functionChoice]; 39 | selectedFunc(); 40 | return 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/fat_pointer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using IntroductionFunc = void(*)(void* context); 5 | using SumFunc = int(*)(void* context, int a, int b); 6 | 7 | struct VirtualTable 8 | { 9 | IntroductionFunc introduceOneself; 10 | SumFunc answer; 11 | }; 12 | 13 | struct FatPointer 14 | { 15 | // We store this by pointer here, so that we can reuse 16 | // the given set of functions for multiple contexts, 17 | // without copying all of them each time. 18 | VirtualTable* methods; 19 | void* context; 20 | }; 21 | 22 | void test(FatPointer& object) 23 | { 24 | object.methods->introduceOneself(object.context); 25 | int answer = object.methods->answer(object.context, 5, 6); 26 | std::cout << answer << std::endl; 27 | } 28 | 29 | struct Human 30 | { 31 | std::string name; 32 | }; 33 | 34 | struct Dog 35 | { 36 | int favoriteNumber; 37 | }; 38 | 39 | int main() 40 | { 41 | VirtualTable dumbMethods{ 42 | // Doesn't say anything as the introduction. 43 | [](void*){}, 44 | [](void*, int, int){ return 0; }, 45 | }; 46 | VirtualTable dogMethods{ 47 | [](void*){ std::cout << "Woof" << std::endl; }, 48 | [](void* context, int a, int b){ 49 | Dog* d = reinterpret_cast(context); 50 | return d->favoriteNumber; 51 | }, 52 | }; 53 | VirtualTable humanMethods{ 54 | [](void* context){ 55 | Human* h = reinterpret_cast(context); 56 | std::cout << "Hi. My name is "; 57 | std::cout << h->name << std::endl; 58 | }, 59 | [](void*, int a, int b){ 60 | return a + b; 61 | }, 62 | }; 63 | 64 | FatPointer dumbCat{&dumbMethods, nullptr}; 65 | 66 | Dog huskyContext{11}; 67 | FatPointer husky{&dogMethods, &huskyContext}; 68 | 69 | Human johnContext{"John"}; 70 | FatPointer john{&humanMethods, &johnContext}; 71 | 72 | Human janeContext{"Jane"}; 73 | FatPointer jane{&humanMethods, &janeContext}; 74 | 75 | test(dumbCat); 76 | test(husky); 77 | test(john); 78 | test(jane); 79 | 80 | return 0; 81 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/func_void_pointer_context.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct ComputedState 6 | { 7 | float a; 8 | float b; 9 | }; 10 | 11 | void recomputeState(ComputedState* context) 12 | { 13 | context->a *= 2.0f; 14 | context->b += 1.0f; 15 | } 16 | void recomputeStateAdapter(void* context) 17 | { 18 | ComputedState* typedContext = static_cast(context); 19 | recomputeState(typedContext); 20 | } 21 | 22 | void resetState(ComputedState* context) 23 | { 24 | *context = {}; 25 | } 26 | void resetStateAdapter(void* context) 27 | { 28 | ComputedState* typedContext = static_cast(context); 29 | resetState(typedContext); 30 | } 31 | 32 | void printState(ComputedState* context) 33 | { 34 | std::cout << "a: " << context->a << std::endl; 35 | std::cout << "b: " << context->b << std::endl; 36 | } 37 | void printStateAdapter(void* context) 38 | { 39 | ComputedState* typedContext = static_cast(context); 40 | printState(typedContext); 41 | } 42 | 43 | void addToFloat(float& value) 44 | { 45 | float n; 46 | do 47 | { 48 | std::cout << "Enter a number to add to the value:"; 49 | std::cin >> n; 50 | } 51 | while (!std::cin.good()); 52 | 53 | value += n; 54 | } 55 | void addToFloatAdapter(void* context) 56 | { 57 | float* typedContext = static_cast(context); 58 | addToFloat(*typedContext); 59 | } 60 | 61 | void printHelloAdapter(void*) 62 | { 63 | std::cout << "Hello!" << std::endl; 64 | } 65 | 66 | using ItemFunc = void(*)(void* context); 67 | 68 | struct Button 69 | { 70 | std::string name; 71 | ItemFunc func; 72 | void* context; 73 | }; 74 | 75 | int main() 76 | { 77 | ComputedState state{}; 78 | float otherNumber = 0.0f; 79 | std::array buttons{ 80 | // Some of the functions may operate on the state 81 | Button{"Recompute", recomputeStateAdapter, &state}, 82 | Button{"Reset", resetStateAdapter, &state}, 83 | Button{"Print", printStateAdapter, &state}, 84 | 85 | // Others may operate on something else 86 | Button{"Add to a", addToFloatAdapter, &state.a}, 87 | Button{"Add to b", addToFloatAdapter, &state.b}, 88 | 89 | // And some may operate on something completely different 90 | Button{"Add to other number", addToFloatAdapter, &otherNumber}, 91 | 92 | // And some may not require any context at all 93 | Button{"Print hello", printHelloAdapter, nullptr}, 94 | }; 95 | 96 | size_t buttonChoice; 97 | while (true) 98 | { 99 | for (size_t i = 0; i < buttons.size(); i++) 100 | { 101 | std::cout << i << " - " << buttons[i].name << std::endl; 102 | } 103 | std::cin >> buttonChoice; 104 | if (!std::cin.good()) 105 | continue; 106 | if (buttonChoice >= buttons.size()) 107 | break; 108 | 109 | Button& button = buttons[buttonChoice]; 110 | 111 | // Now this part of code doesn't have to know anything about the context. 112 | button.func(button.context); 113 | } 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/func_with_context.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | using ItemFunc = void(*)(float&, T context); 8 | 9 | template 10 | void forEachItem(std::span items, ItemFunc func, T context) 11 | { 12 | for (size_t i = 0; i < items.size(); i++) 13 | { 14 | func(items[i], context); 15 | } 16 | } 17 | 18 | void addFunc(float& item, float n) 19 | { 20 | item += n; 21 | } 22 | 23 | struct ComputeContext 24 | { 25 | float sum; 26 | float product; 27 | }; 28 | 29 | void computeStuffFunc(float& item, ComputeContext* context) 30 | { 31 | context->sum += item; 32 | context->product *= item; 33 | } 34 | 35 | int main() 36 | { 37 | std::vector items{1.0f, 2.0f, 3.0f, 4.0f}; 38 | 39 | forEachItem(items, addFunc, 5.0f); 40 | 41 | { 42 | ComputeContext result{0.0f, 1.0f}; 43 | forEachItem(items, computeStuffFunc, &result); 44 | std::cout << result.product << std::endl; 45 | std::cout << result.sum << std::endl; 46 | } 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/functor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Adder 6 | { 7 | float addedValue; 8 | 9 | void operator()(float& value) 10 | { 11 | value += addedValue; 12 | } 13 | }; 14 | 15 | struct Multiplier 16 | { 17 | float factor; 18 | 19 | void operator()(float& value) 20 | { 21 | value *= factor; 22 | } 23 | }; 24 | 25 | void printFloat(float& value) 26 | { 27 | std::cout << value; 28 | } 29 | 30 | template 31 | void forEachItem(std::span values, F functor) 32 | { 33 | for (float& value : values) 34 | { 35 | functor(value); 36 | } 37 | } 38 | 39 | int main() 40 | { 41 | std::vector values{ 1.0f, 2.0f, 3.0f }; 42 | forEachItem(values, Adder{5.0f}); 43 | forEachItem(values, printFloat); 44 | forEachItem(values, Multiplier{2.0f}); 45 | forEachItem(values, printFloat); 46 | forEachItem(values, [&a = values[0]](float& value){ value *= a; }); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/functor_custom_name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Adder 6 | { 7 | float addedValue; 8 | 9 | void execute(float& value) 10 | { 11 | value += addedValue; 12 | } 13 | }; 14 | 15 | struct Multiplier 16 | { 17 | float factor; 18 | 19 | void execute(float& value) 20 | { 21 | value *= factor; 22 | } 23 | }; 24 | 25 | struct Printer 26 | { 27 | void execute(float& value) 28 | { 29 | std::cout << value; 30 | } 31 | }; 32 | 33 | template 34 | void forEachItem(std::span values, F functor) 35 | { 36 | for (float& value : values) 37 | { 38 | functor.execute(value); 39 | } 40 | } 41 | 42 | int main() 43 | { 44 | std::vector values{ 1.0f, 2.0f, 3.0f }; 45 | forEachItem(values, Adder{5.0f}); 46 | forEachItem(values, Printer{}); 47 | forEachItem(values, Multiplier{2.0f}); 48 | forEachItem(values, Printer{}); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/lambda_1_void.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using OperatorFunc = int(*)(int a, int b); 4 | 5 | int main() 6 | { 7 | OperatorFunc addFunc = [](int a, int b) 8 | { 9 | return a + b; 10 | }; 11 | std::cout << addFunc(1, 2); 12 | 13 | // This has a bit of a different effect. 14 | // The type of addFunc2 here is *not* a function pointer. 15 | auto addFunc2 = [](int a, int b) 16 | { 17 | return a + b; 18 | }; 19 | // Doesn't go through a function pointer indirection. 20 | std::cout << addFunc2(1, 2); 21 | 22 | // Still implicitly converts to a function pointer. 23 | OperatorFunc addFunc3 = addFunc2; 24 | 25 | return 0; 26 | } 27 | 28 | 29 | // addFunc2 creates a functor class without private state. 30 | // Like this: 31 | class Functor 32 | { 33 | public: 34 | int operator()(int a, int b) 35 | { 36 | return a + b; 37 | } 38 | }; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/lambda_2_context_copy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | std::array nums { 1, 2 }; 7 | 8 | auto functor = [ 9 | a = nums[0], 10 | b = 10.0f, 11 | nums 12 | ]() mutable 13 | { 14 | nums[0] = 2; 15 | a += 2; 16 | b *= 2; 17 | return a + b; 18 | }; 19 | 20 | // Copies by value (simply copies the functor's memory). 21 | decltype(functor) functorCopy = functor; 22 | 23 | std::cout << nums[0] << std::endl; 24 | std::cout << functor() << std::endl; 25 | std::cout << functor() << std::endl; 26 | std::cout << functor() << std::endl; 27 | std::cout << nums[0] << std::endl; 28 | 29 | std::cout << functorCopy() << std::endl; 30 | } 31 | 32 | 33 | // For the type of the functor variable, 34 | // the compiler generated a type like: 35 | class Functor 36 | { 37 | int a; 38 | float b; 39 | std::array nums; 40 | 41 | public: 42 | Functor( 43 | int a, 44 | std::array nums) : 45 | 46 | a(a), 47 | b(10.0f), 48 | nums(nums) 49 | { 50 | } 51 | 52 | float operator()() 53 | { 54 | nums[0] = 2; 55 | a += 2; 56 | b *= 2; 57 | return a + b; 58 | } 59 | }; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/lambda_3_shared_context.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Context 5 | { 6 | float a; 7 | float b; 8 | }; 9 | 10 | int main() 11 | { 12 | Context context{}; 13 | 14 | auto increase = [&context]() 15 | { 16 | context.a += 1; 17 | context.b *= 2; 18 | }; 19 | 20 | auto reset = [&context]() 21 | { 22 | context.a = 0; 23 | context.b = 1; 24 | }; 25 | 26 | auto print = [&context]() 27 | { 28 | std::cout 29 | << context.a 30 | << ", " 31 | << context.b 32 | << std::endl; 33 | }; 34 | 35 | // The functors are copyable. 36 | auto increase2 = increase; 37 | 38 | print(); // 0, 0 39 | reset(); 40 | print(); // 0, 1 41 | increase(); 42 | print(); // 1, 2 43 | increase(); 44 | print(); // 2, 4 45 | } 46 | 47 | 48 | // For the type of the functor variable, 49 | // the compiler generated a type like: 50 | class Functor 51 | { 52 | // Reference fields are just pointers under the hood. 53 | Context& context; 54 | 55 | public: 56 | Functor(Context& context) 57 | // The *reference* can only be initialized in the member initializer. 58 | : context(context) 59 | { 60 | } 61 | 62 | void operator()() const // <- we haven't said `mutable` 63 | { 64 | std::cout 65 | << context.a 66 | << ", " 67 | << context.b 68 | << std::endl; 69 | } 70 | }; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/lambda_4_functor_sizes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int a = 0; 6 | 7 | { 8 | auto func = [=](){}; 9 | size_t size = sizeof(func); 10 | assert(size == 1); // aka has no fields 11 | } 12 | 13 | { 14 | auto func = [=](){ return a; }; 15 | size_t size = sizeof(func); 16 | assert(size == sizeof(int)); // single copy capture 17 | } 18 | 19 | { 20 | float b = 0; 21 | auto func = [&](){ 22 | a += 2; 23 | b *= 2; 24 | }; 25 | size_t size = sizeof(func); 26 | assert(size == 2 * sizeof(void*)); 27 | } 28 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/pointer_value_union_small_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using Context = uintptr_t; 4 | 5 | void add5(Context context) 6 | { 7 | int* value = reinterpret_cast(context); 8 | *value += 5; 9 | } 10 | 11 | void printInt(Context context) 12 | { 13 | int value = static_cast(context); 14 | std::cout << value; 15 | } 16 | 17 | int main() 18 | { 19 | int value = 0; 20 | add5(reinterpret_cast(&value)); 21 | printInt(static_cast(value)); // 5 22 | return 0; 23 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/std_function.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Note the missing (*), because it's not a function pointer. 7 | using ItemFunc = void(float&); 8 | using ItemStdFunction = std::function; 9 | 10 | void forEachItem(std::span items, ItemStdFunction& func) 11 | { 12 | for (size_t i = 0; i < items.size(); i++) 13 | { 14 | func(items[i]); 15 | } 16 | } 17 | 18 | struct ComputeContext 19 | { 20 | float sum; 21 | float product; 22 | }; 23 | 24 | struct Button 25 | { 26 | std::string name; 27 | std::function func; 28 | }; 29 | 30 | std::function eachItemFunc( 31 | std::span items, 32 | // Moving here makes sense. 33 | // In case it allocated memory, we don't want to reallocate it again. 34 | ItemStdFunction&& func) 35 | { 36 | return [ 37 | // Copy by default. 38 | =, 39 | // Need to force a move, or it will be copied. 40 | func = std::move(func) 41 | ]() mutable 42 | { 43 | forEachItem(items, func); 44 | }; 45 | } 46 | 47 | struct AddCurrentValueFunctor 48 | { 49 | float& currentValue; 50 | 51 | void operator()(float& item) 52 | { 53 | item += currentValue; 54 | } 55 | }; 56 | 57 | int main() 58 | { 59 | std::array items{1.0f, 2.0f, 3.0f, 4.0f}; 60 | 61 | ComputeContext result{0.0f, 1.0f}; 62 | 63 | ItemStdFunction printItemFunc = 64 | [] 65 | (float& item) 66 | { 67 | std::cout << item << ", "; 68 | }; 69 | ItemStdFunction computeStuffFunc = 70 | [&result] 71 | (float& item) 72 | { 73 | result.sum += item; 74 | result.product *= item; 75 | }; 76 | 77 | std::array funcs{ 78 | Button{ 79 | "Add current sum to all items", 80 | eachItemFunc(items, AddCurrentValueFunctor{result.sum}) 81 | }, 82 | Button{ 83 | "Print all items", 84 | eachItemFunc(items, std::move(printItemFunc)) 85 | }, 86 | Button{ 87 | "Compute sum and product", 88 | eachItemFunc(items, std::move(computeStuffFunc)) 89 | }, 90 | Button{ 91 | "Print computed sum and product", 92 | [&result]() 93 | { 94 | std::cout << result.sum << ", " << result.product << std::endl; 95 | }, 96 | }, 97 | Button{ 98 | "Reset items", 99 | eachItemFunc(items, [](float& item) 100 | { 101 | std::cout << "Enter new value: "; 102 | std::cin >> item; 103 | }), 104 | }, 105 | }; 106 | 107 | while (true) 108 | { 109 | std::cout << "Choose a function: " << std::endl; 110 | for (size_t i = 0; i < funcs.size(); i++) 111 | { 112 | std::cout << i << ": " << funcs[i].name << std::endl; 113 | } 114 | 115 | size_t input; 116 | std::cin >> input; 117 | if (!std::cin.good()) 118 | continue; 119 | if (input >= funcs.size()) 120 | break; 121 | 122 | funcs[input].func(); 123 | std::cout << std::endl; 124 | } 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/polymorphism/strategy_func_pointer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct BufferListNode 5 | { 6 | BufferListNode* next; 7 | std::array items; 8 | }; 9 | 10 | // Creates 4 blocks of 8 floats 11 | // | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 12 | // | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | // | 0 | 2 | 4 | 6 | 8 | 10| 12| 14| 14 | // | 0 | 3 | 6 | 9 | 12| 15| 18| 21| 15 | BufferListNode* createTestBuffer() 16 | { 17 | BufferListNode* head = new BufferListNode; 18 | head->items.fill(1.0f); 19 | 20 | BufferListNode* node = head; 21 | for (int i = 0; i < 3; i++) 22 | { 23 | BufferListNode* newNode = new BufferListNode; 24 | node->next = newNode; 25 | node = newNode; 26 | 27 | for (size_t j = 0; j < newNode->items.size(); j++) 28 | { 29 | newNode->items[j] = static_cast(i * j); 30 | } 31 | } 32 | 33 | node->next = nullptr; 34 | return head; 35 | } 36 | 37 | using ItemFunc = void(*)(float&); 38 | 39 | void forEachItem(BufferListNode* head, ItemFunc func) 40 | { 41 | BufferListNode* node = head; 42 | while (node != nullptr) 43 | { 44 | for (size_t i = 0; i < node->items.size(); i++) 45 | { 46 | func(node->items[i]); 47 | } 48 | node = node->next; 49 | } 50 | } 51 | 52 | void printFunc(float& item) 53 | { 54 | std::cout << item << ", "; 55 | } 56 | 57 | void add5Func(float& item) 58 | { 59 | item += 5; 60 | } 61 | 62 | int main() 63 | { 64 | BufferListNode* head = createTestBuffer(); 65 | 66 | { 67 | // store the address of printFunc. 68 | // & is optional. 69 | ItemFunc func = &printFunc; 70 | 71 | // prints each element 72 | forEachItem(head, func); 73 | 74 | std::cout << std::endl; 75 | } 76 | 77 | { 78 | ItemFunc func = add5Func; 79 | forEachItem(head, func); // adds 5 to each element 80 | } 81 | 82 | forEachItem(head, printFunc); // prints each element, again 83 | std::cout << std::endl; 84 | } 85 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/stub.md: -------------------------------------------------------------------------------- 1 | For the C++ OOP part (I think I need to teach this to the 2nd year students): 2 | - Accessibility modifiers 3 | - The concept and motivation of a vtable (polymorphism, virtual methods) 4 | - Linear search of implemented vtable vs adjusting the pointer 5 | - Interfaces (abstract classes without fields) for polymorphism 6 | - Single inheritance of fields (no pointer adjustment) 7 | - Virtual inheritance (pointer adjustment) 8 | - Useless diamond inheritance, how solved at a low level (see link in resources), syntax 9 | - `std::static_cast`, `std::dynamic_cast`, `std::reinterpret_cast` -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_1/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | T getValue() 5 | { 6 | return {}; 7 | } 8 | 9 | // We can force a different *specialization* manually (but we don't have to). 10 | template<> 11 | int getValue() 12 | { 13 | return 5; 14 | } 15 | 16 | int main() 17 | { 18 | std::cout << getValue() << std::endl; 19 | // The compiler sees that getValue has been used, 20 | // and inserts a definition created from the templated function 21 | std::cout << getValue() << std::endl; 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_2/compile.bat: -------------------------------------------------------------------------------- 1 | zig c++ -std=c++20 main.cpp f.cpp -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_2/f.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "template.h" 4 | 5 | void f() 6 | { 7 | std::array arr = { 1, 2, 3, 4, 5 }; 8 | std::cout << sum(arr) << std::endl; 9 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_2/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "template.h" 3 | 4 | void f(); 5 | 6 | int main() 7 | { 8 | f(); 9 | std::array arr = { 1, 2 }; 10 | std::cout << sum(arr) << std::endl; 11 | return 0; 12 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_2/template.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | T sum(std::span arr) 5 | { 6 | T result {}; 7 | for (size_t i = 0; i < arr.size(); i++) 8 | result += arr[i]; 9 | return result; 10 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_3/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | struct TwoValues 5 | { 6 | T first; 7 | T second; 8 | }; 9 | 10 | template 11 | T sum(const TwoValues& values) 12 | { 13 | return values.first + values.second; 14 | } 15 | 16 | int main() 17 | { 18 | { 19 | TwoValues t {1, 2}; 20 | std::cout << sum(t) << std::endl; 21 | } 22 | 23 | { 24 | // Omitting the types is allowed. 25 | TwoValues t{1, 2}; 26 | std::cout << sum(t) << std::endl; 27 | } 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_4/compile.bat: -------------------------------------------------------------------------------- 1 | zig c++ -std=c++20 main.cpp f.cpp -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_4/f.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "two_values.h" 3 | 4 | void f() 5 | { 6 | TwoValues t {1, 2}; 7 | // TwoValues::getFirst compiled for the second time. 8 | std::cout << t.getFirst() << std::endl; 9 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_4/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "two_values.h" 3 | 4 | void f(); 5 | 6 | int main() 7 | { 8 | TwoValues t {1, 2}; 9 | // TwoValues::getFirst() is compiled once 10 | std::cout << t.getFirst() << std::endl; 11 | 12 | return 0; 13 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_4/two_values.h: -------------------------------------------------------------------------------- 1 | template 2 | struct TwoValues 3 | { 4 | T first; 5 | T second; 6 | 7 | T getFirst() 8 | { 9 | return this->first; 10 | } 11 | }; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_5/compile.bat: -------------------------------------------------------------------------------- 1 | zig c++ -std=c++20 main.cpp f.cpp -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_5/f.cpp: -------------------------------------------------------------------------------- 1 | #include "f.h" 2 | 3 | template 4 | T f(T value) 5 | { 6 | return value; 7 | } 8 | 9 | // Explicit template instantiation. 10 | // Without this line, the linker won't be able to find a definition, 11 | // because none would exist in any of the compilation units. 12 | // You have to do this for each type that you're going to use in the other files. 13 | template int f(int value); -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_5/f.h: -------------------------------------------------------------------------------- 1 | // Templated *declaration* 2 | template 3 | T f(T a); -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_5/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "f.h" 3 | 4 | int main() 5 | { 6 | std::cout << f(10) << std::endl; 7 | return 0; 8 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_6/compile.bat: -------------------------------------------------------------------------------- 1 | zig c++ -std=c++20 main.cpp f.cpp -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_6/f.cpp: -------------------------------------------------------------------------------- 1 | #include "f.h" 2 | 3 | template 4 | T Test::getValue() 5 | { 6 | return this->value; 7 | } 8 | 9 | // Constructors work just like regular methods in this regard. 10 | template 11 | Test::Test(T value) 12 | { 13 | this->value = value; 14 | } 15 | 16 | // Won't link without this line. 17 | template class Test; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_6/f.h: -------------------------------------------------------------------------------- 1 | // Templated *declaration* 2 | template 3 | class Test 4 | { 5 | T value; 6 | 7 | public: 8 | Test(T value); 9 | T getValue(); 10 | }; -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/template/example_6/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "f.h" 3 | 4 | int main() 5 | { 6 | Test t{5}; 7 | std::cout << t.getValue() << std::endl; 8 | return 0; 9 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/vector/README.md: -------------------------------------------------------------------------------- 1 | This is the math kind of vector, not the dynamic array kind of vector. 2 | The STL actually provides a template class for this, it's called [`std::valarray`](https://en.cppreference.com/w/cpp/numeric/valarray). -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/vector/mutation.cpp: -------------------------------------------------------------------------------- 1 | struct Vector 2 | { 3 | int x; 4 | int y; 5 | 6 | Vector operator+(Vector other) const 7 | { 8 | Vector result; 9 | result.x = this->x + other.x; 10 | result.y = this->y + other.y; 11 | return result; 12 | } 13 | 14 | Vector operator-(Vector other) const 15 | { 16 | Vector result; 17 | result.x = this->x - other.x; 18 | result.y = this->y - other.y; 19 | return result; 20 | } 21 | 22 | Vector operator*(int scalar) const 23 | { 24 | Vector result; 25 | result.x = this->x * scalar; 26 | result.y = this->y * scalar; 27 | return result; 28 | } 29 | 30 | Vector& operator+=(const Vector& other) 31 | { 32 | *this = *this + other; 33 | return *this; 34 | } 35 | 36 | Vector& operator-=(const Vector& other) 37 | { 38 | *this = *this - other; 39 | return *this; 40 | } 41 | 42 | Vector& operator*=(int scalar) 43 | { 44 | *this = *this * scalar; 45 | return *this; 46 | } 47 | }; 48 | 49 | 50 | int main() 51 | { 52 | Vector a{1, 2}; 53 | Vector b{3, 4}; 54 | 55 | Vector result = a + b; 56 | // You CAN do stuff like this, because it returns a reference. 57 | (result *= 5) -= a; 58 | result += b; 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/vector/operator.cpp: -------------------------------------------------------------------------------- 1 | struct Vector 2 | { 3 | int x; 4 | int y; 5 | 6 | Vector operator+(Vector other) const 7 | { 8 | Vector result; 9 | result.x = this->x + other.x; 10 | result.y = this->y + other.y; 11 | return result; 12 | } 13 | 14 | Vector operator-(Vector other) const 15 | { 16 | Vector result; 17 | result.x = this->x - other.x; 18 | result.y = this->y - other.y; 19 | return result; 20 | } 21 | 22 | Vector operator*(int scalar) const 23 | { 24 | Vector result; 25 | result.x = this->x * scalar; 26 | result.y = this->y * scalar; 27 | return result; 28 | } 29 | }; 30 | 31 | 32 | int main() 33 | { 34 | Vector a{1, 2}; 35 | Vector b{3, 4}; 36 | 37 | Vector result = a + b; 38 | result = result * 5 - a; 39 | result = result + b; 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /en/05a_programming_fundamentals/vector/procedural.cpp: -------------------------------------------------------------------------------- 1 | struct Vector 2 | { 3 | int x; 4 | int y; 5 | }; 6 | 7 | Vector add(Vector a, Vector b) 8 | { 9 | Vector result; 10 | result.x = a.x + b.x; 11 | result.y = a.y + b.y; 12 | return result; 13 | } 14 | 15 | Vector subtract(Vector a, Vector b) 16 | { 17 | Vector result; 18 | result.x = a.x - b.x; 19 | result.y = a.y - b.y; 20 | return result; 21 | } 22 | 23 | Vector scale(Vector a, int scalar) 24 | { 25 | Vector result; 26 | result.x = a.x * scalar; 27 | result.y = a.y * scalar; 28 | return result; 29 | } 30 | 31 | int main() 32 | { 33 | Vector a{1, 2}; 34 | Vector b{3, 4}; 35 | 36 | Vector result = add(a, b); 37 | result = subtract(scale(result, 5), a); 38 | result = add(result, b); 39 | 40 | return 0; 41 | } -------------------------------------------------------------------------------- /en/06_arrays/array.cpp: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | // | 18 | 10 | 10 | 10 | 10 | 4 | int arr[5] = {}; 5 | arr[0] = 8; 6 | 7 | // for (int i = 0; i < 5; i++) 8 | // { 9 | // arr[i] = arr[i] + 10; 10 | // } 11 | 12 | { 13 | int i = 0; 14 | while (i < 5) 15 | { 16 | arr[i] = arr[i] + 10; 17 | i++; 18 | } 19 | } 20 | 21 | sum(&arr[0], 5); // pass length explicitly 22 | sum(&arr[0], sizeof(arr) / sizeof(arr[0])); // 20 / 4 = 5 23 | } 24 | 25 | int sum(int* arr, size_t length) 26 | { 27 | int result = 0; 28 | for (size_t i = 0; i < length; i++) 29 | { 30 | result += arr[i]; 31 | // result = result + *(arr + i); 32 | } 33 | return result; 34 | } -------------------------------------------------------------------------------- /en/06_arrays/std_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int main() 3 | { 4 | // int arr[5]{}; 5 | // arr[0] = 8; 6 | 7 | std::array arr {}; 8 | arr[0] = 8; 9 | 10 | for (int i = 0; i < 5; i++) 11 | { 12 | arr[i] = arr[i] + 10; 13 | } 14 | 15 | { 16 | int i = 0; 17 | while (i < 5) 18 | { 19 | arr[i] = arr[i] + 10; 20 | i++; 21 | } 22 | } 23 | 24 | sum(arr); 25 | } 26 | 27 | // Don't focus too much on the syntax (the template bit), 28 | // you don't have to remember this yet. 29 | template 30 | int sum(std::array arr) 31 | { 32 | int result = 0; 33 | for (size_t i = 0; i < arr.size(); i++) 34 | { 35 | result += arr[i]; 36 | // NOTE: can't use pointer arithmetic here. 37 | } 38 | return result; 39 | } 40 | 41 | #if false 42 | 43 | // NOTE: 44 | // The above copies all elements of the array passed in into the parameter `arr`. 45 | // You can use a pointer (or a reference) if you don't want to copy. 46 | // Example: 47 | template 48 | int sum(std::array* arr) 49 | { 50 | int result = 0; 51 | for (size_t i = 0; i < (*arr).size(); i++) 52 | { 53 | result += (*arr)[i]; 54 | } 55 | return result; 56 | } 57 | 58 | // Or with a reference: 59 | template 60 | int sum(std::array& arr) 61 | { 62 | int result = 0; 63 | for (size_t i = 0; i < arr.size(); i++) 64 | { 65 | result += arr[i]; 66 | } 67 | return result; 68 | } 69 | 70 | #endif -------------------------------------------------------------------------------- /en/06_arrays/std_span.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // struct std::span 5 | // { 6 | // int* ptr; 7 | // size_t length; 8 | // }; 9 | 10 | int sum(std::span arr); 11 | 12 | int main() 13 | { 14 | int arr[5]{}; 15 | arr[0] = 8; 16 | 17 | for (int i = 0; i < 5; i++) 18 | { 19 | arr[i] = arr[i] + 10; 20 | } 21 | 22 | { 23 | int i = 0; 24 | while (i < 5) 25 | { 26 | arr[i] = arr[i] + 10; 27 | i++; 28 | } 29 | } 30 | 31 | std::cout << sum(arr); 32 | } 33 | 34 | // std::span = { pointer to first element, length } 35 | int sum(std::span arr) 36 | { 37 | int result = 0; 38 | for (size_t i = 0; i < arr.size(); i++) 39 | { 40 | result += arr[i]; 41 | } 42 | return result; 43 | } -------------------------------------------------------------------------------- /en/06_arrays/stub.md: -------------------------------------------------------------------------------- 1 | - More on C arrays, why they suck 2 | - Static array and `std::array` 3 | - `std::span` 4 | - `char[x]` vs `const char*` vs `std::string_view` 5 | - Dynamic arrays (custom implementation), with and without resizing 6 | - Basic templates 7 | 8 | For more advanced students: 9 | - foreach syntax 10 | - iterators? 11 | - Ownership of memory, `std::span` 12 | - `std::string` -------------------------------------------------------------------------------- /en/06_arrays/t.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | int sum(int (&arr)[N]) 5 | { 6 | int result = 0; 7 | for (size_t i = 0; i < N; i++) 8 | { 9 | result += arr[i]; 10 | } 11 | return result; 12 | } 13 | 14 | int main() 15 | { 16 | int arr[4]{}; 17 | sum(arr); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /en/07_serialization/stub.md: -------------------------------------------------------------------------------- 1 | - Reading and writing files 2 | - Defining domain data models 3 | - Serialization and deserialization 4 | - CSV files (JSON files introduced but not used) 5 | - Using `std::vector&`, `std::string_view` and `std::span` to avoid copying -------------------------------------------------------------------------------- /en/07_serialization/validation/01_bool_example.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | bool validateCar(const Car& car, int currentYear); 4 | 5 | int main() 6 | { 7 | int currentYear = getCurrentYear(); 8 | Car car{ 9 | "", // empty string not allowed 10 | "ABC", 11 | "123123", 12 | 2000, 13 | 4, 14 | }; 15 | 16 | bool isValid; 17 | 18 | isValid = validateCar(car, currentYear); // false 19 | 20 | car.companyName = "Audi"; 21 | isValid = validateCar(car, currentYear); // true 22 | 23 | car.producedYear = currentYear + 1; 24 | isValid = validateCar(car, currentYear); // false 25 | 26 | // etc. 27 | 28 | if (isValid) 29 | return 0; 30 | 31 | return 1; 32 | } 33 | 34 | bool validateCar(const Car& car, int currentYear) 35 | { 36 | if (car.companyName.size() == 0) 37 | return false; 38 | if (car.modelName.size() == 0) 39 | return false; 40 | if (car.numberplateText.size() < 6) 41 | return false; 42 | if (car.numberOfDoors < 0) 43 | return false; 44 | if (car.producedYear > currentYear) 45 | return false; 46 | return true; 47 | } 48 | -------------------------------------------------------------------------------- /en/07_serialization/validation/02_string_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | bool validateCar(const Car& car, std::ostream& error, int currentYear); 5 | 6 | int main() 7 | { 8 | int currentYear = getCurrentYear(); 9 | Car car{ 10 | "", // empty string not allowed 11 | "ABC", 12 | "123123", 13 | 2000, 14 | 4, 15 | }; 16 | 17 | bool isValid = validateCar(car, std::cout, currentYear); 18 | 19 | car.companyName = "Audi"; 20 | isValid = validateCar(car, std::cout, currentYear); 21 | 22 | car.producedYear = currentYear + 1; 23 | isValid = validateCar(car, std::cout, currentYear); 24 | 25 | if (isValid) 26 | return 0; 27 | return 1; 28 | } 29 | 30 | bool validateCar(const Car& car, std::ostream& error, int currentYear) 31 | { 32 | if (car.companyName.size() == 0) 33 | { 34 | error << "companyName is empty" << std::endl; 35 | return false; 36 | } 37 | if (car.modelName.size() == 0) 38 | { 39 | error << "modelName is empty" << std::endl; 40 | return false; 41 | } 42 | { 43 | size_t size = car.numberplateText.size(); 44 | size_t minSymbols = 6; 45 | if (size < 6) 46 | { 47 | error << "numberplaceText has less than "; 48 | error << minSymbols; 49 | error << " symbols, the actual size was "; 50 | error << size; 51 | error << std::endl; 52 | return false; 53 | } 54 | } 55 | if (car.numberOfDoors < 0) 56 | { 57 | error << "numberOfDoors is negative"; 58 | error << std::endl; 59 | return false; 60 | } 61 | if (car.producedYear > currentYear) 62 | { 63 | error << "producedYear is less than the current year "; 64 | error << currentYear; 65 | error << std::endl; 66 | return false; 67 | } 68 | return true; 69 | } 70 | -------------------------------------------------------------------------------- /en/07_serialization/validation/03_string_multiple_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | bool validateCar(const Car& car, std::ostream& error, int currentYear); 5 | 6 | int main() 7 | { 8 | int currentYear = 2000; 9 | Car car{ 10 | "", // empty string not allowed 11 | "ABC", 12 | "123", 13 | 2001, 14 | 4, 15 | }; 16 | 17 | bool isValid = validateCar(car, std::cout, currentYear); 18 | if (!isValid) 19 | return 1; 20 | 21 | return 0; 22 | } 23 | 24 | bool validateCar(const Car& car, std::ostream& error, int currentYear) 25 | { 26 | bool isValid = true; 27 | if (car.companyName.size() == 0) 28 | { 29 | error << "companyName is empty" << std::endl; 30 | isValid = false; 31 | } 32 | if (car.modelName.size() == 0) 33 | { 34 | error << "modelName is empty" << std::endl; 35 | isValid = false; 36 | } 37 | { 38 | size_t size = car.numberplateText.size(); 39 | size_t minSymbols = 6; 40 | if (size < minSymbols) 41 | { 42 | error << "numberplaceText has less than "; 43 | error << minSymbols; 44 | error << " symbols, the actual size was "; 45 | error << size; 46 | error << std::endl; 47 | isValid = false; 48 | } 49 | } 50 | if (car.numberOfDoors < 0) 51 | { 52 | error << "numberOfDoors is negative"; 53 | error << std::endl; 54 | isValid = false; 55 | } 56 | if (car.producedYear > currentYear) 57 | { 58 | error << "producedYear is less than the current year "; 59 | error << currentYear; 60 | error << std::endl; 61 | isValid = false; 62 | } 63 | return isValid; 64 | } 65 | -------------------------------------------------------------------------------- /en/07_serialization/validation/04_enum_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | enum class ValidationResultKind 5 | { 6 | Valid = 0, 7 | CompanyName_Empty = 1, 8 | ModelName_Empty = 2, 9 | NumberplateText_TooShort = 3, 10 | NumberOfDoors_Negative = 4, 11 | ProducedYear_BeyondCurrentYear = 5, 12 | }; 13 | 14 | ValidationResultKind validateCar(const Car& car, int currentYear); 15 | 16 | int main() 17 | { 18 | int currentYear = getCurrentYear(); 19 | Car car{ 20 | "", // empty string not allowed 21 | "ABC", 22 | "123123", 23 | 2000, 24 | 4, 25 | }; 26 | 27 | ValidationResultKind result = validateCar(car, currentYear); 28 | 29 | switch (result) 30 | { 31 | case ValidationResultKind::Valid: 32 | std::cout << "All fine"; 33 | break; 34 | 35 | case ValidationResultKind::NumberOfDoors_Negative: 36 | std::cout << "Number of doors was negative?? bruh"; 37 | break; 38 | 39 | default: 40 | std::cout << "Some other error has occured"; 41 | break; 42 | } 43 | 44 | // You can use the int value of the enum for the error code. 45 | // Valid is 0, which checks out with the "no-error" exit code of 0. 46 | return static_cast(result); 47 | } 48 | 49 | ValidationResultKind validateCar(const Car& car, int currentYear) 50 | { 51 | if (car.companyName.size() == 0) 52 | { 53 | return ValidationResultKind::CompanyName_Empty; 54 | } 55 | if (car.modelName.size() == 0) 56 | { 57 | return ValidationResultKind::ModelName_Empty; 58 | } 59 | { 60 | size_t size = car.numberplateText.size(); 61 | size_t minSymbols = 6; 62 | if (size < minSymbols) 63 | { 64 | return ValidationResultKind::NumberplateText_TooShort; 65 | } 66 | } 67 | if (car.numberOfDoors < 0) 68 | { 69 | return ValidationResultKind::NumberOfDoors_Negative; 70 | } 71 | if (car.producedYear > currentYear) 72 | { 73 | return ValidationResultKind::ProducedYear_BeyondCurrentYear; 74 | } 75 | return ValidationResultKind::Valid; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /en/07_serialization/validation/07_exception_usage_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | // Try different inputs: 7 | std::string str = "12311111111111abc"; 8 | // std::string str = "abc"; 9 | // std::string str = "123"; 10 | // std::string str = "123abc"; 11 | 12 | bool converted = false; 13 | int i; 14 | try 15 | { 16 | i = std::stoi(str); 17 | converted = true; 18 | } 19 | catch (const std::invalid_argument& e) 20 | { 21 | std::cout 22 | << "Invalid argument: " 23 | << e.what() // prints the string describing the exception. 24 | << std::endl; 25 | } 26 | catch (const std::out_of_range& e) 27 | { 28 | std::cout 29 | << "Out of range: " 30 | << e.what() 31 | << std::endl; 32 | } 33 | 34 | if (converted) 35 | { 36 | std::cout << i << std::endl; 37 | } 38 | } -------------------------------------------------------------------------------- /en/07_serialization/validation/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #pragma once 4 | 5 | struct Car 6 | { 7 | std::string companyName; 8 | std::string modelName; 9 | std::string numberplateText; 10 | int producedYear; 11 | int numberOfDoors; 12 | }; 13 | 14 | #include 15 | #include 16 | 17 | inline int getCurrentYear() 18 | { 19 | std::time_t currentTimestamp = std::time(0); 20 | // https://stackoverflow.com/questions/12212339/does-memory-for-localtime-need-to-be-deallocated 21 | std::tm* timeInfo = std::localtime(¤tTimestamp); 22 | std::time_t* t = ¤tTimestamp; 23 | int year = timeInfo->tm_year; 24 | return year; 25 | } -------------------------------------------------------------------------------- /en/08_searching_algorithms/binarySearch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct SearchResult 6 | { 7 | size_t foundIndex; 8 | bool isElementFound; 9 | }; 10 | 11 | // | 1 | 3 | 6 | 9 | 15 | 25 | 12 | // 9 13 | // 14 | // | 1 | 3 | 6 | 9 | 15 | 25 | 15 | // ^ | ^ 16 | // 17 | // | 1 | 3 | 6 | 9 | 15 | 25 | 18 | // ^ | ^ 19 | // 20 | // | 1 | 3 | 6 | 9 | 15 | 25 | 3 21 | // ^ 22 | // ^ 23 | // 24 | // | 1 | 3 | 6 | 9 | 15 | 25 | 25 | // | 26 | 27 | SearchResult binarySearch(std::span arr, int elementToFind) 28 | { 29 | const SearchResult elementNotFoundResult = {0, false}; 30 | 31 | if (arr.empty()) 32 | { 33 | return elementNotFoundResult; 34 | } 35 | 36 | // This is to account for the case where it would *underflow*. 37 | // 38 | // It would underflow when we try to move the high index to the left of the 0th position, 39 | // which would take it to -1, which is also size_t's max value, 40 | // so it will make the check pass, even though 41 | // the high index is now in front of the low index. 42 | // 43 | // You can try and debug the application without this check, and try and search for 44 | // an element that is smaller than the first element in the array, 45 | // to see for youself what I mean. 46 | if (arr[0] > elementToFind) 47 | { 48 | return elementNotFoundResult; 49 | } 50 | 51 | size_t indexLow = 0; 52 | size_t indexHigh = arr.size() - 1; 53 | 54 | while (indexLow <= indexHigh) 55 | { 56 | size_t currentIndex = (indexHigh - indexLow) / 2 + indexLow; 57 | int currentElement = arr[currentIndex]; 58 | 59 | if (elementToFind > currentElement) 60 | { 61 | indexLow = currentIndex + 1; 62 | } 63 | else if (elementToFind < currentElement) 64 | { 65 | indexHigh = currentIndex - 1; 66 | } 67 | else // if (elementToFind == currentElement) 68 | { 69 | return {currentIndex, true}; 70 | } 71 | } 72 | 73 | return elementNotFoundResult; 74 | } 75 | 76 | int main() 77 | { 78 | std::array arr = {1, 5, 7, 10, 15, 32, 89}; 79 | SearchResult result = binarySearch(arr, 0); 80 | 81 | if (result.isElementFound) 82 | { 83 | std::cout << "Element found at index " << result.foundIndex; 84 | } 85 | else 86 | { 87 | std::cout << "Element not found."; 88 | } 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/binarySearchTree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | Node* left; 8 | Node* right; 9 | }; 10 | 11 | struct BinarySearchTree 12 | { 13 | Node* root; 14 | }; 15 | 16 | Node* find(BinarySearchTree tree, int value) 17 | { 18 | Node* currentNode = tree.root; 19 | while (currentNode != nullptr) 20 | { 21 | if (currentNode->value == value) 22 | { 23 | // currentNode is the target node; 24 | break; 25 | } 26 | else if (value < currentNode->value) 27 | { 28 | currentNode = currentNode->left; 29 | } 30 | else 31 | { 32 | currentNode = currentNode->right; 33 | } 34 | } 35 | 36 | return currentNode; 37 | } 38 | 39 | Node* addNode(BinarySearchTree* tree, int value) 40 | { 41 | Node* node = new Node; 42 | node->value = value; 43 | node->left = nullptr; 44 | node->right = nullptr; 45 | 46 | if (tree->root == nullptr) 47 | { 48 | tree->root = node; 49 | return node; 50 | } 51 | 52 | Node* currentNode = tree->root; 53 | while (true) 54 | { 55 | if (value > currentNode->value) 56 | { 57 | if (currentNode->right != nullptr) 58 | { 59 | currentNode = currentNode->right; 60 | } 61 | else 62 | { 63 | currentNode->right = node; 64 | break; 65 | } 66 | } 67 | else 68 | { 69 | if (currentNode->left != nullptr) 70 | { 71 | currentNode = currentNode->left; 72 | } 73 | else 74 | { 75 | currentNode->left = node; 76 | break; 77 | } 78 | } 79 | } 80 | return node; 81 | } 82 | 83 | int main() 84 | { 85 | std::array values{1, 5, 3, 4, 9, 7}; 86 | BinarySearchTree tree; 87 | tree.root = nullptr; 88 | 89 | for (size_t i = 0; i < values.size(); i++) 90 | { 91 | int currentValue = values[i]; 92 | addNode(&tree, currentValue); 93 | } 94 | 95 | Node* node = find(tree, 5); 96 | if (node == nullptr) 97 | { 98 | std::cout << "Node not found"; 99 | } 100 | if (node->left != nullptr) 101 | { 102 | std::cout << node->left->value; 103 | } 104 | if (node->right != nullptr) 105 | { 106 | std::cout << node->right->value; 107 | } 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/binarySearchTreeArray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Node 6 | { 7 | int value; 8 | Node* left; 9 | Node* right; 10 | }; 11 | 12 | Node* find(Node* treeRoot, int value) 13 | { 14 | Node* currentNode = treeRoot; 15 | while (currentNode != nullptr) 16 | { 17 | if (currentNode->value == value) 18 | { 19 | // currentNode is the target node; 20 | break; 21 | } 22 | else if (value < currentNode->value) 23 | { 24 | currentNode = currentNode->left; 25 | } 26 | else 27 | { 28 | currentNode = currentNode->right; 29 | } 30 | } 31 | 32 | return currentNode; 33 | } 34 | 35 | int main() 36 | { 37 | std::array numbers{ 5, 7, 2, 6, 9 }; 38 | 39 | Node* firstNodeAddress = new Node[numbers.size()]; 40 | std::span nodes {firstNodeAddress, numbers.size()}; 41 | 42 | for (size_t count = 0; count < numbers.size(); count++) 43 | { 44 | int value = numbers[count]; 45 | 46 | Node* newNode = &nodes[count]; 47 | newNode->value = value; 48 | newNode->left = nullptr; 49 | newNode->right = nullptr; 50 | 51 | if (count == 0) 52 | { 53 | continue; 54 | } 55 | 56 | Node* currentNode = &nodes[0]; 57 | while (true) 58 | { 59 | if (value > currentNode->value) 60 | { 61 | if (currentNode->right == nullptr) 62 | { 63 | currentNode->right = newNode; 64 | break; 65 | } 66 | else 67 | { 68 | currentNode = currentNode->right; 69 | } 70 | } 71 | else 72 | { 73 | if (currentNode->left == nullptr) 74 | { 75 | currentNode->left = newNode; 76 | break; 77 | } 78 | else 79 | { 80 | currentNode = currentNode->left; 81 | } 82 | } 83 | } 84 | } 85 | 86 | Node* node = find(&nodes[0], 7); 87 | if (node == nullptr) 88 | { 89 | std::cout << "Node not found"; 90 | } 91 | if (node->left != nullptr) 92 | { 93 | std::cout << node->left->value; 94 | } 95 | if (node->right != nullptr) 96 | { 97 | std::cout << node->right->value; 98 | } 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/binarySearchTreeArrayIndices.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Node 6 | { 7 | int value; 8 | size_t leftIndex; 9 | size_t rightIndex; 10 | }; 11 | 12 | struct BinarySearchTree 13 | { 14 | std::vector nodes; 15 | }; 16 | 17 | Node* addNode(BinarySearchTree* tree, int value) 18 | { 19 | size_t count = tree->nodes.size(); 20 | tree->nodes.push_back({ value, 0, 0 }); 21 | 22 | // nodes.push_back({}); 23 | // Node* node = &nodes.back(); 24 | // node->value = value; 25 | // node->leftIndex = 0; 26 | // node->rightIndex = 0; 27 | 28 | if (count == 0) 29 | { 30 | return &tree->nodes[count]; 31 | } 32 | 33 | size_t currentIndex = 0; 34 | while (true) 35 | { 36 | Node* currentNode = &tree->nodes[currentIndex]; 37 | size_t* indexSlot; 38 | if (value > currentNode->value) 39 | { 40 | indexSlot = ¤tNode->rightIndex; 41 | } 42 | else 43 | { 44 | indexSlot = ¤tNode->leftIndex; 45 | } 46 | 47 | if (*indexSlot == 0) 48 | { 49 | *indexSlot = count; 50 | break; 51 | } 52 | else 53 | { 54 | currentIndex = *indexSlot; 55 | } 56 | } 57 | 58 | return &tree->nodes[count]; 59 | } 60 | 61 | Node* find(BinarySearchTree* tree, int value) 62 | { 63 | if (tree->nodes.size() == 0) 64 | { 65 | return nullptr; 66 | } 67 | 68 | size_t currentIndex = 0; 69 | while (true) 70 | { 71 | Node* currentNode = &tree->nodes[currentIndex]; 72 | if (value == currentNode->value) 73 | { 74 | return currentNode; 75 | } 76 | 77 | if (value > currentNode->value) 78 | { 79 | currentIndex = currentNode->rightIndex; 80 | } 81 | else 82 | { 83 | currentIndex = currentNode->leftIndex; 84 | } 85 | 86 | if (currentIndex == 0) 87 | { 88 | return nullptr; 89 | } 90 | } 91 | } 92 | 93 | void find9AndPrint(BinarySearchTree* tree) 94 | { 95 | Node* node = find(tree, 9); 96 | if (node == nullptr) 97 | { 98 | std::cout << "Node not found"; 99 | } 100 | if (node->leftIndex != 0) 101 | { 102 | std::cout << tree->nodes[node->leftIndex].value << std::endl; 103 | } 104 | if (node->rightIndex != 0) 105 | { 106 | std::cout << tree->nodes[node->rightIndex].value << std::endl; 107 | } 108 | } 109 | 110 | int main() 111 | { 112 | std::array values{5, 7, 2, 6, 9}; 113 | 114 | BinarySearchTree tree{{}}; 115 | 116 | // nodes.reserve(values.size() * 2); 117 | 118 | for (size_t count = 0; count < values.size(); count++) 119 | { 120 | int value = values[count]; 121 | addNode(&tree, value); 122 | } 123 | 124 | addNode(&tree, 10); 125 | find9AndPrint(&tree); 126 | 127 | addNode(&tree, 8); 128 | find9AndPrint(&tree); 129 | } 130 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/binarySearchTreeRecursive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node 5 | { 6 | int value; 7 | Node* left; 8 | Node* right; 9 | }; 10 | 11 | struct BinarySearchTree 12 | { 13 | Node* root; 14 | }; 15 | 16 | Node* findInSubtree(Node* subtreeRoot, int value) 17 | { 18 | if (subtreeRoot == nullptr) 19 | { 20 | return nullptr; 21 | } 22 | 23 | if (value == subtreeRoot->value) 24 | { 25 | return subtreeRoot; 26 | } 27 | 28 | Node* nextSubtreeRoot; 29 | if (value > subtreeRoot->value) 30 | { 31 | nextSubtreeRoot = subtreeRoot->right; 32 | } 33 | else 34 | { 35 | nextSubtreeRoot = subtreeRoot->left; 36 | } 37 | Node* r = findInSubtree(nextSubtreeRoot, value); 38 | return r; 39 | } 40 | 41 | Node* find(BinarySearchTree tree, int value) 42 | { 43 | return findInSubtree(tree.root, value); 44 | } 45 | 46 | void addNodeIntoSubtree(Node* subtreeRoot, Node* newNode) 47 | { 48 | Node** nextSubtreeRoot; 49 | if (newNode->value > subtreeRoot->value) 50 | { 51 | nextSubtreeRoot = &subtreeRoot->right; 52 | } 53 | else 54 | { 55 | nextSubtreeRoot = &subtreeRoot->left; 56 | } 57 | 58 | if (*nextSubtreeRoot == nullptr) 59 | { 60 | *nextSubtreeRoot = newNode; 61 | } 62 | else 63 | { 64 | addNodeIntoSubtree(*nextSubtreeRoot, newNode); 65 | } 66 | } 67 | 68 | Node* addNode(BinarySearchTree* tree, int value) 69 | { 70 | Node* node = new Node; 71 | node->value = value; 72 | node->left = nullptr; 73 | node->right = nullptr; 74 | 75 | if (tree->root == nullptr) 76 | { 77 | tree->root = node; 78 | return node; 79 | } 80 | 81 | addNodeIntoSubtree(tree->root, node); 82 | 83 | return node; 84 | } 85 | 86 | int main() 87 | { 88 | std::array values{5, 7, 2, 6, 9, 10, 8}; 89 | BinarySearchTree tree; 90 | tree.root = nullptr; 91 | 92 | for (size_t i = 0; i < values.size(); i++) 93 | { 94 | int currentValue = values[i]; 95 | addNode(&tree, currentValue); 96 | } 97 | 98 | Node* node = find(tree, 9); 99 | if (node == nullptr) 100 | { 101 | std::cout << "Node not found"; 102 | } 103 | if (node->left != nullptr) 104 | { 105 | std::cout << node->left->value; 106 | } 107 | if (node->right != nullptr) 108 | { 109 | std::cout << node->right->value; 110 | } 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/linearSearch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct SearchResult 6 | { 7 | size_t foundIndex; 8 | bool isElementFound; 9 | }; 10 | 11 | // N / 2 * 1 12 | // N = 1000 -> 1 000 000 13 | // N = 500 -> 500 000 14 | // O(N / 2 + 1) = O(N) 15 | // O(5 * 1) = O(1) 16 | SearchResult linearSearch(std::span arr, int elementToFind) 17 | { 18 | for (size_t i = 0; i < arr.size(); i++) // N / 2 19 | { 20 | int currentElement = arr[i]; 21 | if (currentElement == elementToFind) // 1 22 | { 23 | // SearchResult result; 24 | // result.foundIndex = i; 25 | // result.isElementFound = true; 26 | // return result; 27 | return { i, true }; 28 | } 29 | } 30 | return { 0, false }; 31 | } 32 | 33 | // O(N^2 + N) = O(N^2) 34 | 35 | // N * N * 2 = N^2 * 2 36 | // N = 1000 -> 2 000 000 37 | // N = 1 000 000 -> 2 000 000 000 000 38 | // O(N * N * 2) = O(N * N) = O(N^2) 39 | // O(5) = O(1) 40 | int someProduct(std::span arr) 41 | { 42 | int result = 0; 43 | for (size_t i = 0; i < arr.size(); i++) // N 44 | { 45 | for (size_t j = 0; j < arr.size(); j++) // N 46 | { 47 | result += arr[i] * arr[j]; // 2 48 | } 49 | } 50 | return result; 51 | } 52 | 53 | int main() 54 | { 55 | std::array arr = { 1, 6, 2, 5, 9 }; 56 | SearchResult result = linearSearch(arr, 5); 57 | 58 | if (result.isElementFound) 59 | { 60 | std::cout << "Element found at index " << result.foundIndex; 61 | } 62 | else 63 | { 64 | std::cout << "Elemenet not found."; 65 | } 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/stub.md: -------------------------------------------------------------------------------- 1 | - Linear search 2 | - Binary search (possible variations like exponential or fibonacci search) 3 | - Binary search tree (note on allocators, aka if you construct it, use it a bunch, then you don't need it, use an arena, or just allocate nodes and use indices instead of pointers) 4 | - Complexity analysis (should complexity be a separate chapter? I mean, I think it's pretty simple) -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/README.md: -------------------------------------------------------------------------------- 1 | [Video (ru)](https://youtube.com/live/uzZ7Q3UhLko?feature=share) 2 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/example.maze: -------------------------------------------------------------------------------- 1 | BB 2 | W 3 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/excel_water.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/08_searching_algorithms/waves_algorithm/excel_water.xlsx -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/maze.maze: -------------------------------------------------------------------------------- 1 | #### 2 | ## 3 | #w # 4 | #### 5 | -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/minecraft/README.md: -------------------------------------------------------------------------------- 1 | You need the version 1.20.1 of Minecraft with Fabric. -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/minecraft/map.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/08_searching_algorithms/waves_algorithm/minecraft/map.rar -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/minecraft/mods/fabric-carpet-1.20-1.4.112v230608.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/08_searching_algorithms/waves_algorithm/minecraft/mods/fabric-carpet-1.20-1.4.112v230608.jar -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/minecraft/mods/subtick-mc1.20.1-v1.0.15.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/08_searching_algorithms/waves_algorithm/minecraft/mods/subtick-mc1.20.1-v1.0.15.jar -------------------------------------------------------------------------------- /en/08_searching_algorithms/waves_algorithm/walls.maze: -------------------------------------------------------------------------------- 1 | BBBBB 2 | BW BB 3 | BB BB 4 | B B 5 | BBB B -------------------------------------------------------------------------------- /en/09_generic_data_structures/associative_array_linear.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Bucket 6 | { 7 | int value; 8 | std::string_view key; 9 | bool occupied; 10 | }; 11 | 12 | using HashFunc = size_t(*)(std::string_view key); 13 | static const inline size_t UNDERLYING_ARRAY_LEN = 8; 14 | 15 | struct AssociativeArray 16 | { 17 | HashFunc hashFunc; 18 | std::array buckets; 19 | }; 20 | 21 | size_t calculateIndex(AssociativeArray* array, std::string_view key) 22 | { 23 | const size_t hash = array->hashFunc(key); 24 | size_t index = hash % array->buckets.size(); 25 | return index; 26 | } 27 | 28 | int* addElement(AssociativeArray* array, std::string_view key) 29 | { 30 | size_t index = calculateIndex(array, key); 31 | const size_t initialIndex = index; 32 | 33 | while (true) 34 | { 35 | Bucket* bucket = &array->buckets[index]; 36 | if (!bucket->occupied) 37 | { 38 | bucket->key = key; 39 | bucket->occupied = true; 40 | return &bucket->value; 41 | } 42 | 43 | index = (index + 1) % array->buckets.size(); 44 | if (index == initialIndex) 45 | { 46 | return nullptr; 47 | } 48 | } 49 | } 50 | 51 | int* findElement(AssociativeArray* array, std::string_view key) 52 | { 53 | size_t index = calculateIndex(array, key); 54 | const size_t initialIndex = index; 55 | 56 | while (true) 57 | { 58 | Bucket* bucket = &array->buckets[index]; 59 | if (!bucket->occupied) 60 | { 61 | return nullptr; 62 | } 63 | 64 | if (bucket->key == key) 65 | { 66 | return &bucket->value; 67 | } 68 | 69 | index = (index + 1) % array->buckets.size(); 70 | if (index == initialIndex) 71 | { 72 | return nullptr; 73 | } 74 | } 75 | } 76 | 77 | size_t firstLetterIndex(std::string_view key) 78 | { 79 | if (key.empty()) 80 | { 81 | return 0; 82 | } 83 | 84 | size_t firstLetter = static_cast(key.at(0)); 85 | size_t firstAlphabetLetter = static_cast('a'); 86 | return firstLetter - firstAlphabetLetter; 87 | } 88 | 89 | int main() 90 | { 91 | AssociativeArray array{}; 92 | array.hashFunc = firstLetterIndex; 93 | 94 | { 95 | int* newElement = addElement(&array, "abc"); 96 | *newElement = 2; 97 | } 98 | { 99 | int* newElement = addElement(&array, "c"); 100 | *newElement = 5; 101 | } 102 | { 103 | int* newElement = addElement(&array, "ab"); 104 | *newElement = 6; 105 | } 106 | 107 | std::cout << "abc: " << *findElement(&array, "abc") << std::endl; 108 | std::cout << "ab: " << *findElement(&array, "ab") << std::endl; 109 | } 110 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/buffer_without_abstraction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | std::array arr; 8 | size_t currentIndex = 0; 9 | 10 | for (; currentIndex < arr.size(); currentIndex++) 11 | { 12 | std::cout << "Enter a number: "; 13 | int input; 14 | std::cin >> input; 15 | 16 | if (input == -1) 17 | { 18 | break; 19 | } 20 | arr[currentIndex] = input; 21 | } 22 | 23 | size_t elementCount = currentIndex; 24 | for (size_t i = 0; i < elementCount; i++) 25 | { 26 | std::cout 27 | << "arr[" 28 | << i 29 | << "] = " 30 | << arr[i] 31 | << std::endl; 32 | } 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /en/09_generic_data_structures/doubly_linked_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Node 4 | { 5 | int value; 6 | Node* nextNode; 7 | Node* previousNode; 8 | }; 9 | 10 | struct LinkedList 11 | { 12 | Node* firstNode; 13 | Node* lastNode; 14 | }; 15 | 16 | Node* addNodeToEnd(LinkedList* list, int value) 17 | { 18 | Node* newNode = new Node; 19 | newNode->nextNode = nullptr; // 0 20 | newNode->value = value; 21 | 22 | newNode->previousNode = list->lastNode; 23 | 24 | if (list->lastNode != nullptr) 25 | { 26 | list->lastNode->nextNode = newNode; 27 | } 28 | 29 | list->lastNode = newNode; 30 | 31 | if (list->firstNode == nullptr) 32 | { 33 | list->firstNode = newNode; 34 | } 35 | 36 | return newNode; 37 | } 38 | 39 | void removeFromStart(LinkedList* list) 40 | { 41 | assert(list->firstNode != nullptr); 42 | 43 | Node* firstNode = list->firstNode; 44 | Node* secondNode = firstNode->nextNode; 45 | 46 | if (secondNode != nullptr) 47 | { 48 | secondNode->previousNode = nullptr; 49 | } 50 | 51 | if (firstNode == list->lastNode) 52 | { 53 | list->lastNode = nullptr; 54 | } 55 | 56 | list->firstNode = secondNode; 57 | 58 | delete firstNode; 59 | } 60 | 61 | void removeFromEnd(LinkedList* list) 62 | { 63 | assert(list->lastNode != nullptr); 64 | 65 | Node* lastNode = list->lastNode; 66 | Node* secondToLastNode = lastNode->previousNode; 67 | 68 | if (list->firstNode == lastNode) 69 | { 70 | list->firstNode = nullptr; 71 | } 72 | 73 | if (secondToLastNode != nullptr) 74 | { 75 | secondToLastNode->nextNode = nullptr; 76 | } 77 | 78 | list->lastNode = secondToLastNode; 79 | 80 | delete lastNode; 81 | } 82 | 83 | 84 | void remove(LinkedList* list, Node* node) 85 | { 86 | Node* nextNode = node->nextNode; 87 | Node* previousNode = node->previousNode; 88 | 89 | if (nextNode != nullptr) 90 | { 91 | nextNode->previousNode = previousNode; 92 | } 93 | else 94 | { 95 | assert(list->lastNode == node); 96 | list->lastNode = previousNode; 97 | } 98 | 99 | if (previousNode != nullptr) 100 | { 101 | previousNode->nextNode = nextNode; 102 | } 103 | else 104 | { 105 | assert(list->firstNode == node); 106 | list->firstNode = nextNode; 107 | } 108 | 109 | delete node; 110 | } 111 | 112 | 113 | int main() 114 | { 115 | LinkedList list{}; 116 | Node* n1 = addNodeToEnd(&list, 1); 117 | Node* n2 = addNodeToEnd(&list, 2); 118 | Node* n3 = addNodeToEnd(&list, 3); 119 | Node* n9 = addNodeToEnd(&list, 9); 120 | 121 | remove(&list, n3); 122 | remove(&list, n9); 123 | } -------------------------------------------------------------------------------- /en/09_generic_data_structures/dynamic_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static const inline int DEFAULT_CAPACITY = 4; 5 | 6 | struct DynamicArray 7 | { 8 | int* buffer; 9 | size_t capacity; 10 | size_t count = 0; 11 | }; 12 | 13 | void addElement(DynamicArray* arr, int value) 14 | { 15 | if (arr->capacity <= arr->count) 16 | { 17 | size_t newCapacity; 18 | if (arr->capacity == 0) 19 | { 20 | newCapacity = DEFAULT_CAPACITY; 21 | } 22 | else 23 | { 24 | newCapacity = arr->capacity * 2; 25 | } 26 | 27 | int* newArr = new int[newCapacity]; 28 | for (size_t i = 0; i < arr->count; i++) 29 | { 30 | newArr[i] = arr->buffer[i]; 31 | } 32 | delete[] arr->buffer; 33 | arr->buffer = newArr; 34 | } 35 | 36 | arr->buffer[arr->count] = value; 37 | arr->count = arr->count + 1; 38 | } 39 | 40 | int getElementAtIndex(const DynamicArray* arr, size_t index) 41 | { 42 | // 15 | 22 | 10 | ** | ... 43 | // 3 44 | assert(index < arr->count); 45 | return arr->buffer[index]; 46 | } 47 | 48 | DynamicArray createDynamicArray(size_t capacity = DEFAULT_CAPACITY) 49 | { 50 | void* memoryBlock = new int[capacity]; 51 | int* mem = (int*) memoryBlock; 52 | 53 | DynamicArray arr; 54 | arr.buffer = mem; 55 | arr.capacity = capacity; 56 | arr.count = 0; 57 | 58 | return arr; 59 | } 60 | 61 | void destroyDynamicArray(DynamicArray* arr) 62 | { 63 | delete[] arr->buffer; 64 | } 65 | 66 | 67 | int main() 68 | { 69 | DynamicArray arr = createDynamicArray(); 70 | 71 | while (true) 72 | { 73 | std::cout << "Enter a number: "; 74 | int input; 75 | std::cin >> input; 76 | 77 | if (input == -1) 78 | { 79 | break; 80 | } 81 | addElement(&arr, input); 82 | } 83 | 84 | for (size_t i = 0; i < arr.count; i++) 85 | { 86 | std::cout 87 | << "arr[" 88 | << i 89 | << "] = " 90 | << getElementAtIndex(&arr, i) 91 | << std::endl; 92 | } 93 | 94 | destroyDynamicArray(&arr); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/dynamic_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Buffer 5 | { 6 | // | ** | ?? | ?? | ?? | 7 | // | 60 | ** | ?? | ?? | 8 | // | 60 | 79 | ** | ?? | 9 | // | 60 | 79 | 42 | ** | 10 | // | 60 | 79 | 42 | 58 | ** 11 | int* arr; 12 | size_t maxElementCount; 13 | size_t currentIndex = 0; 14 | }; 15 | 16 | void addElement(Buffer* buffer, int value) 17 | { 18 | size_t maxElementCount = buffer->maxElementCount; 19 | assert(buffer->currentIndex < maxElementCount); 20 | 21 | buffer->arr[buffer->currentIndex] = value; 22 | buffer->currentIndex = buffer->currentIndex + 1; 23 | } 24 | 25 | size_t getElementCount(Buffer* buffer) 26 | { 27 | return buffer->currentIndex; 28 | } 29 | 30 | size_t getMaxElementCount(Buffer* buffer) 31 | { 32 | return buffer->maxElementCount; 33 | } 34 | 35 | int getElementAtIndex(Buffer* buffer, size_t index) 36 | { 37 | // 15 | 22 | 10 | ** | ... 38 | // 3 39 | size_t elementCount = getElementCount(buffer); 40 | assert(index < elementCount); 41 | return buffer->arr[index]; 42 | } 43 | 44 | Buffer createDynamicArray(size_t maxElementCount) 45 | { 46 | void* memoryBlock = malloc(maxElementCount * sizeof(int)); 47 | int* arr = (int*) memoryBlock; 48 | 49 | Buffer buffer; 50 | buffer.arr = arr; 51 | buffer.maxElementCount = maxElementCount; 52 | buffer.currentIndex = 0; 53 | 54 | return buffer; 55 | } 56 | 57 | void destroyDynamicBuffer(Buffer* buffer) 58 | { 59 | free(buffer->arr); 60 | } 61 | 62 | 63 | int main() 64 | { 65 | std::cout << "Enter max number of elements" << std::endl; 66 | size_t maxElementCount; 67 | std::cin >> maxElementCount; 68 | 69 | // (stack memory) 70 | // | address | value | 71 | // | 100 | 500 | <- buffer.arr 72 | // | 108 | 4 | <- buffer.maxElementCount 73 | // | 116 | 0 | <- buffer.currentIndex 74 | 75 | // (heap memory) 76 | // | address | value | 77 | // | 500 | ?? | <- buffer.arr[0] 78 | // | 504 | ?? | <- buffer.arr[1] 79 | // | 508 | ?? | <- buffer.arr[2] 80 | // | 512 | ?? | <- buffer.arr[3] 81 | Buffer buffer = createDynamicArray(maxElementCount); 82 | 83 | for (size_t i = 0; i < getMaxElementCount(&buffer); i++) 84 | { 85 | std::cout << "Enter a number: "; 86 | int input; 87 | std::cin >> input; 88 | 89 | if (input == -1) 90 | { 91 | break; 92 | } 93 | addElement(&buffer, input); 94 | } 95 | 96 | size_t elementCount = getElementCount(&buffer); 97 | for (size_t i = 0; i < elementCount; i++) 98 | { 99 | std::cout 100 | << "arr[" 101 | << i 102 | << "] = " 103 | << getElementAtIndex(&buffer, i) 104 | << std::endl; 105 | } 106 | 107 | destroyDynamicBuffer(&buffer); 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/graph.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct GraphNode 5 | { 6 | int value; 7 | std::array neighbors; 8 | }; 9 | 10 | void printValuesOfNeighborsOfNeighbors(GraphNode* node) 11 | { 12 | for (size_t i = 0; i < node->neighbors.size(); i++) 13 | { 14 | GraphNode* neighbor = node->neighbors[i]; 15 | if (neighbor == nullptr) 16 | { 17 | break; 18 | } 19 | 20 | for (size_t j = 0; j < neighbor->neighbors.size(); j++) 21 | { 22 | GraphNode* neigborsNeighbor = neighbor->neighbors[j]; 23 | 24 | if (neigborsNeighbor == nullptr) 25 | { 26 | break; 27 | } 28 | 29 | std::cout << neigborsNeighbor->value; 30 | } 31 | } 32 | } 33 | 34 | int main() 35 | { 36 | GraphNode* n1 = new GraphNode{}; 37 | n1->value = 1; 38 | 39 | GraphNode* n2 = new GraphNode{}; 40 | n2->value = 2; 41 | 42 | GraphNode* n3 = new GraphNode{}; 43 | n3->value = 3; 44 | 45 | GraphNode* n4 = new GraphNode{}; 46 | n4->value = 4; 47 | 48 | n1->neighbors[0] = n2; 49 | n1->neighbors[1] = n3; 50 | n1->neighbors[2] = n4; 51 | 52 | n2->neighbors[0] = n1; 53 | n2->neighbors[1] = n3; 54 | n2->neighbors[2] = n4; 55 | 56 | n4->neighbors[0] = n3; 57 | 58 | printValuesOfNeighborsOfNeighbors(n2); 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/buffer_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/buffer_example.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/buffer_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/buffer_example_1.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/doubly_linked_list_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/doubly_linked_list_memory.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/graph1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/graph1.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/linked_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/linked_list.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/linked_list_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/linked_list_memory.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/linked_list_memory_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/linked_list_memory_1.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/quene.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/quene.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/queue2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/queue2.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/images/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/09_generic_data_structures/images/stack.png -------------------------------------------------------------------------------- /en/09_generic_data_structures/linked_list.cpp: -------------------------------------------------------------------------------- 1 | #include "linked_list_impl.cpp" 2 | 3 | int main() 4 | { 5 | LinkedList list{}; 6 | addNodeToEnd(&list, 1); 7 | addNodeToEnd(&list, 2); 8 | } 9 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/linked_list_impl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Node 4 | { 5 | int value; 6 | Node* nextNode; 7 | }; 8 | 9 | struct LinkedList 10 | { 11 | Node* firstNode; 12 | Node* lastNode; 13 | }; 14 | 15 | Node* addNodeToStart(LinkedList* list, int value) // enqueue 16 | { 17 | Node* newNode = new Node; 18 | newNode->nextNode = list->firstNode; 19 | newNode->value = value; 20 | 21 | list->firstNode = newNode; 22 | 23 | if (list->lastNode == nullptr) 24 | { 25 | list->lastNode = newNode; 26 | } 27 | 28 | return newNode; 29 | } 30 | 31 | Node* addNodeToEnd(LinkedList* list, int value) // enqueue 32 | { 33 | Node* newNode = new Node; 34 | newNode->nextNode = nullptr; // 0 35 | newNode->value = value; 36 | 37 | if (list->lastNode != nullptr) 38 | { 39 | list->lastNode->nextNode = newNode; 40 | } 41 | 42 | list->lastNode = newNode; 43 | 44 | if (list->firstNode == nullptr) 45 | { 46 | list->firstNode = newNode; 47 | } 48 | 49 | return newNode; 50 | } 51 | 52 | int removeFromStart(LinkedList* list) // dequeue 53 | { 54 | assert(list->firstNode != nullptr); 55 | 56 | Node* firstNode = list->firstNode; 57 | Node* secondNode = firstNode->nextNode; 58 | 59 | if (firstNode == list->lastNode) 60 | { 61 | list->lastNode = nullptr; 62 | } 63 | 64 | list->firstNode = secondNode; 65 | 66 | int value = firstNode->value; 67 | delete firstNode; 68 | return value; 69 | } 70 | 71 | void removeAfter(LinkedList* list, Node* node) 72 | { 73 | assert(node->nextNode != nullptr); 74 | 75 | Node* elementToDelete = node->nextNode; 76 | Node* elementAfterElementToDelete = elementToDelete->nextNode; 77 | 78 | node->nextNode = elementAfterElementToDelete; 79 | 80 | // if (elementToDelete->nextNode == nullptr) 81 | if (elementToDelete == list->lastNode) 82 | { 83 | list->lastNode = node; 84 | } 85 | 86 | delete elementToDelete; 87 | } 88 | 89 | bool isEmpty(const LinkedList* list) 90 | { 91 | return list->firstNode == nullptr; 92 | } 93 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/queue.cpp: -------------------------------------------------------------------------------- 1 | #include "linked_list_impl.cpp" 2 | #include 3 | #include 4 | 5 | struct Queue 6 | { 7 | LinkedList list; 8 | }; 9 | 10 | void enqueue(Queue* queue, int value) 11 | { 12 | addNodeToEnd(&queue->list, value); 13 | } 14 | 15 | int dequeue(Queue* queue) 16 | { 17 | int result = removeFromStart(&queue->list); 18 | return result; 19 | } 20 | 21 | bool isEmpty(const Queue* queue) 22 | { 23 | return isEmpty(&queue->list); 24 | } 25 | 26 | int main() 27 | { 28 | std::array arr{ 1, 2, 3, 4, 5 }; 29 | Queue queue{}; 30 | for (int v : arr) 31 | { 32 | enqueue(&queue, v); 33 | } 34 | 35 | while (!isEmpty(&queue)) 36 | { 37 | int item = dequeue(&queue); 38 | std::cout << item << std::endl; 39 | if (item == 3) 40 | { 41 | enqueue(&queue, 10); 42 | } 43 | } 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/queue_ring_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "linked_list_impl.cpp" 2 | #include 3 | #include 4 | #include 5 | 6 | struct Queue 7 | { 8 | std::span buffer; 9 | size_t len; 10 | size_t currentIndex; 11 | }; 12 | 13 | Queue createQueue(size_t capacity) 14 | { 15 | return { 16 | { new int[capacity], capacity }, 17 | 0, 18 | 0, 19 | }; 20 | } 21 | 22 | void deleteQueue(Queue* queue) 23 | { 24 | delete[] queue->buffer.data(); 25 | } 26 | 27 | bool isEmpty(const Queue* queue) 28 | { 29 | return queue->len == 0; 30 | } 31 | 32 | void enqueue(Queue* queue, int value) 33 | { 34 | size_t capacity = queue->buffer.size(); 35 | assert(capacity > queue->len); 36 | queue->buffer[queue->currentIndex] = value; 37 | queue->currentIndex = (queue->currentIndex + 1) % capacity; 38 | queue->len += 1; 39 | } 40 | 41 | int dequeue(Queue* queue) 42 | { 43 | size_t capacity = queue->buffer.size(); 44 | assert(!isEmpty(queue)); 45 | size_t oldestItemIndex = (queue->currentIndex + capacity - queue->len) % capacity; 46 | int result = queue->buffer[oldestItemIndex]; 47 | queue->len -= 1; 48 | return result; 49 | } 50 | 51 | int main() 52 | { 53 | std::array arr{ 1, 2, 3, 4, 5 }; 54 | Queue queue = createQueue(5); 55 | for (int v : arr) 56 | { 57 | enqueue(&queue, v); 58 | } 59 | 60 | while (!isEmpty(&queue)) 61 | { 62 | int item = dequeue(&queue); 63 | std::cout << item << std::endl; 64 | if (item == 3) 65 | { 66 | enqueue(&queue, 10); 67 | } 68 | } 69 | 70 | deleteQueue(&queue); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/stack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Stack 5 | { 6 | int* arr; 7 | size_t maxElementCount; 8 | size_t currentIndex = 0; 9 | }; 10 | 11 | void pushElement(Stack* stack, int value) 12 | { 13 | size_t maxElementCount = stack->maxElementCount; 14 | assert(stack->currentIndex < maxElementCount); 15 | 16 | stack->arr[stack->currentIndex] = value; 17 | stack->currentIndex = stack->currentIndex + 1; 18 | } 19 | 20 | 21 | size_t getElementCount(Stack* stack); 22 | int popElement(Stack* stack) 23 | { 24 | assert(getElementCount(stack) > 0); 25 | size_t newCurrentIndex = stack->currentIndex - 1; 26 | int value = stack->arr[newCurrentIndex]; 27 | stack->currentIndex = newCurrentIndex; 28 | return value; 29 | } 30 | 31 | size_t getElementCount(Stack* stack) 32 | { 33 | return stack->currentIndex; 34 | } 35 | 36 | size_t getMaxElementCount(Stack* stack) 37 | { 38 | return stack->maxElementCount; 39 | } 40 | 41 | int getElementAtIndex(Stack* stack, size_t index) 42 | { 43 | // 15 | 22 | 10 | ** | ... 44 | // 3 45 | size_t elementCount = getElementCount(stack); 46 | assert(index < elementCount); 47 | return stack->arr[index]; 48 | } 49 | 50 | Stack createDynamicStack(size_t maxElementCount) 51 | { 52 | void* memoryBlock = malloc(maxElementCount * sizeof(int)); 53 | int* arr = (int*) memoryBlock; 54 | 55 | Stack stack; 56 | stack.arr = arr; 57 | stack.maxElementCount = maxElementCount; 58 | stack.currentIndex = 0; 59 | 60 | return stack; 61 | } 62 | 63 | void destroyDynamicStack(Stack* stack) 64 | { 65 | free(stack->arr); 66 | } 67 | 68 | 69 | int main() 70 | { 71 | std::cout << "Enter max number of elements" << std::endl; 72 | size_t maxElementCount; 73 | std::cin >> maxElementCount; 74 | Stack stack = createDynamicStack(maxElementCount); 75 | 76 | for (size_t i = 0; i < getMaxElementCount(&stack); i++) 77 | { 78 | std::cout << "Enter a number: "; 79 | int input; 80 | std::cin >> input; 81 | 82 | if (input == -1) 83 | { 84 | break; 85 | } 86 | pushElement(&stack, input); 87 | } 88 | 89 | size_t elementCount = getElementCount(&stack); 90 | for (size_t i = 0; i < elementCount; i++) 91 | { 92 | int topElement = popElement(&stack); 93 | std::cout 94 | << topElement 95 | << std::endl; 96 | } 97 | 98 | std::cout 99 | << "Number of elements left in the stack = " 100 | << getElementCount(&stack) 101 | << std::endl; 102 | 103 | destroyDynamicStack(&stack); 104 | 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/stack_video.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Node 4 | { 5 | int value; 6 | Node* next; 7 | }; 8 | 9 | struct Stack 10 | { 11 | Node* firstNode; 12 | }; 13 | 14 | void push(Stack* stack, int value) 15 | { 16 | Node* node = new Node; 17 | node->value = value; 18 | node->next = stack->firstNode; 19 | 20 | stack->firstNode = node; 21 | } 22 | 23 | bool isEmpty(const Stack* stack) 24 | { 25 | return stack->firstNode == nullptr; 26 | } 27 | 28 | int pop(Stack* stack) 29 | { 30 | Node* firstNode = stack->firstNode; 31 | stack->firstNode = firstNode->next; 32 | int result = firstNode->value; 33 | delete firstNode; 34 | return result; 35 | } 36 | 37 | int main() 38 | { 39 | Stack stack{}; 40 | 41 | push(&stack, 1); 42 | push(&stack, 2); 43 | push(&stack, 3); 44 | 45 | assert(pop(&stack) == 3); 46 | assert(pop(&stack) == 2); 47 | 48 | push(&stack, 4); 49 | assert(pop(&stack) == 4); 50 | 51 | assert(!isEmpty(&stack)); 52 | 53 | pop(&stack); 54 | 55 | assert(isEmpty(&stack)); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /en/09_generic_data_structures/static_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Buffer 6 | { 7 | // | ** | ?? | ?? | ?? | 8 | // | 60 | ** | ?? | ?? | 9 | // | 60 | 79 | ** | ?? | 10 | // | 60 | 79 | 42 | ** | 11 | // | 60 | 79 | 42 | 58 | ** 12 | std::array arr; 13 | size_t currentIndex = 0; 14 | }; 15 | 16 | void addElement(Buffer* buffer, int value) 17 | { 18 | size_t maxElementCount = buffer->arr.size(); 19 | assert(buffer->currentIndex < maxElementCount); 20 | 21 | buffer->arr[buffer->currentIndex] = value; 22 | buffer->currentIndex = buffer->currentIndex + 1; 23 | } 24 | 25 | size_t getElementCount(Buffer* buffer) 26 | { 27 | return buffer->currentIndex; 28 | } 29 | 30 | size_t getMaxElementCount(Buffer* buffer) 31 | { 32 | return buffer->arr.size(); 33 | } 34 | 35 | int getElementAtIndex(Buffer* buffer, size_t index) 36 | { 37 | // 15 | 22 | 10 | ** | ... 38 | // 3 39 | size_t elementCount = getElementCount(buffer); 40 | assert(index < elementCount); 41 | return buffer->arr[index]; 42 | } 43 | 44 | 45 | int main() 46 | { 47 | Buffer buffer{}; 48 | 49 | for (size_t i = 0; i < getMaxElementCount(&buffer); i++) 50 | { 51 | std::cout << "Enter a number: "; 52 | int input; 53 | std::cin >> input; 54 | 55 | if (input == -1) 56 | { 57 | break; 58 | } 59 | addElement(&buffer, input); 60 | } 61 | 62 | size_t elementCount = getElementCount(&buffer); 63 | for (size_t i = 0; i < elementCount; i++) 64 | { 65 | std::cout 66 | << "arr[" 67 | << i 68 | << "] = " 69 | << getElementAtIndex(&buffer, i) 70 | << std::endl; 71 | } 72 | 73 | return 0; 74 | } -------------------------------------------------------------------------------- /en/09_generic_data_structures/stub.md: -------------------------------------------------------------------------------- 1 | - Maybe do dynamic arrays here, and use `std::vector` previously? 2 | - Queue, stack 3 | - Linked lists 4 | - Hash table (hash function, consecutive buckets on hash collision, chaining, the concept of rehashing) -------------------------------------------------------------------------------- /en/10_sorting/examples/01_selection_sort.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | // (N - 1)(2 + ((N - 1) / 2 - 1) * 3 + 4) 4 | // (N - 1)(2.5 + N/2) 5 | // N^2/2 + ..N + C 6 | // O(N^2) -- execution 7 | // O(1) -- memory 8 | void selectionSort(std::span arr) 9 | { 10 | // N - 1 11 | while (arr.size() > 1) 12 | { 13 | // M ~ (N - 1) / 2 14 | 15 | // 2 16 | size_t indexOfMax = 0; 17 | int max = arr[0]; 18 | 19 | // (M - 1) * 3 20 | for (size_t i = 1; i < arr.size(); i++) 21 | { 22 | // 3 23 | if (arr[i] > max) 24 | { 25 | max = arr[i]; 26 | indexOfMax = i; 27 | } 28 | } 29 | 30 | // 3 31 | int lastElement = arr[arr.size() - 1]; 32 | arr[arr.size() - 1] = max; 33 | arr[indexOfMax] = lastElement; 34 | 35 | // 1 36 | arr = { arr.begin(), arr.size() - 1 }; 37 | } 38 | } 39 | 40 | int main() 41 | { 42 | std::array arr = { 5, 4, 3, 9, 1 }; 43 | selectionSort(arr); 44 | assertSorted(arr); 45 | return 0; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /en/10_sorting/examples/01_selection_sort_pointers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void selectionSort(std::span arr) 6 | { 7 | size_t sortedCount = 0; 8 | 9 | while (true) 10 | { 11 | if (sortedCount + 1 >= arr.size()) 12 | { 13 | return; 14 | } 15 | 16 | int* minElement = &arr[sortedCount]; 17 | int* currentElement = minElement + 1; 18 | 19 | while (true) 20 | { 21 | if (currentElement > &arr.back()) 22 | { 23 | break; 24 | } 25 | 26 | if (*currentElement < *minElement) 27 | { 28 | minElement = currentElement; 29 | } 30 | 31 | currentElement += 1; 32 | } 33 | 34 | { 35 | int t = *minElement; 36 | *minElement = arr[sortedCount]; 37 | arr[sortedCount] = t; 38 | } 39 | 40 | sortedCount += 1; 41 | } 42 | } 43 | 44 | int main() 45 | { 46 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 47 | selectionSort(arr); 48 | 49 | for (int el : arr) 50 | { 51 | std::cout << el << ", "; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /en/10_sorting/examples/01_selection_sort_video.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void selectionSort(std::span arr) 6 | { 7 | size_t currentIndex = 0; 8 | 9 | // 1*c + 2*c + ... + (N-2)*c + (N-1)*c 10 | // c(1 ... N-1) = c(1+(N-1) * (N-1)) = c * N *(N-1) 11 | // N - 1 12 | // O(c N (N-1)) = O(N(N-1)) = O(N*N) = O(N^2) 13 | while (true) 14 | { 15 | if (currentIndex + 1 >= arr.size()) 16 | { 17 | return; 18 | } 19 | 20 | int minElement = arr[currentIndex]; 21 | size_t minIndex = currentIndex; 22 | 23 | // M 24 | // M = N - 1 25 | // M = 1 26 | for (size_t i = currentIndex + 1; i < arr.size(); i++) 27 | { 28 | // constant 29 | if (arr[i] < minElement) 30 | { 31 | minIndex = i; 32 | minElement = arr[i]; 33 | } 34 | } 35 | 36 | arr[minIndex] = arr[currentIndex]; 37 | arr[currentIndex] = minElement; 38 | 39 | currentIndex++; 40 | } 41 | } 42 | 43 | int main() 44 | { 45 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 46 | selectionSort(arr); 47 | 48 | for (int el : arr) 49 | { 50 | std::cout << el << ", "; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /en/10_sorting/examples/02_insertion_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | void insertionSort(std::span arr) 7 | { 8 | size_t sortedArraySize = 0; 9 | while (true) 10 | { 11 | if (sortedArraySize == arr.size()) 12 | { 13 | return; 14 | } 15 | int value = arr[sortedArraySize]; 16 | 17 | size_t i = sortedArraySize; 18 | while (i >= 1) 19 | { 20 | int nextValue = arr[i - 1]; 21 | size_t nextPosition = i; 22 | if (nextValue > value) 23 | { 24 | arr[nextPosition] = nextValue; 25 | } 26 | else 27 | { 28 | break; 29 | } 30 | i--; 31 | } 32 | arr[i] = value; 33 | 34 | sortedArraySize++; 35 | } 36 | } 37 | 38 | int main() 39 | { 40 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 41 | insertionSort(arr); 42 | 43 | for (int el : arr) 44 | { 45 | std::cout << el << ", "; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /en/10_sorting/examples/02_insertion_sort_two_steps.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | void insertionSort(std::span arr) 7 | { 8 | size_t sortedCount = 0; 9 | 10 | while (sortedCount < arr.size()) 11 | { 12 | int addedElement = arr[sortedCount]; 13 | 14 | size_t targetPosition = 0; 15 | for (size_t i = sortedCount; i >= 1; i--) 16 | { 17 | int currentElement = arr[i - 1]; 18 | if (currentElement < addedElement) 19 | { 20 | targetPosition = i; 21 | break; 22 | } 23 | } 24 | 25 | for (size_t newIndex = sortedCount; newIndex > targetPosition; newIndex--) 26 | { 27 | size_t oldIndex = newIndex - 1; 28 | arr[newIndex] = arr[oldIndex]; 29 | } 30 | 31 | arr[targetPosition] = addedElement; 32 | sortedCount += 1; 33 | } 34 | } 35 | 36 | int main() 37 | { 38 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 39 | insertionSort(arr); 40 | 41 | for (int el : arr) 42 | { 43 | std::cout << el << ", "; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /en/10_sorting/examples/03_bubble_sort.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | // (N - 1)(C + N / 2) 4 | // N^2/2 + .. N + C 5 | // O(N^2) -- execution 6 | // O(1) -- memory 7 | void bubbleSort(std::span arr) 8 | { 9 | // N - 1 10 | while (arr.size() > 1) 11 | { 12 | // M = (N - 1) / 2 13 | // M - 1 14 | for (size_t index = 0; index < arr.size() - 1; index++) 15 | { 16 | // 5 17 | int left = arr[index]; 18 | int right = arr[index + 1]; 19 | 20 | if (left > right) 21 | { 22 | arr[index + 1] = left; 23 | arr[index] = right; 24 | } 25 | } 26 | 27 | // 1 28 | arr = { arr.begin(), arr.size() - 1 }; 29 | } 30 | } 31 | 32 | int main() 33 | { 34 | std::array arr = { 5, 4, 3, 9, 1 }; 35 | bubbleSort(arr); 36 | assertSorted(arr); 37 | } -------------------------------------------------------------------------------- /en/10_sorting/examples/03_bubble_sort_recursive.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | // O(N^2) 4 | // 5 | // (N - 1) * 4 = 4N - 4 6 | // O(N) -- memory 7 | void bubbleSort(std::span arr) 8 | { 9 | if (arr.size() <= 1) 10 | { 11 | return; 12 | } 13 | 14 | for (size_t index = 0; index < arr.size() - 1; index++) 15 | { 16 | int left = arr[index]; 17 | int right = arr[index + 1]; 18 | 19 | if (left > right) 20 | { 21 | arr[index + 1] = left; 22 | arr[index] = right; 23 | } 24 | } 25 | 26 | std::span arr1 = { arr.begin(), arr.size() - 1 }; 27 | 28 | bubbleSort(arr1); 29 | } 30 | 31 | int main() 32 | { 33 | std::array arr; 34 | for (size_t i = 0; i < arr.size(); i++) 35 | { 36 | arr[i] = arr.size() - i; 37 | } 38 | 39 | bubbleSort(arr); 40 | assertSorted(arr); 41 | } 42 | -------------------------------------------------------------------------------- /en/10_sorting/examples/04_merge_sort.cpp: -------------------------------------------------------------------------------- 1 | // log_2(N) 2 | 3 | 4 | #include "common.h" 5 | 6 | using MergeResult = std::span; 7 | 8 | MergeResult createMergeResultBuffer(size_t size) 9 | { 10 | int* buffer = new int[size]; 11 | return { buffer, size }; 12 | } 13 | 14 | void deleteMergeResultBuffer(MergeResult buffer) 15 | { 16 | delete[] buffer.data(); 17 | } 18 | 19 | // "log_2(N)" means "how many times N can be divided by 2?" 20 | 21 | // log_2(N) layers, N items processed in each layer. 22 | 23 | // O(log_2(N) * N) = O(N log(N)) -- execution 24 | // O(2N) = O(N) -- memory 25 | MergeResult mergeSort(std::span arr) 26 | { 27 | if (arr.size() == 0) 28 | { 29 | return MergeResult{}; 30 | } 31 | 32 | if (arr.size() == 1) 33 | { 34 | MergeResult result = createMergeResultBuffer(1); 35 | result[0] = arr[0]; 36 | return result; 37 | } 38 | 39 | size_t size = arr.size(); 40 | size_t halfSize = size / 2; 41 | 42 | // 2 * X 43 | // M was N M --> N / 2 log_2(N) = 10 log_2(N / 2) = 9 44 | MergeResult left = mergeSort({ &arr[0], halfSize }); 45 | MergeResult right = mergeSort({ &arr[halfSize], size - halfSize }); 46 | 47 | MergeResult result = createMergeResultBuffer(size); 48 | 49 | size_t leftIndex = 0; 50 | size_t rightIndex = 0; 51 | size_t resultIndex = 0; 52 | // ~N 53 | while (leftIndex < left.size() && rightIndex < right.size()) 54 | { 55 | int leftValue = left[leftIndex]; 56 | int rightValue = right[rightIndex]; 57 | 58 | if (leftValue < rightValue) 59 | { 60 | result[resultIndex] = leftValue; 61 | leftIndex++; 62 | } 63 | else 64 | { 65 | result[resultIndex] = rightValue; 66 | rightIndex++; 67 | } 68 | resultIndex++; 69 | } 70 | while (leftIndex < left.size()) 71 | { 72 | result[resultIndex] = left[leftIndex]; 73 | leftIndex++; 74 | resultIndex++; 75 | } 76 | while (rightIndex < right.size()) 77 | { 78 | result[resultIndex] = right[rightIndex]; 79 | rightIndex++; 80 | resultIndex++; 81 | } 82 | 83 | deleteMergeResultBuffer(left); 84 | deleteMergeResultBuffer(right); 85 | return result; 86 | } 87 | 88 | int main() 89 | { 90 | std::array arr = { 5, 4, 3, 9, 1 }; 91 | MergeResult result = mergeSort(arr); 92 | assertSorted(result); 93 | deleteMergeResultBuffer(result); 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /en/10_sorting/examples/04_merge_sort_video.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void deleteMergeArr(std::span arr) 6 | { 7 | if (arr.size() < 2) 8 | { 9 | return; 10 | } 11 | 12 | delete[] arr.data(); 13 | } 14 | 15 | std::span allocMergeArr(std::span arr) 16 | { 17 | if (arr.size() >= 2) 18 | { 19 | return arr; 20 | } 21 | if (arr.size() == 0) 22 | { 23 | return { (int*) nullptr, 0 }; 24 | } 25 | int* resultPointer = new int[1]{ arr[0] }; 26 | return { resultPointer, 1 }; 27 | } 28 | 29 | std::span mergeSort(std::span arr) 30 | { 31 | if (arr.size() <= 1) 32 | { 33 | return arr; 34 | } 35 | 36 | // Floor 37 | size_t middle = arr.size() / 2; 38 | size_t leftSize = middle; 39 | size_t rightSize = arr.size() - leftSize; 40 | 41 | int* leftStart = arr.data(); 42 | std::span leftArr{ leftStart, leftSize }; 43 | 44 | int* rightStart = arr.data() + leftSize; 45 | std::span rightArr{ rightStart, rightSize }; 46 | 47 | std::span sortedLeftArr = mergeSort(leftArr); 48 | std::span sortedRightArr = mergeSort(rightArr); 49 | 50 | size_t leftIndex = 0; 51 | size_t rightIndex = 0; 52 | size_t resultIndex = 0; 53 | int* resultPointer = new int[arr.size()]; 54 | std::span resultArr{ resultPointer, arr.size() }; 55 | 56 | while (leftIndex < sortedLeftArr.size() 57 | && rightIndex < sortedRightArr.size()) 58 | { 59 | int leftEl = sortedLeftArr[leftIndex]; 60 | int rightEl = sortedRightArr[rightIndex]; 61 | if (leftEl < rightEl) 62 | { 63 | resultArr[resultIndex] = leftEl; 64 | leftIndex++; 65 | resultIndex++; 66 | } 67 | else 68 | { 69 | resultArr[resultIndex] = rightEl; 70 | rightIndex++; 71 | resultIndex++; 72 | } 73 | } 74 | 75 | while (leftIndex < sortedLeftArr.size()) 76 | { 77 | resultArr[resultIndex] = sortedLeftArr[leftIndex]; 78 | leftIndex++; 79 | resultIndex++; 80 | } 81 | 82 | while (rightIndex < sortedRightArr.size()) 83 | { 84 | resultArr[resultIndex] = sortedRightArr[rightIndex]; 85 | rightIndex++; 86 | resultIndex++; 87 | } 88 | 89 | deleteMergeArr(sortedLeftArr); 90 | deleteMergeArr(sortedRightArr); 91 | 92 | return resultArr; 93 | } 94 | 95 | int main() 96 | { 97 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 98 | std::span sortedArray = mergeSort(arr); 99 | 100 | for (int el : sortedArray) 101 | { 102 | std::cout << el << ", "; 103 | } 104 | 105 | deleteMergeArr(sortedArray); 106 | } 107 | -------------------------------------------------------------------------------- /en/10_sorting/examples/05_quick_sort.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | // O(N log(N)) -- execution 4 | // O(log N) -- memory 5 | void quickSort(std::span arr) 6 | { 7 | if (arr.size() <= 1) 8 | return; 9 | 10 | size_t pivotIndex = 0; 11 | int pivotValue = arr[pivotIndex]; 12 | size_t lessThanCounter = 0; 13 | for (size_t i = 1; i < arr.size(); i++) 14 | { 15 | if (arr[i] >= pivotValue) 16 | continue; 17 | 18 | lessThanCounter++; 19 | 20 | int lesserValue = arr[i]; 21 | int otherValue = arr[lessThanCounter]; 22 | 23 | arr[i] = otherValue; 24 | arr[lessThanCounter] = lesserValue; 25 | } 26 | 27 | arr[pivotIndex] = arr[lessThanCounter]; 28 | arr[lessThanCounter] = pivotValue; 29 | 30 | { 31 | int* leftStart = arr.data(); // &arr[0] 32 | size_t leftLength = lessThanCounter; 33 | quickSort({ leftStart, leftLength }); 34 | } 35 | { 36 | size_t rightStartIndex = lessThanCounter + 1; 37 | int* rightStart = &arr[rightStartIndex]; 38 | size_t rightLength = arr.size() - rightStartIndex; 39 | quickSort({ rightStart, rightLength }); 40 | } 41 | } 42 | 43 | int main() 44 | { 45 | std::array arr = { 5, 4, 3, 9, 1, 10, 1, 8, 12 }; 46 | quickSort(arr); 47 | assertSorted(arr); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /en/10_sorting/examples/05_quick_sort_video.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void quickSort(std::span arr) 6 | { 7 | if (arr.size() <= 1) 8 | { 9 | return; 10 | } 11 | 12 | size_t pivotIndex = 0; 13 | size_t smallerThanPivotIndex = pivotIndex + 1; // a 14 | size_t currentIndex = smallerThanPivotIndex; // b 15 | int pivot = arr[pivotIndex]; 16 | 17 | while (true) 18 | { 19 | int currentElement = arr[currentIndex]; 20 | if (currentElement < pivot) 21 | { 22 | int a = arr[smallerThanPivotIndex]; 23 | arr[smallerThanPivotIndex] = currentElement; 24 | arr[currentIndex] = a; 25 | smallerThanPivotIndex++; 26 | } 27 | currentIndex++; 28 | 29 | if (currentIndex == arr.size()) 30 | { 31 | break; 32 | } 33 | } 34 | 35 | { 36 | int a = arr[smallerThanPivotIndex - 1]; 37 | arr[smallerThanPivotIndex - 1] = arr[pivotIndex]; 38 | arr[pivotIndex] = a; 39 | } 40 | 41 | std::span left{ arr.data(), smallerThanPivotIndex - 1 }; 42 | std::span right{ &arr[smallerThanPivotIndex], arr.size() - smallerThanPivotIndex }; 43 | 44 | quickSort(left); 45 | quickSort(right); 46 | } 47 | 48 | int main() 49 | { 50 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 51 | quickSort(arr); 52 | 53 | for (int el : arr) 54 | { 55 | std::cout << el << ", "; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /en/10_sorting/examples/06_heap_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void heapify(std::span arr, size_t parentIndex) 6 | { 7 | while (true) 8 | { 9 | size_t leftIndex = parentIndex * 2 + 1; 10 | size_t rightIndex = parentIndex * 2 + 2; 11 | size_t indexOfLargest = parentIndex; 12 | 13 | if (leftIndex < arr.size()) 14 | { 15 | int largest = arr[indexOfLargest]; 16 | int left = arr[leftIndex]; 17 | if (largest < left) 18 | { 19 | indexOfLargest = leftIndex; 20 | } 21 | } 22 | 23 | if (rightIndex < arr.size()) 24 | { 25 | int largest = arr[indexOfLargest]; 26 | int right = arr[rightIndex]; 27 | if (largest < right) 28 | { 29 | indexOfLargest = rightIndex; 30 | } 31 | } 32 | 33 | if (indexOfLargest == parentIndex) 34 | { 35 | return; 36 | } 37 | 38 | { 39 | int largest = arr[indexOfLargest]; 40 | arr[indexOfLargest] = arr[parentIndex]; 41 | arr[parentIndex] = largest; 42 | 43 | parentIndex = indexOfLargest; 44 | } 45 | } 46 | } 47 | 48 | void heapSort(std::span arr) 49 | { 50 | for (size_t i = (arr.size() / 2) + 1; i >= 1; i--) 51 | { 52 | heapify(arr, i - 1); 53 | } 54 | 55 | for (size_t i = 0; i < arr.size(); i++) 56 | { 57 | int root = arr[0]; 58 | size_t currentLast = arr.size() - i - 1; 59 | 60 | arr[0] = arr[currentLast]; 61 | arr[currentLast] = root; 62 | 63 | size_t newLen = currentLast; 64 | std::span heapArr{ arr.data(), newLen }; 65 | 66 | heapify(heapArr, 0); 67 | } 68 | } 69 | 70 | int main() 71 | { 72 | std::array arr{11, 5, 8, 15, 21, 32, 1, 7}; 73 | heapSort(arr); 74 | 75 | for (int el : arr) 76 | { 77 | std::cout << el << ", "; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /en/10_sorting/examples/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static void assertSorted(std::span arr) 6 | { 7 | for (size_t i = 1; i < arr.size(); i++) 8 | { 9 | assert(arr[i - 1] <= arr[i]); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /en/10_sorting/examples/merge_sort_complexity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/en/10_sorting/examples/merge_sort_complexity.png -------------------------------------------------------------------------------- /en/10_sorting/examples/readme.md: -------------------------------------------------------------------------------- 1 | Game with the cards used to demo sorting is called **Balatro**. -------------------------------------------------------------------------------- /en/10_sorting/stub.md: -------------------------------------------------------------------------------- 1 | - Bubble 2 | - Insertion 3 | - Selection 4 | - Merge 5 | - Quick 6 | - Heap 7 | - Radix (for those who are interested) 8 | - Shell (this was on the exam, so I assume it's needed?) -------------------------------------------------------------------------------- /en/11_multidimensional_arrays/stub.md: -------------------------------------------------------------------------------- 1 | - Illife 2 | - Dope vector 3 | - The problem of multilevel iteration without nesting for loops (I have come across this problem like 3 times in my career) -------------------------------------------------------------------------------- /ru/labs/algoritms/01_git.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа №1 2 | 3 | > См. [видео](https://youtu.be/OgsTtVSwJUk) 4 | 5 | 1. Создайте аккаунт гитхаб (если еще нет) 6 | 2. Создайте репозиторий для лабораторных работ 7 | 3. Попробуте работать с гитхабом с локальной копии: 8 | - Общее понимание идей (локальная копия, remote, commit, repository, push); 9 | - Создайте файл с Hello World программой в C++, добавьте его коммитом, синхронизируйте remote с локальной копией. 10 | - Конфигурируйте авторизацию для своей машины при первом push-e на remote (либо через токен, либо через браузерную авторизацию) 11 | 4. Дополнительно: pull request, branch, gitignore 12 | -------------------------------------------------------------------------------- /ru/labs/algoritms/03_linked_lists.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 3 2 | 3 | Тема: **Связные списки** 4 | 5 | ## Linked lists (связные списки) 6 | 7 | Распишите код для следующих структур данных. 8 | 9 | > Можете выделять память динамически в heap используя `new` или `malloc`, отдельно для каждого нода. 10 | > Можете пользоваться [примерами](../../../en/09_generic_data_structures). 11 | 12 | Можете использовать `template`. 13 | 14 | 1. Singly linked list (односвязный список): 15 | - Структура должна иметь поля под указатели на первый и последний нод списка; 16 | 17 | - `Node* insertAfter(LinkedList* list, Node* node, int value)` создает новый нод 18 | и добавляет его после данного нода. 19 | В случае если `node == nullptr`, нод добавляется в начало списка. 20 | Возвращает указатель на созданный нод; 21 | 22 | - `FindNodeResult find(LinkedList* list, int value)` ищет нод до нода с заданным значением в списке; 23 | Возвращает нод с этим значением, а также нод до него. 24 | `FindNodeResult` определите сами. 25 | 26 | Если используете `template`, можете добавить еще один параметр и передавать функтор поиска; 27 | 28 | - `void removeAfter(LinkedList* list, Node* node)` удаляет нод следующий данному ноду из списка. 29 | В случае если `node == nullptr`, удаляется первый нод списка; 30 | 31 | - `void assertNoCycles(LinkedList* list)`, который проверяет, чтобы в списке не было циклов. 32 | Используйте эту функцию для проверки логики, можете делать `assert` в других функциях что это 33 | условие выполняется (называется `contract`). 34 | Этот метод довольно сложно реализовать без дополнительной информации в структуре, 35 | поэтому рекомендую также хранить текущее количество нодов в списке в `LinkedList` структуре. 36 | В этой функции просто пытайтесть посчитать длину заного, и если она становится больше реальной длины, 37 | у вас где-то цикл. 38 | 39 | 2. Doubly linked list (двусвязный список): 40 | - Структура должна иметь поля под указатели на первый и последний нод списка; 41 | 42 | - `Node* insertAfter(LinkedList* list, Node* node, int value)`; 43 | 44 | - `Node* insertBefore(LinkedList* list, Node* node, int value)`; 45 | 46 | - `Node* find(LinkedList* list, int value)` ищет нод с данным значением в списке 47 | (применяются заметки для `find` выше); 48 | 49 | - `void remove(LinkedList* list, Node* node)` удаляет нод из списка; 50 | 51 | - `void assertNoCycles(LinkedList* list)`. 52 | Тут подойдет либо подход с длиной, либо можете сделать это 53 | путем проверки взаимосвязей во всех нодах, и проверки концов, поскольку из 54 | одного нода может отходить максимум 2 связи. 55 | 56 | Распишите функции теста для каждой из функций, вызывайте их в `main`. 57 | 58 | -------------------------------------------------------------------------------- /ru/labs/algoritms/04_graphs.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 4 2 | 3 | ## Графы (Graphs) как структура данных 4 | 5 | Используйте идею связных списков, чтобы реализовать графы. 6 | Графы -- это списки, где каждый нод может иметь несколько соседних нодов. 7 | 8 | Пример графа есть [здесь](../../../en/09_generic_data_structures/graph.cpp). 9 | 10 | 1. Определите структуру нода из графа. 11 | Она должны иметь поле `int` для значения нода, а также динамический буфер для соседних нодов. 12 | Можете использовать код из [static_buffer](../../../en/09_generic_data_structures/static_buffer.cpp) 13 | или [dynamic_array](../../../en/09_generic_data_structures/dynamic_array.cpp). 14 | > Можете использовать `std::vector`, но тогда убедитесь, что понимаете RAII. 15 | 16 | 17 | 2. Выполните одну из конфигураций графа: 18 | 19 | ```mermaid 20 | flowchart LR 21 | A(1) --> B(2) 22 | A --> C(3) 23 | A --> D(4) 24 | B --> C 25 | C --> D 26 | D --> A 27 | ``` 28 | 29 | ```mermaid 30 | flowchart LR 31 | A(1) --> B(2) 32 | B --> C(3) 33 | C --> D(4) 34 | D --> A 35 | D <--> B 36 | ``` 37 | 38 | 3. В направленных графах, нод `A` может быть соседом для нода `B`, 39 | при том что нод `B` на обязательно является соседом нода `A`. 40 | Для ненаправленных графов, ноды `A` и `B` всегда являются соседями друг друга. 41 | Объясните как эта идея отобразится в том, как граф будет выглядеть в памяти. 42 | 43 | 4. Напишите функцию, которая считает сумму значений соседних нодов заданного нода. 44 | 45 | 5. Выполните алгоритмы прохода DFS и BFS. Можете добавить дополнительную информацию в сами ноды. 46 | -------------------------------------------------------------------------------- /ru/labs/algoritms/05_stack_queue.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 5 2 | 3 | Тема: **Stack & Queue** 4 | 5 | ## Стек (stack) 6 | 7 | Выполните код для стека. 8 | 9 | Стек может быть основан на динамическом массиве (`std::vector`, или своя реализация) или связном списке. 10 | Сделайте оба варианта. 11 | 12 | Если никогда не делали сами динамический массив, рекомендую сделать и это. 13 | Пример есть [здесь](../../../en/09_generic_data_structures/dynamic_array.cpp). 14 | 15 | Стек отличается следующими операциями: 16 | - `bool isEmpty(const Stack* stack)` проверяет если стек пустой; 17 | - `void push(Stack* stack, int value)` добавляет поверх элементов стека; 18 | - `int* getLastElement(Stack* stack)` (можете назвать как вам логичнее) дает адрес (или ссылку) элемента сверху, не удаляя его; 19 | - `void pop(Stack* stack)` удаяет элемент сверху (последний добавленный). 20 | 21 | Пример есть [здесь](../../../en/09_generic_data_structures/stack.cpp). 22 | Пример немного отличается от требований, поскольку в примере стек фиксированного максимального размера. 23 | 24 | 25 | ## Очередь (queue) 26 | 27 | Выполните код для очереди. 28 | 29 | Бесконечную очередь можно сделать довольно просто используя связной список, удаляя сначала, и добавляя в конец. 30 | Очередь фиксированного размера можно сделать через ring buffer, 31 | через динамический ring buffer ее можно тоже сделать бесконечной 32 | (тут можно придумать креативные подходы по расширению буфера) 33 | 34 | Сделайте как минимум один из подходов (проще всего через список). 35 | 36 | Очередь отличается следующими операциями: 37 | - `bool isEmpty(const Queue* queue)` проверяет если очередь пустая; 38 | - `void enqueue(Queue* queue, int value)` добавляет элемент **в конец** очереди; 39 | - `int* front(Queue* queue)` дает адрес (или ссылку) **первого** элемента из очереди; 40 | - `void dequeue(Queue* queue)` удаляет элемент **с начала** очереди. 41 | 42 | Пример есть [здесь](../../../en/09_generic_data_structures/queue.cpp). 43 | Но это по факту связный список с дополнительными функциями / другими именами функций, 44 | в своей базовой имплементации. 45 | 46 | -------------------------------------------------------------------------------- /ru/labs/algoritms/07_sorting_algorithms.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 7 2 | 3 | Тема: **Алгоритмы сортировки.** 4 | 5 | ## Реализация алгоритмов 6 | 7 | Реализуйте 4 алгоритма сортировки: 8 | - 2 со сложностью $` O(N^2) `$ (Bubble, Insertion, Selection, Shell). 9 | - 2 со сложностью $` O(N log(N)) `$ (Heap, Merge, Quick). 10 | - Можете также реализовать Radix Sort, этот алгоритм в некотором смысле особенный. 11 | 12 | Алгоритм должен быть сделан в виде функции, принимающей параметром `std::span`, 13 | а также любой другой контекст, необходимый для 14 | сортировки (например, функция сравнения элементов). 15 | Функция должна возвращать либо `void`, когда сортировка присходит in-place, 16 | либо отсортированную копию массива, когда не in-place (merge sort), 17 | в котором случае память входного `std::span` не должна быть изменена. 18 | Разрешается засунуть параметры в единую структуру контекста, если считаете это необходимым. 19 | 20 | ## Сбор данных для анализа 21 | 22 | Аналогично 2 лабе, запустите алгоритмы для: 23 | - Разных размерностей массива (большой массив это 1000+ элементов); 24 | - Разных изначальных конфигураций расположения элементов в массиве. 25 | 26 | Сохраняйте как результат выполнения алгоритмов: 27 | - Затраченное время на выполнение; 28 | - Количество совершенных проверок между двумя элементами; 29 | - Количество совершенных swap-ов или копирований; 30 | - Другие данные, как считаете нужным. 31 | 32 | Подсчитывайте общее и среднее время выполнения алгоритмов. 33 | 34 | ## Анализ полученных данных 35 | 36 | Проведите анализ полученных данных: 37 | - Сравните, как время выполнения и прочее зависит от входных данных 38 | (алгоритм, размерность массива, расположение элементов). 39 | - Выведите практическую сложность времени выполнения и затраченной памяти алгоритмов 40 | (как увеличивается время выполнения в зависимости от размерности массива). 41 | - Выведите теоретическую сложность времени выполнения и затраченной памяти выполненных алгоритмов, 42 | или исходя из описания алгоритма, или исходя из написанного кода. 43 | - Объясните, какие плюсы и минусы алгоритмов со сложностью выполнения $` O(N log(N)) `$ между собой. 44 | Как подход к проблеме влияет на наилучшее и наихудшее время выполнения (зависит от расположения элементов?). 45 | 46 | -------------------------------------------------------------------------------- /ru/labs/common/01_computer_architecture.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 1 2 | 3 | Тема: **Архитектура компьютера**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=yLDtNDtAvUE&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=1) 6 | 7 | ## Вопросы, которые необходимо изучить 8 | 9 | - Что такое процессор 10 | - Что такое память 11 | - Отличие общей памяти (RAM) от памяти процессора (регистры) 12 | - Что такое инструкция 13 | - Почему инструкциям необходим идентификатор 14 | - Что такое машинный код 15 | - Что такое адрес памяти 16 | - Что такое байт 17 | -------------------------------------------------------------------------------- /ru/labs/common/02_number_systems.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 2 2 | 3 | Тема: **Системы счисления**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=h4jq2BBiLSI&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=2) 6 | 7 | ## Примеры 8 | 9 | 1. Сложить 1231234 и 3311224 (не переводя в 10-чную систему). 10 | 2. Сложить 1100112 и 1110112 (не переводя в 10-чную систему). 11 | 3. Умножить 657 и 337 (не переводя в 10-чную систему). 12 | 3. Умножить 10111102 на 10112 (не переводя в 10-чную систему). 13 | 1. Конвертировать 110100112 в 10-чную систему. 14 | 2. Конвертировать 98510 в двоичную. 15 | 2. Конвертировать 2213 в двоичную (не переводя в 10-чную, записав коефициенты и позиции в двоичной и перемножив). 16 | 17 | -------------------------------------------------------------------------------- /ru/labs/common/03_numbers.md: -------------------------------------------------------------------------------- 1 | да# Лаборатоная работа 3 2 | 3 | Тема: **Как числа хранятся в байтах**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=3HnvK8WrK4M&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=3) 6 | 7 | ## Вопросы 8 | 9 | - Объясните как вывести максимальное число, которое можно хранить в одном байте. В двух? 10 | - Почему это максимальное число равно количеству комбинаций цифр в позициях - 1? 11 | - Если дано число `x` (например, `0000 0011`), что нужно сделать, чтобы получить его отрицательную версию 12 | (в системе two's complement)? Выведете формулу / алгоритм (`1111 1101`). 13 | - Когда $`a + b < a`$, где и $`a`$ и $`b`$ положительные (`a` и `b` на 8 бит)? 14 | - Какие цифры есть в 16-чной системе? 15 | - Как перевести `0101 1111` в 16-чную систему? 16 | - В каких еще системах счисления можно записать 8 бит, не делая вычислений? 17 | >
18 | > подсказка 19 | > 20 | > Группы бит по X = одна цифра в той системе. 21 | >
22 | > 23 | >
24 | > подсказка 2 25 | > 26 | > В 16-чной системе счисления, X = 4. 27 | >
28 | > 29 | >
30 | > подсказка 3 31 | > 32 | > Группируя по 2 бита за раз, получим `01 01 11 11`. 33 | > Каждое из этих значений можно записать одним символом в системе счисления, 34 | > где количество цифр = количество чисел в 2 битах. 35 | > В 2 битах могут быть 4 числа (`00`, `01`, `10`, `11`). 36 | > То есть, можем использовать 4-чную систему: `01 01 11 11 -> 1 1 3 3 -> 1133`) 37 | >
38 | > 39 | >
40 | > вопрос 41 | > 42 | > Почему система должная быть степенью двойки? 43 | >
44 | 45 | -------------------------------------------------------------------------------- /ru/labs/common/04_algorithm.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 4 2 | 3 | Тема: **Алгоритм (на высоком уровне)**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=C6plSGSYuyc&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=4) 6 | 7 | ## Концепты 8 | 9 | - Параметр, Аргумент 10 | - Имплементация (реализация) 11 | - Интерфейс 12 | - Input / Output 13 | - Индекс 14 | - Sentinel 15 | - Переменная, значение переменной 16 | 17 | ## Практические навыки 18 | 19 | - Как подходить к решению сложных задач? 20 | >
21 | > Наводящий вопрос 22 | > 23 | > Например, если дали задание "приготовить комплексный обед", как приступить к его выполнению? 24 | >
25 | > 26 | >
27 | > Подсказка 1 28 | > 29 | > "Приготовить комплексный обед" -- сложное задание, состоящее из высокоуровневых подзаданий: 30 | > приготовить первое, приготовить второе. 31 | >
32 | > 33 | >
34 | > Подсказка 2 35 | > 36 | > Проводим анализ: что нужно для первого, что для второго. 37 | > Выбираем что именно будем говорить. Выявляем необходимые ингредиенты, посуду. 38 | >
39 | > 40 | >
41 | > Подсказка 3 42 | > 43 | > Подготавливаем ингредиенты и посуду. Готовим блюда по шагам, описанным в рецепте. 44 | >
45 | > 46 | >
47 | > Ответ 48 | > 49 | > Производим анализ комплексной задачи. 50 | > Разбиваем ее на крупные, высокоуровневые подзадачи. 51 | > Проводим анализ подзадач. 52 | > Разбиваем их на более мелкие подзадачи. 53 | > Продолжаем до тех пор, пока не доходим до элементарных задач, которые больше невозможно разбить, 54 | > или которые уже являются решенными (будь то, находим рецепт со всеми шагами в интернете). 55 | >
56 | 57 | - Как список из чисел записать в линейной памяти? 58 | 59 | - Что нужно сделать, чтобы пройтись по всем элементам списка? Посчитать сумму элементов списка? 60 | >
61 | > Ответ 62 | > 63 | > В таком случае всегда нужна переменная (ячейка памяти), которая следит за "текущим" значением. 64 | > Будь то индекс, текущая сумма, или множество посещенных вершин графа -- всегда будет нужна переменная. 65 | >
66 | 67 | - Приведите пример алгоритма, который ссылается на другой алгоритм при своем выполнении. 68 | 69 | ## Практика 70 | 71 | - Выведите алгоритм решения следующей задачи: "Дано 2 списка с равным количеством чисел. Вычислите попарную сумму элементов из этих списков (первый элемент из первого списка, первый из второго; второй элемент из первого списка, второй из второго; ...)" 72 | 73 | 74 | -------------------------------------------------------------------------------- /ru/labs/common/05_function_execution.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 5 2 | 3 | Тема: **Что такое функции, вызов функций, stack**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=jTRJM_gmhU4&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=5) 6 | 7 | ## Концепты 8 | 9 | - Выполнимый файл (executable) 10 | - Функция 11 | - Адрес инструкции, Instruction Pointer 12 | - Stack, Stack Pointer 13 | - Адрес возврата 14 | - Выход из функции 15 | - Возврат значения из функции 16 | - Локальная переменная 17 | 18 | ## Анализ 1 19 | 20 | **Возможно ли (технически) перезаписать локальную переменную из другой функции?** 21 | 22 | Объясните код ниже (код начинает выполняться с функции `main`). 23 | Этот код не скомпилируется как есть, проанализируйте его на концептуальном уровне. 24 | `sp` означает stack pointer. 25 | Предположите, что локальные переменные хранятся на стеке, и что адрес возврата занимает 4 байта. 26 | Чему будет равен `x` и почему? 27 | 28 | ```c 29 | void f() 30 | { 31 | *(sp - 8) = 1; 32 | return; 33 | } 34 | 35 | void main() 36 | { 37 | int x; 38 | x = 0; 39 | f(); 40 | return; // x = ? 41 | } 42 | ``` 43 | 44 |
45 | Ответ 46 | Стек будет выглядеть следующим образом. 47 | 48 | 1. До строки с вызовом `f();` 49 | 50 | | sp - 4 | sp | 51 | | ----- | -- | 52 | | x (0) | ?? | 53 | 54 | 2. На первой строке `f`: 55 | 56 | | sp - 8 | sp - 4 | sp | 57 | | ----- | ------ | -- | 58 | | x (0) | адрес возврата к `return;` из `g` | ?? | 59 | 60 | 3. На `return;` из `f` 61 | 62 | | sp - 8 | sp - 4 | sp | 63 | | ----- | ------ | -- | 64 | | x (1) | адрес возврата к `return;` из `g` | ?? | 65 | 66 | 4. На `return;` из `g` 67 | 68 | | sp - 4 | sp | 69 | | ----- | ------ | 70 | | x (1) | адрес возврата к `return;` из `g` | 71 | 72 | `sp - 8` при выполнении `f` ссылается на адрес локальной переменной `x` из `g`. 73 |
74 | 75 | Если предположить, что при попытке возврата на адрес инструкции 0, программа крашится (завершается с ошибкой), 76 | как заставить программу выше крашнуться, сменив 1 символ в коде? 77 | 78 |
79 | Ответ 80 | `sp - 8 --> sp - 4`, что равно адресу адреса возврата. 81 | Таким образом, сможете перезаписать адрес возврата на 0. 82 | При попытке возврата по этому адресу, программа крашнется. 83 |
84 | 85 | 86 | > Подобное явление - это частая ошибка в C, особенно при работе с массивами. 87 | > Оно также носит имя *stack corruption*. 88 | > Компилятор иногда вставляет в стек защиту от этого в режиме debugging, 89 | > что помогает найти подобные ошибки (погуглите если интересно). 90 | 91 | 92 | ## Анализ 2 93 | 94 | **Бесконечная рекурсия** 95 | 96 | > Код начинает выполняться с функции `main`. 97 | 98 | Объясните что сделает программа ниже: 99 | 100 | ``` 101 | void f() 102 | { 103 | f(); 104 | return; 105 | } 106 | int main() 107 | { 108 | f(); 109 | return 0; 110 | } 111 | ``` 112 | 113 | > При попытке сдвига `sp` за пределы стека (за пределы максимального адреса, выделенного под стек), 114 | > случается stack overflow. И программа обычно крашится. 115 | -------------------------------------------------------------------------------- /ru/labs/common/06_compiler_install.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 6 2 | 3 | Тема: **Установка компилятор**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=80rlPY4qFxM&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=6) 6 | 7 | ## Задания 8 | 9 | - Установите msys2 + GCC / WSL + GCC / Zig. 10 | - Запустите компилятор (`g++`) через консоль. 11 | - С успехом скомпилируйте исходный файл. 12 | - Запустите полученный выполнимый файл. 13 | - Настройте PATH чтобы `g++` можно было вызывать без указания полного пути. 14 | - Используйте флаг `-o` чтобы указать файл вывода. 15 | -------------------------------------------------------------------------------- /ru/labs/common/07_git.md: -------------------------------------------------------------------------------- 1 | # Лаборатоная работа 7 2 | 3 | Тема: **Установка компилятор**. 4 | 5 | [Сопровождающее видео](https://www.youtube.com/watch?v=OgsTtVSwJUk&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=7) 6 | 7 | ## Концепты 8 | 9 | - git репозиторий 10 | - staging area (`git add`) 11 | - commit, commit hash, commit log (commit history) 12 | - branch 13 | - checkout 14 | - remote 15 | - Папка .git 16 | - Файл .gitignore 17 | - `git config` vs `git config --global` 18 | - rebase, merge 19 | - PR (Pull Request) 20 | - `git push`, `git pull` 21 | 22 | ## Вопросы 23 | 24 | - Как получить копию git репозитория из GitHub со всей историей на другом компьютере? 25 | >
26 | > Ответ 27 | > 28 | > Вы могли бы создать новый репозиторий на другом компьютере, привязать его к remote на GitHub, сделать `git pull`. 29 | > Еще можно сразу через `git clone`, который также сам найдет нужную основную ветку. 30 | >
31 | 32 | - Как сделать Pull Request используя git (не GitHub)? 33 | >
34 | > Ответ 35 | > Никак. Понятие Pull Request не существует в git. 36 | >
37 | 38 | - Вы создали branch для фичи1, на основе основной ветки. Поработали над ней. 39 | Теперь создали branch для фичи2, тоже на основе основной ветки. Поработали над ней. 40 | Сделали PR и влили фича1 в основную ветку. Притянули основную ветку локльно через `git pull`. 41 | Как теперь правильно влить фича2 в основную ветку? 42 | >
43 | > Ответ 44 | > Вы можете открыть PR напрямую из фича2 в основую ветку. Если конфликтов нет, PR сработает. 45 | > 46 | > Если конфликты есть, лучше всего сделать `git rebase master` будучи на ветке фича2, 47 | > разрешить конфликты локально, исправляя файлы в которых они возникли, 48 | > и использую команду `git rebase --continue` после исправления. 49 | > 50 | > После этого обновите ветку, сохраненную на GitHub, используя `git push --force` или `git push --force-with-lease` 51 | > (`--force` нужен, потому что rebase перезаписывает порядок коммитов в этой ветке). 52 | > PR обновится сам, и уже не покажет конфликтов (PR идет всегда относительно текущего состояния ветки, а не изначального). 53 | >
54 | -------------------------------------------------------------------------------- /ru/labs/cpp/01_basics.md: -------------------------------------------------------------------------------- 1 | # 1. Базовый синтаксис переменных и поинтеров 2 | 3 | Сопровождающее [видео](https://www.youtube.com/watch?v=9AhNOjjyAwU&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=8). 4 | 5 | Используя инфу из папки `05_programming_fundamentals`, файл `doc.md`, 6 | и ориентируясь по примеру `memory_example_1` из той же папки, реализуйте следующие задания: 7 | 8 | 1. Объявить i типа инт 9 | 2. Инициализировать на 69 10 | 3. Определить переменную number типа инт, дать значение 72 11 | 4. Перезаписать значение i на 69 + 72 (т.е. i + number) 12 | 5. Определить группу переменных (массив) из 3 элементов (инициализированных на 0) 13 | 6. Создать указатель на i (iPointer) 14 | 7. Считать данные по адресу из указателя в переменную number 15 | 8. Вписать в i через указатель значение 15 16 | 9. Сменить адрес в iPointer на адрес первого элемента массива 17 | 10. Переместиться на третий элемент массива, используя pointer arithmetic 18 | 11. Вписать в первый элемент массива напрямую, и в третий через iPointer, значения 5 и 6 19 | 20 | -------------------------------------------------------------------------------- /ru/labs/cpp/02_struct.md: -------------------------------------------------------------------------------- 1 | # 2. Структуры 2 | 3 | Сопровождающее [видео](https://www.youtube.com/watch?v=9AhNOjjyAwU&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=8&t=2457). 4 | 5 | Объяните словами что происходит в примере [`memory_example_2`](../../../en/05_programming_fundamentals/memory_example_2). 6 | Можете скопировать файл с кодом и написать комментариями прямо в коде, что происходит. 7 | Используйте excel таблицу из примера, чтобы визуализировать планировку памяти. 8 | 9 | Можете в целом комментировать не каждый шаг, а что выведеться на каждом этапе, и почему 10 | (на что указывает в момент времени тот или иной указатель, что на данный момент записано в памяти, т.п.). 11 | Можете также использовать дебаггер для лучшего понимания. 12 | 13 | -------------------------------------------------------------------------------- /ru/labs/cpp/03_object.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 3 2 | 3 | Тема: *Объекты*. 4 | 5 | Сопровождающее [видео](https://www.youtube.com/watch?v=8xXxJ0PZutE&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=9). 6 | 7 | ## Задания 8 | 9 | Какие тут типы, и какие тут объекты? перечислите все. 10 | 11 | ```cpp 12 | struct Leg 13 | { 14 | int length; 15 | }; 16 | 17 | struct Arm 18 | { 19 | int power; 20 | }; 21 | 22 | struct Person 23 | { 24 | std::array legs; 25 | Arm arms[2]; 26 | }; 27 | 28 | int main() 29 | { 30 | Person person; 31 | } 32 | ``` 33 | 34 |
35 | Подсказка (объект) 1 36 | Объект - это кусок памяти конкретного типа. 37 |
38 | 39 |
40 | Подсказка (объект) 2 41 | Объект может быть любого типа. 42 |
43 | 44 |
45 | Подсказка (поля) 1 46 | 47 | Вспомните синтаксис объявления полей в структурах. 48 |
49 | 50 |
51 | Подсказка (поля) 2 52 | 53 | Синтаксис объявления полей похож на синтаксис объявления переменных. 54 | ``` 55 | тип имя; 56 | ``` 57 |
58 | 59 |
60 | Подсказка (тип) 1 61 | Структура - это пользовательский тип. 62 |
63 | 64 |
65 | Подсказка (тип) 2 66 | 67 | Типы имеют имя. 68 | Имя типа - это не обязательно один идентификатор (слово), тип может иметь и более сложное имя. 69 | 70 | Например, `std::vector` - это все тоже имя типа. 71 |
72 | 73 |
74 | Подсказка (поля) 3 75 | 76 | Определения полей это не объекты. 77 | 78 | Поля могут быть объектами только внутри уже имеющегося другого объекта. 79 | Тип этого другого объекта должен быть тем, внутри которого объявлено поле (пользовательский тип). 80 | 81 | Стандартные типы (такие как `int`) не содержат полей. 82 | Только пользовательские типы (структуры) могут объявлять поля. 83 |
84 | 85 |
86 | Подсказка (массив) 1 87 | Массивы хранят в себе несколько объектов. 88 |
89 | 90 |
91 | Подсказка (массив) 2 92 | C массивы не являются объектами в обыкновенном смысле слова. 93 | У них есть странности. 94 |
95 | 96 | -------------------------------------------------------------------------------- /ru/labs/cpp/04_bool.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 4 2 | 3 | Тема: `bool`, flow control. 4 | 5 | Сопровождающие видео: 6 | - [`bool`, flow control](https://www.youtube.com/watch?v=21m4VfonFnA&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=10) 7 | - [span](https://www.youtube.com/watch?v=3aXFuiHxb9k&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=11) (до строк) 8 | 9 | ## Рефакторинг 10 | 11 | Зарефакторьте этот код, используя guard clause / early return. 12 | 13 | ```cpp 14 | #include 15 | 16 | int main() 17 | { 18 | int number = 10; 19 | 20 | if (number == 5) 21 | { 22 | std::cout << "The number is 5" << std::endl; 23 | } 24 | else 25 | { 26 | std::cout << "The number is not 5" << std::endl; 27 | 28 | if (number % 2 == 1) 29 | { 30 | std::cout << "The number is not divisible by 2" << std::endl; 31 | } 32 | else 33 | { 34 | std::cout << "The number is divisible by 2" << std::endl; 35 | 36 | if (number == 6) 37 | { 38 | std::cout << "The number is 6" << std::endl; 39 | } 40 | } 41 | } 42 | } 43 | ``` 44 | 45 | ## Сложное логическое выражение 46 | 47 | Дан базовый код: 48 | 49 | ```cpp 50 | #include 51 | 52 | void main() 53 | { 54 | int apples; 55 | int pears; 56 | int oranges; 57 | 58 | std::cout << "Apples:"; 59 | std::cin >> apples; 60 | 61 | std::cout << "Pears:"; 62 | std::cin >> pears; 63 | 64 | std::cout << "Oranges:"; 65 | std::cin >> oranges; 66 | 67 | // ... 68 | } 69 | ``` 70 | 71 | 1. Если количество яблок больше 5, количество груш меньше 8 72 | и количество апельсинов ровно в 2 раза больше чем количество яблок, 73 | напечатайте на экран "Hello". 74 | 75 | 2. Сделайте временную переменную с результатом выражения. 76 | Проверяйте ее в if. 77 | 78 | 3. Сделайте по временной переменной для каждого из подусловий. 79 | Вычисляйте общее условие, используя эти подусловия. 80 | 81 | 4. Объявите временные переменные подусловий в блоке, 82 | чтобы эти переменные не были видны за пределами блока. 83 | Используйте внешнее условие вне блока (блок существует для инициализации общего условия). 84 | 85 | Разрешается так же из этого блока сделать функцию. 86 | 87 | 5. Зарефакторьте 3 переменные с количеством фруктов в одну структуру (`FruitCounts`) 88 | с 3 полями, по одному для каждого типа фруктов. 89 | Переделайте код, чтобы везде использовалась эта структура. 90 | 91 | 92 | ## Цикл 93 | 94 | - Сделайте функцию которая попарно перемножает числа из 2 массивов, записывая результат в 1-ый массив. 95 | 96 | ``` 97 | void product(std::span inputOutput, std::span coefficients) 98 | { 99 | // ... 100 | } 101 | ``` 102 | 103 | - Убедитесь в ней в том, что спаны одинаковой длины, используя `assert`. 104 | 105 |
106 | Как? 107 | 108 | ```cpp 109 | assert(inputOutput.size() == coefficients.size()); 110 | ``` 111 |
112 | 113 | - Реализуйте версию с бесконечным циклом, используя `break` вручную. 114 | 115 | - Реализуйте версию с циклом `while` с условием. 116 | 117 | - Реализуйте версию с циклом `for`. 118 | -------------------------------------------------------------------------------- /ru/labs/cpp/05_string_basic.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 5 2 | 3 | Тема: *основы строк.* 4 | 5 | Сопровождающие [видео](https://www.youtube.com/watch?v=3aXFuiHxb9k&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=11&t=639): 6 | 7 | ## Задание 1 8 | 9 | Сделайте функцию, которая считает сколько символов `1` в строке (`std::string_view`). 10 | 11 | Сделайте несколько тестов для всех случаев (ни одной 1, несколько 1, все 1) используя `assert`. 12 | 13 |
14 | Пример 15 | 16 | ``` 17 | void runTests() 18 | { 19 | assert(countOnes("001100") == 2); 20 | // ... 21 | } 22 | ``` 23 |
24 | 25 | ## Задание 2 26 | 27 | Сделайте функцию, которая находит в строке ` `, 28 | и выдает кусок строки от позиции после этой позиции до следующего ` `. 29 | Если следующего нет, пускай выдает остальную часть строки. 30 | 31 | Сделайте тесты, как в прошлом задании. 32 | 33 | Примеры: 34 | ``` 35 | secondWord("Hello world") == "world" 36 | secondWord("Hello my dear") == "my" 37 | secondWord("") == "" 38 | secondWord(" ") == "" 39 | secondWord(" a ") == "a" 40 | secondWord("a ") == "" 41 | secondWord("a b") == "" 42 | secondWord("hello world dear") == "" 43 | ``` 44 | -------------------------------------------------------------------------------- /ru/labs/cpp/06_linker.md: -------------------------------------------------------------------------------- 1 | # Лабораторная работа 6. 2 | 3 | Тема: Линкер 4 | 5 | [Видео про фазы компиляции](https://www.youtube.com/watch?v=CEl6YS4XhQQ&list=PL4sUOB8DjVlWUcSaCu0xPcK7rYeRwGpl7&index=12). 6 | 7 | ## Простой пример 8 | 9 | 1. Объявите в новом файле `main.cpp` функцию которая принимает `int` и возвращает `int` с именем `hello`. 10 | 2. Вызовите функцию в функции `main` и выведите результат в консоль. 11 | 3. Попробуйте скомпилировать. Объясните полученную ошибку. 12 | 4. Определите функцию в файле `main.cpp` (любое валидное тело) 13 | и попробуйте скомпилировать. (Должно пойти). 14 | 15 | ## Пример с 2 файлами 16 | 17 | 1. Объявите в новом файле `main.cpp` функцию которая принимает `int` и возвращает `int` с именем `hello`. 18 | 2. Вызовите функцию в функции `main` и выведите результат в консоль. 19 | 3. Объявите в новом файле `f.cpp` функцию которая принимает `int` и возвращает `int` с именем `hello`. 20 | 4. Попробуйте скомпилировать (оба файла разом). Объясните ошибки. 21 | 5. *Определите* фунцию `hello` в файле `f.cpp`, заменив определением ее объявление, и попробуйте скомпилировать. (Должно пойти). 22 | 6. Попробуйте скомпилировать только файл `main.cpp`. Объясните ошибки. 23 | 7. Добавьте к определению функции в `f.cpp` модификатор `static`. 24 | 8. Попробуйте скомпилировать. Объясните ошибки. 25 | 9. Перекопируйте определение функции в `main.cpp`, включая `static`, заменив ее объявление. 26 | 10. Попробуйте скомпилировать. Объясните почему работает. 27 | 11. Объясните сколько копий тела функции `hello` скомпилируется в финальный executable 28 | (можете предположить, что компилятор не уберет неиспользованные копии). 29 | 30 | -------------------------------------------------------------------------------- /ru/labs/cpp/11_iterator.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonC9018/uniCourse_dataStructuresAndAlgorithms/3be1675937ff9c5d860c4d4b15ba21d8d6646994/ru/labs/cpp/11_iterator.md -------------------------------------------------------------------------------- /ru/labs/cpp/README.md: -------------------------------------------------------------------------------- 1 | These topics are for people learning C++ rather than algorithms and data structures. -------------------------------------------------------------------------------- /tests/main.cpp: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | // const_cast 4 | // dynamic_cast 5 | // bit_cast 6 | } 7 | -------------------------------------------------------------------------------- /workspace.tmux: -------------------------------------------------------------------------------- 1 | rename-session asdc 2 | send "nvim ." C-m 3 | new-window -t 2 -n terminal 4 | select-window -t 1 5 | --------------------------------------------------------------------------------