1#include <iostream>
2#include <utility>
3
4class Nodo { // Um nó guarda o dado e um ponteiro para o próximo
5private: // Atributos privados: só os métodos acessam
6 int dato_;
7 Nodo* siguiente_;
8public:
9 Nodo(int dato, Nodo* siguiente = nullptr) {
10 dato_ = dato;
11 siguiente_ = siguiente;
12 }
13 int getDato() const { return dato_; }
14 void setDato(int dato) { dato_ = dato; }
15 Nodo* getSiguiente() const { return siguiente_; }
16 void setSiguiente(Nodo* siguiente) { siguiente_ = siguiente; }
17};
18
19class Lista {
20private:
21 Nodo* cabeza_; // Primeiro nó da lista
22 int n_; // Número de nós
23
24public:
25 Lista() { // Construtor padrão: cria uma lista vazia
26 cabeza_ = nullptr;
27 n_ = 0;
28 }
29
30 ~Lista() { // Destrutor: libera todos os nós
31 while (cabeza_ != nullptr) {
32 Nodo* borra = cabeza_;
33 cabeza_ = borra->getSiguiente();
34 delete borra;
35 }
36 }
37
38 Lista(const Lista& origin) { // Construtor de cópia: faz uma cópia profunda
39 cabeza_ = nullptr;
40 n_ = 0;
41 Nodo* aux = origin.cabeza_;
42 while (aux != nullptr) {
43 insertarElemento(aux->getDato());
44 aux = aux->getSiguiente();
45 }
46 invertirLista(); // Inserir na cabeça inverte a ordem, então inverte-se de novo
47 }
48
49 Lista& operator=(const Lista& origin) { // Atribuição por cópia: libera os nós antigos e depois copia
50 if (this != &origin) { // Protege contra a autoatribuição
51 while (cabeza_ != nullptr) { // Libera os nós que a lista já tinha
52 Nodo* borra = cabeza_;
53 cabeza_ = borra->getSiguiente();
54 delete borra;
55 }
56 n_ = 0;
57 Nodo* aux = origin.cabeza_;
58 while (aux != nullptr) {
59 insertarElemento(aux->getDato());
60 aux = aux->getSiguiente();
61 }
62 invertirLista();
63 }
64 return *this;
65 }
66
67 Lista(Lista&& origin) noexcept { // Construtor de movimentação: toma os nós da origem
68 cabeza_ = origin.cabeza_;
69 n_ = origin.n_;
70 origin.cabeza_ = nullptr; // Deixa a origem vazia
71 origin.n_ = 0;
72 }
73
74 Lista& operator=(Lista&& origin) noexcept { // Atribuição por movimentação: libera os nós antigos e depois toma os novos
75 if (this != &origin) { // Protege contra a autoatribuição
76 while (cabeza_ != nullptr) { // Libera os nós que a lista já tinha
77 Nodo* borra = cabeza_;
78 cabeza_ = borra->getSiguiente();
79 delete borra;
80 }
81 cabeza_ = origin.cabeza_;
82 n_ = origin.n_;
83 origin.cabeza_ = nullptr; // Deixa a origem vazia
84 origin.n_ = 0;
85 }
86 return *this;
87 }
88
89 int getTamano() const { return n_; }
90 Nodo* getCabeza() const { return cabeza_; }
91
92 void insertarElemento(int valor) { // Inserir no início: O(1)
93 Nodo* nodo = new Nodo(valor, nullptr);
94 n_ += 1;
95 nodo->setSiguiente(cabeza_);
96 cabeza_ = nodo;
97 }
98
99 void imprimirLista() const { // Imprime todos os elementos
100 Nodo* siguiente = cabeza_;
101 for (int i = 0; i < n_; i++) {
102 std::cout << siguiente->getDato() << " ";
103 siguiente = siguiente->getSiguiente();
104 }
105 std::cout << std::endl;
106 }
107
108 void eliminarNodo(int indice) { // Remove o nó da posição indicada
109 if (indice < 0 || indice >= n_) return; // Índice inválido: nada acontece
110 if (indice == 0) {
111 Nodo* eliminar = cabeza_;
112 cabeza_ = eliminar->getSiguiente();
113 delete eliminar;
114 n_--;
115 return;
116 }
117 Nodo* eliminanodo_anterio = cabeza_;
118 for (int i = 0; i < indice - 1; i++) {
119 eliminanodo_anterio = eliminanodo_anterio->getSiguiente();
120 }
121 Nodo* eliminanodo = eliminanodo_anterio->getSiguiente();
122 eliminanodo_anterio->setSiguiente(eliminanodo->getSiguiente());
123 delete eliminanodo;
124 n_--;
125 }
126
127 void invertirLista() { // Inverte a lista no próprio lugar
128 Nodo* anterior = nullptr;
129 Nodo* actual = cabeza_;
130 Nodo* siguiente = nullptr;
131 for (int i = 0; i < n_; i++) {
132 siguiente = actual->getSiguiente();
133 actual->setSiguiente(anterior);
134 anterior = actual;
135 actual = siguiente;
136 }
137 cabeza_ = anterior;
138 }
139};
140
141int main() {
142 Lista l1;
143 l1.insertarElemento(10);
144 l1.insertarElemento(20);
145 l1.insertarElemento(30);
146
147 Lista l2;
148 l2.insertarElemento(100);
149
150 l2 = l1; // Atribuição por cópia (sem swap)
151 l2.imprimirLista();
152
153 Lista l3;
154 l3 = std::move(l1); // Atribuição por movimentação (sem swap)
155 l3.imprimirLista();
156
157 return 0;
158}