1#include <iostream>
2#include <utility>
3
4class Nodo { // Un nodo guarda el dato y el puntero al siguiente
5private: // Atributos privados: solo se tocan con los métodos
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_; // Primer nodo de la lista
22 int n_; // Número de nodos
23
24public:
25 Lista() { // Constructor por defecto: crea una lista vacía
26 cabeza_ = nullptr;
27 n_ = 0;
28 }
29
30 ~Lista() { // Destructor: libera todos los nodos
31 while (cabeza_ != nullptr) {
32 Nodo* borra = cabeza_;
33 cabeza_ = borra->getSiguiente();
34 delete borra;
35 }
36 }
37
38 Lista(const Lista& origin) { // Constructor de copia: hace una copia 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(); // Insertar por la cabeza invierte el orden, así que se invierte de nuevo
47 }
48
49 Lista& operator=(const Lista& origin) { // Asignación por copia: libera los nodos antiguos y luego copia
50 if (this != &origin) { // Protege contra la autoasignación
51 while (cabeza_ != nullptr) { // Libera los nodos que ya tenía la lista
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 { // Constructor de movimiento: roba los nodos del origen
68 cabeza_ = origin.cabeza_;
69 n_ = origin.n_;
70 origin.cabeza_ = nullptr; // Deja el origen vacío
71 origin.n_ = 0;
72 }
73
74 Lista& operator=(Lista&& origin) noexcept { // Asignación por movimiento: libera los nodos antiguos y roba los nuevos
75 if (this != &origin) { // Protege contra la autoasignación
76 while (cabeza_ != nullptr) { // Libera los nodos que ya tenía la lista
77 Nodo* borra = cabeza_;
78 cabeza_ = borra->getSiguiente();
79 delete borra;
80 }
81 cabeza_ = origin.cabeza_;
82 n_ = origin.n_;
83 origin.cabeza_ = nullptr; // Deja el origen vacío
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) { // Inserta al inicio: 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 los 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) { // Elimina el nodo de la posición indicada
109 if (indice < 0 || indice >= n_) return; // Índice no válido: no hace nada
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() { // Invierte la lista in situ
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; // Asignación por copia (sin swap)
151 l2.imprimirLista();
152
153 Lista l3;
154 l3 = std::move(l1); // Asignación por movimiento (sin swap)
155 l3.imprimirLista();
156
157 return 0;
158}