1#include <iostream>
2#include <utility>
3
4class Nodo { // Ein Knoten enthält die Daten und Zeiger auf den vorherigen und den nächsten
5private: // Private Attribute: nur die Methoden greifen darauf zu
6 int dato_;
7 Nodo* anterior_;
8 Nodo* siguiente_;
9public:
10 Nodo(int dato, Nodo* anterior = nullptr, Nodo* siguiente = nullptr) {
11 dato_ = dato;
12 anterior_ = anterior;
13 siguiente_ = siguiente;
14 }
15 int getDato() const { return dato_; }
16 void setDato(int dato) { dato_ = dato; }
17 Nodo* getAnterior() const { return anterior_; }
18 void setAnterior(Nodo* anterior) { anterior_ = anterior; }
19 Nodo* getSiguiente() const { return siguiente_; }
20 void setSiguiente(Nodo* siguiente) { siguiente_ = siguiente; }
21};
22
23class Lista {
24private:
25 Nodo* cabeza_; // Erster Knoten der Liste
26 Nodo* cola_; // Letzter Knoten der Liste
27 int n_; // Anzahl der Knoten
28
29public:
30 Lista() { // Standardkonstruktor: erzeugt eine leere Liste
31 cabeza_ = nullptr;
32 cola_ = nullptr;
33 n_ = 0;
34 }
35
36 ~Lista() { // Destruktor: gibt alle Knoten frei
37 while (cabeza_ != nullptr) {
38 Nodo* borra = cabeza_;
39 cabeza_ = borra->getSiguiente();
40 delete borra;
41 }
42 cola_ = nullptr;
43 }
44
45 Lista(const Lista& origin) { // Kopierkonstruktor: erstellt eine tiefe Kopie
46 cabeza_ = nullptr;
47 cola_ = nullptr;
48 n_ = 0;
49 Nodo* aux = origin.cabeza_;
50 while (aux != nullptr) {
51 insertarAlFinal(aux->getDato()); // Das Einfügen am Ende erhält die ursprüngliche Reihenfolge
52 aux = aux->getSiguiente();
53 }
54 }
55
56 Lista& operator=(const Lista& origin) { // Kopierzuweisung: gibt die alten Knoten frei und kopiert dann
57 if (this != &origin) { // Schützt vor Selbstzuweisung
58 while (cabeza_ != nullptr) { // Gibt die Knoten frei, die die Liste bereits hat
59 Nodo* borra = cabeza_;
60 cabeza_ = borra->getSiguiente();
61 delete borra;
62 }
63 cola_ = nullptr;
64 n_ = 0;
65 Nodo* aux = origin.cabeza_;
66 while (aux != nullptr) {
67 insertarAlFinal(aux->getDato());
68 aux = aux->getSiguiente();
69 }
70 }
71 return *this;
72 }
73
74 Lista(Lista&& origin) noexcept { // Verschiebekonstruktor: übernimmt die Knoten der Quelle
75 cabeza_ = origin.cabeza_;
76 cola_ = origin.cola_;
77 n_ = origin.n_;
78 origin.cabeza_ = nullptr; // Lässt die Quelle leer zurück
79 origin.cola_ = nullptr;
80 origin.n_ = 0;
81 }
82
83 Lista& operator=(Lista&& origin) noexcept { // Verschiebezuweisung: gibt die alten Knoten frei und übernimmt dann die neuen
84 if (this != &origin) { // Schützt vor Selbstzuweisung
85 while (cabeza_ != nullptr) { // Gibt die Knoten frei, die die Liste bereits hat
86 Nodo* borra = cabeza_;
87 cabeza_ = borra->getSiguiente();
88 delete borra;
89 }
90 cola_ = nullptr;
91 cabeza_ = origin.cabeza_;
92 cola_ = origin.cola_;
93 n_ = origin.n_;
94 origin.cabeza_ = nullptr; // Lässt die Quelle leer zurück
95 origin.cola_ = nullptr;
96 origin.n_ = 0;
97 }
98 return *this;
99 }
100
101 int getTamano() const { return n_; }
102 Nodo* getCabeza() const { return cabeza_; }
103 Nodo* getCola() const { return cola_; }
104
105 void insertarElemento(int valor) { // Am Anfang einfügen: O(1)
106 Nodo* nodo = new Nodo(valor);
107 n_ += 1;
108 nodo->setSiguiente(cabeza_);
109 if (cabeza_ != nullptr) {
110 cabeza_->setAnterior(nodo);
111 } else {
112 cola_ = nodo;
113 }
114 cabeza_ = nodo;
115 }
116
117 void insertarAlFinal(int valor) { // Am Ende einfügen: O(1) dank cola_
118 Nodo* nodo = new Nodo(valor);
119 n_ += 1;
120 nodo->setAnterior(cola_);
121 if (cola_ != nullptr) {
122 cola_->setSiguiente(nodo);
123 } else {
124 cabeza_ = nodo;
125 }
126 cola_ = nodo;
127 }
128
129 void imprimirLista() const { // Von Kopf bis Ende ausgeben
130 Nodo* actual = cabeza_;
131 while (actual != nullptr) {
132 std::cout << actual->getDato() << " ";
133 actual = actual->getSiguiente();
134 }
135 std::cout << std::endl;
136 }
137
138 void imprimirListaAtras() const { // Vom Ende bis zum Kopf ausgeben
139 Nodo* actual = cola_;
140 while (actual != nullptr) {
141 std::cout << actual->getDato() << " ";
142 actual = actual->getAnterior();
143 }
144 std::cout << std::endl;
145 }
146
147 void eliminarNodo(int indice) { // Löscht den Knoten am angegebenen Index
148 if (indice < 0 || indice >= n_) return; // Ungültiger Index: nichts passiert
149 Nodo* eliminar = cabeza_;
150 for (int i = 0; i < indice; i++) {
151 eliminar = eliminar->getSiguiente();
152 }
153 if (eliminar->getAnterior() != nullptr) {
154 eliminar->getAnterior()->setSiguiente(eliminar->getSiguiente());
155 } else {
156 cabeza_ = eliminar->getSiguiente();
157 }
158 if (eliminar->getSiguiente() != nullptr) {
159 eliminar->getSiguiente()->setAnterior(eliminar->getAnterior());
160 } else {
161 cola_ = eliminar->getAnterior();
162 }
163 delete eliminar;
164 n_--;
165 }
166
167 void invertirLista() { // Kehrt die Liste in place um: jeder Knoten tauscht anterior_ und siguiente_
168 Nodo* actual = cabeza_;
169 Nodo* temporal = nullptr;
170 while (actual != nullptr) {
171 temporal = actual->getAnterior();
172 actual->setAnterior(actual->getSiguiente());
173 actual->setSiguiente(temporal);
174 actual = actual->getAnterior(); // anterior_ ist jetzt das alte siguiente_
175 }
176 temporal = cabeza_; // Zum Schluss werden Kopf und Ende getauscht
177 cabeza_ = cola_;
178 cola_ = temporal;
179 }
180};
181
182int main() {
183 Lista l1;
184 l1.insertarElemento(10);
185 l1.insertarElemento(20);
186 l1.insertarAlFinal(5);
187 l1.insertarElemento(30);
188
189 Lista l2;
190 l2.insertarElemento(100);
191
192 l2 = l1; // Kopierzuweisung (ohne swap)
193 l2.imprimirLista();
194 l2.imprimirListaAtras();
195
196 Lista l3;
197 l3 = std::move(l1); // Verschiebezuweisung (ohne swap)
198 l3.invertirLista();
199 l3.imprimirLista();
200
201 return 0;
202}