# Listas Simplesmente Encadeadas ###### tags: `interview-training` `linked-list` `c++` ### Estrutura Básica: ```cpp struct ListNode { int val; ListNode* next; ListNode() : val(0), next(nullptr) {} ListNode(int x) : val(x), next(nullptr) {} }; ``` Visualizando... ![](https://upload.wikimedia.org/wikipedia/commons/6/69/ListaEncadeada.jpg) Vantagens: Remover nó em O(1) Desvantagens: Acessar nó qualquer em O(n) ## Operações ##### Obs: os códigos são apenas para aprendizado e não foram testados Remover elemento: ```cpp // Remover Elemento // Obs: para entrevista, não precisa se preocupar em desalocar // a memória do nó que vai ser removido ListNode* removeElement (ListNode* head, int index) { ListNode* prev = nullptr; ListNode* current = head; if(head == nullptr) return head; while(index) { prev = current; current = current -> next; if(current == nullptr) return head; index--; } if(prev == nullptr) { head = head -> next; } else { prev -> next = current -> next; } return head; } ``` Exercícios: https://leetcode.com/problems/delete-node-in-a-linked-list/ https://leetcode.com/problems/remove-nth-node-from-end-of-list/ ___ Inserir Elemento: ```cpp // Inserir elemento ListNode* insertElement (ListNode* head, int val, int index) { ListNode* prev = nullptr; ListNode* current = head; while(index) { prev = current; if(current == nullptr) break; current = current -> next; index--; } ListNode* newNode = new ListNode(val); if(prev == nullptr) { newNode -> next = head; head = newNode; } else { prev->next = newNode; newNode -> next = current; } return head; } ``` ___ Construir lista a partir de um vector: ```cpp // Construir uma lista encadeada a partir de um vector ListNode* build (vector<int> v) { ListNode* prev = nullptr; ListNode* head = nullptr; for(int i = 0; i < v.size(); i++) { ListNode* newNode = new ListNode(v[i]); if(prev == nullptr) head = newNode; else prev->next = newNode; prev = newNode; } return head; } ``` ___ Deep copy: ```cpp // Fazer deep copy (memória precisa ser alocada, os novos // ponteiros não irão apontar para os mesmos endereços da lista de input) ListNode* deepCopy (ListNode* head) { ListNode* prev = nullptr; ListNode* headCopy = nullptr; while(head != nullptr) { ListNode* copyNode = new ListNode(head -> val); if(prev == nullptr) headCopy = copyNode; else prev->next = copyNode; head = head -> next; prev = copyNode; } return headCopy; } ``` ___ Reverter Lista: ```cpp // Reverter lista ListNode* reverse (ListNode* head) { if(head == nullptr) return head; ListNode* prev = nullptr; ListNode* next = nullptr; while(head != nullptr) { next = head -> next; head -> next = prev; prev = head; head = next; } return prev; } ``` Exercícios: https://leetcode.com/problems/reverse-linked-list/ https://leetcode.com/problems/reverse-nodes-in-k-group/ ___ Printar lista: ```cpp // Printar lista encadeada void print (ListNode* head) { while(head != nullptr) { cout << head -> val << " "; head = head -> next; } cout << endl; } ``` ## Assuntos Extras Detecção de ciclo: Técnica do ponteiro rápido e lento (floyd's Tortoise and Hare), o ponteiro rápido irá andar de dois em dois passos, enquanto que o lento andará de um em um, se os dois se encontrarem, é porque existe um ciclo. Complexidade: O(n) Extra: Como encontrar o início do ciclo? Exercícios: https://leetcode.com/problems/linked-list-cycle/ https://leetcode.com/problems/linked-list-cycle-ii/ ___ Lista com random pointer: ```cpp struct ListNode { int val; ListNode* next; ListNode* random; ListNode() : val(0), next(nullptr), random(nullptr) {} ListNode(int x) : val(x), next(nullptr), random(nullptr) {} }; ``` Visualizando: ![](https://i.imgur.com/wXnYtRP.png) Como fazer deep copy? Opção 1: usar um map <LinkedList*, LinkedList*> associando cada nó da lista original com sua cópia Opção 2: criar uma lista encadeada em que os nós nas posições ímpares são os originais e nas posições pares são as cópias Exercício: https://leetcode.com/problems/copy-list-with-random-pointer/ ___ MergeSort com lista encadeada: Bem direto, bom para treinar, a parte que pode complicar é o merge de duas listas encadeadas, então segue uns exercícios para praticar justamente isso: https://leetcode.com/problems/merge-two-sorted-lists/ https://leetcode.com/problems/merge-k-sorted-lists/ ___ Questões ultra clássicas: Somar dois números que estão na forma de lista encadeada: Obs: atentar aos casos que precisa criar um novo nó https://leetcode.com/problems/add-two-numbers/ Verificar se lista encadeada é um palíndromo: Uma opção é reverter primeira metade da lista, andar na primera metade (revertida) e na segunda e verificar se os nós tem os mesmos valores https://leetcode.com/problems/palindrome-linked-list/