├── aulas ├── aula20 │ ├── image.png │ ├── tree.png │ ├── binary_tree.png │ ├── rooted_nary_tree.png │ ├── aula20.md │ ├── binary_tree.drawio │ └── rooted nary tree.drawio ├── aula17 │ ├── openhashing.png │ └── aula17.md ├── aula21 │ ├── percursos.png │ └── aula21.md ├── aula18 │ ├── closedhashing.png │ └── aula18.md ├── aula16 │ ├── hashtable.drawio.png │ └── aula16.md ├── aula22 │ ├── first_chd_next_sibling.png │ ├── aula22.md │ └── src │ │ ├── narytree.cpp │ │ └── narytree2.cpp ├── aula05 │ └── aula05.md ├── aula02 │ └── aula02.md ├── aula03 │ └── aula03.md ├── aula06 │ ├── aula06.md │ ├── src │ │ └── notas_alunos.txt │ └── exercicios.md ├── aula04 │ └── aula04.md ├── aula25 │ └── src │ │ ├── trie.cpp │ │ ├── narytree.hpp │ │ └── narytree2.hpp ├── aula07 │ ├── src │ │ └── list.cpp │ └── aula07.md ├── aula13 │ ├── src │ │ └── vector.cpp │ └── aula13.md ├── aula26 │ └── src │ │ ├── trie.cpp │ │ ├── narytree.hpp │ │ └── narytree2.hpp ├── aula10 │ └── src │ │ └── list.cpp ├── aula23 │ └── aula23.md ├── aula19 │ └── aula19.md ├── aula08 │ ├── src │ │ └── list.cpp │ └── aula08.md ├── aula11 │ └── src │ │ └── list.cpp ├── aula14 │ ├── src │ │ └── shape.cpp │ └── aula14.md ├── aula12 │ └── aula12.md ├── aula15 │ └── aula15.md └── aula01 │ └── aula01.md ├── cpp ├── img │ ├── coroutines.png │ └── coroutines_graph.png ├── 1_04_main_idx.md ├── 1_24_error_as_values_idx.md ├── 1_13_namespaces_idx.md ├── 1_07_basic_io_idx.md ├── 1_06_control_flow_idx.md ├── 1_15_references_idx.md ├── 1_28_unordered_maps_idx.md ├── 1_21_templates_metaprogramming_idx.md ├── 1_22_static_errors_idx.md ├── 1_01_intro_idx.md ├── 1_16_rule_of_five_idx.md ├── 1_08_file_io_idx.md ├── 1_10_arrays_idx.md ├── 1_09_binary_file_io_idx.md ├── 1_12_functions_idx.md ├── 1_11_strings_idx.md ├── 1_23_exceptions_idx.md ├── 1_18_smart_pointers_idx.md ├── 1_20_templates_idx.md ├── 1_17_rule_of_five_pt2_idx.md ├── 1_19_inheritance_idx.md ├── 1_27_maps_idx.md ├── 1_03_compilation_model_idx.md ├── 1_25_stl_overview_idx.md └── 1_26_vector_idx.md └── README.md /aulas/aula20/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula20/image.png -------------------------------------------------------------------------------- /aulas/aula20/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula20/tree.png -------------------------------------------------------------------------------- /cpp/img/coroutines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/cpp/img/coroutines.png -------------------------------------------------------------------------------- /aulas/aula17/openhashing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula17/openhashing.png -------------------------------------------------------------------------------- /aulas/aula20/binary_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula20/binary_tree.png -------------------------------------------------------------------------------- /aulas/aula21/percursos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula21/percursos.png -------------------------------------------------------------------------------- /cpp/img/coroutines_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/cpp/img/coroutines_graph.png -------------------------------------------------------------------------------- /aulas/aula18/closedhashing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula18/closedhashing.png -------------------------------------------------------------------------------- /aulas/aula16/hashtable.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula16/hashtable.drawio.png -------------------------------------------------------------------------------- /aulas/aula20/rooted_nary_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula20/rooted_nary_tree.png -------------------------------------------------------------------------------- /aulas/aula22/first_chd_next_sibling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CIN0135/CIN0135-20251/HEAD/aulas/aula22/first_chd_next_sibling.png -------------------------------------------------------------------------------- /aulas/aula05/aula05.md: -------------------------------------------------------------------------------- 1 | # Aula 05: Arrays e alocação dinâmica de memória 2 | 3 | - [Arrays e alocação dinâmica](../../cpp/1_10_arrays_idx.md) 4 | 5 | 6 | 7 | 8 | 9 | ___ 10 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula04/aula04.md) [[Próximo >]](../aula06/aula06.md) [[Índice ^]](../index.md) 11 | 12 | 13 | -------------------------------------------------------------------------------- /aulas/aula02/aula02.md: -------------------------------------------------------------------------------- 1 | # Aula 02 2 | 3 | - [Modelo de Compilação C/C++](../../cpp/1_03_compilation_model_idx.md) 4 | - [A função main](../../cpp/1_04_main_idx.md) 5 | 6 | 7 | 8 | ___ 9 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula01/aula01.md) [[Próximo >]](../aula03/aula03.md) [[Índice ^]](../index.md) 10 | 11 | -------------------------------------------------------------------------------- /aulas/aula03/aula03.md: -------------------------------------------------------------------------------- 1 | # Aula 03: Tipos primitivos, ponteiros 2 | 3 | - [Variáveis e Constantes](../../cpp/1_05_vars_constants_idx.md) 4 | - [Ponteiros](../../cpp/1_05_vars_constants_idx.md) 5 | 6 | 7 | 8 | ___ 9 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula02/aula02.md) [[Próximo >]](../aula04/aula04.md) [[Índice ^]](../index.md) 10 | 11 | 12 | -------------------------------------------------------------------------------- /aulas/aula06/aula06.md: -------------------------------------------------------------------------------- 1 | # Aula 06: Strings, Stream I/O, C Structs 2 | 3 | - [Strings](../../cpp/1_11_strings_idx.md) 4 | - [Stream I/O](../../cpp/1_07_basic_io_idx.md) 5 | - [C Structs](https://www.w3schools.com/c/c_structs.php) 6 | 7 | ___ 8 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula05/aula05.md) [[Próximo >]](../aula07/aula07.md) [[Índice ^]](../index.md) 9 | 10 | 11 | -------------------------------------------------------------------------------- /aulas/aula04/aula04.md: -------------------------------------------------------------------------------- 1 | # Aula 04: Controle de fluxo, funções, arrays 2 | 3 | - [Estruturas de controle de fluxo](../../cpp/1_06_control_flow_idx.md) 4 | - [Funções](../../cpp/1_12_functions_idx.md) 5 | - [Arrays](../../cpp/1_10_arrays_idx.md) 6 | 7 | 8 | 9 | 10 | 11 | ___ 12 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula02/aula03.md) [[Próximo >]](../aula05/aula04.md) [[Índice ^]](../index.md) 13 | 14 | 15 | -------------------------------------------------------------------------------- /aulas/aula25/src/trie.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "narytree.hpp" 5 | 6 | 7 | using namespace std; 8 | 9 | 10 | void addWord(Node *root, const string& word) { 11 | cout << "Palavra " << word << " adicionada" << std::endl; 12 | } 13 | 14 | int main() { 15 | 16 | Node *root; 17 | 18 | while (true) { 19 | string s; 20 | cout << "Digite uma palavra: "; 21 | getline(cin, s); 22 | if (s=="") break; 23 | addWord(root, s); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /aulas/aula07/src/list.cpp: -------------------------------------------------------------------------------- 1 | struct Node { 2 | int val; 3 | Node* next; 4 | }; 5 | 6 | Node* newNode(int v) { 7 | Node* ret = new Node; 8 | (*ret).val = v; 9 | ret->next = nullptr; 10 | return ret; 11 | } 12 | 13 | Node *initEmptyList() { 14 | return newNode(-1); 15 | } 16 | 17 | void listAppend(Node *head, int v) { 18 | Node *nn = newNode(v); 19 | Node *cur = head; 20 | while (cur->next != nullptr) { 21 | cur = cur->next; 22 | } 23 | cur->next = nn; 24 | } 25 | 26 | int main() { 27 | Node *head = initEmptyList(); 28 | for (int i = 1; i < 5; i++) { 29 | listAppend(head, i); 30 | } 31 | } -------------------------------------------------------------------------------- /cpp/1_04_main_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Main Function and Program Execution 3 | 4 | * Execution entry point 5 | 6 | ```cpp 7 | // return 0 = success not 0 = failure 8 | int main() { 9 | // do stuff 10 | return 0; // implicit if ommited 11 | } 12 | ``` 13 | 14 | or 15 | 16 | ```cpp 17 | // argc = number or command line arguments 18 | // argv = list of command line arguments 19 | // return 0 = success not 0 = failure 20 | int main(int argc, char **argv) { 21 | // do stuff 22 | return 0; // implicit if ommited 23 | } 24 | ``` 25 | 26 | --- 27 | [[⇦ Previous](1_03_compilation_model_idx.md)] [[Next ⇨](1_05_vars_constants_idx.md)] [[Index ⇧](index.md#1_04_main_idx.md)] 28 | -------------------------------------------------------------------------------- /aulas/aula06/src/notas_alunos.txt: -------------------------------------------------------------------------------- 1 | Ana 2 | 20211863 3 | 5.05 4 | 5 | Bruno 6 | 20207444 7 | 9.90 8 | 9 | Carlos 10 | 20247245 11 | 10.00 12 | 13 | Daniela 14 | 20226603 15 | 2.60 16 | 17 | Eduardo 18 | 20233182 19 | 10.00 20 | 21 | Fernanda 22 | 20222326 23 | 2.61 24 | 25 | Gabriel 26 | 20242270 27 | 10.00 28 | 29 | Helena 30 | 20211096 31 | 5.88 32 | 33 | Igor 34 | 20206962 35 | 9.49 36 | 37 | Joana 38 | 20233246 39 | 10.00 40 | 41 | Kaio 42 | 20245332 43 | 8.27 44 | 45 | Larissa 46 | 20241173 47 | 7.55 48 | 49 | Marcos 50 | 20217807 51 | 3.01 52 | 53 | Natalia 54 | 20202068 55 | 6.52 56 | 57 | Otavio 58 | 20202210 59 | 3.11 60 | 61 | Paula 62 | 20234962 63 | 5.73 64 | 65 | Rafael 66 | 20226809 67 | 10.00 68 | 69 | Sara 70 | 20238416 71 | 8.77 72 | 73 | Tatiane 74 | 20233534 75 | 2.86 76 | 77 | Ulisses 78 | 20224307 79 | 5.33 80 | 81 | Vanessa 82 | 20217550 83 | 7.94 84 | 85 | Wesley 86 | 20221988 87 | 8.86 88 | 89 | Xavier 90 | 20237166 91 | 7.00 92 | 93 | Yara 94 | 20245800 95 | 9.64 96 | 97 | Zeca 98 | 20226447 99 | 7.21 100 | 101 | END 102 | -------------------------------------------------------------------------------- /aulas/aula06/exercicios.md: -------------------------------------------------------------------------------- 1 | ## Laboratório 2 | 3 | ### ATIVIDADES 4 | 5 | 6 | #### Atividade: Reverter um vetor de inteiros 7 | 8 | * Lê do teclado o tamanho do array (N <= 100) 9 | * Cria um array aleatório em ordem crescente com valores entre 0 e 1000 (usar função `rand()`) 10 | * Imprime o array original 11 | * Inverte o array 12 | * Imprime o array invertido 13 | 14 | 15 | #### Atividade: Calcular o produto de duas matrizes 16 | 17 | * Lê três inteiros positivos `M N P` no intervalo `(2, 10)` 18 | * Cria duas matrizes aleatórias `A` e `B` de dimensões `MxN` e `NxP` com valores no intervalo `(-100, +100)` 19 | * Calcula a matriz produto `C = A*B` de dimensões `MxP` 20 | * Imprime a matrizes `A`, `B`, `C` 21 | 22 | 23 | 24 | 25 | #### Atividade: Calcular a média das notas dos alunos de uma turma 26 | 27 | * O arquivo [`notas_alunos.txt`](./src/notas_alunos.txt) possui uma lista de registros, cada um contendo um nome, um número de matrícula e uma nota. O arquivo termina com a linha `END`. Cada nome tem < 10 caracteres. 28 | * Definir uma struct Aluno para esse tipo de registro 29 | * Ler esse arquivo para um array de structs do tipo Aluno 30 | * Calcular a média da turma 31 | * Imprimir a lista de alunos com nota maior ou igual à média 32 | 33 | 34 | ___ 35 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula06/aula04.md) [[Próximo >]](../aula05/aula05.md) [[Índice ^]](../index.md) 36 | 37 | 38 | -------------------------------------------------------------------------------- /aulas/aula22/aula22.md: -------------------------------------------------------------------------------- 1 | # Implementação de árvores enraizadas de grau arbitrário 2 | 3 | - Qualquer quantidade ≥0 de filhos 4 | - A implementação mais direta consiste em armazenar uma lista (ou vector) de ponteiros para filhos 5 | 6 | ```cpp 7 | template 8 | class Node { 9 | T val; 10 | vector chd; // filhos 11 | ... 12 | }; 13 | ``` 14 | (Source: [narytree.cpp](./src/narytree.cpp)) 15 | 16 | - Prós: acesso rápido a cada filho (com vector) 17 | - Contra: quantidade de memória variável por nó 18 | 19 | 💡 É possível representar uma árvre n-ária com qtde constante de memória por nó? 20 | 21 | ## Implementação first-child/next-sibling 22 | 23 | Dois ponteiros por nó: 24 | 1. Primeiro filho 25 | 2. Próximo nó irmão (à direita) 26 | 27 | 28 | 29 | 30 | ```cpp 31 | template 32 | class Node { 33 | private: 34 | T val; 35 | Node* firstChd; 36 | Node* nextSibling; 37 | public: 38 | 39 | } 40 | ``` 41 | (Source: [narytree.cpp](./src/narytree.cpp)) 42 | 43 | 44 | - Prós: quantidade fixa de memória por nó 45 | - Contra: filhos percorridos sequencialmente 46 | 47 | ```cpp 48 | template 49 | Node *Node::Chd(size_t i) { 50 | int cnt = 0; 51 | Node *cur = this->firstChd; 52 | while(cnt < i) { 53 | cur = cur->nextSibling; 54 | cnt++; 55 | } 56 | return cur; 57 | } 58 | ``` 59 | 60 | ___ 61 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula21/aula21.md) [[Próximo >]](../aula23/aula23.md) [[Índice ^]](../index.md) 62 | -------------------------------------------------------------------------------- /aulas/aula13/src/vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Vector { 6 | public: 7 | Vector(); 8 | ~Vector(); 9 | size_t size() { return sz;}; 10 | size_t capacity() { return cap;}; 11 | void append(int val); 12 | void insert(size_t pos, int val); 13 | int operator[](size_t pos); 14 | private: 15 | int *arr = nullptr; 16 | size_t sz; 17 | size_t cap; 18 | void checkAndDouble(); 19 | }; 20 | 21 | 22 | Vector::Vector() 23 | { 24 | sz = 0; 25 | cap = 1; 26 | arr = new int[cap]; 27 | } 28 | 29 | Vector::~Vector() 30 | { 31 | delete arr; 32 | } 33 | 34 | void Vector::checkAndDouble() { 35 | if (sz == cap) { 36 | size_t newcap = 2 * cap; 37 | int *newarr = new int[newcap]; 38 | for (size_t i = 0; i < cap; i++) { 39 | newarr[i] = arr[i]; 40 | } 41 | delete arr; 42 | arr = newarr; 43 | cap = newcap; 44 | } 45 | } 46 | 47 | void Vector::append(int val) 48 | { 49 | checkAndDouble(); 50 | arr[sz++] = val; 51 | } 52 | 53 | void Vector::insert(size_t pos, int val) 54 | { 55 | assert(pos <= this->size()); 56 | checkAndDouble(); 57 | for (int i = sz; i > pos; i--) { 58 | arr[i] = arr[i-1]; 59 | } 60 | arr[pos] = val; 61 | sz++; 62 | } 63 | 64 | 65 | int Vector::operator[](size_t pos) 66 | { 67 | return arr[pos]; 68 | } 69 | 70 | 71 | int main(int argc, char **argv) { 72 | 73 | int n = std::stoi(argv[1]); 74 | 75 | Vector v; 76 | 77 | 78 | for (int i = 0; i < n; i++) { 79 | int pos = rand() % (v.size()+1); 80 | v.insert(pos, i); 81 | } 82 | 83 | //for (int i = 0; i < v.size(); i++) { 84 | // std::cout << "v[" << i << "] = " << v[i] << std::endl; 85 | //} 86 | std::cout << "size = " << v.size() << "\n"; 87 | std::cout << "cap = " << v.capacity() << "\n"; 88 | 89 | } 90 | -------------------------------------------------------------------------------- /aulas/aula26/src/trie.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "narytree.hpp" 5 | 6 | 7 | using namespace std; 8 | 9 | // Procura se parent node tem algum filho com rotulo c 10 | // Se não tem, retorna nullptr 11 | Node *findChild(Node*parent, char c) 12 | { 13 | for (int j = 0; j < parent->NChd(); j++) { 14 | Node *chd = parent->Chd(j); 15 | if (c == chd->Val()) { 16 | return chd; 17 | } 18 | } 19 | return nullptr; 20 | } 21 | 22 | void addWord(Node *root, const string& word) { 23 | Node *cur = root; 24 | int i = 0; 25 | for (i = 0; i < word.size(); i++ ) { 26 | Node *chd = findChild(cur, word[i]); 27 | if (chd) { 28 | cur = chd; 29 | continue; 30 | } 31 | break; 32 | } 33 | for (; i < word.size(); i++) { 34 | Node* newChd = new Node(word[i]); 35 | cur->AddChd(newChd); 36 | cur = newChd; 37 | } 38 | if (!findChild(cur, '$')) { 39 | cur->AddChd(new Node('$')); 40 | } 41 | cout << "Palavra " << word << " adicionada" << std::endl; 42 | } 43 | 44 | 45 | int countLeaves(Node *root) 46 | { 47 | 48 | } 49 | 50 | 51 | int prefixCount(Node *root, const string& prefix) { 52 | Node *cur = root; 53 | int i = 0; 54 | for (i = 0; i < prefix.size(); i++ ) { 55 | Node *chd = findChild(cur, prefix[i]); 56 | if (chd) { 57 | cur = chd; 58 | continue; 59 | } 60 | break; 61 | } 62 | if (i < prefix.size()) { 63 | return 0; 64 | } else { 65 | return countLeaves(cur); 66 | } 67 | } 68 | 69 | 70 | int main() { 71 | Node *root = new Node('\0'); 72 | 73 | while (true) { 74 | string s; 75 | cout << "Digite uma palavra: "; 76 | getline(cin, s); 77 | if (s=="") break; 78 | addWord(root, s); 79 | printTree(root); 80 | cout << "-----------------" << std::endl; 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /aulas/aula25/src/narytree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class Node { 9 | T val; 10 | vector chd; 11 | public: 12 | Node(const T& value) { 13 | val = value; 14 | } 15 | 16 | T const& Val(){ 17 | return val; 18 | } 19 | size_t NChd() { 20 | return chd.size(); 21 | } 22 | Node *Chd(size_t i) { 23 | return chd[i]; 24 | } 25 | void AddChd(Node *c) { 26 | chd.push_back(c); 27 | } 28 | }; 29 | 30 | 31 | 32 | Node *makeExample() { 33 | Node *a = new Node("A"); 34 | Node *aa1 = new Node("AA1"); 35 | Node *aa2 = new Node("AA2"); 36 | Node *aa3 = new Node("AA3"); 37 | a->AddChd(aa1); 38 | a->AddChd(aa2); 39 | a->AddChd(aa3); 40 | Node *b = new Node("B"); 41 | Node *bb1 = new Node("BB1"); 42 | Node *bb2 = new Node("BB2"); 43 | b->AddChd(bb1); 44 | b->AddChd(bb2); 45 | Node *bbb1 = new Node("BBB1"); 46 | Node *bbb2 = new Node("BBB2"); 47 | Node *bbb3 = new Node("BBB3"); 48 | Node *bbb4 = new Node("BBB4"); 49 | bb2->AddChd(bbb1); 50 | bb2->AddChd(bbb2); 51 | bb2->AddChd(bbb3); 52 | bb2->AddChd(bbb4); 53 | Node *c = new Node("C"); 54 | Node *root = new Node("/"); 55 | root->AddChd(a); 56 | root->AddChd(b); 57 | root->AddChd(c); 58 | return root; 59 | } 60 | 61 | template 62 | void printTree(Node *root, int depth = 0) 63 | { 64 | if (root == nullptr) return; 65 | for (int i = 0; i < depth; i++) 66 | cout << " "; 67 | cout << root->Val() << std::endl; 68 | for (int i = 0; i < root->NChd(); i++) 69 | { 70 | auto c = root->Chd(i); 71 | printTree(c, depth+1); 72 | } 73 | 74 | 75 | } 76 | 77 | 78 | int __main() { 79 | 80 | Node *root = makeExample(); 81 | printTree(root); 82 | return 0; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /aulas/aula26/src/narytree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class Node { 9 | T val; 10 | vector chd; 11 | public: 12 | Node(const T& value) { 13 | val = value; 14 | } 15 | 16 | T const& Val(){ 17 | return val; 18 | } 19 | size_t NChd() { 20 | return chd.size(); 21 | } 22 | Node *Chd(size_t i) { 23 | return chd[i]; 24 | } 25 | void AddChd(Node *c) { 26 | chd.push_back(c); 27 | } 28 | }; 29 | 30 | 31 | 32 | Node *makeExample() { 33 | Node *a = new Node("A"); 34 | Node *aa1 = new Node("AA1"); 35 | Node *aa2 = new Node("AA2"); 36 | Node *aa3 = new Node("AA3"); 37 | a->AddChd(aa1); 38 | a->AddChd(aa2); 39 | a->AddChd(aa3); 40 | Node *b = new Node("B"); 41 | Node *bb1 = new Node("BB1"); 42 | Node *bb2 = new Node("BB2"); 43 | b->AddChd(bb1); 44 | b->AddChd(bb2); 45 | Node *bbb1 = new Node("BBB1"); 46 | Node *bbb2 = new Node("BBB2"); 47 | Node *bbb3 = new Node("BBB3"); 48 | Node *bbb4 = new Node("BBB4"); 49 | bb2->AddChd(bbb1); 50 | bb2->AddChd(bbb2); 51 | bb2->AddChd(bbb3); 52 | bb2->AddChd(bbb4); 53 | Node *c = new Node("C"); 54 | Node *root = new Node("/"); 55 | root->AddChd(a); 56 | root->AddChd(b); 57 | root->AddChd(c); 58 | return root; 59 | } 60 | 61 | template 62 | void printTree(Node *root, int depth = 0) 63 | { 64 | if (root == nullptr) return; 65 | for (int i = 0; i < depth; i++) 66 | cout << " "; 67 | cout << root->Val() << std::endl; 68 | for (int i = 0; i < root->NChd(); i++) 69 | { 70 | auto c = root->Chd(i); 71 | printTree(c, depth+1); 72 | } 73 | 74 | 75 | } 76 | 77 | 78 | int __main() { 79 | 80 | Node *root = makeExample(); 81 | printTree(root); 82 | return 0; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /aulas/aula10/src/list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | struct Node { 6 | int val; 7 | Node* next; 8 | }; 9 | 10 | 11 | Node* newNode(int v) { 12 | Node* ret = new Node; 13 | (*ret).val = v; 14 | ret->next = nullptr; 15 | return ret; 16 | } 17 | 18 | Node *initEmptyList() { 19 | return newNode(-1); 20 | } 21 | 22 | 23 | 24 | Node* listNodeAt(Node *head, size_t pos) { 25 | Node *cur = head; 26 | size_t i = 0; 27 | while( cur->next != nullptr && i < pos ) { 28 | cur = cur->next; 29 | i++; 30 | } 31 | return cur; 32 | } 33 | 34 | 35 | Node* listFind(Node *head, int value) { 36 | Node *cur = head; 37 | while( cur->next != nullptr && cur->next->val != value ) { 38 | cur = cur->next; 39 | } 40 | return cur; 41 | } 42 | 43 | 44 | void listInsert(Node *cur, int value) { 45 | assert(cur!=nullptr); 46 | Node *nn = newNode(value); 47 | nn->next = cur->next; 48 | cur->next = nn; 49 | } 50 | 51 | 52 | void listInsertAt(Node *head, size_t pos, int value) { 53 | listInsert(listNodeAt(head, pos), value); 54 | } 55 | 56 | 57 | void listDelete(Node* cur) { 58 | assert(cur->next != nullptr); 59 | Node *toDie = cur->next; 60 | cur->next = toDie->next; 61 | delete toDie; 62 | } 63 | 64 | void listDeleteAt(Node *head, size_t pos) { 65 | listDelete(listNodeAt(head, pos)); 66 | } 67 | 68 | 69 | 70 | class LinkedList { 71 | public: 72 | LinkedList(); 73 | size_t size() { 74 | return sz; 75 | }; 76 | void append(int value); 77 | //void insert(size_t pos, int value); 78 | //int remove(size_t pos); 79 | //int at(size_t pos); 80 | private: 81 | Node *head; 82 | size_t sz; 83 | }; 84 | 85 | LinkedList::LinkedList() { 86 | head = newNode(-1); 87 | sz = 0; 88 | } 89 | 90 | void LinkedList::append(int val) { 91 | Node *nn = newNode(val); 92 | Node *cur = head; 93 | while (cur->next != nullptr) { 94 | cur = cur->next; 95 | } 96 | cur->next = nn; 97 | sz++; 98 | } 99 | 100 | int main() { 101 | LinkedList list; 102 | for (int val = 10; val < 100; val+=10) { 103 | list.append(val); 104 | std::cout << "size = " << list.size() << std::endl; 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /aulas/aula23/aula23.md: -------------------------------------------------------------------------------- 1 | # Laboratório: Árvores N-árias 2 | 3 | Em vários jogos entre dois oponentes, como o Xadrez, temos uma determinada configuração (ou *estado*) inicial do jogo `S0`, sobre a qual os oponentes realizam jogadas de forma alternada, modificando progressivamente o estado corrente do jogo: `S0→S1→S2→S3→...`. Dado uma determinada configuração, `Si`, podemos ter 0 ou mais jogadas válidas. Por exemplo, a partir da configuração inicial do Xadrez, temos 20 jogadas válidas para as peças brancas (avançar uma ou duas casas com cada um dos peões além de duas jogadas possíveis para cada cavalo). Caso não haja nenhuma jogada válida, temos uma **configuração final** que indica que o jogo terminou, sendo possível determinar quem venceu ou se houve um empate. 4 | 5 | Dessa forma, um jogo assim pode ser representado por uma árvore N-ária em que cada nó corresponde a um estado do jogo, e os seus filhos correspondem aos estados alcançáveis a partir dele via jogadas válidas. As folhas da árvore correspondem a configurações finais. 6 | 7 | No **Jogo do Cuscuz** (assim batizado por analogia a uma saudável brincadeira de criança brasileira) temos inicialmente um monte (o cuscuz) de tamanho `N` (inteiro positivo). Cada um dos oponentes pode retirar, alternadamente, um pedaço do cuscuz de tamanho `P` de `1` a `M < N`. Sendo `P1, P2, P3,...` os pedaços retirados alternadamente pelos dois jogadores, o cuscuz terá os tamanhos `S0=N, S1=S0-P1, S2=S1-P2, S3=S2-P3,...`, sendo esses os **estados** do jogo. O jogo termina quando o cuscuz acaba, ou seja `Si=0`, e vence o jogador que retirou o último pedaço do cuscuz. 8 | 9 | 10 | ## Tarefa 1: 11 | 12 | Escrever um programa que lê `N` e `M` e constrói a árvore N-ária correspondente a todas as possíveis partidas do jogo do cuscuz com essa configuração. 13 | 14 | ## Tarefa 2: 15 | 16 | Dada uma sequência de retiradas `P1, P2,..., Pk` determinar se o próximo jogador a jogar tem uma estratégia vencedora, ou seja, se ele ainda pode vencer a partir da próxima jogadas. 17 | 18 | ### Exemplo 19 | 20 | Se `N=10, M=3`, e a sequência de retiradas é `P1=3, P2=2`, então o jogador #1 tem uma estratégia vencedora. Porém, se a sequência for `P1=3, P2=3, P3=1` então o jogador #2 não tem estratégia vencedora. 21 | -------------------------------------------------------------------------------- /aulas/aula21/aula21.md: -------------------------------------------------------------------------------- 1 | # Percurso em árvores binárias 2 | 3 | - Usando a estrutura recursiva da árvore binária, 3 coisas a fazer: 4 | 1. **Visitar** a raiz 5 | 2. **Percorrer** (recursivamente) a subárvore à esquerda 6 | 3. **Percorrer** (recursivamente) a subárvore à direita 7 | - A ordem dessas tarefas determina o tipo do percurso 8 | 9 | 10 | ## Implementação 11 | 12 | ```cpp 13 | void preorder(Node *root) 14 | { 15 | if (root == nullptr) // caso base 16 | return; 17 | visit(root); 18 | preorder(root->left); 19 | preorder(root->right); 20 | } 21 | ``` 22 | - Os demais percursos são similares, mudando apenas a ordem de visita da raiz 23 | - A função `visit` depende da aplicação 24 | - exemplo `cout << root->val << "\n"` imprime os nós na ordem desejada 25 | 26 | ## Exemplo 27 | 28 | 29 | 30 | Pré-ordem: 7, 3, 1, 5, 9, 11 31 | Em ordem: 1, 3, 5, 7, 9, 11 32 | Pós-ordem: 5, 1, 3, 11, 9 , 7 33 | 34 | 35 | ## Aplicações 36 | 37 | Vários algoritmos em árvores consistem basicamente num percurso 38 | 39 | ### Exemplo (altura) 40 | 41 | - A **altura** é o "número de níveis" de uma árvore binária 42 | 43 | ``` 44 | N ---------------------------------- 45 | / \ | 46 | / \ | 1 47 | --------- r1 r2 ----------- --- 48 | | / \ / \ | | 49 | Hleft / \ / \ | | max(Hleft, Hright) 50 | | / \ / \ Hright | 51 | ------ /_______\ / \ | | 52 | /_________\ ----------- ------------ 53 | 54 | ``` 55 | 56 | ```cpp 57 | int height(Node *root) 58 | { 59 | if (root == nullptr) 60 | return 0; // caso base: arvore vazia tem altura 0 61 | int Hleft = height(root->left); 62 | int Hright = height(root->right); 63 | return 1 + max(Hleft, Hright); 64 | } 65 | ``` 66 | 67 | ⚠️ Percurso em **pós-ordem** 68 | 69 | 70 | ___ 71 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula20/aula20.md) [[Próximo >]](../aula22/aula22.md) [[Índice ^]](../index.md) -------------------------------------------------------------------------------- /aulas/aula22/src/narytree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class Node { 9 | T val; 10 | vector chd; 11 | public: 12 | Node(const T& value) { 13 | val = value; 14 | } 15 | 16 | T const& Val(){ 17 | return val; 18 | } 19 | size_t NChd() { 20 | return chd.size(); 21 | } 22 | Node *Chd(size_t i) { 23 | return chd[i]; 24 | } 25 | void AddChd(Node *c) { 26 | chd.push_back(c); 27 | } 28 | }; 29 | 30 | template 31 | void print(Node* root) { 32 | if (!root) return; 33 | std::cout << root->val << "\n"; 34 | for (auto c : root->chd) { 35 | print(c); 36 | } 37 | } 38 | 39 | Node *makeExample() { 40 | Node *a = new Node("A"); 41 | Node *aa1 = new Node("AA1"); 42 | Node *aa2 = new Node("AA2"); 43 | Node *aa3 = new Node("AA3"); 44 | a->AddChd(aa1); 45 | a->AddChd(aa2); 46 | a->AddChd(aa3); 47 | Node *b = new Node("B"); 48 | Node *bb1 = new Node("BB1"); 49 | Node *bb2 = new Node("BB2"); 50 | b->AddChd(bb1); 51 | b->AddChd(bb2); 52 | Node *bbb1 = new Node("BBB1"); 53 | Node *bbb2 = new Node("BBB2"); 54 | Node *bbb3 = new Node("BBB3"); 55 | Node *bbb4 = new Node("BBB4"); 56 | bb2->AddChd(bbb1); 57 | bb2->AddChd(bbb2); 58 | bb2->AddChd(bbb3); 59 | bb2->AddChd(bbb4); 60 | Node *c = new Node("C"); 61 | Node *root = new Node("/"); 62 | root->AddChd(a); 63 | root->AddChd(b); 64 | root->AddChd(c); 65 | return root; 66 | } 67 | 68 | template 69 | void printTree(Node *root, int depth = 0) 70 | { 71 | if (root == nullptr) return; 72 | for (int i = 0; i < depth; i++) 73 | cout << " "; 74 | cout << root->Val() << std::endl; 75 | for (int i = 0; i < root->NChd(); i++) 76 | { 77 | auto c = root->Chd(i); 78 | printTree(c, depth+1); 79 | } 80 | 81 | 82 | } 83 | 84 | 85 | int main() { 86 | 87 | Node *root = makeExample(); 88 | printTree(root); 89 | 90 | } 91 | -------------------------------------------------------------------------------- /cpp/1_24_error_as_values_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Errors As Values 3 | 4 | - Handle errors using return values, providing better performance and control. 5 | - Two commonly used approaches involve `std::optional` and `std::variant`. 6 | 7 | 8 | 9 | ## Representing Optional Values - `std::optional` (C++17) 10 | 11 | - `std::optional` represents an object that may or may not contain a value. 12 | - Useful for functions that might fail but don't need to differentiate causes or give an explicit error message. 13 | - Avoids exception overhead. 14 | 15 | ```cpp 16 | #include 17 | #include 18 | 19 | std::optional divide(int a, int b) { 20 | if (b == 0) return std::nullopt; // No value in case of error 21 | return a / b; 22 | } 23 | 24 | int main() { 25 | auto result = divide(10, 2); 26 | 27 | if (result) { 28 | std::cout << "Result: " << *result << '\n'; 29 | } else { 30 | std::cout << "Error: Division by zero!\n"; 31 | } 32 | } 33 | ``` 34 | 35 | 36 | ## Representing Multiple Possible Outcomes - `std::variant` (C++17) 37 | 38 | - `std::variant` allows returning either a valid result or an error code/message in a type-safe way. 39 | 40 | ```cpp 41 | #include 42 | #include 43 | #include 44 | 45 | using Result = std::variant; 46 | 47 | Result divide(int a, int b) { 48 | if (b == 0) return std::string("Error: Division by zero"); 49 | return a / b; 50 | } 51 | 52 | int main() { 53 | Result result = divide(10, 0); 54 | 55 | if (std::holds_alternative(result)) { 56 | std::cout << "Result: " << std::get(result) << '\n'; 57 | } else { 58 | std::cerr << "ERROR:" << std::get(result) << '\n'; 59 | } 60 | } 61 | ``` 62 | 63 | 64 | ## Comparison 65 | 66 | | Feature | `std::optional` | `std::variant` | 67 | |---------|----------------|----------------| 68 | | Use case | Success or failure without detailed error info | Multiple possible outcomes (value or error) | 69 | | Error details | No | Yes | 70 | | Overhead | Lower | Slightly higher | 71 | | Simplicity | Very simple | Less simple | 72 | 73 | --- 74 | [[⇦ Previous](1_23_exceptions_idx.md)] [[Next ⇨](1_25_stl_overview_idx.md)] [[Index ⇧](index.md#1_24_error_as_values_idx.md)] 75 | -------------------------------------------------------------------------------- /cpp/1_13_namespaces_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Namespaces 3 | 4 | - Namespaces in C++ help organize code and prevent **name conflicts** by grouping related functions, classes, and variables under a unique scope. 5 | - Without namespaces, if two libraries define a function or class with the same name, a **name collision** occurs. 6 | - Namespaces help avoid this by encapsulating identifiers. 7 | - A namespace is defined using the `namespace` keyword: 8 | - The **scope resolution operator** `::` is used to identity the namespace of an identifier. 9 | 10 | 11 | ```cpp 12 | #include 13 | 14 | void print() { std::cout << "Global print\n"; } 15 | 16 | namespace Library { 17 | void print() { std::cout << "Library print\n"; } 18 | } 19 | 20 | int main() { 21 | print(); // Calls global print 22 | Library::print(); // Calls Library's print 23 | } 24 | ``` 25 | 26 | 27 | ## `using` Directive 28 | 29 | - The `using namespace` directive brings **all** names from a namespace into the current scope: 30 | ```cpp 31 | using namespace MyNamespace; 32 | greet(); // No need for MyNamespace:: prefix 33 | ``` 34 | - However we can narrow it down so specific names: 35 | ```cpp 36 | using MyNamespace::greet; 37 | greet(); // Only MyNamespace::greet() is available 38 | ``` 39 | 40 | 41 | ## Nested Namespaces 42 | 43 | - Namespaces can be nested in an hierarchycal structure. 44 | ```cpp 45 | namespace A { 46 | namespace B { 47 | void sayHello() { std::cout << "Hello from A::B\n"; } 48 | } 49 | } 50 | A::B::sayHello(); 51 | ``` 52 | 53 | 54 | ## Anonymous (Unnamed) Namespaces 55 | 56 | - Anonymous namespaces** restrict access **to the current file** (similar to `static` for functions). 57 | ```cpp 58 | namespace { 59 | void hiddenFunction() { std::cout << "Only accessible in this file\n"; } 60 | } 61 | ``` 62 | 63 | 64 | ## Standard (`std`) Namespace 65 | 66 | - C++ standard library identifiers, such as `std::cout` and `std::vector`, are inside the `std` namespace. 67 | 68 | ```cpp 69 | #include 70 | using namespace std; // Avoid this in large projects! 71 | 72 | cout << "Hello, world!" << endl; // std::cout is now accessible without std:: 73 | ``` 74 | 75 | --- 76 | [[⇦ Previous](1_12_functions_idx.md)] [[Next ⇨](1_14_OOP_classes_idx.md)] [[Index ⇧](index.md#1_13_namespaces_idx.md)] 77 | -------------------------------------------------------------------------------- /aulas/aula19/aula19.md: -------------------------------------------------------------------------------- 1 | # Aplicações de HashTables 2 | 3 | ## Dicionário 4 | 5 | Um **Dicionário**, também chamado **mapa** ou **array associativo**, é uma ED que associa **chaves** a **valores**, ou seja, conceitualmente é um conjunto de pares do tipo 6 | 7 | ``` 8 | +--------+-----------+ 9 | | key | value | 10 | +--------+-----------+ 11 | ``` 12 | 13 | com operações 14 | 15 | - `dict.insert(key, value)`: insere o par `(key, value)` 16 | - `dict.contains(key)`: consulta se o dicionário contem algum valor associado à chave `key` 17 | - `dict.get(key)`: consulta o valor associado à chave `key` 18 | 19 | 20 | ### Implementação 21 | 22 | - Um dicionário **não ordenado** é tipicamente implementado com uma hashtable 23 | - A ideia é armazenar na tabela um conjunto de entradas `(key, value)`, usando apenas a `key` para o cálculo da posição 24 | - A princípio, um objeto qualquer pode ser usado como `key` desde que obedeça algumas condições: 25 | - `key` precisa ser mapeável em um valor numério correspondente `k=hashcode(key)` 26 | - `key` precisa ser comparável por equivalência ('==') 27 | - Se `key1 == key2` então devemos ter `hashcode(key1) == hashcode(key2)` 28 | - A posição do par `(key, value)` na tabela será dada por `h(k=hashcode(key))` onde `h` é a função de dispersão da tabela 29 | 30 | 31 | #### Teste de pertinência 32 | 33 | ``` 34 | Dictionary::contains(key) 35 | k = hashcode(key) 36 | for i = 0, 1, .... 37 | pos = h(k, i) // considerando a sondagem 38 | if T[pos] is empty 39 | return false 40 | if T[pos].key == key // necessário comparar devido a colisões 41 | return true 42 | ``` 43 | 44 | 45 | 46 | ## Conjunto (Hashset) 47 | 48 | - Um conjunto não ordenado é uma coleção com as operações 49 | - `set.insert(elem)`: insere o elemento `elem` se não estiver contido 50 | - `set.contains(elem)`: consulta se o conjunto contém `elem` 51 | - Hashtables também podem ser usadas para representar conjuntos 52 | - Para ser adicionado, os elementos precisam obedecer os critérios de chave descritos acima 53 | - `elem` precisa ser mapeável em um valor numério correspondente `k=hashcode(elem)` 54 | - `elem` precisa ser comparável por equivalência ('==') 55 | - Se `elem1 == elem2` então devemos ter `hashcode(elem1) == hashcode(elem2)` 56 | - Dessa forma o Hashset pode ser implementado de forma análoga a um dicionário, apenas ignorando o `value` 57 | 58 | 59 | ___ 60 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula18/aula18.md) [[Próximo >]](../aula20/aula20.md) [[Índice ^]](../index.md) -------------------------------------------------------------------------------- /aulas/aula08/src/list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Node { 5 | int val; 6 | Node* next; 7 | }; 8 | 9 | Node* newNode(int v) { 10 | Node* ret = new Node; 11 | (*ret).val = v; 12 | ret->next = nullptr; 13 | return ret; 14 | } 15 | 16 | Node *initEmptyList() { 17 | return newNode(-1); 18 | } 19 | 20 | void listAppend(Node *head, int v) { 21 | Node *nn = newNode(v); 22 | Node *cur = head; 23 | while (cur->next != nullptr) { 24 | cur = cur->next; 25 | } 26 | cur->next = nn; 27 | } 28 | 29 | 30 | Node* listNodeAt(Node *head, size_t pos) { 31 | Node *cur = head; 32 | size_t i = 0; 33 | while( cur->next != nullptr && i < pos ) { 34 | cur = cur->next; 35 | i++; 36 | } 37 | return cur; 38 | } 39 | 40 | 41 | Node* listFind(Node *head, int value) { 42 | Node *cur = head; 43 | while( cur->next != nullptr && cur->next->val != value ) { 44 | cur = cur->next; 45 | } 46 | return cur; 47 | } 48 | 49 | 50 | void listInsert(Node *cur, int value) { 51 | assert(cur!=nullptr); 52 | Node *nn = newNode(value); 53 | nn->next = cur->next; 54 | cur->next = nn; 55 | } 56 | 57 | 58 | void listInsertAt(Node *head, size_t pos, int value) { 59 | listInsert(listNodeAt(head, pos), value); 60 | } 61 | 62 | 63 | void listDelete(Node* cur) { 64 | assert(cur->next != nullptr); 65 | Node *toDie = cur->next; 66 | cur->next = toDie->next; 67 | delete toDie; 68 | } 69 | 70 | void listDeleteAt(Node *head, size_t pos) { 71 | listDelete(listNodeAt(head, pos)); 72 | } 73 | 74 | 75 | int main() { 76 | Node *head = initEmptyList(); 77 | for (int val = 10; val < 100; val+=10) { 78 | listAppend(head, val); 79 | } 80 | 81 | for (size_t pos = 0; pos < 7; pos++) { 82 | Node* node = listNodeAt(head, pos); 83 | if (node->next!=nullptr) { 84 | std::cout << "list[" << pos << "] = " << node->next->val << std::endl; 85 | } else { 86 | std::cerr << "Posicao [" << pos << "] invalida" << std::endl; 87 | break; 88 | } 89 | } 90 | 91 | for (int value = 0; value < 100; value += 6 ) { 92 | Node *node = listFind(head, value); 93 | if (node->next != nullptr) { 94 | std::cout << "value " << value << " encontrado" << std::endl; 95 | } else { 96 | std::cout << "value " << value << " NAO encontrado" << std::endl; 97 | } 98 | } 99 | 100 | for (int value = 5, i = 0; value < 100; value += 10, i+=2) { 101 | listInsertAt(head, i, value); 102 | } 103 | 104 | 105 | for (size_t i = 0; i < 12; i +=3) { 106 | listDeleteAt(head, i); 107 | } 108 | 109 | 110 | 111 | } -------------------------------------------------------------------------------- /aulas/aula18/aula18.md: -------------------------------------------------------------------------------- 1 | # Resolução de Colisões (Cont.) 2 | 3 | ## II. Closed Hashing 4 | 5 | - Máx. 1 chave por posição 6 | - Tentar posição inicial 7 | - Se ocupada, **sondar sistematicamente** outras posições até encontrar vaga 8 | 9 | ### Função de sondagem 10 | 11 | Dados: 12 | 13 | - Universo das chaves: $U$ 14 | - Tabela de tamanho `m` 15 | - `i` = número da sondagem (tentativas) 16 | 17 | A função de hashing é definida como: 18 | 19 | $$ 20 | \begin{aligned} 21 | h : U \times \{0, \dots, m - 1\} &\rightarrow \{0, \dots, m - 1\}\\ 22 | (k, i) &\mapsto (h_0(k) + p(k, i)) \bmod m 23 | \end{aligned} 24 | $$ 25 | 26 | Legenda: 27 | - `h₀(k)` = posição inicial 28 | - `p(k, i)` = função de ``salto'' da tentativa 29 | 30 | ### Sondagem Linear (Linear Probing) 31 | 32 | $$ 33 | p(k, i) = i 34 | $$ 35 | 36 | ↪ 37 | $$ 38 | h(k, i) = [h_0(k) + i] \mod m 39 | $$ 40 | 41 | #### Exemplo 42 | 43 | `m = 10`, `h₀(k) = k mod m` 44 | 45 | Chaves: 21, 59, 95, 76, 45, 39 46 | 47 | ``` 48 | +----+ ↓ 49 | 0 | 39 | ← inserido após colisão (39) 50 | +----+ 51 | 1 | 21 | 52 | +----+ 53 | 2 | | 54 | +----+ 55 | 3 | | 56 | +----+ 57 | 4 | | 58 | +----+ 59 | 5 | 95 | - posição inicial de 45 ocupada 60 | +----+ ↓ 61 | 6 | 76 | - sondagem linear para 45 (ainda ocupada) 62 | +----+ ↓ 63 | 7 | 45 | ← 45 inserido após sondagem 64 | +----+ 65 | 8 | | 66 | +----+ 67 | 9 | 59 | - posição inicial de 39 ocupada 68 | +----+ ↓ 69 | ``` 70 | 71 | ⚠️ **Problema** : Primary Clustering - Posições vizinhas a regiões densas têm maior chance de serem escolhidas. 72 | 73 | **Exemplo:** 74 | 75 | $$ 76 | P[h = 8] = P[h_0 \in \{5,6,7,8\}] = \frac{4}{10} > P[h = 3] = \frac{1}{10} 77 | $$ 78 | 79 | ### Alternativas 80 | 81 | - **Sondagem quadrática**: $p(k, i) = ai^2 + bi + c$ 82 | 83 | - **Sondagem (pseudo-) aleatória**: $p(k, i) = \Theta[i]$ 84 | 85 | onde $\Theta$ é uma permutação aleatória fixa de `{0,...,m-1}` 86 | 87 | ⚠️ **Problema:** Clustering secundário - Se `h₀` gera cluster, `h` também gera. 88 | 89 | ### Tempo das operações do closed hashing 90 | 91 | 92 | 93 | - Para garantir um tempo máximo $t_{max}$ por operação, escolhemos um fator de carga máximo $\alpha_{max}$ (ex. 0.5) e realizamos o rehashing como descrito anteriormente 94 | 95 | 96 | ___ 97 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula17/aula17.md) [[Próximo >]](../aula19/aula19.md) [[Índice ^]](../index.md) 98 | -------------------------------------------------------------------------------- /aulas/aula11/src/list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class LinkedList { 5 | 6 | private: 7 | struct Node { 8 | int val; 9 | Node* next; 10 | 11 | Node(int v) { 12 | val = v; 13 | next = nullptr; 14 | }; 15 | }; 16 | 17 | Node* locateCursor(size_t pos) { 18 | Node *cur = head; 19 | size_t i = 0; 20 | while( cur->next != nullptr && i < pos ) { 21 | cur = cur->next; 22 | i++; 23 | } 24 | return cur; 25 | } 26 | 27 | public: 28 | LinkedList(); 29 | ~LinkedList(); 30 | size_t size() { 31 | return sz; 32 | }; 33 | void append(int value); 34 | void insert(size_t pos, int value); 35 | int remove(size_t pos); 36 | int at(size_t pos); 37 | private: 38 | Node *head; 39 | size_t sz; 40 | }; 41 | 42 | LinkedList::LinkedList() { 43 | head = new Node(-1); 44 | sz = 0; 45 | } 46 | 47 | LinkedList::~LinkedList() { 48 | std::cout << "Destroying " << this << std::endl; 49 | } 50 | 51 | 52 | void LinkedList::append(int val) { 53 | insert(size(), val); 54 | } 55 | 56 | void LinkedList::insert(size_t pos, int value) { 57 | Node *cur = locateCursor(pos); 58 | Node *nn = new Node(value); 59 | nn->next = cur->next; 60 | cur->next = nn; 61 | sz++; 62 | } 63 | 64 | int LinkedList::remove(size_t pos) { 65 | Node *cur = locateCursor(pos); 66 | assert(cur->next != nullptr); 67 | Node *toDie = cur->next; 68 | cur->next = toDie->next; 69 | int ret = toDie->val; 70 | delete toDie; 71 | sz--; 72 | return ret; 73 | } 74 | 75 | int LinkedList::at(size_t pos) { 76 | Node *cur = locateCursor(pos); 77 | assert(cur->next != nullptr); 78 | return cur->next->val; 79 | } 80 | 81 | 82 | void func() { 83 | LinkedList list; 84 | 85 | LinkedList *anotherList = new LinkedList(); 86 | 87 | for (int i = 0; i < 5; i++) { 88 | list.append((i+1)*20); 89 | anotherList->append((i+1)*20); 90 | } 91 | for (int i = 0; i < list.size(); i++ ) { 92 | std::cout << "list[" << i << "] = " << list.at(i) << std::endl; 93 | } 94 | 95 | for (int i = 0; i < 5; i++) { 96 | list.insert( 2*i , 10+(20*i)); 97 | } 98 | for (int i = 0; i < list.size(); i++ ) { 99 | std::cout << "list[" << i << "] = " << list.at(i) << std::endl; 100 | } 101 | 102 | int deleted = list.remove(9); 103 | std::cout << "removed " << deleted << std::endl; 104 | deleted = list.remove(4); 105 | std::cout << "removed " << deleted << std::endl; 106 | deleted = list.remove(0); 107 | std::cout << "removed " << deleted << std::endl; 108 | for (int i = 0; i < list.size(); i++ ) { 109 | std::cout << "list[" << i << "] = " << list.at(i) << std::endl; 110 | } 111 | 112 | delete anotherList; 113 | } 114 | 115 | 116 | int main() { 117 | std::cout << "Antes\n"; 118 | func(); 119 | std::cout << "Depois" << std::endl; 120 | } -------------------------------------------------------------------------------- /aulas/aula14/src/shape.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Abstract base class 4 | class Shape 5 | { 6 | public: 7 | virtual ~Shape() 8 | { 9 | std::cout << "Destructing Shape\n"; 10 | } // Virtual destructor 11 | 12 | virtual double area() = 0; 13 | 14 | virtual const char* name() 15 | { 16 | return myname; 17 | } 18 | private: 19 | const char *myname = "Shape"; 20 | 21 | public: 22 | int puba = 0; 23 | protected: 24 | int prota = 10; 25 | private: 26 | int priva = 20; 27 | 28 | }; 29 | 30 | 31 | static const double PI = 3.1415; 32 | 33 | // Concrete subclass: Circle 34 | class Circle : protected Shape 35 | { 36 | public: 37 | explicit Circle(double radius): radius{radius} {}; 38 | 39 | double area() override 40 | { 41 | std::cout << "Computing the area of a Circle of radius " << radius << "\n"; 42 | return radius * radius * PI; 43 | } 44 | 45 | const char* name() override 46 | { 47 | return "Circle"; 48 | } 49 | 50 | double Radius () {return radius;} 51 | private: 52 | double radius{0.0}; 53 | }; 54 | 55 | // Concrete subclass: Rectangle 56 | class Rectangle : public Shape 57 | { 58 | public: 59 | Rectangle (double width, double height): width{width}, height{height} {} 60 | 61 | double area() override 62 | { 63 | std::cout << "Computing the area of a " << width << " by " << height << 64 | " Rectangle.\n"; 65 | return width * height; 66 | } 67 | 68 | double Width() {return width;} 69 | double Height() { return height;} 70 | private: 71 | double width{0.0}; 72 | double height{0.0}; 73 | }; 74 | 75 | 76 | void printArea(Shape *s) { 77 | std::cout << "Area da figura \"" << s->name() << "\"\n" << s->area() << std::endl; 78 | } 79 | 80 | 81 | 82 | struct Point { 83 | int x; 84 | int y; 85 | }; 86 | 87 | void draw(Circle c, Point center) 88 | { 89 | std::cout << "Drawing a circle of radius " << c.Radius() << " centered at (" << 90 | center.x << ", " << center.y << ").\n"; 91 | 92 | } 93 | 94 | void draw(Rectangle r, Point topLeft) 95 | { 96 | std::cout << "Drawing a " << r.Width() << " by " << r.Height() << 97 | " rectangle " << " with top-left corner at (" << 98 | topLeft.x << ", " << topLeft.y << ").\n"; 99 | } 100 | 101 | 102 | int main () { 103 | Circle cobj{2}; 104 | 105 | std::cout << cobj.puba << std::endl; 106 | std::cout << cobj.prota << std::endl; 107 | std::cout << cobj.priva << std::endl; 108 | 109 | 110 | 111 | Rectangle robj{3, 4}; 112 | 113 | draw(cobj, Point{0, 0}); 114 | draw(robj, Point{0, 0}); 115 | } 116 | 117 | 118 | // Outputs: 119 | // Drawing a circle of radius 2 centered at (0, 0). 120 | // Drawing a 3 by 4 rectangle with top-left corner at (0, 0). 121 | 122 | 123 | 124 | int amain() { 125 | Circle c(1); 126 | Rectangle r(2,2); 127 | 128 | 129 | printArea(&c); 130 | 131 | printArea(&r); 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /aulas/aula22/src/narytree2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class Node { 9 | T val; 10 | Node* firstChd; 11 | Node* nextSibling; 12 | public: 13 | Node(const T& value) { 14 | val = value; 15 | firstChd = nullptr; 16 | nextSibling = nullptr; 17 | } 18 | 19 | T const& Val(){ 20 | return val; 21 | } 22 | size_t NChd() { 23 | int cnt = 0; 24 | Node *cur = this->firstChd; 25 | while(cur != nullptr) { 26 | cur = cur->nextSibling; 27 | cnt++; 28 | } 29 | return cnt; 30 | } 31 | Node *Chd(size_t i) { 32 | int cnt = 0; 33 | Node *cur = this->firstChd; 34 | while(cnt < i) { 35 | cur = cur->nextSibling; 36 | cnt++; 37 | } 38 | return cur; 39 | } 40 | void AddChd(Node *c) { 41 | if (this->firstChd == nullptr) { 42 | this->firstChd = c; 43 | return; 44 | } 45 | Node *cur = this->firstChd; 46 | while(cur->nextSibling != nullptr) { 47 | cur = cur->nextSibling; 48 | } 49 | cur->nextSibling = c; 50 | } 51 | }; 52 | 53 | 54 | 55 | Node *makeExample() { 56 | Node *a = new Node("A"); 57 | Node *aa1 = new Node("AA1"); 58 | Node *aa2 = new Node("AA2"); 59 | Node *aa3 = new Node("AA3"); 60 | a->AddChd(aa1); 61 | a->AddChd(aa2); 62 | a->AddChd(aa3); 63 | Node *b = new Node("B"); 64 | Node *bb1 = new Node("BB1"); 65 | Node *bb2 = new Node("BB2"); 66 | b->AddChd(bb1); 67 | b->AddChd(bb2); 68 | Node *bbb1 = new Node("BBB1"); 69 | Node *bbb2 = new Node("BBB2"); 70 | Node *bbb3 = new Node("BBB3"); 71 | Node *bbb4 = new Node("BBB4"); 72 | bb2->AddChd(bbb1); 73 | bb2->AddChd(bbb2); 74 | bb2->AddChd(bbb3); 75 | bb2->AddChd(bbb4); 76 | Node *c = new Node("C"); 77 | Node *root = new Node("/"); 78 | root->AddChd(a); 79 | root->AddChd(b); 80 | root->AddChd(c); 81 | return root; 82 | } 83 | 84 | template 85 | void printTree(Node *root, int depth = 0) 86 | { 87 | if (root == nullptr) return; 88 | for (int i = 0; i < depth; i++) 89 | cout << " "; 90 | cout << root->Val() << std::endl; 91 | for (int i = 0; i < root->NChd(); i++) 92 | { 93 | auto c = root->Chd(i); 94 | printTree(c, depth+1); 95 | } 96 | 97 | 98 | } 99 | 100 | 101 | int main() { 102 | 103 | Node *root = makeExample(); 104 | printTree(root); 105 | 106 | } 107 | -------------------------------------------------------------------------------- /aulas/aula25/src/narytree2.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class Node { 9 | T val; 10 | Node* firstChd; 11 | Node* nextSibling; 12 | public: 13 | Node(const T& value) { 14 | val = value; 15 | firstChd = nullptr; 16 | nextSibling = nullptr; 17 | } 18 | 19 | T const& Val(){ 20 | return val; 21 | } 22 | size_t NChd() { 23 | int cnt = 0; 24 | Node *cur = this->firstChd; 25 | while(cur != nullptr) { 26 | cur = cur->nextSibling; 27 | cnt++; 28 | } 29 | return cnt; 30 | } 31 | Node *Chd(size_t i) { 32 | int cnt = 0; 33 | Node *cur = this->firstChd; 34 | while(cnt < i) { 35 | cur = cur->nextSibling; 36 | cnt++; 37 | } 38 | return cur; 39 | } 40 | void AddChd(Node *c) { 41 | if (this->firstChd == nullptr) { 42 | this->firstChd = c; 43 | return; 44 | } 45 | Node *cur = this->firstChd; 46 | while(cur->nextSibling != nullptr) { 47 | cur = cur->nextSibling; 48 | } 49 | cur->nextSibling = c; 50 | } 51 | }; 52 | 53 | 54 | 55 | Node *makeExample() { 56 | Node *a = new Node("A"); 57 | Node *aa1 = new Node("AA1"); 58 | Node *aa2 = new Node("AA2"); 59 | Node *aa3 = new Node("AA3"); 60 | a->AddChd(aa1); 61 | a->AddChd(aa2); 62 | a->AddChd(aa3); 63 | Node *b = new Node("B"); 64 | Node *bb1 = new Node("BB1"); 65 | Node *bb2 = new Node("BB2"); 66 | b->AddChd(bb1); 67 | b->AddChd(bb2); 68 | Node *bbb1 = new Node("BBB1"); 69 | Node *bbb2 = new Node("BBB2"); 70 | Node *bbb3 = new Node("BBB3"); 71 | Node *bbb4 = new Node("BBB4"); 72 | bb2->AddChd(bbb1); 73 | bb2->AddChd(bbb2); 74 | bb2->AddChd(bbb3); 75 | bb2->AddChd(bbb4); 76 | Node *c = new Node("C"); 77 | Node *root = new Node("/"); 78 | root->AddChd(a); 79 | root->AddChd(b); 80 | root->AddChd(c); 81 | return root; 82 | } 83 | 84 | template 85 | void printTree(Node *root, int depth = 0) 86 | { 87 | if (root == nullptr) return; 88 | for (int i = 0; i < depth; i++) 89 | cout << " "; 90 | cout << root->Val() << std::endl; 91 | for (int i = 0; i < root->NChd(); i++) 92 | { 93 | auto c = root->Chd(i); 94 | printTree(c, depth+1); 95 | } 96 | 97 | 98 | } 99 | 100 | 101 | int __main() { 102 | 103 | Node *root = makeExample(); 104 | printTree(root); 105 | 106 | } 107 | -------------------------------------------------------------------------------- /aulas/aula26/src/narytree2.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class Node { 9 | T val; 10 | Node* firstChd; 11 | Node* nextSibling; 12 | public: 13 | Node(const T& value) { 14 | val = value; 15 | firstChd = nullptr; 16 | nextSibling = nullptr; 17 | } 18 | 19 | T const& Val(){ 20 | return val; 21 | } 22 | size_t NChd() { 23 | int cnt = 0; 24 | Node *cur = this->firstChd; 25 | while(cur != nullptr) { 26 | cur = cur->nextSibling; 27 | cnt++; 28 | } 29 | return cnt; 30 | } 31 | Node *Chd(size_t i) { 32 | int cnt = 0; 33 | Node *cur = this->firstChd; 34 | while(cnt < i) { 35 | cur = cur->nextSibling; 36 | cnt++; 37 | } 38 | return cur; 39 | } 40 | void AddChd(Node *c) { 41 | if (this->firstChd == nullptr) { 42 | this->firstChd = c; 43 | return; 44 | } 45 | Node *cur = this->firstChd; 46 | while(cur->nextSibling != nullptr) { 47 | cur = cur->nextSibling; 48 | } 49 | cur->nextSibling = c; 50 | } 51 | }; 52 | 53 | 54 | 55 | Node *makeExample() { 56 | Node *a = new Node("A"); 57 | Node *aa1 = new Node("AA1"); 58 | Node *aa2 = new Node("AA2"); 59 | Node *aa3 = new Node("AA3"); 60 | a->AddChd(aa1); 61 | a->AddChd(aa2); 62 | a->AddChd(aa3); 63 | Node *b = new Node("B"); 64 | Node *bb1 = new Node("BB1"); 65 | Node *bb2 = new Node("BB2"); 66 | b->AddChd(bb1); 67 | b->AddChd(bb2); 68 | Node *bbb1 = new Node("BBB1"); 69 | Node *bbb2 = new Node("BBB2"); 70 | Node *bbb3 = new Node("BBB3"); 71 | Node *bbb4 = new Node("BBB4"); 72 | bb2->AddChd(bbb1); 73 | bb2->AddChd(bbb2); 74 | bb2->AddChd(bbb3); 75 | bb2->AddChd(bbb4); 76 | Node *c = new Node("C"); 77 | Node *root = new Node("/"); 78 | root->AddChd(a); 79 | root->AddChd(b); 80 | root->AddChd(c); 81 | return root; 82 | } 83 | 84 | template 85 | void printTree(Node *root, int depth = 0) 86 | { 87 | if (root == nullptr) return; 88 | for (int i = 0; i < depth; i++) 89 | cout << " "; 90 | cout << root->Val() << std::endl; 91 | for (int i = 0; i < root->NChd(); i++) 92 | { 93 | auto c = root->Chd(i); 94 | printTree(c, depth+1); 95 | } 96 | 97 | 98 | } 99 | 100 | 101 | int __main() { 102 | 103 | Node *root = makeExample(); 104 | printTree(root); 105 | 106 | } 107 | -------------------------------------------------------------------------------- /aulas/aula17/aula17.md: -------------------------------------------------------------------------------- 1 | # Resolução de Colisões 2 | 3 | ## I. Open hashing 4 | 5 | - Várias chaves na mesma posição (por ex., em uma lista encadeada) 6 | 7 | **Exemplo:**                             8 | 9 | - `h(k) = k mod 10` 10 | 11 | ``` 12 | +---+ 13 | 0 | | 14 | . 15 | . 16 | . 17 | 4 | | 18 | +---+ 19 | 5 | ----→ 195 → 1215 → 75 → ⊥ 20 | +---+ 21 | 6 | | 22 | . 23 | . 24 | . 25 | 9 | | 26 | +---+ 27 | ``` 28 | 29 | ### Análise 30 | 31 | #### Pior caso: todas as chaves na mesma posição 32 | ⟹ acesso, ins, del precisa comparar com todas as `n` chaves na coleção 33 | 34 | #### Melhor caso: sem colisões 35 | ⟹ acesso, ins, del realiza no máximo uma comparação 36 | 37 | #### Caso médio: 38 | 39 | - Hipótese da **dispersão uniforme simples**: A probabilidade de uma chave cair em qualquer posição é a mesma das demais 40 | 41 | $$ 42 | \mathbb{P}[h(k) = i] = \frac{1}{m} \quad \forall i, \text{ independente das outras chaves} 43 | $$ 44 | 45 | - Número esperado de chaves por posição da tabela: 46 | $$ 47 | \mathbb{E}[\text{chaves na posição } i] = \frac{n}{m} \quad \forall i, \text{ independente das outras chaves} 48 | $$ 49 | 50 | - Número de comparações na busca falhada (= inserção): compara com todas as `n/m` chaves da posição 51 | 52 | - Número de comparações na busca bem-sucedida (= remoção): na média compara com metade das chaves da posição 53 | 54 | 55 | #### Definição: Fator de carga 56 | 57 | - `α = n/m`, onde 58 | - `n` = número de elementos na coleção 59 | - `m` = número de posições da tabela 60 | - O fator de carga dá uma ideia da ocupação média da tabela 61 | 62 | ⇨ Tempo médio (número de comparações) das operações no hashing aberto 63 | 64 | 65 | 66 | (*) supondo dispersão uniforme simples 67 | 68 | ### Rehashing 69 | 70 | - Para manter o tempo limitado a um valor máximo $t_{max}$, precisamos limitar o fator de carga a um valor máximo $\alpha_{max}$ (ex. 0,75) 71 | - Quanto maior o $\alpha_{max}$, maior o $t_{max}$, porém menor o espaço usado pela tabela 72 | - Quando o fator de carga $alpha$ atingir o limite $\alpha_{max}$, executa uma redistribuição (**rehashing**): 73 | - Cria uma nova tabela com o dobro da capacidade atual `m'=2*m` 74 | - **Re-insere** todos os elementos da tabela na nova tabela, usando o mesmo processo de inserção, porém considerando o novo valor `m'` no cálculo da função de dispersão 75 | - Ao final, descarta a antiga tabela e continua com a nova tabela. O novo fator de carga será $\alpha' = n/m' = \alpha/2 < \alpha_{max}$ 76 | 77 | ⚠️ Por razões análogas aos da [análise dos arrays dinâmicos](../aula13/aula13.md), o tempo de duplicação das tabelas devido ao rehashing é amortizado ao longo das inserções, acrescentando apenas um fator constante na média por elemento. 78 | 79 | 80 | ___ 81 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula16/aula16.md) [[Próximo >]](../aula18/aula18.md) [[Índice ^]](../index.md) -------------------------------------------------------------------------------- /aulas/aula12/aula12.md: -------------------------------------------------------------------------------- 1 | # Aula 12: Pilhas e Filas 2 | 3 | 4 | ## Pilhas 5 | 6 | - Especialização de uma Lista 7 | - Ainda uma estrutura dinâmica linear 8 | - Porém com Inserção / Remoção / Acesso mais restrito 9 | - Política LIFO (Last In, First Out): 10 | - Acesso apenas ao último elemento (topo da pilha) 11 | - Inserções/Remoções apenas no topo 12 | - Operações: 13 | - `stack.top()`: consulta o valor do topo da pilha 14 | - `stack.push(v)`: empilha o valor `v`, i.e. acrescenta `v` ao final (topo) da pilha 15 | - `stack.pop()`: desempilha o valor do topo da pilha 16 | 17 | ### Conceitualmente 18 | 19 | ``` 20 | +-----+ 21 | | E | <- Topo (último elemento empilhado) 22 | +-----+ 23 | | D | 24 | +-----+ 25 | | C | 26 | +-----+ 27 | | B | 28 | +-----+ 29 | | A | <- Base (primeiro elemento adicionado) 30 | +-----+ 31 | ``` 32 | 33 | ### Implementação com Lista Encadeada 34 | 35 | - Uma pilha pode ser implementada internamente como uma lista encadeada 36 | 37 | 38 | ``` 39 | top +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ 40 | ------>| \ | --|---->| E | --|---->| D | --|---->| C | --|---->| B | --|---->| A | --|------+ 41 | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | 42 | === 43 | ``` 44 | 45 | 46 | ## Filas 47 | 48 | - Especialização de uma Lista 49 | - Ainda uma estrutura dinâmica linear 50 | - Porém com Inserção / Remoção / Acesso mais restrito 51 | - Política FIFO (First In, First Out): 52 | - Acesso apenas ao primeiro e último elementos (cabeça e cauda) 53 | - Inserções apenas no final 54 | - Remoções apenas do topo 55 | - Operações: 56 | - `queue.enqueue(v)`: enfileira o valor `v`, i.e. acrescenta `v` ao final cauda da fila 57 | - `queue.dequeue()`: desenfileira o valor do início da fila 58 | 59 | ### Conceitualmente 60 | 61 | ``` 62 | +-----+-----+-----+-----+-----+ 63 | Saida <===== | A | B | C | D | E | <===== Entrada 64 | +-----+-----+-----+-----+-----+ 65 | ``` 66 | 67 | ### Implementação com Lista Encadeada 68 | 69 | - Uma pilha pode ser implementada internamente como uma lista encadeada 70 | 71 | 72 | ``` 73 | head +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ 74 | ------>| \ | --|---->| A | --|---->| B | --|---->| C | --|---->| D | --|---->| E | --|------+ 75 | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | 76 | ^ === 77 | | 78 | tail 79 | ``` 80 | 81 | 82 | 83 | ___ 84 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula11/aula11.md) [[Próximo >]](../aula13/aula13.md) [[Índice ^]](../index.md) 85 | -------------------------------------------------------------------------------- /cpp/1_07_basic_io_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Basic I/O 3 | 4 | 5 | Standard streams of **iostream** library: 6 | 7 | - **`std::cout`** → Standard output (console) 8 | - **`std::cin`** → Standard input (keyboard) 9 | - **`std::cerr`** → Standard error (unbuffered) 10 | - **`std::clog`** → Standard log output (buffered) 11 | 12 | 13 | 14 | ## Output with `std::cout` 15 | 16 | ```cpp 17 | #include 18 | 19 | int main() { 20 | std::cout << "Hello, World!" << std::endl; 21 | return 0; 22 | } 23 | ``` 24 | 25 | - `std::cout` → Standard output stream. 26 | - `<<` → Insertion operator (outputs data). 27 | - `"Hello, World!"` → The message to be printed. 28 | - `std::endl` → Inserts a newline **and flushes the output buffer**. 29 | 30 | 31 | 32 | ## Read input with `std::cin` 33 | 34 | ```cpp 35 | #include 36 | 37 | int main() { 38 | int age; 39 | std::cout << "Enter your age: "; 40 | std::cin >> age; 41 | std::cout << "You are " << age << " years old.\n"; // does not flush the buffer 42 | return 0; 43 | } 44 | ``` 45 | 46 | - `std::cin >> age;` → Reads an integer input from the user. 47 | - If the input type does not match, `cin` enters an error state. 48 | 49 | 50 | ### Handling invalid input 51 | 52 | ```cpp 53 | while(true) { 54 | std::cout << "Enter your age: "; 55 | std::cin >> age; 56 | if (std::cin.fail() || age < 0) { 57 | std::cerr << "Invalid input!\n"; 58 | continue; 59 | } 60 | } 61 | ``` 62 | 63 | 64 | ## Inputting Strings 65 | 66 | - By default, `std::cin` stops reading at the first space. 67 | - To read full lines, use `std::getline()`. 68 | 69 | ```cpp 70 | #include 71 | #include 72 | 73 | int main() { 74 | std::string name; 75 | std::cout << "Enter your full name: "; 76 | std::cin.ignore(); // clear input buffer 77 | std::getline(std::cin, name); 78 | std::cout << "Hello, " << name << "!\n"; 79 | return 0; 80 | } 81 | ``` 82 | 83 | 84 | ## Error Messages with `std::cerr` 85 | 86 | - `std::cerr` is used for error messages and is **not buffered** i.e. prints **immediately**. 87 | 88 | ```cpp 89 | std::cerr << "Error: File not found!\n"; 90 | ``` 91 | 92 | 93 | 94 | ## Logging with `std::clog` 95 | 96 | - `std::clog` is used for logging messages and is **buffered**, meaning output might be delayed. 97 | - Similar to `std::cerr` but unbuffered. 98 | - Usually redirected to whatever logging means 99 | 100 | ```cpp 101 | std::clog << "Logging info: Application started...\n"; 102 | ``` 103 | 104 | --- 105 | [[⇦ Previous](1_06_control_flow_idx.md)] [[Next ⇨](1_08_file_io_idx.md)] [[Index ⇧](index.md#1_07_basic_io_idx.md)] 106 | -------------------------------------------------------------------------------- /cpp/1_06_control_flow_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Control Flow 3 | 4 | 5 | ## Conditional Statements 6 | 7 | 8 | ### if 9 | 10 | - Executes a block if a condition is true 11 | 12 | ```cpp 13 | if (x > 0) { 14 | // code 15 | } 16 | ``` 17 | 18 | 19 | ### if-else 20 | 21 | - Executes one block if true, another if false 22 | 23 | ```cpp 24 | if (x > 0) { 25 | // code 26 | } else { 27 | // code 28 | } 29 | ``` 30 | 31 | 32 | ### else if 33 | 34 | - Checks multiple conditions 35 | 36 | ```cpp 37 | if (x > 10) { 38 | // code 39 | } else if (x > 5) { 40 | // code 41 | } else { 42 | // code 43 | } 44 | ``` 45 | 46 | 47 | ### switch 48 | 49 | - Multi-way branching based on **integral (integers, char, bool) and enum** values 50 | 51 | ```cpp 52 | switch (x) { 53 | case 1: 54 | // code 55 | break; 56 | case 2: 57 | // code 58 | break; 59 | default: 60 | // code 61 | } 62 | ``` 63 | 64 | 65 | 66 | ## Looping Constructs 67 | 68 | 69 | ### for 70 | 71 | - Loop with initialization, condition, and increment 72 | 73 | ```cpp 74 | for (int i = 0; i < 10; i++) { 75 | // code 76 | } 77 | ``` 78 | 79 | 80 | ### while 81 | 82 | - Loops while a condition is true 83 | 84 | ```cpp 85 | while (x > 0) { 86 | // code 87 | } 88 | ``` 89 | 90 | 91 | ### do-while 92 | 93 | - Executes at least once, then loops while the condition is true 94 | 95 | ```cpp 96 | do { 97 | // code 98 | } while (x > 0); 99 | ``` 100 | 101 | 102 | ## Jump Statements 103 | 104 | 105 | ### break 106 | 107 | - Exits a loop or `switch` statement 108 | 109 | ```cpp 110 | if (x == 5) break; 111 | ``` 112 | 113 | 114 | ### continue 115 | 116 | - Skips the current iteration and moves to the next 117 | 118 | ```cpp 119 | for (int i = 0; i < 10; i++) { 120 | if (i == 5) continue; 121 | // code 122 | } 123 | ``` 124 | 125 | 126 | ### return 127 | 128 | - Exits a function, optionally returning a value 129 | 130 | ```cpp 131 | return x; 132 | ``` 133 | 134 | 135 | ### goto _(Avoid)_ 136 | 137 | - Jumps to a labeled statement 138 | 139 | ```cpp 140 | goto label; 141 | label: 142 | // code 143 | ``` 144 | 145 | --- 146 | [[⇦ Previous](1_05_vars_constants_idx.md)] [[Next ⇨](1_07_basic_io_idx.md)] [[Index ⇧](index.md#1_06_control_flow_idx.md)] 147 | -------------------------------------------------------------------------------- /cpp/1_15_references_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # References (`&`) 3 | 4 | - A **reference** in C++ is an alias for an existing variable. 5 | - It provides a way to access the same object using a different name, **without creating a copy**. 6 | 7 | 8 | ## Syntax of References 9 | 10 | ```cpp 11 | int a = 10; 12 | int& ref = a; // 'ref' is a reference to 'a' 13 | ``` 14 | - `ref` is not a new variable but another name for `a`. 15 | - Any change to `ref` affects `a`, and vice versa. 16 | 17 | ```cpp 18 | #include 19 | int main() { 20 | int x = 5; 21 | int& y = x; // y is a reference to x 22 | 23 | std::cout << "x: " << x << ", y: " << y << std::endl; 24 | y = 10; // Modifies x too 25 | 26 | std::cout << "x: " << x << ", y: " << y << std::endl; 27 | } 28 | ``` 29 | 30 | ### Output 31 | ``` 32 | x: 5, y: 5 33 | x: 10, y: 10 34 | ``` 35 | 36 | 37 | ## Properties of References 38 | 39 | - **Must be initialized at declaration** 40 | ```cpp 41 | int& ref; // ERROR: References must be initialized 42 | ``` 43 | - **Cannot be reassigned** 44 | ```cpp 45 | int a = 10, b = 20; 46 | int& ref = a; 47 | ref = b; // This does NOT change ref to reference 'b', it just assigns 'b' to 'a' 48 | ``` 49 | - **Cannot be null** 50 | ```cpp 51 | int& ref = nullptr; // ERROR: References must refer to a valid object 52 | ``` 53 | - **Does not consume extra memory** (unlike pointers) 54 | - Faster than pointers (do not require dereferencing) 55 | - Safer than pointers 56 | 57 | 58 | 59 | ## Using References in Functions 60 | 61 | 62 | ### Pass-by-Reference (Avoids Copying) 63 | 64 | - Faster than passing by value (no copy). 65 | 66 | ```cpp 67 | void scale(Vector2D& v, double factor) { 68 | v.scale(factor); // Modifies the original object 69 | } 70 | ``` 71 | 72 | 73 | ### Returning a Reference 74 | 75 | ```cpp 76 | int& getMax(int& a, int& b) { 77 | return (a > b) ? a : b; 78 | } 79 | ``` 80 | 81 | ⚠️ Do not return references to local variables! 82 | 83 | 84 | 85 | ## Unmutable `const` References 86 | 87 | - Used for **read-only access**. 88 | 89 | ```cpp 90 | void print(const Vector2D& v) { // Cannot modify v 91 | std::cout << v.X() << ", " << v.Y() << std::endl; 92 | } 93 | ``` 94 | 95 | - Works with Temporary Values 96 | 97 | ```cpp 98 | const int& ref = 5; // OK (compiles) 99 | int& ref2 = 5; // ERROR: Cannot bind non-const reference to a temporary 100 | ``` 101 | 102 | 103 | ## When to Use References? 104 | 105 | - When passing large objects to functions (`const&` for efficiency). 106 | - When returning values from functions (to avoid copying). 107 | - When you want to ensure the reference is **never null**. 108 | 109 | --- 110 | [[⇦ Previous](1_14_OOP_classes_idx.md)] [[Next ⇨](1_16_rule_of_five_idx.md)] [[Index ⇧](index.md#1_15_references_idx.md)] 111 | -------------------------------------------------------------------------------- /cpp/1_28_unordered_maps_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # `std::unordered_map` (vs. `std::map`) 3 | 4 | - `std::unordered_map` is a **hash table-based associative container** 5 | - Creation/lookup/insertion/deletion similar to `std::map` but with key differences: 6 | 7 | 8 | | Feature | `std::map` | `std::unordered_map` | 9 | |---------|-----------|----------------------| 10 | | **Implementation** | **Balanced BST (Red-Black Tree)** | **Hash Table** | 11 | | **Ordering** | **Keys are sorted** | **No specific order** | 12 | | **Lookup Complexity** | **O(log n)** | **O(1) average, O(n) worst case** | 13 | | **Insertion Complexity** | **O(log n)** | **O(1) average, O(n) worst case** | 14 | | **Memory Usage** | **Less overhead** | **More due to hash table buckets** | 15 | | **Best for** | When **order matters** | When **fast lookups** matter | 16 | 17 | 18 | 19 | ## Using `std::unordered_map` with Custom Classes 20 | 21 | - To use a custom class as a key in `std::unordered_map`, we must provide: 22 | - "Equals" comparison operator (`operator==()`). 23 | - A hash function because it uses hashing instead of comparisons. This can be done either: 24 | - By specializing the `std::hash` functor. 25 | - By providing a custom Hash functor. 26 | 27 | ```cpp 28 | #include 29 | #include 30 | #include 31 | 32 | struct Point { 33 | int x, y; 34 | bool operator==(const Point& other) const { // Required for unordered_map 35 | return x == other.x && y == other.y; 36 | } 37 | }; 38 | 39 | // Specializing std::hash 40 | namespace std { 41 | template <> 42 | struct hash { 43 | std::size_t operator()(const Point& p) const { 44 | // Combine the hash values of the members 45 | return std::hash()(p.x) ^ (std::hash()(p.y) << 1); 46 | } 47 | }; 48 | } 49 | 50 | // Custom hash functor 51 | struct PointHash { 52 | std::size_t operator()(const Point& p) const { 53 | return std::hash()(p.x) ^ (std::hash()(p.y) << 1); 54 | } 55 | }; 56 | 57 | int main() { 58 | std::unordered_map pointMap; 59 | 60 | pointMap[{1, 2}] = "A"; 61 | pointMap[{3, 4}] = "B"; 62 | 63 | std::cout << "Point (1,2): " << pointMap[{1, 2}] << std::endl; 64 | 65 | std::unordered_map pointMap2; 66 | 67 | pointMap2[{5, 6}] = "C"; 68 | pointMap2[{7, 8}] = "D"; 69 | 70 | std::cout << "Point (7,8): " << pointMap2[{7, 8}] << std::endl; 71 | } 72 | ``` 73 | 74 | 75 | ### ⚠️ Key Rule: Consistency Between `==` and Hash Function 76 | 77 | - When using a custom class as a key in an `std::unordered_map`, there is a critical **interdependency** between them:j 78 | **If two objects are considered equal, their hash values ️must be the same.** 79 | 80 | ``` 81 | If obj1 == obj2, then hash(obj1) == hash(obj2) 82 | ``` 83 | 84 | - This is because `std::unordered_map` relies on the hash value to group keys into buckets. If two keys are equal but produce different hash values, the map will not work correctly, leading to undefined behavior or logical errors. 85 | 86 | --- 87 | [[⇦ Previous](1_27_maps_idx.md)] [[Next ⇨](1_29_iterators_idx.md)] [[Index ⇧](index.md#1_28_unordered_maps_idx.md)] 88 | -------------------------------------------------------------------------------- /aulas/aula16/aula16.md: -------------------------------------------------------------------------------- 1 | # Tabelas de Dispersão 2 | 3 | **Problema:** 4 | Manter coleção dinâmica de registros com busca (exata e unitária) **muito** eficiente. 5 | 6 | **Supomos que** cada registro possui chave numérica num conjunto 7 | 8 | $$ 9 | U = \{ 0, \dots, u - 1 \} 10 | $$ 11 | 12 | Registro: 13 | 14 | ``` 15 | +-----+------+ 16 | | key | data | 17 | +-----+------+ 18 | ``` 19 | 20 | ## Ideia 0: 21 | 22 | * Usar array de booleanos $T = (t[0], \dots, t[u-1])$ 23 | * Registro com chave $k$ na posição $T[k]$ 24 | * Inserir/Remover/Consultar requer apenas acesso à posição $T[k]$ → Instantâneo com arrays 25 | 26 | **Problema:** $u \gg n$ (nº de registros) $\Rightarrow$ ineficiência de memória 27 | 28 | This page is also very clear — here's a full transcription: 29 | 30 | 31 | ## Ideia 1: Hash table 32 | 33 | 34 | 35 | 36 | * $K=\{k_0,\ldots,k_{n-1}\} \subset U$: conjunto de chaves 37 | * $h: K \rightarrow \{0..m-1\}$: função de dispersão que mapeia cada chave numa posição da tabela 38 | * $T$: tabela com $m \propto n$ posições 39 | 40 | ⚠️ Uma **colisão** ocorre quando duas chaves são mapeada na mesma posição da tabela 41 | 42 | 43 | ### Tarefas: 44 | 45 | - I. Definir função de dispersão 46 | - II. Tratar colisões 47 | 48 | 49 | ## Funções de Dispersão 50 | 51 | ### Requisitos: 52 | 53 | 1. **Dispersar uniformemente** as chaves pela tabela 54 | 2. **Ser robusta** a regularidades e viéses nas chaves 55 | 56 | ### Desafios: 57 | 58 | 1. Distribuição das chaves desconhecida 59 | 2. Regularidades frequentes 60 | 61 | ⚠️ **Não existe receita única** ⇒ **heurísticas** 62 | 63 | 64 | ### Exemplo 1 — Heurística da divisão 65 | 66 | $$ 67 | h(k) = k \bmod m 68 | $$ 69 | 70 | * Eficiência depende de $m$ 71 | * Sensível a regularidades 72 | * Por exemplo, se $m = 2^r$, então: 73 | 74 | $$ 75 | k = 101010011110110 76 | $$ 77 | 78 | $$ 79 | h(k) = \text{r bits menos significativos (lsb's)} 80 | $$ 81 | 82 | * Regularidades nos bits menos significativos (**lsb's**) são **muito comuns** → isso leva a **colisões**. 83 | 84 | * ✅ Estratégia: 85 | - Escolher $m$ como um **número primo**, **não próximo** de potências de 2 ou 10 (bases comuns em dados reais). 86 | 87 | 88 | 89 | ### Exemplo 2 – Heurística da Multiplicação 90 | 91 | $$ 92 | h(k) = ((A \cdot k) \mod 2^w) \ \text{rsh} \ (w - r) 93 | $$ 94 | 95 | 📌 Onde: 96 | 97 | * $A$ é um **inteiro ímpar** tal que $2^{w-1} < A < 2^w$ (primeiro e último bits = 1) 98 | * `rsh` = **right-shift binário** (deslocamento à direita) 99 | * $m = 2^r$ é o número de posições da tabela 100 | * $w$ é o número de bits de um inteiro 101 | 102 | #### Exemplo: 103 | 104 | * $m = 8 = 2^3 \Rightarrow r = 3$ 105 | * $w = 7$ 106 | * $A = 1010001$ 107 | * $k = 1101011$ 108 | 109 | ``` 110 | 1011001 : A 111 | 1101011 : k 112 | -------------- 113 | 1011001 114 | 1011001 115 | 0000000 116 | 1011001 117 | 0000000 118 | 1011001 119 | 1011001 120 | -------------- 121 | 10010100110011 : A*k 122 | -------------- 123 | 0110011 : (A*k mod 2^w) 124 | -------------- 125 | 011 : (A*k mod 2^w) >> (w-r) 126 | ``` 127 | 128 | $$ 129 | h(k) = \text{3 bits no ``meio'' do produto} 130 | $$ 131 | 132 | ___ 133 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula15/aula15.md) [[Próximo >]](../aula17/aula17.md) [[Índice ^]](../index.md) -------------------------------------------------------------------------------- /aulas/aula20/aula20.md: -------------------------------------------------------------------------------- 1 | # Árvores 2 | 3 | - Matematicamente, uma árvore é um grafo conexo acíclico 4 | - Grafo: **nós** (vértices) ligados por **arestas** `G=(V,E)` 5 | - Conexo: existe sempre um caminho entre dois nós quaisquer 6 | - Acíclico: Não contém ciclos, i.e. caminhos que começam e terminam no mesmo nó 7 | 8 | 9 | 10 | ⚠️ Esta definição não leva em conta a direção das arestas 11 | 12 | Vamos nos concentrar no uso de árvores como estruturas de dados para armazenar informação de forma estruturada nos nós 13 | 14 | ## Árvores enraizadas 15 | 16 | - Numa árvore enraizada as arestas têm uma direção 17 | ``` 18 | .--------. 19 | | Nó pai | 20 | `--------' 21 | | 22 | | 23 | v 24 | .----------. 25 | | Nó filho | 26 | `----------' 27 | ``` 28 | 29 | - Um nó pai pode ter 0 ou mais filhos 30 | - Cada nó tem exatamente um nó pai, com exceção de um único nó que não tem pai 31 | - O nó que não tem pai é chamado **raiz** (root) 32 | - Os nós que não têm filhos são chamados **folhas** 33 | - Os demais nós são chamados **nós internos** 34 | 35 | 36 | 37 | - Árvores enraizadas são usadas para representar estruturas hierárquicas, ex. um sistema de arquivos 38 | 39 | ``` 40 | . 41 | ├── modules 42 | │   ├── drivers 43 | │   │   ├── amdgpu_drv.so 44 | │   │   ├── ati_drv.so 45 | │   │   ├── fbdev_drv.so 46 | │   │   ├── intel_drv.so 47 | │   │   ├── modesetting_drv.so 48 | │   │   ├── nouveau_drv.so 49 | │   │   ├── qxl_drv.so 50 | │   │   ├── radeon_drv.so 51 | │   │   ├── vesa_drv.so 52 | │   │   └── vmware_drv.so 53 | │   ├── extensions 54 | │   │   └── libglx.so 55 | │   ├── input 56 | │   │   ├── inputtest_drv.so 57 | │   │   ├── libinput_drv.so 58 | │   │   └── wacom_drv.so 59 | │   ├── libexa.so 60 | │   ├── libfbdevhw.so 61 | │   ├── libglamoregl.so 62 | │   ├── libint10.so 63 | │   ├── libshadowfb.so 64 | │   ├── libshadow.so 65 | │   ├── libvgahw.so 66 | │   └── libwfb.so 67 | ├── protocol.txt 68 | ├── Xorg 69 | └── Xorg.wrap 70 | ``` 71 | 72 | ## Árvores binárias 73 | 74 | - Um tipo particular de árvore enraizada são as **árvores binárias** 75 | - Numa árvore binária cada nó tem no máximo 2 filhos 76 | - Cada nó implementado como um registro 77 | 78 | ``` 79 | +-------+-------+-------+ 80 | | left | val | right | 81 | +--/----+-------+----\--+ 82 | / \ 83 | v v 84 | ``` 85 | - `node.val`: valor (informação) associado ao nó 86 | - `node.left`: ponteiro para o nó filho à esquerda 87 | - `node.right`: ponteiro para o nó filho à direita 88 | 89 | ### Definição recursiva 90 | 91 | A definição abaixo ajuda a pensar numa árvore binária como uma estrutura recursiva, conveniente para muitos algoritmos 92 | 93 | 1. Um conjunto vazio de nós é uma árvore binária (árvore vazia) 94 | 2. Se 95 | - `N` é um nó 96 | - `T1` e `T2` são ávores binárias *disjuntas* com raízes `r1` e `r2` 97 | - `N` não está nem em `T1` nem `T2` 98 | Então 99 | 100 | ``` 101 | T: N 102 | / \ 103 | / \ 104 | r1 r2 105 | T1 / \ / \ T2 106 | / \ / \ 107 | /______\ /______\ 108 | ``` 109 | é uma árvore binária 110 | 111 | 112 | ### Exemplo 113 | 114 | 115 | 116 | 117 | ___ 118 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula19/aula19.md) [[Próximo >]](../aula21/aula21.md) [[Índice ^]](../index.md) -------------------------------------------------------------------------------- /cpp/1_21_templates_metaprogramming_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Templates and Generic Programming: Advanced Issues 3 | 4 | 5 | ## Template Metaprogramming (TMP) 6 | 7 | - Templates can be used for **compile-time computation**. 8 | 9 | 10 | ### `constexpr` and `if constexpr` 11 | 12 | - C++17 introduced `if constexpr` to evaluate conditions at compile-time. 13 | - The `if constexpr` block removes unused branches at compile-time. 14 | 15 | ```cpp 16 | template 17 | void process(T value) { 18 | if constexpr (std::is_integral_v) { 19 | std::cout << "Integer type\n"; 20 | } else { 21 | std::cout << "Non-integer type\n"; 22 | } 23 | } 24 | ``` 25 | 26 | 27 | ### SFINAE (Substitution Failure Is Not An Error) 28 | 29 | - SFINAE allows **template overload selection** based on conditions. 30 | 31 | ```cpp 32 | template >> 33 | void process(T value) { 34 | std::cout << "Integer type\n"; 35 | } 36 | ``` 37 | - This function is only enabled if `T` is an integer. 38 | 39 | 40 | 41 | ## CRTP (Curiously Recurring Template Pattern) 42 | 43 | - CRTP is used for **static polymorphism**. 44 | - Used extensively in C++/WinRT. 45 | 46 | ```cpp 47 | template 48 | class IWorker { 49 | public: 50 | void do_work() { 51 | static_cast(this)->do_work_impl(); 52 | } 53 | }; 54 | 55 | class Worker : public IWorker { 56 | public: 57 | void do_work_impl() { std::cout << "Worker do_work_impl\n"; } 58 | }; 59 | 60 | template 61 | void func(IWorker &worker) { // Receives any obj implementing IWorker 62 | worker.do_work(); 63 | } 64 | 65 | int main() { 66 | Worker w; 67 | w.do_work(); // Calls Worker::do_work_impl() 68 | func(w); 69 | } 70 | ``` 71 | 72 | - Avoids **virtual function overhead**. 73 | 74 | 75 | 76 | ## Templates and Inheritance 77 | 78 | - Templates can be used as **base classes**. 79 | ```cpp 80 | template 81 | class Base { }; 82 | 83 | class Derived : public Base { }; 84 | ``` 85 | 86 | - When referring to a **dependent base class member**, use `typename` and `template`: 87 | - Necessary because of name resolution issues: 88 | - If used `Base::Type` only, the compiler doesn't know if this is, for example, an static member of `Base`. 89 | 90 | ```cpp 91 | template 92 | class Base { 93 | protected: 94 | using Type = T; 95 | }; 96 | 97 | template 98 | class Derived : public Base { 99 | typename Base::Type value; // Required! 100 | }; 101 | ``` 102 | 103 | 104 | ## Performance & Compilation Aspects 105 | 106 | - **Header-Only Libraries:** Templates are **defined** in headers because they need to be instantiated at compile-time. 107 | - **Code Bloat:** Every unique template instantiation generates separate code. 108 | - **Link-Time Optimization (LTO):** Helps reduce redundant instantiations. 109 | 110 | --- 111 | [[⇦ Previous](1_20_templates_idx.md)] [[Next ⇨](1_22_static_errors_idx.md)] [[Index ⇧](index.md#1_21_templates_metaprogramming_idx.md)] 112 | -------------------------------------------------------------------------------- /cpp/1_22_static_errors_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Error Handling 3 | 4 | - Errors can be treated at compile and/or runtime. 5 | 6 | 7 | 8 | # Compile Time (static) Error-check 9 | 10 | - Detect and prevent incorrect usage before the program runs. 11 | 12 | 13 | ## `static_assert`: Compile Time Assertions (C++11) 14 | 15 | - `static_assert` allows checking conditions at compile time. 16 | - The condition must be testable at compile time. 17 | - If the condition is false, compilation **fails** with an error message. 18 | 19 | ```cpp 20 | // Example: Ensuring an Integer Type 21 | template 22 | void process() { 23 | static_assert(std::is_integral::value, "T must be an integral type!"); 24 | } 25 | int main() { 26 | process(); // OK Compiles 27 | process(); // Compilation Error: "T must be an integral type!" 28 | } 29 | ``` 30 | 31 | 32 | ## `constexpr` for Compile-time Evaluation (C++11) 33 | 34 | - A `constexpr` function may be evaluate at compile time ensuring correctness before runtime. 35 | 36 | ```cpp 37 | constexpr int factorial(int n) { // evaluates at compile time if n is a constant expression 38 | return (n <= 1) ? 1 : (n * factorial(n - 1)); 39 | } 40 | 41 | static_assert(factorial(5) == 120, "Factorial calculation is incorrect!"); 42 | ``` 43 | 44 | 45 | ## SFINAE (Substitution Failure Is Not An Error) 46 | 47 | 48 | - SFINAE helps detect invalid template instantiations 49 | 50 | ```cpp 51 | // Example: Enable Function Only for Integers 52 | #include 53 | 54 | template 55 | typename std::enable_if::value>::type foo(T) { 56 | // Only works for integral types 57 | } 58 | 59 | int main() { 60 | foo(10); // OK, int is integral 61 | foo(3.14); // Compilation Error 62 | } 63 | ``` 64 | 65 | 66 | ## Type Traits 67 | 68 | - Type traits in `` allows for compile-time type checks. 69 | 70 | ```cpp 71 | template 72 | void check() { 73 | static_assert(std::is_same::value, "T must be int!"); 74 | } 75 | 76 | check(); // OK 77 | check(); // Compilation Error 78 | ``` 79 | 80 | 81 | ## Prevent Instantiation Using Deleted Functions 82 | 83 | - You can **prevent instantiation** of certain templates by deleting them. 84 | 85 | ```cpp 86 | template 87 | class Example {}; 88 | 89 | // Explicitly disable `double` 90 | template <> 91 | class Example = delete; 92 | 93 | Example obj1; // OK 94 | Example obj2; // Compilation Error 95 | ``` 96 | 97 | 98 | ## `concepts` (C++20) 99 | 100 | - C++20 introduces **concepts** to enforce type constraints at compile time. 101 | 102 | ```cpp 103 | #include 104 | 105 | template // Requires `T` to be an integer 106 | void process(T value) {} 107 | 108 | process(10); // OK 109 | process(3.14); // Compilation Error 110 | ``` 111 | 112 | 113 | ## Learn more 114 | 115 | - [Type traits](https://en.cppreference.com/w/cpp/meta#Type_traits) 116 | - [Concepts](https://en.cppreference.com/w/cpp/concepts) 117 | 118 | --- 119 | [[⇦ Previous](1_21_templates_metaprogramming_idx.md)] [[Next ⇨](1_23_exceptions_idx.md)] [[Index ⇧](index.md#1_22_static_errors_idx.md)] 120 | -------------------------------------------------------------------------------- /cpp/1_01_intro_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Introduction to Modern C++ 3 | 4 | 5 | ## What is C++ 6 | 7 | - C++ is a high-performance, general-purpose programming language that combines procedural, object-oriented, and generic programming paradigms. 8 | - Originally developed by Bjarne Stroustrup in the early 1980s as an extension of C. 9 | - Offers direct memory management, low-level system access, and high efficiency while also supporting abstraction and modularity. 10 | - Widely used in systems programming, game development, real-time applications, and performance-critical software. 11 | - C++ is standardized by the International Organization for Standardization (ISO) through the C++ Standard Committee. 12 | - The first official standard, C++98, was published in 1998, and since then, the language has evolved through successive standards released approximately every three years. 13 | - Each new standard has introduced major improvements in expressiveness, safety, and performance. 14 | 15 | 16 | ## Evolution from C\+\+98 to C\+\+20 17 | 18 | - **C++98 (1998)**: Introduced the Standard Template Library (STL), including containers, iterators, and algorithms. 19 | - **C++03 (2003)**: Primarily a bug-fix release with minor enhancements. 20 | - **C++11 (2011) - "Modern C++ Begins"**: 21 | - Move semantics (`std::move`, `std::unique_ptr`) 22 | - Smart pointers (`std::shared_ptr`, `std::weak_ptr`) 23 | - Lambda functions 24 | - Range-based for loops 25 | - `auto` type deduction 26 | - `nullptr`, `constexpr`, `enum class` 27 | - **C++14 (2014)**: Small refinements to C++11 (e.g., generic lambdas, `std::make_unique`). 28 | - **C++17 (2017)**: 29 | - `std::optional`, `std::variant`, and `std::any` 30 | - `std::filesystem` 31 | - Structured bindings (`auto [x, y] = pair;`) 32 | - Parallel algorithms in the STL 33 | - **C++20 (2020) - "The Next Big Leap"**: 34 | - Concepts (for better template constraints) 35 | - Coroutines 36 | - Ranges library 37 | - `std::span` for safer array handling 38 | - Modules (replacing traditional header files) 39 | - `constexpr` expansion (more compile-time computations) 40 | 41 | 42 | 43 | ## Key Features of Modern C++ 44 | 45 | - **Move Semantics**: Optimizes performance by avoiding deep copies. 46 | - **Smart Pointers**: Eliminates manual memory management errors. 47 | - **Lambdas & Functional Programming**: Allows concise inline function expressions. 48 | - **Type Deduction (`auto`, `decltype`)**: Reduces verbosity while improving readability. 49 | - **Ranges & Algorithms**: Simplifies iteration and data manipulation. 50 | - **Coroutines**: Enables more efficient asynchronous programming. 51 | - **Modules**: Reduces compile times and eliminates header file complexities. 52 | - **Better Multi-threading Support**: `std::thread`, `std::async`, `std::mutex`, `std::atomic`. 53 | 54 | 55 | ## Why C++ is Still Relevant Today 56 | 57 | Despite the rise of newer languages like Rust and Go, C++ remains widely used due to: 58 | 59 | 1. **Performance & Efficiency**: Unlike managed languages (e.g., Java, C#), C++ gives direct control over memory and system resources. 60 | 2. **Embedded Systems & Game Development**: Used in real-time systems, gaming engines (Unreal Engine), and high-performance applications. 61 | 3. **Large-Scale Applications**: Banks, aerospace, automotive, and robotics heavily rely on C++. 62 | 4. **Cross-Platform Development**: Code can be compiled for Windows, Linux, macOS, and embedded systems with minimal modifications. 63 | 5. **Backbone of Modern Languages**: C++ influences languages like Rust, Swift, and C#. 64 | 65 | 66 | --- 67 | [[⇦ Previous](index.md)] [[Next ⇨](1_02_csharp_vs_cpp_idx.md)] [[Index ⇧](index.md#1_01_intro_idx.md)] 68 | -------------------------------------------------------------------------------- /cpp/1_16_rule_of_five_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # RAII and the Rule of Five 3 | 4 | 5 | ## RAII 6 | 7 | - RAII (Resource Acquisition Is Initialization) is a design pattern in C++ that ensures **automatic resource management** using **constructors and destructors**. 8 | - The key idea is to acquire a resource (memory, file, lock, etc.) in a constructor and release it in the destructor, ensuring proper cleanup 9 | - Without RAII, we risk resource leaks, especially when exceptions occur. 10 | 11 | Consider a generalization of previous `Vector2D` to multidimensional spaces. 12 | 13 | ```cpp 14 | class VectorND { 15 | private: 16 | size_t n; // vector size 17 | double* arr; // heap-allocated values 18 | public: 19 | // Constructor (resource acquisition) 20 | VectorND(size_t dim, double defaultValue = 0) : n{ dim }, arr{ new double[dim] } { 21 | for (size_t i = 0; i < n; arr[i++] = defaultValue); 22 | } 23 | // Destructor (resource release) 24 | ~VectorND() { delete[] arr; } // Always cleans up! 25 | }; 26 | 27 | 28 | void safeFunction() { 29 | VectorND v(1000000); // Memory is allocated safely 30 | throw std::runtime_error("Something went wrong!"); // Destructor still runs! 31 | } 32 | ``` 33 | ↪ Now, even if an exception is thrown, the destructor runs and cleans up memory automatically! 34 | 35 | 36 | 37 | ## The Rule of Five 38 | 39 | To fully implement RAII, a class should implement five special methods: 40 | 41 | 1. **Destructor** → Releases resource 42 | 2. **Copy Constructor** → Creates a deep copy 43 | 3. **Copy Assignment** → Ensures proper resource management 44 | 4. **Move Constructor** → Enables efficient transfers 45 | 5. **Move Assignment** → Prevents unnecessary copies 46 | 47 | 48 | ### 1. Destructor 49 | 50 | - Ensures **automatic resource cleanup** when an object goes out of scope. 51 | - See previous examples 52 | 53 | 54 | 55 | ### 2. Copy Constructor (Cloning) 56 | 57 | - Creates a **deep copy** of other instance to avoid shared ownership of resources. 58 | - Prevents dangling references, double free and other issues 59 | 60 | ```cpp 61 | // Copy constructor 62 | class VectorND { 63 | // ... 64 | VectorND(const VectorND& other) : n{ other.n }, arr{ new double[other.n] } { 65 | for (size_t i = 0; i < n; i++) arr[i] = other.arr[i]; 66 | } 67 | // ... 68 | }; 69 | int main() { 70 | VectorND a(3, 1.0); 71 | VectorND b = a; // Calls copy constructor 72 | } 73 | ``` 74 | ⚠️ If not provided, the default copy constructor would **shallow copy** `arr`, causing **double deletion** when both objects are destroyed. 75 | 76 | 77 | 78 | ### 3. Copy Assignment Operator 79 | 80 | - Same rationale of Copy constructor for already existing objects 81 | - Handles **self-assignment** safely. 82 | - Deletes old memory before allocating a new copy. 83 | 84 | ```cpp 85 | class VectorND { 86 | //... 87 | // Copy assignment 88 | VectorND& operator=(const VectorND& other) { 89 | if (this == &other) return *this; // Self-assignment check 90 | delete[] arr; // Free existing resource 91 | n = other.n; 92 | arr = new double[n]; // Allocate new memory 93 | for (size_t i = 0; i < n; i++) arr[i] = other.arr[i]; 94 | return *this; 95 | } 96 | //... 97 | }; 98 | int main() { 99 | VectorND a(3, 1.0); 100 | VectorND b(3, 2.0); 101 | b = a; // Calls copy assignment 102 | } 103 | ``` 104 | 105 | 106 | (to be continued...) 107 | 108 | --- 109 | [[⇦ Previous](1_15_references_idx.md)] [[Next ⇨](1_17_rule_of_five_pt2_idx.md)] [[Index ⇧](index.md#1_16_rule_of_five_idx.md)] 110 | -------------------------------------------------------------------------------- /cpp/1_08_file_io_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # File I/O 3 | 4 | - File handling using the `` library includes three main classes: 5 | - `std::ifstream` (input file stream) → for reading files 6 | - `std::ofstream` (output file stream) → for writing files 7 | - `std::fstream` (file stream) → for both reading and writing 8 | - For text files, similar to standard I/O streams. 9 | 10 | 11 | ## Writing to a File 12 | 13 | ```cpp 14 | #include 15 | #include // Include file stream library 16 | 17 | int main() { 18 | std::ofstream outFile("example.txt"); // Open file for writing 19 | 20 | if (!outFile) { 21 | std::cerr << "Error opening file for writing.\n"; 22 | return 1; 23 | } 24 | 25 | outFile << "Hello, File I/O in C++!\n"; // Write to file 26 | outFile.close(); // Closes the file: advised but not strictly necessary here 27 | 28 | return 0; 29 | } 30 | ``` 31 | 32 | ⚠️ If the file does not exist, it will be created. If it exists, it will be **overwritten**. 33 | 34 | 35 | 36 | ## Reading from a File 37 | 38 | ```cpp 39 | #include 40 | #include 41 | #include 42 | 43 | int main() { 44 | std::ifstream inFile("example.txt"); // Open file for reading 45 | 46 | if (!inFile) { 47 | std::cerr << "Error opening file for reading.\n"; 48 | return 1; 49 | } 50 | 51 | std::string line; 52 | while (std::getline(inFile, line)) { // Read line by line 53 | std::cout << line << '\n'; 54 | } 55 | 56 | inFile.close(); 57 | return 0; 58 | } 59 | ``` 60 | 61 | - `std::getline(inFile, line)` reads one line at a time until EOF. 62 | 63 | 64 | 65 | ## Appending to a File 66 | 67 | ```cpp 68 | #include 69 | #include 70 | 71 | int main() { 72 | std::ofstream outFile("example.txt", std::ios::app); // Open in append mode 73 | 74 | if (!outFile) { 75 | std::cerr << "Error opening file for appending.\n"; 76 | return 1; 77 | } 78 | 79 | outFile << "Appending a new line!\n"; // Append content 80 | outFile.close(); 81 | 82 | return 0; 83 | } 84 | ``` 85 | 86 | - `std::ios::app` ensures new data is added to the end of the file so that it is not overwritten. 87 | 88 | 89 | 90 | ## Reading and Writing Using `fstream` 91 | 92 | ```cpp 93 | #include 94 | #include 95 | 96 | int main() { 97 | std::fstream file("example.txt", std::ios::in | std::ios::out | std::ios::app); 98 | 99 | if (!file) { 100 | std::cerr << "Error opening file.\n"; 101 | return 1; 102 | } 103 | 104 | file << "Using fstream to write!\n"; // Writing 105 | file.seekg(0); // Move read position to beginning 106 | 107 | std::string line; 108 | while (std::getline(file, line)) { // Reading 109 | std::cout << line << '\n'; 110 | } 111 | 112 | file.close(); 113 | return 0; 114 | } 115 | ``` 116 | 117 | - `std::ios::in | std::ios::out | std::ios::app` allows both reading and writing. 118 | 119 | 120 | 121 | ## Checking File Existence 122 | 123 | ```cpp 124 | 125 | #include 126 | 127 | bool fileExists(const std::string& filename) { 128 | std::ifstream file(filename); 129 | return file.good(); 130 | } 131 | ``` 132 | 133 | - `file.good()` returns `true` if the file exists and is accessible. 134 | 135 | 136 | 137 | ## See More 138 | 139 | [Standard Library Header \](https://en.cppreference.com/w/cpp/header/fstream) 140 | 141 | --- 142 | [[⇦ Previous](1_07_basic_io_idx.md)] [[Next ⇨](1_09_binary_file_io_idx.md)] [[Index ⇧](index.md#1_08_file_io_idx.md)] 143 | -------------------------------------------------------------------------------- /cpp/1_10_arrays_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Arrays 3 | 4 | - **Fixed-size** (*static*) collection of elements of the **same type** (*homogeneous*). 5 | - Stored in a block of contiguous memory locations -> efficient indexing and traversal. 6 | 7 | 8 | ## Basic Declaration 9 | 10 | ```cpp 11 | int numbers[5]; // An array of 5 integers (uninitialized) 12 | ``` 13 | 14 | - The size **must be known at compile-time** (for regular arrays). 15 | - Elements are stored **contiguously in memory**. 16 | 17 | 18 | ## Initialization at Declaration 19 | 20 | ```cpp 21 | int numbers[5] = {1, 2, 3, 4, 5}; // Fully initialized array 22 | int zeros[5] = {}; // All elements set to 0 (only for global/static arrays) 23 | int partial[5] = {1, 2}; // First 2 elements set, others default to 0 24 | int numbers[] = {1, 2, 3, 4, 5}; // Array of size 5 (compiler infers size) 25 | ``` 26 | 27 | 28 | ### Default Values 29 | 30 | - Local arrays: **Uninitialized (garbage values)** 31 | - Global/static arrays: **Zero-initialized** 32 | 33 | 34 | 35 | ## Accessing and Modifying Elements 36 | 37 | 38 | ### Indexing (Zero-Based) 39 | 40 | ```cpp 41 | int arr[3] = {10, 20, 30}; 42 | std::cout << arr[0]; // Prints 10 43 | std::cout << arr[1]; // Prints 20 44 | ``` 45 | 46 | 47 | ### Modifying elements: 48 | 49 | ```cpp 50 | arr[2] = 50; // Now arr = {10, 20, 50} 51 | ``` 52 | 53 | 54 | ### ⚠️ Out-of-Bounds Access 55 | 56 | - C++ **does not check array bounds**! 57 | 58 | ```cpp 59 | std::cout << arr[10]; // Undefined behavior! 60 | ``` 61 | 62 | 63 | 64 | ## Iteration 65 | 66 | 67 | ### For Loop 68 | 69 | ```cpp 70 | int arr[] = {1, 2, 3, 4, 5}; 71 | int size = sizeof(arr) / sizeof(arr[0]); // Compute array size 72 | 73 | for (int i = 0; i < size; i++) { 74 | std::cout << arr[i] << " "; 75 | } 76 | ``` 77 | 78 | 79 | ### Range-Based For Loop (C++11) 80 | 81 | ```cpp 82 | for (int num : arr) { 83 | std::cout << num << " "; 84 | } 85 | ``` 86 | 87 | - **Safer** than a regular for-loop. 88 | 89 | 90 | 91 | ## Multidimensional Arrays 92 | 93 | 94 | ### 2D Array (Matrix) 95 | 96 | ```cpp 97 | int matrix[2][3] = { {1, 2, 3}, {4, 5, 6} }; 98 | 99 | for (int i = 0; i < 2; i++) { 100 | for (int j = 0; j < 3; j++) { 101 | std::cout << matrix[i][j] << " "; 102 | } 103 | std::cout << std::endl; 104 | } 105 | ``` 106 | 107 | 108 | ## Arrays and Pointers 109 | 110 | 111 | ### Arrays Decay into Pointers 112 | 113 | - An array **name** is a pointer to the first element 114 | 115 | ```cpp 116 | int arr[5] = {10, 20, 30, 40, 50}; 117 | int *ptr = arr; // Equivalent to &arr[0] 118 | std::cout << *ptr; // Prints 10 119 | ``` 120 | 121 | 122 | ### Pointer arithmetic 123 | 124 | ```cpp 125 | std::cout << *(ptr + 1); // Prints 20 (equivalent to arr[1]) 126 | ``` 127 | 128 | 129 | ### Dynamically allocated arrays 130 | 131 | * Pointers are used for dynamically-allocated arrays 132 | 133 | ```cpp 134 | unsigned int size; 135 | std::cout << "Enter array size: "; 136 | std::cin >> size; 137 | int *sqarr = new int[size]; // Array size only known at runtime 138 | for (unsigned int i = 0; i < size; i++) { 139 | sqarr[i] = i * i; 140 | } 141 | delete[] sqarr; // free array memory 142 | ``` 143 | 144 | --- 145 | [[⇦ Previous](1_09_binary_file_io_idx.md)] [[Next ⇨](1_11_strings_idx.md)] [[Index ⇧](index.md#1_10_arrays_idx.md)] 146 | -------------------------------------------------------------------------------- /cpp/1_09_binary_file_io_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Binary File I/O 3 | 4 | - Binary files store data in raw form, preserving structure without conversion. 5 | - File handling done using `std::ifstream`, `std::ofstream`, and `std::fstream` with the `std::ios::binary` **mode** (`std::ios_base::openmode`). 6 | 7 | 8 | 9 | ## Writing Binary Data 10 | 11 | ```cpp 12 | #include 13 | #include 14 | 15 | struct Data { 16 | int id; 17 | double value; 18 | }; 19 | 20 | int main() { 21 | std::ofstream outFile("data.bin", std::ios::binary); 22 | 23 | if (!outFile) { 24 | std::cerr << "Error opening file for writing.\n"; 25 | return 1; 26 | } 27 | 28 | Data d = {1, 99.99}; // Sample data 29 | outFile.write(reinterpret_cast(&d), sizeof(d)); // Write binary data 30 | outFile.close(); 31 | 32 | return 0; 33 | } 34 | ``` 35 | 36 | - `reinterpret_cast` instructs the compiler to look at the structure as a raw byte (char) array for writing. 37 | 38 | 39 | 40 | ## Reading Binary Data 41 | 42 | ```cpp 43 | #include 44 | #include 45 | 46 | struct Data { 47 | int id; 48 | double value; 49 | }; 50 | 51 | int main() { 52 | std::ifstream inFile("data.bin", std::ios::binary); 53 | 54 | if (!inFile) { 55 | std::cerr << "Error opening file for reading.\n"; 56 | return 1; 57 | } 58 | 59 | Data d; 60 | inFile.read(reinterpret_cast(&d), sizeof(d)); // Read binary data 61 | 62 | std::cout << "ID: " << d.id << ", Value: " << d.value << '\n'; 63 | 64 | inFile.close(); 65 | return 0; 66 | } 67 | ``` 68 | 69 | - `inFile.read()` reads bytes "as is" from the file into the into the memory location of the struct. 70 | 71 | 72 | ## Appending Binary Data 73 | 74 | ```cpp 75 | #include 76 | #include 77 | 78 | struct Data { 79 | int id; 80 | double value; 81 | }; 82 | 83 | int main() { 84 | std::ofstream outFile("data.bin", std::ios::binary | std::ios::app); 85 | 86 | if (!outFile) { 87 | std::cerr << "Error opening file for appending.\n"; 88 | return 1; 89 | } 90 | 91 | Data d = {2, 123.45}; 92 | outFile.write(reinterpret_cast(&d), sizeof(d)); // Append binary data 93 | 94 | outFile.close(); 95 | return 0; 96 | } 97 | ``` 98 | 99 | - `std::ios::app` ensures new data is added at the end of the file. 100 | 101 | 102 | 103 | ## Seeking in Binary Files 104 | 105 | - You can move the file pointer to read or write at specific positions using 106 | - `seekg()` (input) and 107 | - `seekp()` (output). 108 | 109 | ```cpp 110 | #include 111 | #include 112 | 113 | struct Data { 114 | int id; 115 | double value; 116 | }; 117 | 118 | int main() { 119 | std::fstream file("data.bin", std::ios::binary | std::ios::in | std::ios::out); 120 | 121 | if (!file) { 122 | std::cerr << "Error opening file.\n"; 123 | return 1; 124 | } 125 | 126 | file.seekg(0, std::ios::end); // Move to end of file 127 | std::streampos fileSize = file.tellg(); // Get file size 128 | int numRecords = fileSize / sizeof(Data); 129 | std::cout << "Total Records: " << numRecords << '\n'; 130 | 131 | if (numRecords > 0) { 132 | file.seekg(0, std::ios::beg); // Move to the first record 133 | Data d; 134 | file.read(reinterpret_cast(&d), sizeof(d)); 135 | std::cout << "First Record - ID: " << d.id << ", Value: " << d.value << '\n'; 136 | } 137 | 138 | file.close(); 139 | return 0; 140 | } 141 | ``` 142 | 143 | - `seekg(offset, direction)` moves the read pointer, and `tellg()` gets the current position. 144 | 145 | --- 146 | [[⇦ Previous](1_08_file_io_idx.md)] [[Next ⇨](1_10_arrays_idx.md)] [[Index ⇧](index.md#1_09_binary_file_io_idx.md)] 147 | -------------------------------------------------------------------------------- /aulas/aula14/aula14.md: -------------------------------------------------------------------------------- 1 | # Aula 14: Herança e Polimorfismo na Programação Orientada a Objetos (POO) 2 | 3 | Além da abstração e encapsulamento (vistos [anteriormente](../aula10/aula10.md)), a POO se baseia em outros dois conceitos-chave: herança e polimorfismo. 4 | 5 | 6 | ## Herança 7 | 8 | A **herança** é um mecanismo da POO que permite a crição de subtipos de um certo TAD. Através dela, uma **classe derivada**, ou **subclasse**, "herda" atributos e métodos de outra **classe base**, ou **superclasse**. Isso promove a **reutilização de código** e facilita a manutenção. 9 | 10 | 11 | ### Exemplo de Herança em C++ 12 | 13 | ```cpp 14 | // Abstract base class 15 | class Shape 16 | { 17 | public: 18 | virtual ~Shape() 19 | { 20 | std::cout << "Destructing Shape\n"; 21 | } // Virtual destructor 22 | virtual double area() = 0; 23 | }; 24 | 25 | 26 | static const double PI = 3.1415; 27 | 28 | // Concrete subclass: Circle 29 | class Circle : public Shape 30 | { 31 | public: 32 | explicit Circle(double radius): radius{radius} {}; 33 | double area() override 34 | { 35 | std::cout << "Computing the area of a Circle of radius " << radius << "\n"; 36 | return radius * radius * PI; 37 | } 38 | private: 39 | double radius{0.0}; 40 | }; 41 | 42 | // Concrete subclass: Rectangle 43 | class Rectangle : public Shape 44 | { 45 | public: 46 | Rectangle (double width, double height): width{width}, height{height} {} 47 | double area() override 48 | { 49 | std::cout << "Computing the area of a " << width << " by " << height << 50 | " Rectangle.\n"; 51 | return width * height; 52 | } 53 | private: 54 | double width{0.0}; 55 | double height{0.0}; 56 | }; 57 | ``` 58 | 59 | A herança permite descrever uma **Interface**, ou seja, um contrato ou comportamento básico esperado para vários tipos. Em C++ isso é feito através de funções virtuais (`virtual`) que permitem definir **(super)classes abstratas**. 60 | 61 | 62 | ## Polimorfismo 63 | 64 | O **polimorfismo** permite que uma mesma interface ou método tenha diferentes implementações. Isso melhora a **extensibilidade** e a **flexibilidade** do código. 65 | 66 | ### Tipos de Polimorfismo 67 | 68 | 1. Polimorfismo de Sobrecarga (Compile-time) 69 | - Mesma função com diferentes assinaturas. 70 | 71 | 2. Polimorfismo de Sobrescrita (Runtime) 72 | - Métodos da classe derivada substituem os da classe base. 73 | 74 | 75 | #### Polimorfismo por Sobrecarga 76 | 77 | A **sobrecarga** ocorre quando definimos várias funções com o mesmo nome, mas com parâmetros diferentes. 78 | 79 | ```cpp 80 | struct Point { 81 | int x; 82 | int y; 83 | }; 84 | 85 | void draw(Circle &c, Point center) 86 | { 87 | std::cout << "Drawing a circle of radius " << c.Radius() << " centered at (" << 88 | center.x << ", " << center.y << ").\n"; 89 | 90 | } 91 | 92 | void draw(Rectangle &r, Point topLeft) 93 | { 94 | std::cout << "Drawing a " << r.Width() << " by " << r.Height() << 95 | " rectangle " << " with top-left corner at (" << 96 | topLeft.x << ", " << topLeft.y << ").\n"; 97 | } 98 | 99 | 100 | int main () { 101 | Circle cobj{2}; 102 | Rectangle robj{3, 4}; 103 | draw(cobj, Point{0, 0}); 104 | draw(robj, Point{0, 0}); 105 | } 106 | 107 | 108 | // Outputs: 109 | // Drawing a circle of radius 2 centered at (0, 0). 110 | // Drawing a 3 by 4 rectangle with top-left corner at (0, 0). 111 | 112 | ``` 113 | 114 | #### Polimorfismo por Sobrescrita com Métodos Virtuais 115 | 116 | A **sobrescrita** permite que uma classe filha forneça sua própria implementação para um método da classe pai. 117 | 118 | ```cpp 119 | int main() { 120 | Shape *c = new Circle(2); 121 | Shape *r = new Rectangle(3,4); 122 | double area = c->area(); 123 | std::cout << "Area = " << area << std::endl; 124 | area = r->area(); 125 | std::cout << "Area = " << area << std::endl; 126 | delete c; 127 | delete r; 128 | } 129 | ``` 130 | 131 | ## Material Adicional 132 | 133 | [Herança em C++](../../cpp/1_19_inheritance_idx.md) 134 | 135 | ___ 136 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula13/aula13.md) [[Próximo >]](../aula15/aula15.md) [[Índice ^]](../index.md) 137 | 138 | 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CIN0135 Estruturas de Dados Orientadas a Objeto 2025.1 2 | 3 | ### 👨‍🏫 Prof. Paulo Fonseca 4 | 5 | ### ⏰ Horários: Ter 13-15h Qui 15-17h 6 | 7 | ### 🖥️ Sala: Grad 05 8 | 9 | ### 📆 Calendário: 10 | 11 | | Mês | Dia | Data | Atividade | Conteúdo | 12 | |-------|------|------|-----------|---------------------------------------------------------| 13 | | Mai | Ter | 06 | Aula 01 | [Apresentação, Linguagens compiladas vs. interpretadas](aulas/aula01/aula01.md) | 14 | | | Qui | 08 | Aula 02 | [Modelo de compilação C/C++](./aulas/aula02/aula02.md) | 15 | | | Ter | 13 | Aula 03 | [Variáveis, Constantes, Ponteiros](./aulas/aula03/aula03.md) | 16 | | | Qui | 15 | Aula 04 | [Controle de fluxo, funções, arrays](./aulas/aula04/aula04.md) | 17 | | | Ter | 20 | Aula 05 | [Arrays e alocação dinâmica de memória](./aulas/aula05/aula05.md) | 18 | | | Qui | 22 | Aula 06 | [Strings, Stream I/O, C Structs](./aulas/aula06/aula06.md) | 19 | | | Ter | 27 | Aula 07 | [Listas Simplesmente Encadeadas I](./aulas/aula07/aula07.md) | 20 | | | Qui | 29 | Aula 08 | [Listas Simplesmente Encadeadas II](./aulas/aula07/aula08.md) | 21 | | Jun | Ter | 03 | Aula 09 | LABORATÓRIO: GitHub Classroom | 22 | | | Qui | 05 | Aula 10 | [Introdução à Programação Orientada a Objetos: Abstração e Encapsulamento](./aulas/aula10/aula10.md) | 23 | | | Ter | 10 | Aula 11 | [Construtores, destrutores](./aulas/aula11/aula11.md) | 24 | | | Qui | 12 | Aula 12 | [Filas e Pilhas](./aulas/aula12/aula12.md) | 25 | | | Ter | 17 | Aula 13 | [Arrays dinâmicos](./aulas/aula13/aula13.md) | 26 | | | Qui | 19 | Feriado | *Corpus Christi* | 27 | | | Ter | 24 | Feriado | *São João* | 28 | | | Qui | 26 | Aula 14 | [POO: Herança e Polimorfismo](./aulas/aula14/aula14.md) | 29 | | Jul | Ter | 01 | Aula 15 | [C++: Ponteiros vs referências, Templates e Programação Genérica](./aulas/aula15/aula15.md) | 30 | | | Qui | 03 | Prova | **PROVA 1** | 31 | | | Ter | 08 | Aula 16 | [Hashtables I: Definição, funções de dispersão](./aulas/aula16/aula16.md) | 32 | | | Qui | 10 | Aula 17 | [Hashtables II: Resolução de colisões por encadeamento](./aulas/aula17/aula15.md) | 33 | | | Ter | 15 | ------- | Aula suspensa devido a participação em banca de concurso | 34 | | | Qui | 17 | Aula 18 | [Hashtables III: Resolução de colisões por endereçamento aberto](./aulas/aula18/aula18.md) | 35 | | | Ter | 22 | Aula 19 | [Hashtables IV: Hashsets e dicionários](./aulas/aula19/aula19.md) | 36 | | | Qui | 24 | Aula 20 | [Árvores I: definição, árvores binárias, percurso em árvores](./aulas/aula20/aula20.md) | 37 | | | Ter | 29 | Aula 21 | [Árvores II: aplicação de percursos em árvores binárias, árvores n-árias](./aulas/aula21/aula21.md) | 38 | | Ago | Qui | 31 | Aula 22 | [Árvores III: Implementação de Árvores n-árias](./aulas/aula22.md) | 39 | | | Ter | 05 | Aula 23 | [Árvores IV: Exercícios árvores](./aulas/aula23.md) | 40 | | | Qui | 07 | Aula 24 | Exercícios e Revisão para Prova 2 | 41 | | | Ter | 12 | Aula 25 | Exercícios e Revisão para Prova 2 | 42 | | | Qui | 14 | Prova 2 | **PROVA 2** | 43 | | | Ter | 19 | Aula 26 | Revisão para Prova final (reposição 15/07) | 44 | | | Qui | 21 | Final | **PROVA FINAL** | 45 | 46 | ### ✅ Avaliação: 47 | 48 | - 2 Unidades 49 | - Cada unidade: 50 | - Listas de Exercício de Programação = 60% 51 | - Prova = 40% -------------------------------------------------------------------------------- /cpp/1_12_functions_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Functions 3 | 4 | - A **function** in C++ is a block of reusable code that performs a specific task. 5 | - Functions improve: 6 | - code organization 7 | - modularity 8 | - reusability. 9 | 10 | 11 | 12 | ## Function Prototypes and Definitions 13 | 14 | 15 | ### Function Prototype 16 | 17 | - Function **declaration** specifying: 18 | - The **return type** 19 | - The **function name** 20 | - The **parameter list** 21 | - Allows writing code calling the function before defining it 22 | - **WHAT** the function does 23 | 24 | 25 | 26 | ### Function Defintion 27 | 28 | - Actual implementation of intended behaviour according to the declaration 29 | - **HOW** the function does 30 | 31 | 32 | ```cpp 33 | #include 34 | 35 | // Function prototype (declaration) 36 | int add(int a, int b); 37 | 38 | int main() { 39 | std::cout << add(3, 4); // Function call 40 | } 41 | 42 | // Function definition 43 | int add(int a, int b) { 44 | return a + b; 45 | } 46 | ``` 47 | 48 | 49 | 50 | ## Function Overloading 51 | 52 | - Multiple functions **with the same name but different parameter lists** 53 | - Return type **alone** cannot differentiate overloaded functions (parameter lists must be different) 54 | - Which version is used decided at runtime depending on the arguments 55 | 56 | ```cpp 57 | #include 58 | 59 | // Overloaded functions 60 | int multiply(int a, int b) { return a * b; } 61 | double multiply(double a, double b) { return a * b; } 62 | int multiply(int a, int b, int c) { return a * b * c; } 63 | 64 | int main() { 65 | std::cout << multiply(3, 4) << std::endl; // Calls multiply(int, int) 66 | std::cout << multiply(2.5, 3.0) << std::endl; // Calls multiply(double, double) 67 | std::cout << multiply(2, 3, 4) << std::endl; // Calls multiply(int, int, int) 68 | } 69 | ``` 70 | 71 | 72 | ## Default Arguments 73 | 74 | - A **default argument** is a value assigned to a function parameter **if no argument is provided** during the function call. 75 | - Default arguments **must be specified in the function prototype or definition**. 76 | - If a function is **overloaded**, the version without default arguments is preferred. 77 | 78 | ```cpp 79 | #include 80 | 81 | // Function with default argument 82 | void greet(std::string name = "Guest") { 83 | std::cout << "Hello, " << name << "!" << std::endl; 84 | } 85 | 86 | int main() { 87 | greet(); // Uses default: "Hello, Guest!" 88 | greet("Alice"); // Overrides default: "Hello, Alice!" 89 | } 90 | ``` 91 | 92 | 93 | 94 | ### Multiple Default Arguments 95 | 96 | - **Must be defined from right to left** (cannot skip middle arguments). 97 | 98 | ```cpp 99 | void displayInfo(std::string name, int age = 25, std::string city = "Unknown") { 100 | std::cout << name << ", " << age << " years old, from " << city << std::endl; 101 | } 102 | 103 | displayInfo("John"); // Uses default age and city 104 | displayInfo("Emily", 30); // Uses default city 105 | displayInfo("Alex", 40, "New York"); // Overrides all defaults 106 | ``` 107 | 108 | 109 | 110 | ## Inline Functions 111 | 112 | - An **inline function** suggests to the compiler to replace the function call with its actual code **to reduce function call overhead**. 113 | - Useful for small, frequently used functions. 114 | 115 | ```cpp 116 | #include 117 | 118 | // Inline function 119 | inline int square(int x) { 120 | return x * x; 121 | } 122 | 123 | int main() { 124 | std::cout << square(5); // Compiler may replace with "5 * 5" 125 | } 126 | ``` 127 | 128 | ⚠️ **Note:** 129 | - The **compiler ultimately decides** whether to inline the function. 130 | - Inlining large functions increases code size (can harm performance due to cache misses). 131 | - Avoid inlining recursive or complex functions. 132 | 133 | --- 134 | [[⇦ Previous](1_11_strings_idx.md)] [[Next ⇨](1_13_namespaces_idx.md)] [[Index ⇧](index.md#1_12_functions_idx.md)] 135 | -------------------------------------------------------------------------------- /aulas/aula20/binary_tree.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /aulas/aula15/aula15.md: -------------------------------------------------------------------------------- 1 | # C++: Ponteiros vs Referências 2 | 3 | Ponteiros e referências são formas de acessar e manipular variáveis indiretamente, mas diferem em como funcionam e são usados. 4 | 5 | ## Ponteiros (`*`) 6 | 7 | Um **ponteiro** é uma variável que **armazena o endereço de memória** de outra variável. 8 | 9 | - **Declaração:** Usa o símbolo `*`. 10 | ```cpp 11 | int a = 10; 12 | int* p = &a; // p é um ponteiro que armazena o endereço de 'a' 13 | ``` 14 | - **Acesso ao valor:** Para acessar ou modificar o valor apontado, usa-se o operador de **desreferenciação (`*`)**: 15 | ```cpp 16 | *p = 20; // altera o valor de 'a' para 20 17 | ``` 18 | - **Reatribuição:** Ponteiros podem ser **mudados** para apontar para diferentes variáveis: 19 | ```cpp 20 | int b = 30; 21 | p = &b; // agora p aponta para 'b' 22 | ``` 23 | - **Podem ser nulos:** Um ponteiro pode não apontar para nada: 24 | ```cpp 25 | int* p = nullptr; 26 | ``` 27 | - **Aritmética de ponteiros:** É possível realizar operações como incrementar (`p++`) para percorrer arrays. 28 | 29 | 30 | ## Referências (`&`) 31 | 32 | Uma **referência** é um **apelido** para uma variável existente. Ela não armazena o endereço, mas age como um alias direto da variável. 33 | 34 | - **Declaração:** Usa o símbolo `&` (na declaração, não na atribuição). 35 | ```cpp 36 | int a = 10; 37 | int& r = a; // 'r' é uma referência para 'a' 38 | ``` 39 | - **Acesso ao valor:** Operações em `r` afetam diretamente `a`, sem necessidade de desreferenciação: 40 | ```cpp 41 | r = 20; // altera o valor de 'a' para 20 42 | ``` 43 | - **Não podem ser reatribuídas:** Após serem inicializadas, referências **não podem apontar para outra variável**. 44 | - **Nunca são nulas:** Uma referência sempre está vinculada a uma variável válida. 45 | - **Uso comum:** Muito usadas para **passagem de parâmetros** em funções, evitando cópias desnecessárias. 46 | 47 | ## Comparação Rápida 48 | 49 | | **Aspecto** | **Ponteiro (`*`)** | **Referência (`&`)** | 50 | |----------------------|--------------------------------------------------|------------------------------------------------| 51 | | **Declaração** | `int* p = &a;` | `int& r = a;` | 52 | | **Acesso ao valor** | `*p = 20;` | `r = 20;` | 53 | | **Reatribuição** | Pode apontar para diferentes variáveis. | Não pode ser reatribuída após inicialização. | 54 | | **Valor nulo** | Pode ser `nullptr`. | Nunca é nula. | 55 | | **Aritmética** | Suporta (ex.: `p++`). | Não suporta aritmética. | 56 | | **Uso típico** | Estruturas dinâmicas (listas, árvores), arrays. | Passagem eficiente de argumentos em funções. | 57 | 58 | 59 | - **Use referências** quando quiser passar variáveis para funções de forma eficiente e segura, sem risco de `nullptr`. 60 | - **Use ponteiros** quando precisar de mais flexibilidade, como apontar para diferentes objetos, trabalhar com estruturas dinâmicas, ou quando o valor pode ser opcional (`nullptr`). 61 | 62 | 63 | ## Templates e Programação Genérica 64 | 65 | - **Ideia Básica**: Criar código "parametrizado" com diferentes tipos de dados sem duplicar código. 66 | - Dois tipos básicos: 67 | 1. Function Templates 68 | 2. Class Templates 69 | 70 | 71 | ### Function Templates (Templates de Função) 72 | 73 | 74 | Permitem criar **funções genéricas** que funcionam com diferentes tipos de dados. 75 | 76 | ```cpp 77 | template 78 | T max(T a, T b) { 79 | return (a > b) ? a : b; 80 | } 81 | ``` 82 | 83 | - Pode ser usado com `int`, `double`, `char`, etc. 84 | ```cpp 85 | max(3, 7); // int 86 | max(4.5, 2.3); // double 87 | ``` 88 | 89 | ### Class Templates (Templates de Classe) 90 | 91 | Permitem criar **classes genéricas**, especialmente containers 92 | 93 | #### **Exemplo:** 94 | ```cpp 95 | template 96 | class Box { 97 | T value; 98 | public: 99 | Box(T v) : value(v) {} 100 | T getValue() { return value; } 101 | }; 102 | ``` 103 | 104 | - Pode instanciar com diferentes tipos: 105 | ```cpp 106 | Box intBox(10); 107 | Box strBox("Hello"); 108 | ``` 109 | 110 | ## Material adicional 111 | 112 | - [Referências](../../cpp/1_15_references_idx.md) 113 | - [Templates](../../cpp/1_20_templates_idx.md) 114 | 115 | ___ 116 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula14/aula14.md) [[Próximo >]](../aula16/aula16.md) [[Índice ^]](../index.md) 117 | 118 | -------------------------------------------------------------------------------- /aulas/aula01/aula01.md: -------------------------------------------------------------------------------- 1 | # Aula 01 2 | 3 | ## Apresentação 4 | 5 | ## Liguagens Interpretadas vs. Compiladas 6 | 7 | Numa linguagem de programação interpretada, o código fonte de um programa é lido e excecutado por um outro programa chamado de *interpretador*. Tecnicamente, o programa realmente excecutado é sempre o interpretador, que recebe como entrada o código fonte do programa pretendido e simula a sua execução linha por linha, dando a impressão que este último é que está sendo executado. 8 | 9 | Python é um exemplo de linguagem interpretada. Considere o código fonte `hello.py` abaixo. 10 | 11 | ```Python 12 | # hello.py 13 | print("Hello, world!") 14 | ``` 15 | 16 | Para executar este programa, usamos um comando como 17 | 18 | ```bash 19 | $ python3 hello.py 20 | ``` 21 | 22 | O que estamos fazendo é executando o programa `python3`, que é um interpretador da linguagem, dando como entrada o código fonte `hello.py`. 23 | 24 | 25 | ### Exercício 26 | 27 | No Linux, é bem possível que o comando `python3` na verdade seja um *link simbólico*, uma espécie de *atalho* para o arquivo executável do interpretador. Utilize o comando `which` para descobrir o verdadeiro arquivo excecutável. 28 | 29 | ```bash 30 | $ which python3 31 | ``` 32 | 33 | Um resultado possível seria `/usr/bin/python3`. Você pode tentar inspecionar o tipo desse arquivo através do comando `file`. 34 | 35 | ```bash 36 | $ file -L /usr/bin/pyhton3 37 | ``` 38 | 39 | Você poderá obter uma resposta como 40 | 41 | ``` 42 | /usr/bin/python3: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=947 43 | 293c63a6947244e5917909de136125fe62b01, for GNU/Linux 3.2.0, stripped 44 | ``` 45 | 46 | A parte importante é você obervar que este é um arquivo executável (`ELF 64-bit executable`). 47 | 48 | Já se você tentar usar o comando `file` no seu arquivo `hello.py` 49 | 50 | ```bash 51 | $ file hello.py 52 | ``` 53 | 54 | você vai obter como resposta algo como 55 | 56 | ``` 57 | hello.py: ASCII text 58 | ``` 59 | 60 | ou seja, o seu "programa" `hello.py` na verdade é apenas um arquivo texto em código ASCII, ou um "*script*", a ser reproduzido pelo programa interpretador. 61 | 62 | ---- 63 | 64 | 65 | Já numa linguagem *compilada*, um arquivo executável deve ser produzido a partir do código-fonte para ser executado diretamente. O processo que converte o código-fonte em um arquivo executável é chamado de *compilação*. Tecnicamente, o processo de compilação normalmente é composto várias etapas e realizado por vários programas, dentre os quais destacam-se o [*compilador*](https://pt.wikipedia.org/wiki/Compilador) e o [*ligador*](https://pt.wikipedia.org/wiki/Ligador). Grosso modo, o compilador produz o chamado *código-objeto*, que é uma versão do programa em linguagem de máquina que, entretanto, ainda não está pronta para execução. O que ocorre é que o programa pode ser composto de vários códigos-objetos que precisam ser combinados, e/ou o(s) código(s)-objeto(s) também podem depender de bibliotecas do sistema. O papel do ligador é combinar os códigos-objetos e resolver as referências às bibliotecas do sistema, produzindo um programa executável. 66 | 67 | Um exemplo linguagem compilada é a Linguagem C. Considere código fonte `hello.c` abaixo, equivalente ao `hello.py` acima. 68 | 69 | ```C 70 | /* hello.c */ 71 | #include 72 | 73 | int main() { 74 | printf("Hello, world!"); 75 | } 76 | ``` 77 | 78 | Para compilar esse programa no Linux, podemos usar o comando 79 | 80 | ```bash 81 | $ cc hello.c 82 | ``` 83 | 84 | Esse comando usa o programa `cc` que já combina o compilador e o ligador numa única chamada, produzindo o arquivo executável `a.out`. Se este programa for executado 85 | 86 | ```bash 87 | $ ./a.out 88 | ``` 89 | 90 | obteremos o mesmo resultado acima, com a mensagem "Hello, world!" sendo impressa no terminal. 91 | 92 | ### Exercício 93 | 94 | Para dividir o processo de compilação em duas etapas, vamos primeiro executar 95 | 96 | ```bash 97 | $ cc -c hello.c 98 | ``` 99 | 100 | O código-objeto `hello.o` será criado. Inspecione o tipo desse arquivo como o comando `file` e tente executá-lo diretamente. O que acontece? 101 | 102 | Apesar deste programa simples ser composto de apenas um código-objeto, este possui uma chamada a uma função `printf` que é uma função da biblioteca do sistema declarada no cabeçalho `stdio.h`. Para usar o ligador e produzir o arquivo executável: 103 | 104 | ```bash 105 | $ cc hello.o 106 | ``` 107 | Novamente, o arquivo executável `a.out` será recriado. 108 | 109 | 110 | 111 | ___ 112 | [[Código-fonte: /src]](./src) [[< Anterior]](../../README.md) [[Próximo >]](../aula02/aula02.md) [[Índice ^]](../../README.md) 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /cpp/1_11_strings_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Strings 3 | 4 | In C++, strings can be handled in two main ways: 5 | 1. **C-style strings** (null-terminated character arrays) 6 | 2. **`std::string` class** (from the Standard Library) 7 | 8 | 9 | 10 | ## C-Style Strings (`char` Arrays) 11 | 12 | - Array of characters terminated by a null character (`\0`). 13 | - **Fixed-size**, cannot grow dynamically. 14 | 15 | ```cpp 16 | #include 17 | 18 | int main() { 19 | char greeting[] = "Hello"; // Implicit null-termination 20 | std::cout << greeting << std::endl; 21 | 22 | char name[6] = {'A', 'l', 'i', 'c', 'e', '\0'}; // Manually terminated 23 | std::cout << name << std::endl; 24 | } 25 | ``` 26 | 27 | 28 | ### Common Functions from `` 29 | 30 | ```cpp 31 | #include 32 | #include 33 | 34 | int main() { 35 | char str1[] = "Hello"; 36 | char str2[] = "World"; 37 | 38 | std::cout << strlen(str1) << std::endl; // Get string length 39 | std::cout << strcat(str1, str2) << std::endl; // Concatenate (unsafe!) 40 | std::cout << strcmp(str1, str2) << std::endl; // Compare two strings 41 | } 42 | ``` 43 | 44 | ⚠️ `strcat()` and `strcpy()` can cause buffer overflows! 45 | 46 | 47 | 48 | ## `std::string` Class 49 | 50 | - The **`std::string`** class (from ``) provides a safer and more convenient way to work with strings. 51 | - Advantages over C-style strings: 52 | - Automatic memory management** (dynamic size). 53 | - Easy concatenation (`+`). 54 | - Safer and more powerful functions. 55 | 56 | ```cpp 57 | #include 58 | #include 59 | 60 | int main() { 61 | std::string s1 = "Hello"; 62 | std::string s2 = "World"; 63 | 64 | std::cout << s1 + " " + s2 << std::endl; // Concatenation 65 | std::cout << s1.length() << std::endl; // Get length 66 | std::cout << s1.substr(1, 3) << std::endl; // Extract substring 67 | } 68 | ``` 69 | 70 | 71 | ### Common `std::string` Operations 72 | 73 | 74 | #### Concatenation 75 | 76 | ```cpp 77 | std::string first = "Hello, "; 78 | std::string last = "World!"; 79 | std::string full = first + last; // "Hello, World!" 80 | ``` 81 | 82 | 83 | #### Getting Length 84 | 85 | ```cpp 86 | std::string text = "Example"; 87 | std::cout << text.length(); // 7 88 | ``` 89 | 90 | 91 | #### Accessing Characters 92 | 93 | ```cpp 94 | std::string word = "Hello"; 95 | std::cout << word[1]; // 'e' 96 | word[0] = 'J'; // Changes to "Jello" 97 | ``` 98 | 99 | 100 | #### Comparing Strings 101 | 102 | ```cpp 103 | std::string a = "apple", b = "banana"; 104 | if (a == b) std::cout << "Equal"; 105 | else std::cout << "Not equal"; // "Not equal" 106 | ``` 107 | 108 | 109 | #### Substring Extraction 110 | 111 | ```cpp 112 | std::string phrase = "C++ Programming"; 113 | std::string sub = phrase.substr(4, 11); // "Programming" 114 | ``` 115 | 116 | 117 | #### Finding a Substring 118 | 119 | ```cpp 120 | std::string sentence = "Hello, world!"; 121 | size_t pos = sentence.find("world"); // Returns index 7 122 | ``` 123 | 124 | 125 | 126 | ## Converting Between C-Strings and `std::string` 127 | 128 | 129 | ### C-style -> `std::string` 130 | 131 | ```cpp 132 | char cstr[] = "C-style string"; 133 | std::string str = cstr; // Implicit conversion 134 | ``` 135 | 136 | 137 | ### `std::string` -> C-style 138 | 139 | ```cpp 140 | std::string str = "C++ String"; 141 | const char* cstr = str.c_str(); // Converts to C-string 142 | ``` 143 | 144 | ⚠️ `c_str()` returns a `const char*`, so do not modify it! 145 | 146 | 147 | 148 | ## Input and Output with Strings 149 | 150 | 151 | ### Reading a Single Word 152 | 153 | ```cpp 154 | std::string name; 155 | std::cin >> name; // Stops at first whitespace 156 | ``` 157 | 158 | 159 | ### Reading an Entire Line 160 | 161 | ```cpp 162 | std::string sentence; 163 | std::getline(std::cin, sentence); 164 | ``` 165 | 166 | --- 167 | [[⇦ Previous](1_10_arrays_idx.md)] [[Next ⇨](1_12_functions_idx.md)] [[Index ⇧](index.md#1_11_strings_idx.md)] 168 | -------------------------------------------------------------------------------- /cpp/1_23_exceptions_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Runtime Errors & Exception Handling 3 | 4 | - C++ provides multiple mechanisms to handle runtime errors, including: 5 | - assertions 6 | - exceptions 7 | - `noexcept` 8 | 9 | 10 | 11 | ## Assertions (`assert`) 12 | 13 | - Used to check preconditions/invariants (usually) **in debug builds** 14 | - `NDEBUG` macro disables it in Release mode. 15 | - Terminates the program if a condition fails. 16 | 17 | ```cpp 18 | #include 19 | 20 | int divide(int a, int b) { 21 | assert(b != 0 && "Division by zero!"); // Catches division by zero in debug mode 22 | return a / b; 23 | } 24 | 25 | int main() { 26 | int result = divide(10, 0); // Triggers assertion failure 27 | return 0; 28 | } 29 | ``` 30 | 31 | 32 | 33 | ## Exception Handling (`try`, `catch`, `throw`) 34 | 35 | - C++ uses **exceptions** to handle runtime errors safely. 36 | - Errors are **thrown** using `throw`, **caught** using `catch`, and handled inside a `try` block. 37 | 38 | ```cpp 39 | #include 40 | #include // For standard exceptions 41 | 42 | int safeDivide(int a, int b) { 43 | if (b == 0) throw std::runtime_error("Division by zero error!"); // Throws an exception 44 | return a / b; 45 | } 46 | 47 | int main() { 48 | try { 49 | int result = safeDivide(10, 0); // Throws exception 50 | std::cout << "Result: " << result << '\n'; 51 | } catch (const std::exception& e) { 52 | std::cerr << "Caught exception: " << e.what() << '\n'; // Handles error 53 | } 54 | 55 | return 0; 56 | } 57 | ``` 58 | 59 | - `throw` raises an exception. 60 | - `try` block wraps **code that may fail**. 61 | - `catch` handles exceptions gracefully. 62 | 63 | 64 | 65 | ### Catching Different Exceptions 66 | 67 | - You can catch **specific** or **all** exceptions. 68 | - Go top-down from more specific to more general exceptions. 69 | 70 | ```cpp 71 | try { 72 | throw std::out_of_range("Index out of range"); 73 | } catch (const std::out_of_range& e) { 74 | std::cerr << "Caught out_of_range: " << e.what() << '\n'; 75 | } catch (const std::exception& e) { 76 | std::cerr << "Caught generic exception: " << e.what() << '\n'; 77 | } catch (...) { 78 | std::cerr << "Caught unknown exception\n"; // Catches everything 79 | } 80 | ``` 81 | 82 | 83 | 84 | ## `noexcept`: Declaring Non-Throwing Functions 85 | 86 | - `noexcept` tells the compiler that a function **won't throw exceptions**. 87 | - It **enables compiler optimizations** and improves **performance**. 88 | - If a `noexcept` function throws, `std::terminate()` is called. 89 | 90 | ```cpp 91 | void safeFunction() noexcept { 92 | // Guarantees no exceptions 93 | } 94 | 95 | void riskyFunction() noexcept(false) { 96 | throw std::runtime_error("Error!"); // Exception allowed 97 | } 98 | ``` 99 | 100 | 101 | ## Standard Exception Hierarchy (`std::exception`) 102 | 103 | - C++ provides a **hierarchy of exceptions** in ``. 104 | 105 | 106 | ### Base Class: `std::exception` 107 | 108 | - All standard exceptions derive from `std::exception`. 109 | 110 | ```cpp 111 | #include 112 | #include 113 | 114 | int main() { 115 | try { 116 | throw std::runtime_error("Something went wrong!"); 117 | } catch (const std::exception& e) { 118 | std::cerr << "Caught: " << e.what() << '\n'; // Prints error message 119 | } 120 | } 121 | ``` 122 | ↪ `what()` returns an error message. 123 | 124 | 125 | ### Common Standard Exceptions 126 | 127 | | Exception | Description | 128 | |----------------------|-------------| 129 | | `std::runtime_error` | Generic runtime error | 130 | | `std::logic_error` | Logical program error (e.g., violating preconditions) | 131 | | `std::out_of_range` | Accessing out-of-bounds elements | 132 | | `std::invalid_argument` | Invalid function arguments | 133 | | `std::bad_alloc` | Memory allocation failure (`new` failed) | 134 | | `std::overflow_error` | Arithmetic overflow | 135 | | `std::underflow_error` | Arithmetic underflow | 136 | 137 | ```cpp 138 | try { 139 | throw std::out_of_range("Index out of bounds"); 140 | } catch (const std::out_of_range& e) { 141 | std::cerr << "Out of range: " << e.what() << '\n'; 142 | } 143 | ``` 144 | 145 | 146 | ## Learn More 147 | 148 | - [Standard Exceptions](https://en.cppreference.com/w/cpp/header/exception) 149 | 150 | --- 151 | [[⇦ Previous](1_22_static_errors_idx.md)] [[Next ⇨](1_24_error_as_values_idx.md)] [[Index ⇧](index.md#1_23_exceptions_idx.md)] 152 | -------------------------------------------------------------------------------- /cpp/1_18_smart_pointers_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Smart Pointers (`std::unique_ptr` & `std::shared_ptr`) 3 | 4 | - Traditional C++ requires manual `new` and `delete` leading to: 5 | - Memory leaks (forgetting to `delete`) 6 | - Dangling pointers (accessing after deletion) 7 | - Exception safety issues 8 | - Modern C++ introduces **smart pointers** (`std::unique_ptr` and `std::shared_ptr`) to **automatically** manage dynamic memory safely, following the RAII principle. 9 | - Eliminates/simplifies manual memory management and prevents memory leaks. 10 | 11 | 12 | ## `std::unique_ptr` – Exclusive Ownership 13 | 14 | - Owns a resource exclusively (no copies allowed). 15 | - Automatically deletes the resource when it goes out of scope. 16 | - Follows the Rule of Five: 17 | - No copy constructor or copy assignment 18 | - Move constructor & move assignment 19 | 20 | ```cpp 21 | #include 22 | #include 23 | 24 | class VectorND { 25 | public: 26 | VectorND(size_t dim) { std::cout << "VectorND created\n"; } 27 | ~VectorND() { std::cout << "VectorND destroyed\n"; } 28 | }; 29 | 30 | int main() { 31 | std::unique_ptr vec1 = std::make_unique(1000); 32 | 33 | // std::unique_ptr cannot be copied! 34 | // std::unique_ptr vec2 = vec1; // Error 35 | 36 | // But it can be moved: 37 | std::unique_ptr vec2 = std::move(vec1); // Ownership transferred 38 | 39 | return 0; // vec2 goes out of scope, VectorND is automatically deleted 40 | } 41 | ``` 42 | 43 | 44 | ## `std::shared_ptr` – Shared Ownership 45 | 46 | - Allows multiple pointers to share ownership of the same resource. 47 | - Uses **reference counting** to track the number of owners. 48 | - Automatically deletes the resource when the last owner is destroyed. 49 | 50 | ```cpp 51 | #include 52 | #include 53 | 54 | class VectorND { 55 | public: 56 | VectorND(size_t dim) { std::cout << "VectorND created\n"; } 57 | ~VectorND() { std::cout << "VectorND destroyed\n"; } 58 | }; 59 | 60 | int main() { 61 | std::shared_ptr vec1 = std::make_shared(1000); 62 | { 63 | std::shared_ptr vec2 = vec1; // Shared ownership 64 | std::cout << "Reference count: " << vec1.use_count() << "\n"; // 2 65 | } 66 | // vec2 goes out of scope, but vec1 still exists 67 | std::cout << "Reference count: " << vec1.use_count() << "\n"; // 1 68 | 69 | return 0; // vec1 is destroyed, resource is deallocated 70 | } 71 | ``` 72 | 73 | 74 | ## Key Differences Between `std::unique_ptr` and `std::shared_ptr` 75 | 76 | | Feature | `std::unique_ptr` | `std::shared_ptr` | 77 | |-------------------|------------------|------------------| 78 | | Ownership | **Exclusive** (only one owner) | **Shared** (multiple owners) | 79 | | Copyable? | ❌ **No** (only movable) | ✅ **Yes** (increments ref count) | 80 | | Moveable? | ✅ **Yes** | ✅ **Yes** | 81 | | Reference Counting? | ❌ **No** | ✅ **Yes** (deletes when ref count reaches 0) | 82 | | Performance | ✅ **Fastest** (no ref counting overhead) | ❌ **Slightly slower** (ref counting) | 83 | 84 | 85 | 86 | ## Smart Pointers and the Rule of Five 87 | 88 | - Smart pointers may eliminate the need for manual Rule of Five implementations: 89 | - No need for custom destructors (handled by smart pointers) 90 | - No need for copy/move constructors (ownership is managed automatically) 91 | 92 | 93 | ### Without Smart Pointers: 94 | 95 | ```cpp 96 | class VectorND { 97 | private: 98 | size_t n; 99 | double* arr; 100 | public: 101 | VectorND(size_t dim) : n{ dim }, arr{ new double[dim] } {} 102 | 103 | // Rule of Five 104 | ~VectorND() { delete[] arr; } // Destructor 105 | VectorND(const VectorND& other); // Copy Constructor (Deep Copy) 106 | VectorND& operator=(const VectorND& other); // Copy Assignment 107 | VectorND(VectorND&& other) noexcept; // Move Constructor 108 | VectorND& operator=(VectorND&& other) noexcept; // Move Assignment 109 | }; 110 | ``` 111 | 112 | 113 | ### With `std::unique_ptr`: 114 | 115 | ```cpp 116 | class VectorND { 117 | private: 118 | size_t n; 119 | std::unique_ptr arr; // Smart pointer manages memory 120 | public: 121 | VectorND(size_t dim) : n{ dim }, arr{ std::make_unique(dim) } {} 122 | }; 123 | ``` 124 | - No need for destructor 125 | - No need for copy/move constructors 126 | - Memory is automatically managed 127 | 128 | --- 129 | [[⇦ Previous](1_17_rule_of_five_pt2_idx.md)] [[Next ⇨](1_19_inheritance_idx.md)] [[Index ⇧](index.md#1_18_smart_pointers_idx.md)] 130 | -------------------------------------------------------------------------------- /aulas/aula13/aula13.md: -------------------------------------------------------------------------------- 1 | # Aula 13: Arrays Dinâmicos 2 | 3 | Os mecanismos de abstração/encapsulamento permitem esconder os detalhes de implementação de uma classe, expondo para o utilizador apenas uma interface para utilização de objetos da classe que respeita a semântica, ou contrato pré-estabelecido. No caso de uma lista, enquanto coleção linear dinâmica e homogênea, podemos prover uma implementação baseada num array. 4 | 5 | **Problema 1**: Array é uma estrutura estática. Podemos pré-alocar uma capacidade inicial`cap`, mas quando essa capacidade se esgotar, não necessariamente poderemos aumentá-la. 6 | 7 | **Solução 1**: Criar um novo array, com o dobro da capacidade inicial, e copiar os valores para o novo array. 8 | 9 | **Problema 2**: Uma única operação de inserção pode resultar na necessidade de copiar todos os elementos do array. 10 | 11 | **Atenuante 2**: Isso não é tão problemático assim. Considere uma sequência de inserções sucessivas ao final da lista 12 | 13 | ``` 14 | Array dinâmico 15 | Início: cap=1, sz=0 operação #inserções(+) #cópias(=) 16 | 17 | _ 18 | 19 | 0 1) 1 0 20 | + 21 | 22 | 0 1 2) 1 1 23 | = + cap=2 24 | 25 | 0 1 2 _ 3) 1 2 = . + 1 => 1 26 | = = + cap=4 | 27 | | 28 | 0 1 2 3 4) 1 0 1 => 1 29 | + 30 | 31 | 0 1 2 3 4 _ _ _ 5) 1 4 = . + . + . + 1 => 1 32 | = = = = + cap=8 | | | 33 | | | | 34 | 0 1 2 3 4 5 _ _ 6) 1 0 1 | | => 1 35 | + | | 36 | | | 37 | 0 1 2 3 4 5 6 _ 7) 1 0 1 | => 1 38 | + | 39 | | 40 | 0 1 2 3 4 5 6 7 8) 1 0 1 => 1 41 | + 42 | 43 | 0 1 2 3 4 5 6 7 8 _ _ _ _ _ _ _ 9) 1 8 = . + . + . + ... + . + 1 => 1 44 | = = = = = = = = + cap=16 | | | ... | 45 | | | | ... | 46 | 0 1 2 3 4 5 6 7 8 9 _ _ _ _ _ _ 10) 1 0 1 | | ... | => 1 47 | + | | ... | 48 | | | ... | 49 | 0 1 2 3 4 5 6 7 8 9 A _ _ _ _ _ 11) 1 0 1 | ... | => 1 50 | + | ... | 51 | | ... | 52 | 0 1 2 3 4 5 6 7 8 9 A B _ _ _ _ 12) 1 0 1 ... | => 1 53 | . . . 54 | . . . 55 | . . . 56 | | 57 | 0 1 2 3 4 5 6 7 8 9 A B C D E F 16) 1 0 1 => 1 58 | + 59 | . . 60 | . . 61 | . . 62 | 63 | --------------------------------------------------- 64 | 65 | (!) MÉDIA AGREGADA ≃ 1 ins + 1 cópia por operação 66 | 67 | ``` 68 | 69 | O código [arraylist.cpp](./src/arraylist.cpp) contém um protótipo de implementação de uma array dinâmico (a.k.a. array list, vector) de ints. Repare em particular no método privado que verifica e dobra o tamanho do array, se necessário, i.e. assim que `sz==cap`. Repare nos operadores `new[]` e `delete[]` para alocar/liberar arrays na heap. 70 | 71 | ```cpp 72 | void ArrayList::check_and_double() { 73 | if (sz < cap) return; 74 | //cout << "Doubling" << endl; 75 | size_t new_cap = 2 * cap; 76 | int *new_arr = new int[new_cap]; 77 | for (size_t i = 0; i < sz; i++) { 78 | new_arr[i] = arr[i]; 79 | } 80 | delete[] arr; 81 | arr = new_arr; 82 | cap = new_cap; 83 | } 84 | ``` 85 | 86 | 87 | 88 | ### Referências 89 | 90 | [1] [Clifford Shaffer. Data structures and algorithm analysis in C++, Cap 4](http://people.cs.vt.edu/~shaffer/Book/) 91 | 92 | 93 | ___ 94 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula12/aula12.md) [[Próximo >]](../aula14/aula14.md) [[Índice ^]](../index.md) 95 | 96 | 97 | -------------------------------------------------------------------------------- /cpp/1_20_templates_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Templates and Generic Programming 3 | 4 | - Templates in C++ allow for **generic programming**, i.e. code that works with **any data type** while avoiding code duplication. 5 | - Two main kinds of templates: 6 | - Function templates 7 | - Class templates. 8 | 9 | 10 | ## Function Templates 11 | 12 | - Allows writing a single function definition that can operate on different data types. 13 | 14 | ```cpp 15 | template 16 | void swapValues(T& a, T& b) { 17 | T temp = a; 18 | a = b; 19 | b = temp; 20 | } 21 | 22 | int main() { 23 | int x = 5, y = 10; 24 | swapValues(x, y); // Works with int 25 | 26 | double a = 1.2, b = 3.4; 27 | swapValues(a, b); // Works with double 28 | 29 | return 0; 30 | } 31 | ``` 32 | - The **`template `** tells the compiler that `T` is a **placeholder** for a type. 33 | - The compiler **instantiates** the template with actual types (`int`, `double`, etc.) at compile-time. 34 | 35 | 36 | ### Function Template Overloading 37 | 38 | - Templates can also be overloaded to specialize behavior for certain types. 39 | 40 | ```cpp 41 | template 42 | void print(T value) { 43 | std::cout << "Generic: " << value << "\n"; 44 | } 45 | 46 | // Overloaded template for `char*` 47 | template <> 48 | void print(char* value) { 49 | std::cout << "String specialization: \"" << value << "\"\n"; 50 | } 51 | ``` 52 | 53 | 54 | ## Class Templates 55 | 56 | - Defines a **blueprint** for a class that works with multiple data types. 57 | 58 | ```cpp 59 | template 60 | class Vector { 61 | private: 62 | T* arr; 63 | size_t size; 64 | public: 65 | Vector(size_t n) : size(n), arr(new T[n]) {} 66 | ~Vector() { delete[] arr; } 67 | 68 | T& operator[](size_t i) { return arr[i]; } 69 | }; 70 | 71 | int main() { 72 | Vector v1(10); // A vector of integers 73 | Vector v2(5); // A vector of doubles 74 | } 75 | ``` 76 | 77 | ⚠️ `Vector` and `Vector` are **separate types** generated from the template. 78 | 79 | 80 | 81 | ## Template Instantiation & Specialization 82 | 83 | - Templates are instantiated when a specific **type** is provided. 84 | 85 | 86 | ### Full Specialization 87 | 88 | - A template can be **fully specialized** to behave differently for a specific type. 89 | 90 | ```cpp 91 | template 92 | class Example { 93 | public: 94 | void show() { std::cout << "Generic version\n"; } 95 | }; 96 | 97 | // Full specialization for `int` 98 | template <> 99 | class Example { 100 | public: 101 | void show() { std::cout << "Specialized for int\n"; } 102 | }; 103 | ``` 104 | 105 | 106 | ### Partial Specialization 107 | 108 | - Allows modifying behavior for a **subset** of template parameters. 109 | 110 | ```cpp 111 | template 112 | class Pair { }; 113 | 114 | // Specialization when both types are the same 115 | template 116 | class Pair { }; 117 | ``` 118 | 119 | 120 | ## Variadic Templates (C++11) 121 | 122 | - Variadic templates allow a **variable number of template parameters** using **`...` (ellipsis).** 123 | 124 | ```cpp 125 | template 126 | void print(T first, Args... args) { 127 | std::cout << first << " "; 128 | if constexpr (sizeof...(args) > 0) print(args...); // compile-time check 129 | } 130 | 131 | int main() { 132 | print(1, 2.5, "Hello", 'C'); 133 | } 134 | ``` 135 | - `Args...` is a **parameter pack** that holds multiple types. 136 | - `sizeof...(args)` checks the number of remaining arguments. 137 | 138 | 139 | 140 | ## Non-Type Template Parameters 141 | 142 | - Templates can accept non-type values (integers, pointers, etc.). 143 | 144 | ```cpp 145 | template 146 | class Buffer { 147 | private: 148 | char data[N]; 149 | }; 150 | Buffer<1024> buf; // Buffer with 1024 bytes 151 | ``` 152 | 153 | 154 | ### `auto` as a Non-Type Parameter (C++17) 155 | 156 | ```cpp 157 | template 158 | void printValue() { std::cout << N << "\n"; } 159 | 160 | printValue<42>(); // Prints 42 161 | ``` 162 | 163 | 164 | ## Template Aliases & Deduction 165 | 166 | 167 | ### Using `using` for Template Aliases 168 | 169 | ```cpp 170 | template 171 | using Vec = std::vector; 172 | 173 | Vec v; // Equivalent to std::vector 174 | ``` 175 | 176 | 177 | ### Template Argument Deduction (C++17) 178 | 179 | ```cpp 180 | template 181 | class Container { 182 | public: 183 | Container(T) { } 184 | }; 185 | 186 | // Before C++17: 187 | Container c1(42); 188 | 189 | // C++17 Deduction: 190 | Container c2(42); // Automatically deduces `T = int` 191 | ``` 192 | 193 | 194 | 195 | --- 196 | [[⇦ Previous](1_19_inheritance_idx.md)] [[Next ⇨](1_21_templates_metaprogramming_idx.md)] [[Index ⇧](index.md#1_20_templates_idx.md)] 197 | -------------------------------------------------------------------------------- /cpp/1_17_rule_of_five_pt2_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # RAII and The Rule of Five (Continued) 3 | 4 | 5 | ## Move Semantics in C++ 6 | 7 | - Optimizes performance by **transferring ownership** of resources **instead of copying them**. 8 | - Avoids expensive deep copies. 9 | 10 | 11 | ### Problem with Copy Semantics 12 | 13 | - By default, C++ **copies objects** when passing them around, which can be costly. 14 | 15 | ```cpp 16 | class VectorND { 17 | private: 18 | size_t n; 19 | double* arr; 20 | public: 21 | VectorND(size_t dim) : n{ dim }, arr{ new double[dim] } {} 22 | 23 | // Copy constructor (Deep copy) 24 | VectorND(const VectorND& other) : n{ other.n }, arr{ new double[other.n] } { 25 | for (size_t i = 0; i < n; i++) arr[i] = other.arr[i]; 26 | } 27 | 28 | ~VectorND() { delete[] arr; } 29 | }; 30 | int main() { 31 | VectorND a(1000); 32 | VectorND b = a; // Creates a deep copy, allocating new memory 33 | } 34 | ``` 35 | ⚠️ Allocates new memory and copies all elements of `a` to `b` even if `a` is no longer needed. 36 | 37 | 38 | 39 | ## 4. Move Constructor 40 | 41 | - The Rule of Five preconizes a **move constructor** to **"move"** an object around without creating copies. 42 | - Instead of duplicating/cloning the state, we **transfer ownership** of the resources. 43 | 44 | ```cpp 45 | VectorND { 46 | //... 47 | // Move Constructor (Steals resources) 48 | VectorND(VectorND&& other) noexcept : n{ other.n }, arr{ other.arr } { 49 | other.n = 0; 50 | other.arr = nullptr; // Prevents double deletion 51 | } 52 | //... 53 | }; 54 | int main() { 55 | VectorND a(1000); 56 | VectorND b = std::move(a); // Moves ownership from a to b 57 | } 58 | ``` 59 | - `b` takes ownership of `a`'s data. 60 | - `a` becomes empty (`arr = nullptr`) and **ready for safe destruction**. 61 | - No expensive deep copy! 62 | 63 | 64 | 65 | ## 5. Move Assignment Operator 66 | 67 | - In the Rule of Five, we need a **move assignment operator** to transfer ownership. 68 | 69 | ```cpp 70 | VectorND { 71 | //... 72 | // Move Assignment Operator 73 | VectorND& operator=(VectorND&& other) noexcept { 74 | if (this == &other) return *this; // Self-assignment check 75 | 76 | delete[] arr; // Free existing memory 77 | 78 | // Transfer ownership 79 | n = other.n; 80 | arr = other.arr; 81 | 82 | // Nullify source to prevent double delete 83 | other.n = 0; 84 | other.arr = nullptr; 85 | 86 | return *this; 87 | } 88 | //... 89 | }; 90 | int main() { 91 | VectorND a(1000); 92 | VectorND b(500); 93 | b = std::move(a); // Moves a into b 94 | } 95 | ``` 96 | 97 | 98 | ## How Does the Compiler Decide Between Copying and Moving? 99 | 100 | - The compiler uses **value categories** to determine whether to **copy** or **move** an object. 101 | 102 | | **Category** | **Definition** | **Move Applied?** | 103 | |--------------|----------------|----------------| 104 | | **Lvalue** | Named variable | ❌ No move | 105 | | **Rvalue** | Temporary object | ✅ Move constructor | 106 | 107 | 108 | ### Rvalue References (`&&`) and Move Semantics 109 | 110 | - If an object **has a name**, it's an **lvalue** → **Copy constructor** is used. 111 | - If an object **has no name** (temporary object), it's an **rvalue** → **Move constructor** is used. 112 | 113 | ```cpp 114 | VectorND a(1000); 115 | VectorND b = a; // Uses copy constructor (a is an lvalue) 116 | VectorND c = std::move(a); // Uses move constructor (a is treated as an rvalue) 117 | ``` 118 | 119 | 120 | ### Rvalue from Function Return 121 | 122 | - Move semantics should be used when returning large objects from functions 123 | 124 | ```cpp 125 | VectorND createRandomVector(size_t n) { 126 | VectorND ret = VectorND(n); 127 | for (size_t i = 0; i < n; ret[i++] = rand()); 128 | return ret; // ret about to be destroyed 129 | } 130 | //... 131 | VectorND v = createRandomVector(1000000); // Move/RVO is applied 132 | ``` 133 | 134 | - The function returns an **unnamed temporary object** → **Rvalue** 135 | - The compiler applies **return value optimization (RVO)** or **move semantics** 136 | - Before C++11: Copy constructor used 137 | - C++11: Move Semantics 138 | - C++17: RVO (Copy ellision) mandatory 139 | 140 | 141 | 142 | ## Rule of Five Summary 143 | 144 | | Special Function | Purpose | When Called | 145 | |------------------|----------|------------| 146 | | **Copy Constructor** | Deep copy state/resources (copy `arr`) | `VectorND b = a;` | 147 | | **Copy Assignment** | Deep copy, handles self-assignment | `b = a;` | 148 | | **Move Constructor** | Transfers ownership (steals resource) | `VectorND b = std::move(a);` | 149 | | **Move Assignment** | Transfers ownership, cleans up old | `b = std::move(a);` | 150 | | **Destructor** | Cleans up memory (`delete[] arr;`) | When object goes out of scope | 151 | 152 | 153 | 154 | --- 155 | [[⇦ Previous](1_16_rule_of_five_idx.md)] [[Next ⇨](1_18_smart_pointers_idx.md)] [[Index ⇧](index.md#1_17_rule_of_five_pt2_idx.md)] 156 | -------------------------------------------------------------------------------- /cpp/1_19_inheritance_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # Inheritance 3 | 4 | - Allows a class (**child**) to derive properties and behavior from another class (**parent**). 5 | - Enables code reuse, polymorphism, and extensibility. 6 | 7 | 8 | ## Syntax 9 | 10 | ```cpp 11 | class Parent { 12 | public: 13 | void show() { std::cout << "Parent class" << std::endl; } 14 | }; 15 | 16 | class Child : public Parent { // Child class inherits Parent 17 | }; 18 | ``` 19 | 20 | ↪ `Child` has all public and protected members of `Parent`. 21 | 22 | ```cpp 23 | int main() { 24 | Child c; 25 | c.show(); // Output: Parent class 26 | } 27 | ``` 28 | 29 | ↪ `Child` can access `show()` without redefining it. 30 | 31 | 32 | 33 | ## Virtual Methods (Polymorphism) 34 | 35 | - A **virtual method** allows (but does not require) derived classes to override it, ensuring **dynamic dispatch (late binding)**. 36 | 37 | ```cpp 38 | class Base { 39 | public: 40 | virtual void display() { // Virtual function 41 | std::cout << "Base class display" << std::endl; 42 | } 43 | }; 44 | 45 | class Derived : public Base { 46 | public: 47 | void display() override { // Overrides Base::display() 48 | std::cout << "Derived class display" << std::endl; 49 | } 50 | }; 51 | 52 | int main() { 53 | Base* b = new Derived(); // Polymorphic behavior 54 | b->display(); // Calls Derived's display() 55 | delete b; 56 | } 57 | ``` 58 | 59 | ↪ Virtual functions ensure correct method is called based on the actual object type, not the pointer type. 60 | 61 | 62 | ## Abstract Classes 63 | 64 | - A class is **abstract** if it has at least one **pure virtual function**. 65 | - A pure virtual method has no implementation and **MUST** be defined by each concrete subclass. 66 | - An abstract class cannot be instantiated directly. 67 | - May be used to replace the concept of **interface** in other languages. 68 | 69 | ```cpp 70 | class Shape { 71 | public: 72 | virtual void draw() = 0; // Pure virtual function 73 | }; 74 | ``` 75 | ↪ Shape is abstract because `draw()` is pure virtual (`= 0`). 76 | 77 | 78 | 79 | ## Concrete Class 80 | 81 | - A class is **concrete** if it provides implementations for all its functions. 82 | 83 | ```cpp 84 | class Circle : public Shape { 85 | public: 86 | void draw() override { // pure virtual function implementation 87 | std::cout << "Drawing Circle" << std::endl; 88 | } 89 | }; 90 | ``` 91 | 92 | 93 | ## Types of Inheritance 94 | 95 | - The access specifier (`public`, `protected`, `private`) affects **how members are inherited**. 96 | 97 | | Inheritance Type | Parent's `public` Members | Parent's `protected` Members | Parent's `private` Members | 98 | |------------------|-------------------------|-----------------------------|----------------------------| 99 | | **Public (`: public`)** | **Public** | **Protected** | Not accessible | 100 | | **Protected (`: protected`)** | **Protected** | **Protected** | Not accessible | 101 | | **Private (`: private`)** | **Private** | **Private** | Not accessible | 102 | 103 | ```cpp 104 | class Base { 105 | protected: 106 | int x; 107 | public: 108 | void show() { std::cout << "Base" << std::endl; } 109 | }; 110 | 111 | class PublicDerived : public Base {}; 112 | class ProtectedDerived : protected Base {}; 113 | class PrivateDerived : private Base {}; 114 | 115 | int main() { 116 | PublicDerived pub; 117 | pub.show(); // Allowed 118 | 119 | ProtectedDerived prot; 120 | // prot.show(); ERROR: show() becomes protected 121 | 122 | PrivateDerived priv; 123 | // priv.show(); ERROR: show() becomes private 124 | } 125 | ``` 126 | 127 | 128 | 129 | ## Method Overriding 130 | 131 | - A **child class** can override a **base class** method. 132 | - Requires **virtual** in base class. 133 | - The `override` keyword ensures compiler checks for proper overriding. 134 | 135 | ```cpp 136 | class Parent { 137 | public: 138 | virtual void greet() { std::cout << "Hello from Parent" << std::endl; } 139 | }; 140 | 141 | class Child : public Parent { 142 | public: 143 | void greet() override { std::cout << "Hello from Child" << std::endl; } 144 | }; 145 | ``` 146 | 147 | 148 | ## Virtual Destructors & Abstract Classes 149 | 150 | 151 | ### Virtual Destructors 152 | 153 | - Ensure proper cleanup when deleting polymorphic objects. 154 | - If a base class does not provide a virtual destructor, it is not called during child object destruction. 155 | 156 | ```cpp 157 | class Base { 158 | public: 159 | virtual ~Base() { std::cout << "Base destructor" << std::endl; } 160 | }; 161 | 162 | class Derived : public Base { 163 | public: 164 | ~Derived() { std::cout << "Derived destructor" << std::endl; } 165 | }; 166 | 167 | int main() { 168 | Base* obj = new Derived(); 169 | delete obj; // Calls both destructors 170 | } 171 | ``` 172 | ↪ **Output** 173 | ``` 174 | Derived destructor 175 | Base destructor 176 | ``` 177 | 178 | 179 | ## Multiple Inheritance 180 | 181 | - A class can inherit from **multiple base classes**. 182 | 183 | ```cpp 184 | class A { public: void showA() { std::cout << "A\n"; } }; 185 | class B { public: void showB() { std::cout << "B\n"; } }; 186 | 187 | class C : public A, public B {}; 188 | ``` 189 | ↪ `C` now has access to `showA()` and `showB()`. 190 | 191 | --- 192 | [[⇦ Previous](1_18_smart_pointers_idx.md)] [[Next ⇨](1_20_templates_idx.md)] [[Index ⇧](index.md#1_19_inheritance_idx.md)] 193 | -------------------------------------------------------------------------------- /cpp/1_27_maps_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # `std::map` 3 | 4 | - **Sorted associative container** that stores key-value pairs. 5 | - Keys ordered using `<` (by default). 6 | - Implemented as a balanced binary search tree (usually Red-Black Tree), ensuring O(log n) worst-case insertions, deletions, and lookups. 7 | - **Keys are unique**: If you insert a duplicate key, the value is updated. 8 | 9 | ```cpp 10 | #include 11 | #include 12 | 13 | int main() { 14 | std::map myMap; 15 | 16 | // Insert elements 17 | myMap[1] = "One"; 18 | myMap[2] = "Two"; 19 | myMap[3] = "Three"; 20 | 21 | // Access elements 22 | std::cout << "Key 2: " << myMap[2] << std::endl; // Output: "Two" 23 | } 24 | ``` 25 | 26 | 27 | ## Iterating Over 28 | 29 | 30 | ### Using a Range-Based Loop (C++11+) 31 | 32 | ```cpp 33 | for (const auto& [key, value] : myMap) { 34 | std::cout << key << " => " << value << std::endl; 35 | } 36 | ``` 37 | ⚠️ Uses **structured bindings** for clean syntax. 38 | 39 | 40 | 41 | ### Using an Iterator 42 | 43 | ```cpp 44 | for (auto it = myMap.begin(); it != myMap.end(); ++it) { 45 | std::cout << it->first << " => " << it->second << std::endl; 46 | } 47 | ``` 48 | 49 | 50 | ### Reverse Iteration 51 | 52 | ```cpp 53 | for (auto it = myMap.rbegin(); it != myMap.rend(); ++it) { 54 | std::cout << it->first << " => " << it->second << std::endl; 55 | } 56 | ``` 57 | 58 | 59 | ## Lookup 60 | 61 | 62 | | **Method** | **Behavior** | **Exception on Missing Key?** | 63 | |-----------------|----------|--------------------------| 64 | | `operator[]` | Returns a reference to the value, if the key exists. Otherwise, inserts a new default-constructed value. | No exception. Inserts and returns default value. | 65 | | `find()` | Returns an iterator to the element if found; otherwise returns `map.end()`. Does not modify the map. | No exception. Returns `end()`. | 66 | | `at()` | Returns a reference to the value, if the key exists. Otherwise, throws `std::out_of_range`. | Throws `std::out_of_range`. | 67 | 68 | 69 | ```cpp 70 | #include 71 | #include 72 | 73 | int main() { 74 | std::map myMap = {{1, "One"}, {2, "Two"}}; 75 | 76 | // operator[] 77 | myMap[3] = "Three"; // Inserts {3, "Three"} if key 3 doesn't exist 78 | 79 | // find() 80 | auto it = myMap.find(2); 81 | if (it != myMap.end()) { 82 | std::cout << "Found: " << it->second << std::endl; 83 | } 84 | 85 | // at() 86 | try { 87 | std::cout << "Value at 2: " << myMap.at(2) << std::endl; 88 | std::cout << "Value at 4: " << myMap.at(4) << std::endl; // Throws std::out_of_range 89 | } catch (const std::out_of_range &e) { 90 | std::cerr << "Exception: " << e.what() << std::endl; 91 | } 92 | 93 | return 0; 94 | } 95 | ``` 96 | 97 | 98 | ## Using `std::map` with User-Defined Classes as Keys 99 | 100 | - `std::map` requires a **sorting mechanism** for keys. 101 | - By default, it uses `operator<`, so you must define it for custom key types. 102 | 103 | 104 | ### Using a Custom Class as a Key 105 | 106 | ```cpp 107 | #include 108 | #include 109 | 110 | class Point { 111 | public: 112 | int x, y; 113 | 114 | Point(int x, int y) : x{x}, y{y} {} 115 | 116 | // Define operator< for sorting 117 | bool operator<(const Point& other) const { 118 | return (x < other.x) || (x == other.x && y < other.y); 119 | } 120 | }; 121 | 122 | // Print function for Point 123 | std::ostream& operator<<(std::ostream& os, const Point& p) { 124 | return os << "(" << p.x << ", " << p.y << ")"; 125 | } 126 | 127 | int main() { 128 | std::map pointMap; 129 | 130 | // Inserting values 131 | pointMap[{2, 3}] = "Point A"; 132 | pointMap[{1, 4}] = "Point B"; 133 | pointMap[{3, 1}] = "Point C"; 134 | 135 | // Iterating over map 136 | for (const auto& [point, name] : pointMap) { 137 | std::cout << point << " => " << name << std::endl; 138 | } 139 | 140 | return 0; 141 | } 142 | ``` 143 | 144 | 145 | ### Using a Custom Comparator 146 | 147 | - If you don’t want or cannot modify the class, you can pass a comparator functor. 148 | 149 | ```cpp 150 | struct PointComparator { 151 | bool operator()(const Point& p1, const Point& p2) const { 152 | return (p1.x + p1.y) < (p2.x + p2.y); // Custom sort: sum of coordinates 153 | } 154 | }; 155 | 156 | std::map pointMap; 157 | ``` 158 | 159 | 160 | 161 | ## Using `std::map` with User-Defined Classes as Values 162 | 163 | - Values don’t need comparison operators, but should be copyable and/or movable. 164 | 165 | ```cpp 166 | class Person { 167 | public: 168 | std::string name; 169 | int age; 170 | 171 | Person(std::string name, int age) : name{std::move(name)}, age{age} {} 172 | 173 | void print() const { 174 | std::cout << name << " (Age: " << age << ")" << std::endl; 175 | } 176 | }; 177 | 178 | int main() { 179 | std::map people; 180 | people.emplace(1, Person("Alice", 30)); 181 | people.emplace(2, Person("Bob", 25)); 182 | 183 | for (const auto& [id, person] : people) { 184 | std::cout << "ID " << id << ": "; 185 | person.print(); 186 | } 187 | } 188 | ``` 189 | ⚠️ Use `emplace()` to construct `Person` in-place, avoiding unnecessary copies. 190 | 191 | 192 | --- 193 | [[⇦ Previous](1_26_vector_idx.md)] [[Next ⇨](1_28_unordered_maps_idx.md)] [[Index ⇧](index.md#1_27_maps_idx.md)] 194 | -------------------------------------------------------------------------------- /aulas/aula08/aula08.md: -------------------------------------------------------------------------------- 1 | # Aula 08: Listas Encadeadas II 2 | 3 | ## Operações básicas 4 | 5 | 0) Inicialização de uma Lista vazia (OK) 6 | 1) Acesso por posição 7 | 2) Busca por valor 8 | 3) Inserção 9 | 4) Remoção 10 | 11 | 12 | ### Acesso por posição 13 | 14 | 1. Cria um cursor `cur` indicador da posição corrente apontando para o nó sentinela 15 | 2. Inicializa o índice de posição corrente `i=0` 16 | 3. Enquanto a posição corrente for menor do que a posição desejada `pos`: 17 | 18 | 3.1. Avança o cursor para o próximo elemento 19 | 3.2. Incrementa o índice da posição corrente 20 | 4. Retorna o cursor na posição atual 21 | 22 | **IMPORTANTE:** 23 | * Nesta representação, uma referência "**lógica**" para um elemento/nó é dada por um ponteiro "**físico**" para o nó imediatamente anterior. 24 | * Desta forma, o primeiro elemento, de índice `[0]`) é representado por um ponteiro para o nó sentinela (i.e. com o mesmo valor de `head`). 25 | * Sabemos que uma referência `cur` é válida, i.e. se referencia um elemento dentro dos limites do tamanho da lista, se `cur->next != NULL`. 26 | 27 | 28 | ### Busca por valor 29 | 30 | Ideia semelhante à busca por posição, varrendo a lista um Nó de cada vez até encontrar o valor procurado ou atingir o último elemento da lista (**cauda**). 31 | 32 | 1. Cria um cursor `cur` indicador da posição corrente apontando para o nó sentinela 33 | 2. Enquanto o valor do elemento corrente (que é o do nó seguinte ao cursor) for diferente do valor procurado, ou chegou à cauda da lista: 34 | 2.1. Avança o cursor para o próximo elemento 35 | 2.2. Incrementa o índice da posição corrente 36 | 4. Retorna o cursor na posição atual 37 | 38 | **IMPORTANTE**: 39 | * Localizar um elemento, seja por posição, seja por valor, requer percorrer a lista desde o início, um elemento de cada vez, até alcançar a posição pretendida. 40 | * No pior caso, isso pode exigir visitar todos os elementos da lista. 41 | 42 | ### Inserção 43 | 44 | Para inserir um novo nó na posição dada por um cursor `cur`: 45 | 46 | ``` 47 | Passo 1) cria novo nó com valor desejado 48 | 49 | +---+---+ +---+---+ 50 | ... --->| X | -|--------------------->| Z | -|--- ... 51 | +---+---+ +---+---+ 52 | ^ 53 | | +---+---+ 54 | cur |val| | 55 | +---+---+ 56 | ^ 57 | | 58 | (1) new_node 59 | 60 | 61 | Passo 2) ajusta o sucessor (next) do novo nó 62 | 63 | +---+---+ +---+---+ 64 | ... --->| X | -|--------------------->| Z | -|--- ... 65 | +---+---+ +-->+---+---+ 66 | ^ | 67 | | +---+---+ | 68 | cur |val| -|---+ (2) 69 | +---+---+ 70 | ^ 71 | | 72 | new_node 73 | 74 | Passo 3) ajusta o sucessor do cursor 75 | 76 | +---+---+ +---+---+ 77 | ... --->| X | -|--+ \ --- +-->| Z | -|--- ... 78 | +---+---+ | | +---+---+ 79 | ^ | | 80 | | (3) | +---+---+ | 81 | cur +-->|val| -|---+ 82 | +---+---+ 83 | ^ 84 | | 85 | new_node 86 | ``` 87 | 88 | **NOTA:** O cursor agora representa uma referência lógica para o novo nó que foi inserido. 89 | 90 | - Podemos combinar essa função com a localização por posição para inserir um nó numa dada posição `pos` da lista. 91 | 92 | **NOTA**: Se a lista tem tamanho (lógico) `n` (`n+1` nós, incluindo o sentinela): 93 | * Inserir no final da lista: `insert_at(head, n, val) == append(head, val)` 94 | * Inserir no início da lista: `insert_cur(head, val) == insert_at(head, 0, val) == prepend(head, val)` 95 | 96 | **IMPORTANTE**: 97 | * Uma vez obtida a referência para a posição corrente, inserir um novo elemento nesse posição requer apenas uma quantidade fixa (constante) de operações. 98 | * Porém, para chegar à posição desejada, precisamos percorrer a lista como explicado acima. 99 | 100 | ### Remoção 101 | 102 | Para remover um nó válido da posição corrente referenciado por um cursor `cur` (pré-condição: `cur->next != NULL`) 103 | 104 | ``` 105 | Passo 1) cria ponteiro para nó a ser removido 106 | 107 | +---+---+ +---+---+ +---+---+ 108 | ... --->| X | -|------>| Y | -|------->| Z | -|--- ... 109 | +---+---+ +---+---+ +---+---+ 110 | ^ ^ 111 | | | 112 | cur (1) to_die 113 | 114 | 115 | Passo 2) ajusta o sucessor do cursor (bypass) 116 | 117 | (2) 118 | +----------------+ 119 | | | 120 | +---+---+ | +---+---+ +--->+---+---+ 121 | ... --->| X | -|--+ / | Y | -|------->| Z | -|--- ... 122 | +---+---+ +---+---+ +---+---+ 123 | ^ ^ 124 | | | 125 | cur to_die 126 | 127 | 128 | Passo 3) apaga o nó pretendido da memória 129 | 130 | 131 | +-----------------+ 132 | | | 133 | +---+---+ | ///////// | +---+---+ 134 | ... --->| X | -|--+ ///////// +--->| Z | -|--- ... 135 | +---+---+ ///////// +---+---+ 136 | ^ ^ 137 | | | 138 | cur to_die (3) 139 | 140 | 141 | ``` 142 | **NOTA:** O cursor agora representa uma referência lógica para o nó seguinte ao nó removido, e que passa a ocupar aquela posição corrente. 143 | 144 | **IMPORTANTE**: 145 | * Uma vez obtida a referência para a posição a ser removida, a remoção em si requer apenas uma quantidade fixa (constante) de operações. 146 | * Porém, para chegar à posição desejada, precisamos percorrer a lista como explicado acima. 147 | 148 | 149 | 150 | ## Referências 151 | 152 | [1] [Clifford Shaffer. Data structures and algorithm analysis in C++, Cap 4](http://people.cs.vt.edu/~shaffer/Book/) 153 | 154 | 155 | 156 | ___ 157 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula07/aula07.md) [[Próximo >]](../aula09/aula09.md) [[Índice ^]](../index.md) 158 | 159 | 160 | -------------------------------------------------------------------------------- /cpp/1_03_compilation_model_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # C++ Compilation Model 3 | 4 | The **C++ compilation model** consists of five main components: 5 | 1. Header Files (`.h`, `.hpp`) 6 | 2. Translation Units (`.cpp` + included headers) 7 | 3. Preprocessor (Expands macros and includes) 8 | 4. Compiler (Compiles source files using MSVC `cl.exe`) 9 | 5. Linker (Combines compiled files into an executable or library using `link.exe`) 10 | 11 | 12 | 13 | ## 1. Header Files (`.h`, `.hpp`) 14 | - **Header files** contain **declarations** of functions, classes, and variables but **not implementations**. 15 | - They are meant to be **included** in multiple source files using `#include`. 16 | - They help with **code reuse and modularity**. 17 | 18 | 19 | ### Example: `math_utils.h` (Header File) 20 | ```cpp 21 | #ifndef MATH_UTILS_H 22 | #define MATH_UTILS_H 23 | 24 | int add(int a, int b); // Function declaration (prototype) 25 | 26 | #endif // MATH_UTILS_H 27 | ``` 28 | - `#ifndef ... #define ... #endif` prevents **multiple inclusions** of the file. 29 | 30 | 31 | ## 2. Translation Units (`.cpp` + Included Headers) 32 | - A **translation unit** is a **single source file (`.cpp`)** plus all its included **headers (`.h`)**. 33 | - Each `.cpp` file is **compiled separately** into an **object file (`.obj`)**. 34 | - **Each translation unit has its own compilation context**. 35 | 36 | 37 | ### Example: `math_utils.cpp` (Translation Unit) 38 | ```cpp 39 | #include "math_utils.h" // Include header file 40 | 41 | int add(int a, int b) { // Function definition (implementation) 42 | return a + b; 43 | } 44 | ``` 45 | 46 | 47 | ## 3. Preprocessor (Expands Macros and Includes) 48 | 49 | - The **preprocessor** processes directives like `#include`, `#define`, and `#ifdef` before compilation. 50 | - It **replaces macros** and **includes** the content of header files into source files. 51 | - Produces an **expanded source file** that is passed to the compiler. 52 | 53 | 54 | 55 | ### Preprocessing Example 56 | 57 | #### Using gcc 58 | 59 | ```sh 60 | g++ -E math_utils.cpp -o math_utils.i 61 | ``` 62 | - `-E`: Runs only the preprocessor 63 | - `-o math_utils.i`: Writes the output to `math_utils.i` 64 | This will produce a file (`math_utils.i`) that contains the fully preprocessed source code. 65 | 66 | 67 | #### Using MSVC `cl.exe` 68 | 69 | ```sh 70 | cl /P math_utils.cpp /Fi:math_utils.i 71 | ``` 72 | - `/P`: Runs only the preprocessor. 73 | - `/Fi:`: Specifies the output preprocessed file (`math_utils.i`). 74 | 75 | 76 | 77 | ## 4. Compiler (Compiles Each Translation Unit) 78 | - The **compiler processes each translation unit separately**, performing: 79 | 1. **Preprocessing**: Expands `#include` files, replaces macros. 80 | 2. **Compilation**: Translates C++ code into assembly/machine code. 81 | 3. **Optimization**: Improves performance. 82 | 4. **Code Generation**: Produces object files (`.obj`). 83 | 84 | 85 | ### Compilation Example 86 | 87 | #### Using gcc 88 | 89 | ```sh 90 | g++ -c math_utils.cpp -o math_utils.o 91 | ``` 92 | 93 | - `-c`: Compile only, do not link 94 | - `-o math_utils.o`: Specify the name of the output object file 95 | 96 | - This will produce `math_utils.o`, the compiled object file. 97 | 98 | 99 | #### Using MSVC `cl.exe` 100 | 101 | ```sh 102 | cl /c math_utils.cpp /Fo:math_utils.obj 103 | ``` 104 | - `/c`: Compile without linking. 105 | - `/Fo:`: Specifies output object file (`math_utils.obj`). 106 | 107 | 108 | 109 | ## 5. Linker (Combines Object Files into Executable) 110 | - The **linker** combines multiple object files (`.obj`) into a single **executable (`.exe`)**. 111 | - It resolves **symbol references** (e.g., function calls across files). 112 | - It **links system libraries** (e.g., `kernel32.lib`, `windowsapp.lib`). 113 | 114 | 115 | ### Example: Linking 116 | 117 | #### Using `g++` 118 | 119 | ```sh 120 | g++ math_utils.o main.o -o my_program 121 | ``` 122 | 123 | * Produces `my_program` (executable on Unix-like systems, or `my_program.exe` on Windows). 124 | 125 | 126 | #### Using `link.exe` 127 | ```sh 128 | link math_utils.obj main.obj /OUT:my_program.exe 129 | ``` 130 | - Produces `my_program.exe` (Windows executable). 131 | 132 | 133 | 134 | ## Putting It All Together 135 | 136 | Compilation pipeline 137 | 138 | 139 | 140 | ## Complete Example 141 | 142 | ### Header (`math_utils.h`) 143 | ```cpp 144 | #ifndef MATH_UTILS_H 145 | #define MATH_UTILS_H 146 | 147 | int add(int a, int b); 148 | 149 | #endif 150 | ``` 151 | 152 | 153 | ### Implementation (`math_utils.cpp`) 154 | ```cpp 155 | #include "math_utils.h" 156 | 157 | int add(int a, int b) { 158 | return a + b; 159 | } 160 | ``` 161 | 162 | 163 | ### Main File (`main.cpp`) 164 | ```cpp 165 | #include 166 | #include "math_utils.h" 167 | 168 | int main() { 169 | std::cout << "Sum: " << add(3, 4) << std::endl; 170 | return 0; 171 | } 172 | ``` 173 | 174 | 175 | ### Compilation & Linking Commands 176 | 177 | #### Using `g++` 178 | 179 | ```sh 180 | g++ -E math_utils.cpp -o math_utils.i # Preprocess math_utils.cpp 181 | g++ -c math_utils.cpp -o math_utils.o # Compile math_utils.cpp 182 | g++ -c main.cpp -o main.o # Compile main.cpp 183 | g++ math_utils.o main.o -o my_program # Link object files into executable 184 | ./my_program # Run the program (Unix-like) or my_program.exe on Windows 185 | ``` 186 | 187 | #### Using MSVC 188 | ```sh 189 | cl /P math_utils.cpp /Fi:math_utils.i # Preprocess math_utils.cpp 190 | cl /c math_utils.cpp /Fo:math_utils.obj # Compile math_utils.cpp 191 | cl /c main.cpp /Fo:main.obj # Compile main.cpp 192 | link math_utils.obj main.obj /OUT:my_program.exe # Link object files into executable 193 | my_program.exe # Run the program 194 | ``` 195 | 196 | --- 197 | [[⇦ Previous](1_02_csharp_vs_cpp_idx.md)] [[Next ⇨](1_04_main_idx.md)] [[Index ⇧](index.md#1_03_compilation_model_idx.md)] 198 | -------------------------------------------------------------------------------- /cpp/1_25_stl_overview_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # C++ Standard Template Library (STL) Overview 3 | 4 | - The **Standard Template Library (STL)** provides generic and reusable divided into: 5 | 1. **Containers** – Data structures to store elements. 6 | 2. **Iterators** – Provide a way to traverse containers. 7 | 3. **Algorithms** – Perform operations like searching, sorting, and modifying data. 8 | 4. **Function Objects (Functors) & Utilities** – Enable custom behavior in algorithms. 9 | - It follows a template-based approach, enabling efficient and type-safe operations. 10 | 11 | 12 | 13 | ## 1. Containers 14 | 15 | - Used to store collections of objects. 16 | 17 | 18 | ### Sequence Containers (Ordered Collections) 19 | 20 | - [`std::vector`](https://en.cppreference.com/w/cpp/container/vector) – Dynamic array with fast random access. 21 | - [`std::deque`](https://en.cppreference.com/w/cpp/container/deque) – Double-ended queue for fast insert/delete at both ends. 22 | - [`std::list`](https://en.cppreference.com/w/cpp/container/list)– Doubly linked list (efficient insert/remove anywhere). 23 | - [`std::forward_list`](https://en.cppreference.com/w/cpp/container/forward_list)– Singly linked list (lighter, but forward-only). 24 | - [`std::array`](https://en.cppreference.com/w/cpp/container/array) – Fixed-size array (C++11). 25 | 26 | **Example: Using `std::vector`** 27 | 28 | ```cpp 29 | #include 30 | #include 31 | 32 | int main() { 33 | std::vector numbers = {1, 2, 3, 4, 5}; 34 | numbers.push_back(6); // Add element at the end 35 | 36 | for (int num : numbers) { 37 | std::cout << num << " "; 38 | } 39 | } 40 | ``` 41 | 42 | 43 | ### Associative Containers (Sorted Key-Value or Set-Based) 44 | 45 | - [`std::set`](https://en.cppreference.com/w/cpp/container/set) – Unique, sorted elements. 46 | - [`std::multiset`](https://en.cppreference.com/w/cpp/container/multiset) – Sorted, but allows duplicate elements. 47 | - [`std::map`](https://en.cppreference.com/w/cpp/container/map) – Key-value pairs, sorted by key. 48 | - [`std::multimap`](https://en.cppreference.com/w/cpp/container/multimap) – Like `map`, but allows duplicate keys. 49 | 50 | **Example: Using `std::map`** 51 | 52 | ```cpp 53 | #include 54 | #include 55 | 56 | int main() { 57 | std::map scores = {{"Alice", 90}, {"Bob", 85}}; 58 | scores["Charlie"] = 95; // Insert new key-value pair 59 | 60 | for (const auto& [name, score] : scores) { 61 | std::cout << name << ": " << score << '\n'; 62 | } 63 | } 64 | ``` 65 | 66 | 67 | ### Unordered Containers (Hash-Based, Fast Lookups) 68 | 69 | - [`std::unordered_set`](https://en.cppreference.com/w/cpp/container/unordered_set) – Unique elements, no order. 70 | - [`std::unordered_map`](https://en.cppreference.com/w/cpp/container/unordered_map) – Key-value pairs, no order. 71 | - [`std::unordered_multiset`](https://en.cppreference.com/w/cpp/container/unordered_multiset) – Allows duplicates, no order. 72 | - [`std::unordered_multimap`](https://en.cppreference.com/w/cpp/container/unordered_multimap) – Key-value pairs, allows duplicate keys. 73 | 74 | **Example: Using `std::unordered_set`** 75 | 76 | ```cpp 77 | #include 78 | #include 79 | 80 | int main() { 81 | std::unordered_set numbers = {4, 2, 8, 1, 3}; 82 | 83 | numbers.insert(5); 84 | numbers.erase(2); 85 | 86 | for (int num : numbers) { 87 | std::cout << num << " "; 88 | } 89 | } 90 | ``` 91 | 92 | 93 | ## 2. Iterators 94 | 95 | - Provide a generic way to traverse through elements in containers. 96 | 97 | 98 | ### Types of Iterators 99 | 100 | 1. **Input Iterator** → Read-only, forward traversal (`std::istream_iterator`). 101 | 2. **Output Iterator** → Write-only (`std::ostream_iterator`). 102 | 3. **Forward Iterator** → Read/write, single pass (`std::forward_list`). 103 | 4. **Bidirectional Iterator** → Can move forward/backward (`std::list`, `std::map`). 104 | 5. **Random Access Iterator** → Fast indexing (`std::vector`, `std::deque`). 105 | 106 | **Example: Using Iterators** 107 | 108 | ```cpp 109 | #include 110 | #include 111 | 112 | int main() { 113 | std::vector numbers = {10, 20, 30, 40, 50}; 114 | 115 | for (std::vector::iterator it = numbers.begin(); it != numbers.end(); ++it) { 116 | std::cout << *it << " "; 117 | } 118 | } 119 | ``` 120 | 121 | **Example: Range-Based For Loop (C++11)** 122 | 123 | ```cpp 124 | #include 125 | #include 126 | 127 | int main() { 128 | std::vector numbers = {10, 20, 30}; 129 | 130 | for (int num : numbers) { 131 | std::cout << num << " "; 132 | } 133 | } 134 | ``` 135 | 136 | 137 | 138 | ## 3. Algorithms 139 | 140 | The **``** header provides many common operations, such as: 141 | - **Sorting:** `std::sort(begin, end)` 142 | - **Searching:** `std::binary_search(begin, end, value)` 143 | - **Min/Max:** `std::min_element(begin, end)`, `std::max_element(begin, end)` 144 | - **Counting:** `std::count(begin, end, value)` 145 | - **Modifying:** `std::reverse(begin, end)`, `std::transform(begin, end, output, func)` 146 | 147 | **Example: Sorting a Vector** 148 | 149 | ```cpp 150 | #include 151 | #include 152 | #include 153 | 154 | int main() { 155 | std::vector numbers = {5, 3, 8, 1, 2}; 156 | 157 | std::sort(numbers.begin(), numbers.end()); 158 | 159 | for (int num : numbers) { 160 | std::cout << num << " "; 161 | } 162 | } 163 | ``` 164 | 165 | 166 | ## 4. Function Objects (Functors) & Utilities 167 | 168 | - **Function Objects (Functors):** Custom callable objects that can be used with STL algorithms. 169 | - **Lambdas (C++11+):** Anonymous functions for inline behavior. 170 | - **Pair (`std::pair`):** Stores two values together. 171 | - **Tuple (`std::tuple`):** Stores multiple values. 172 | 173 | **Example: Using a Functor** 174 | 175 | ```cpp 176 | #include 177 | #include 178 | #include 179 | 180 | struct MultiplyByTwo { 181 | int operator()(int x) const { return x * 2; } 182 | }; 183 | 184 | int main() { 185 | std::vector numbers = {1, 2, 3, 4, 5}; 186 | 187 | std::transform(numbers.begin(), numbers.end(), numbers.begin(), MultiplyByTwo()); 188 | 189 | for (int num : numbers) { 190 | std::cout << num << " "; 191 | } 192 | } 193 | ``` 194 | 195 | **Example: Using a Lambda (C++11)** 196 | 197 | ```cpp 198 | #include 199 | #include 200 | #include 201 | 202 | int main() { 203 | std::vector numbers = {1, 2, 3, 4, 5}; 204 | 205 | std::transform(numbers.begin(), numbers.end(), numbers.begin(), 206 | [](int x) { return x * 2; }); 207 | 208 | for (int num : numbers) { 209 | std::cout << num << " "; 210 | } 211 | } 212 | ``` 213 | 214 | --- 215 | [[⇦ Previous](1_24_error_as_values_idx.md)] [[Next ⇨](1_26_vector_idx.md)] [[Index ⇧](index.md#1_25_stl_overview_idx.md)] 216 | -------------------------------------------------------------------------------- /aulas/aula20/rooted nary tree.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 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 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /cpp/1_26_vector_idx.md: -------------------------------------------------------------------------------- 1 | 2 | # `std::vector` 3 | 4 | - **Dynamic Array** with: 5 | - Contiguous memory → Elements are stored like an array, ensuring fast access. 6 | - Random access (O(1) complexity) → Supports direct element access via indexing. 7 | - Automatic resizing → Expands automatically when needed. 8 | - Efficient insertions/deletions → `push_back()` is amortized O(1) but insertions/removals in the middle are O(n) worst-case. 9 | - Supports iterators → Works well with STL algorithms. 10 | - One of the most commonly used containers in STL. 11 | 12 | 13 | ## Creation/Destruction 14 | 15 | - If a vector holds objects, its destruction triggers the destruction of each element. 16 | 17 | ```cpp 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | class Foo { 25 | public: 26 | Foo(int i): i{i} {} 27 | ~Foo() { 28 | cout << "destructing " << *this << endl; 29 | } 30 | friend ostream& operator<<(ostream &os, const Foo& foo) { 31 | os << "Foo{" << foo.i <<"}"; 32 | return os; 33 | } 34 | private: 35 | int i; 36 | }; 37 | 38 | int main() { 39 | vector foos = {1,2,3}; 40 | 41 | for (auto &f: foos) { 42 | cout << f << endl; 43 | } 44 | 45 | // The three Foo instances of foos are automatically destructed 46 | } 47 | ``` 48 | 49 | - If a vector holds pointers to objects, its destruction **does not** trigger the destruction of individual elements. They must be manually destructed. 50 | 51 | ```cpp 52 | int main() { 53 | vector pfoos; 54 | pfoos.push_back(new Foo(4)); 55 | pfoos.push_back(new Foo(5)); 56 | pfoos.push_back(new Foo(6)); 57 | for (auto &pf: pfoos) { 58 | cout << *pf << endl; 59 | } 60 | // clear individual elements 61 | for (auto &pf: pfoos) { 62 | delete pf; 63 | } 64 | pfoos.clear(); 65 | // 66 | } 67 | ``` 68 | 69 | - Objects held by smart pointers are destructed with the vector when no other reference remains. 70 | 71 | ```cpp 72 | int main() { 73 | auto nine = make_shared(9); 74 | if (true) { 75 | vector> spfoos; 76 | spfoos.push_back(make_shared(7)); 77 | spfoos.push_back(make_shared(8)); 78 | spfoos.push_back(nine); 79 | } // first two objects destroyed with the vector 80 | cout << "------" << endl; 81 | cout << *nine << " lives! " << endl; 82 | } 83 | ```` 84 | 85 | 86 | ## Memory Management and Capacity 87 | 88 | | **Function** | **Description** | 89 | |--------------|----------------| 90 | | `size()` | Number of elements in the vector | 91 | | `capacity()` | Allocated storage size (≥ `size()`) | 92 | | `empty()` | Returns `true` if vector is empty | 93 | | `reserve(n)` | Pre-allocates memory for at least `n` elements | 94 | | `shrink_to_fit()` | Reduces capacity to match size | 95 | 96 | ```cpp 97 | #include 98 | #include 99 | 100 | int main() { 101 | std::vector v; 102 | v.reserve(10); // Pre-allocate memory 103 | 104 | std::cout << "Size: " << v.size() << '\n'; // Prints Size: 0 105 | std::cout << "Capacity: " << v.capacity() << '\n'; // Prints Capacity: 10 106 | 107 | for (int i = 0; i < 5; ++i) v.push_back(i); 108 | 109 | std::cout << "Size: " << v.size() << '\n'; // Prints Size: 5 110 | std::cout << "Capacity: " << v.capacity() << '\n'; // Prints Capacity: 10 111 | 112 | v.shrink_to_fit(); 113 | 114 | std::cout << "Size: " << v.size() << '\n'; // Prints Size: 5 115 | std::cout << "Capacity: " << v.capacity() << '\n'; // Prints Capacity: 5 116 | } 117 | ``` 118 | 119 | 120 | ## Accessing Elements 121 | 122 | | **Operation** | **Description** | 123 | |--------------|----------------| 124 | | `v[i]` | Access element at index `i` (O(1) w/o bounds check) | 125 | | `v.at(i)` | Access element at index `i` (O(1) w/ bounds check) | 126 | | `front()` | Returns the first element (unsafe) | 127 | | `back()` | Returns the last element (unsafe) | 128 | 129 | ```cpp 130 | #include 131 | #include 132 | 133 | int main() { 134 | std::vector v = {10, 20, 30}; 135 | 136 | std::cout << v[1] << '\n'; // Direct access (unsafe) 137 | std::cout << v.at(1) << '\n'; // Bounds-checked access (safe) 138 | } 139 | ``` 140 | 141 | 142 | ## Adding and Removing Elements 143 | 144 | | **Operation** | **Description** | 145 | |--------------|----------------| 146 | | `push_back(value)` | Adds an element at the end (O(1) amortized) | 147 | | `pop_back()` | Removes the last element (O(1)) | 148 | | `insert(pos, value)` | Inserts an element at a specific position (O(n)) | 149 | | `erase(pos)` | Removes an element at a specific position (O(n)) | 150 | | `clear()` | Removes all elements | 151 | 152 | ```cpp 153 | #include 154 | #include 155 | 156 | int main() { 157 | std::vector v = {10, 20, 30}; 158 | 159 | v.insert(v.begin() + 1, 15); // Insert 15 at index 1 160 | v.erase(v.begin()); // Remove first element 161 | 162 | for (int num : v) std::cout << num << " "; 163 | } 164 | ``` 165 | 166 | 167 | ### Adding with `std::vector::emplace` 168 | 169 | - `std::vector::push_back` first creates an object and then copies/moves it. 170 | - `std::vector::emplace` constructs an element directly **in place** inside a `std::vector`. 171 | 172 | ```cpp 173 | vec.emplace(position, args...); 174 | - `position` → Iterator where the element should be inserted. 175 | - `args...` → Arguments forwarded to the constructor of the element type. 176 | 177 | vec.emplace_back, args...); 178 | - equivalent to vec.emplace(vec.end(), args...); 179 | ``` 180 | 181 | ```cpp 182 | #include 183 | #include 184 | 185 | class Foo { 186 | public: 187 | int x; 188 | Foo(int x) : x{x} { std::cout << "Constructing Foo(" << x << ")\n"; } 189 | // ... 190 | }; 191 | 192 | int main() { 193 | std::vector vec; 194 | 195 | Foo f(10); // Constructs Foo 196 | vec.push_back(f); // Copies Foo into vector 197 | vec.push_back(Foo(20)); // Creates temp Foo, then moves it 198 | 199 | vec.emplace_back(30); // Construct directly in vector 200 | vec.emplace(vec.begin() + 1, 25); // No extra temporary object 201 | return 0; 202 | } 203 | ``` 204 | 205 | 206 | 207 | ## Traversing a `vector` 208 | 209 | 210 | ### Using an Iterator 211 | 212 | ```cpp 213 | #include 214 | #include 215 | 216 | int main() { 217 | std::vector v = {10, 20, 30}; 218 | 219 | for (std::vector::iterator it = v.begin(); it != v.end(); ++it) { 220 | std::cout << *it << " "; 221 | } 222 | } 223 | ``` 224 | 225 | 226 | ### Using Range-Based Loop (C++11) 227 | 228 | ```cpp 229 | #include 230 | #include 231 | 232 | int main() { 233 | std::vector v = {10, 20, 30}; 234 | 235 | for (int num : v) { 236 | std::cout << num << " "; 237 | } 238 | } 239 | ``` 240 | 241 | 242 | ## Moving and Swapping 243 | 244 | - **Move Semantics (`std::move()`)** avoids expensive deep copies. 245 | - **`swap()`** efficiently exchanges two vectors. 246 | 247 | ```cpp 248 | #include 249 | #include 250 | 251 | int main() { 252 | std::vector v1 = {1, 2, 3}; 253 | std::vector v2 = std::move(v1); // v1 is now empty 254 | 255 | std::cout << "v2 size: " << v2.size() << '\n'; 256 | } 257 | ``` 258 | 259 | ```cpp 260 | #include 261 | #include 262 | 263 | int main() { 264 | std::vector a = {1, 2, 3}; 265 | std::vector b = {4, 5, 6}; 266 | 267 | a.swap(b); 268 | 269 | for (int num : a) std::cout << num << " "; // Outputs: 4 5 6 270 | } 271 | ``` 272 | 273 | --- 274 | [[⇦ Previous](1_25_stl_overview_idx.md)] [[Next ⇨](1_27_maps_idx.md)] [[Index ⇧](index.md#1_26_vector_idx.md)] 275 | -------------------------------------------------------------------------------- /aulas/aula07/aula07.md: -------------------------------------------------------------------------------- 1 | # Aula 07: Listas Encadeadas I 2 | 3 | ## Definição 4 | 5 | * ED linear homogênea dinâmica 6 | - "linear": elementos em sequência, identificados por posição 7 | - "homogêna": elementos do mesmo tipo 8 | - "dinâmica": quantidade variável de elementos e memória 9 | 10 | ## Representação 11 | 12 | * Cada elemento armazenado num "**Nó**" 13 | * Além do valor do elemento (`val`), cada nó possui uma *referência* (ponteiro) para o próximo nó (`next`) 14 | 15 | ``` 16 | Linked List Node 17 | 18 | +-------+--------+ 19 | | val | next -|---> 20 | +-------+--------+ 21 | 22 | ``` 23 | Em C++ 24 | 25 | ```cpp 26 | struct Node { 27 | int val; 28 | Node *next; 29 | }; 30 | ``` 31 | 32 | 33 | * Guardamos uma referência especial para o primeiro Nó da lista, chamado **cabeça** (*head*). 34 | * Além disso, usamos a representação de [[1]](#referencias) em que sempre temos um nó inicial chamado **sentinela**, cujo valor não faz parte **logicamente** da lista. O nó sentinela serve apenas para demarcar **fisicamente** o início da lista. 35 | 36 | ## Exemplos 37 | 38 | A) Lista Vazia 39 | 40 | ``` 41 | +---+---+ 42 | head ---->| \ | -|---+ 43 | +---+---+ | 44 | | 45 | === 46 | ``` 47 | 48 | Repare que a lista vazia tem pelo menos o nó sentinela, ou seja `head` é sempre um ponteiro para um nó válido. 49 | 50 | 51 | B) Lista com os 4 primeiros primos 52 | 53 | ``` 54 | Índices "lógicos" 55 | dos elementos: [0] [1] [2] [3] 56 | 57 | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ 58 | head ---->| \ | -|--->| 2 | -|--->| 3 | -|--->| 5 | -|--->| 7 | -|---+ 59 | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | 60 | | 61 | === 62 | ``` 63 | 64 | ## Operações básicas 65 | 66 | 0) Inicialização de uma Lista vazia 67 | 1) Acesso por posição 68 | 2) Busca por valor 69 | 3) Inserção 70 | 4) Remoção 71 | 72 | 73 | ### Inicialização de uma Lista vazia 74 | 75 | 1. Aloca memória para um novo nó 76 | 2. Inicializa valor e next 77 | 78 | 79 | ### Acesso por posição 80 | 81 | 1. Cria um cursor `cur` indicador da posição corrente apontando para o nó sentinela 82 | 2. Inicializa o índice de posição corrente `i=0` 83 | 3. Enquanto a posição corrente for menor do que a posição desejada `pos`: 84 | 85 | 3.1. Avança o cursor para o próximo elemento 86 | 3.2. Incrementa o índice da posição corrente 87 | 4. Retorna o cursor na posição atual 88 | 89 | **IMPORTANTE:** 90 | * Nesta representação, uma referência "**lógica**" para um elemento/nó é dada por um ponteiro "**físico**" para o nó imediatamente anterior. 91 | * Desta forma, o primeiro elemento, de índice `[0]`) é representado por um ponteiro para o nó sentinela (i.e. com o mesmo valor de `head`). 92 | * Sabemos que uma referência `cur` é válida, i.e. se referencia um elemento dentro dos limites do tamanho da lista, se `cur->next != NULL`. 93 | 94 | 95 | ### Busca por valor 96 | 97 | Ideia semelhante à busca por posição, varrendo a lista um Nó de cada vez até encontrar o valor procurado ou atingir o último elemento da lista (**cauda**). 98 | 99 | 1. Cria um cursor `cur` indicador da posição corrente apontando para o nó sentinela 100 | 2. Enquanto o valor do elemento corrente (que é o do nó seguinte ao cursor) for diferente do valor procurado, ou chegou à cauda da lista: 101 | 2.1. Avança o cursor para o próximo elemento 102 | 2.2. Incrementa o índice da posição corrente 103 | 4. Retorna o cursor na posição atual 104 | 105 | **IMPORTANTE**: 106 | * Localizar um elemento, seja por posição, seja por valor, requer percorrer a lista desde o início, um elemento de cada vez, até alcançar a posição pretendida. 107 | * No pior caso, isso pode exigir visitar todos os elementos da lista. 108 | 109 | ### Inserção 110 | 111 | Para inserir um novo nó na posição dada por um cursor `cur`: 112 | 113 | ``` 114 | Passo 1) cria novo nó com valor desejado 115 | 116 | +---+---+ +---+---+ 117 | ... --->| X | -|--------------------->| Z | -|--- ... 118 | +---+---+ +---+---+ 119 | ^ 120 | | +---+---+ 121 | cur |val| | 122 | +---+---+ 123 | ^ 124 | | 125 | (1) new_node 126 | 127 | 128 | Passo 2) ajusta o sucessor (next) do novo nó 129 | 130 | +---+---+ +---+---+ 131 | ... --->| X | -|--------------------->| Z | -|--- ... 132 | +---+---+ +-->+---+---+ 133 | ^ | 134 | | +---+---+ | 135 | cur |val| -|---+ (2) 136 | +---+---+ 137 | ^ 138 | | 139 | new_node 140 | 141 | Passo 3) ajusta o sucessor do cursor 142 | 143 | +---+---+ +---+---+ 144 | ... --->| X | -|--+ \ --- +-->| Z | -|--- ... 145 | +---+---+ | | +---+---+ 146 | ^ | | 147 | | (3) | +---+---+ | 148 | cur +-->|val| -|---+ 149 | +---+---+ 150 | ^ 151 | | 152 | new_node 153 | ``` 154 | 155 | **NOTA:** O cursor agora representa uma referência lógica para o novo nó que foi inserido. 156 | 157 | - Podemos combinar essa função com a localização por posição para inserir um nó numa dada posição `pos` da lista. 158 | 159 | **NOTA**: Se a lista tem tamanho (lógico) `n` (`n+1` nós, incluindo o sentinela): 160 | * Inserir no final da lista: `insert_at(head, n, val) == append(head, val)` 161 | * Inserir no início da lista: `insert_cur(head, val) == insert_at(head, 0, val) == prepend(head, val)` 162 | 163 | **IMPORTANTE**: 164 | * Uma vez obtida a referência para a posição corrente, inserir um novo elemento nesse posição requer apenas uma quantidade fixa (constante) de operações. 165 | * Porém, para chegar à posição desejada, precisamos percorrer a lista como explicado acima. 166 | 167 | ### Remoção 168 | 169 | Para remover um nó válido da posição corrente referenciado por um cursor `cur` (pré-condição: `cur->next != NULL`) 170 | 171 | ``` 172 | Passo 1) cria ponteiro para nó a ser removido 173 | 174 | +---+---+ +---+---+ +---+---+ 175 | ... --->| X | -|------>| Y | -|------->| Z | -|--- ... 176 | +---+---+ +---+---+ +---+---+ 177 | ^ ^ 178 | | | 179 | cur (1) to_die 180 | 181 | 182 | Passo 2) ajusta o sucessor do cursor (bypass) 183 | 184 | (2) 185 | +----------------+ 186 | | | 187 | +---+---+ | +---+---+ +--->+---+---+ 188 | ... --->| X | -|--+ / | Y | -|------->| Z | -|--- ... 189 | +---+---+ +---+---+ +---+---+ 190 | ^ ^ 191 | | | 192 | cur to_die 193 | 194 | 195 | Passo 3) apaga o nó pretendido da memória 196 | 197 | 198 | +-----------------+ 199 | | | 200 | +---+---+ | ///////// | +---+---+ 201 | ... --->| X | -|--+ ///////// +--->| Z | -|--- ... 202 | +---+---+ ///////// +---+---+ 203 | ^ ^ 204 | | | 205 | cur to_die (3) 206 | 207 | 208 | ``` 209 | **NOTA:** O cursor agora representa uma referência lógica para o nó seguinte ao nó removido, e que passa a ocupar aquela posição corrente. 210 | 211 | **IMPORTANTE**: 212 | * Uma vez obtida a referência para a posição a ser removida, a remoção em si requer apenas uma quantidade fixa (constante) de operações. 213 | * Porém, para chegar à posição desejada, precisamos percorrer a lista como explicado acima. 214 | 215 | 216 | 217 | ## Referências 218 | 219 | [1] [Clifford Shaffer. Data structures and algorithm analysis in C++, Cap 4](http://people.cs.vt.edu/~shaffer/Book/) 220 | 221 | 222 | 223 | ___ 224 | [[Código-fonte: /src]](./src) [[< Anterior]](../aula06/aula06.md) [[Próximo >]](../aula08/aula08.md) [[Índice ^]](../index.md) 225 | 226 | 227 | --------------------------------------------------------------------------------