1#include <iostream>
2#include <utility>
3
4class Nodo { // Un nœud contient la donnée et un pointeur vers le suivant
5private: // Attributs privés : seules les méthodes y touchent
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_; // Premier nœud de la liste
22 int n_; // Nombre de nœuds
23
24public:
25 Lista() { // Constructeur par défaut : crée une liste vide
26 cabeza_ = nullptr;
27 n_ = 0;
28 }
29
30 ~Lista() { // Destructeur : libère tous les nœuds
31 while (cabeza_ != nullptr) {
32 Nodo* borra = cabeza_;
33 cabeza_ = borra->getSiguiente();
34 delete borra;
35 }
36 }
37
38 Lista(const Lista& origin) { // Constructeur de copie : fait une copie profonde
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(); // L'insertion en tête inverse l'ordre, on le rétablit donc
47 }
48
49 Lista& operator=(const Lista& origin) { // Affectation par copie : libère les anciens nœuds, puis copie
50 if (this != &origin) { // Protège contre l'auto-affectation
51 while (cabeza_ != nullptr) { // Libère les nœuds que la liste possède déjà
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 { // Constructeur de déplacement : prend les nœuds de la source
68 cabeza_ = origin.cabeza_;
69 n_ = origin.n_;
70 origin.cabeza_ = nullptr; // Laisse la source vide
71 origin.n_ = 0;
72 }
73
74 Lista& operator=(Lista&& origin) noexcept { // Affectation par déplacement : libère les anciens nœuds, puis prend les nouveaux
75 if (this != &origin) { // Protège contre l'auto-affectation
76 while (cabeza_ != nullptr) { // Libère les nœuds que la liste possède déjà
77 Nodo* borra = cabeza_;
78 cabeza_ = borra->getSiguiente();
79 delete borra;
80 }
81 cabeza_ = origin.cabeza_;
82 n_ = origin.n_;
83 origin.cabeza_ = nullptr; // Laisse la source vide
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) { // Insertion en tête : 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 { // Affiche tous les éléments
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) { // Supprime le nœud à l'indice donné
109 if (indice < 0 || indice >= n_) return; // Indice invalide : rien ne se passe
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() { // Inverse la liste sur place
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; // Affectation par copie (sans swap)
151 l2.imprimirLista();
152
153 Lista l3;
154 l3 = std::move(l1); // Affectation par déplacement (sans swap)
155 l3.imprimirLista();
156
157 return 0;
158}