Imaginemos Un Mundo Libre
-
Upload
kestler-reyes -
Category
Documents
-
view
220 -
download
0
description
Transcript of Imaginemos Un Mundo Libre
http://c.conclase.net/curso/index.php?cap=029
Imaginemos un mundo libreEl blog de Ronny, dedicado a la libertad de acceso al conocimiento.
Listas enlazadas – Clase Lista,Nodo en c++
con 15 comentarios
Una lista es una estructura de datos que nos permite agrupar elementos de una manera organizada. Las listas al igual que los algoritmos son importantísimas en la computación y críticas en muchos programas informáticos.
Las listas están compuestas por nodos, estos nodos tienen un dato o valor y un puntero a otro(s) nodo(s).
Existen varios tipos de listas: Simplemente enlazada, doblemente enlazada, circular simplemente enlazada, circular doblemente enlazada.
Vamos a revisar las listas enlazadas simples, por ser el punto de partida y fundamentales para poder entender las otras.
Una lista enlazada tiene un conjunto de nodos, los cuales almacenan 2 tipos de información: El dato que contienen y un puntero al siguiente nodo en la lista. El último nodo de la lista tiene como siguiente nodo el valor NULL. Entonces las listas enlazadas simples solo pueden ser recorridas en una dirección, apuntando al nodo siguiente, mas no a un nodo anterior.
Aquí una ejemplo de un lista enlazada simple.
ver fuente
imprimir ?
01 En cristiano:
02 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL
03
04 Internamente:05 Nodo-> Dato: 55 Direcion: 0x3d2c00 Siguiente: 0x3d2c8006 Nodo-> Dato: 60 Direcion: 0x3d2c80 Siguiente: 0x3d2c9007 Nodo-> Dato: 31 Direcion: 0x3d2c90 Siguiente: 0x3d2ca008 Nodo-> Dato: 5 Direcion: 0x3d2ca0 Siguiente: 0x3d2cb009 Nodo-> Dato: 4 Direcion: 0x3d2cb0 Siguiente: 0x3d2cc0
10 Nodo-> Dato: 51 Direcion: 0x3d2cc0 Siguiente: 0x3d3ab811 Nodo-> Dato: 9 Direcion: 0x3d3ab8 Siguiente: 0x3d3ac812 Nodo-> Dato: 27 Direcion: 0x3d3ac8 Siguiente: 0x3d3ad813 Nodo-> Dato: 68 Direcion: 0x3d3ad8 Siguiente: 0x3d3ae8
14 Nodo-> Dato: 62 Direcion: 0x3d3ae8 Siguiente: 0
Obviamente, internamente no existen las palabras nodo, dato,dirección y siguiente, es solo una representación.
Como una lista es una estructura de datos dinámica, el tamaño de la misma puede cambiar durante la ejecución del programa.
Como vimos en post anteriores, se puede generar memoria dinámicamente para un array, pero un array es una estructura estática pues su tamaño tiene un limite y así creáramos array dinámicos hay que redimensionar el tamaño si es necesario, lo cual ya implica un costo de volver a generar memoria dinámica.
Entonces podemos ver una ventaja de la listas sobre los arrays: No tener que redimensionar la estructura y poder agregar elemento tras elemento indefinidamente.
Cuando uno ya ha trabajado con arrays (vectores y matrices) y empieza a estudiar las listas, se da cuenta que una restricción de las listas es el acceso a los elementos. En un vector podíamos hacer algo como v[50] y nos estábamos refiriendo al índice 50 del vector v. A esto se le conoce como acceso aleatorio.
En el caso de las listas el acceso es secuencial, es decir, para acceder a un elemento del conjunto debemos de recorrer uno por uno los elementos hasta llegar al solicitado. Rápidamente se puede concluir que el tiempo de acceso a los elementos de un array es muchísimo más rápido que en una lista. Esta es una gran desventaja de las listas, por lo que buscar elementos por índice sería muy costoso. Esto no quiere decir que trabajar con arrays sea mejor que con listas. Las listas son muy flexibles y para muchos casos son imprescindibles.
Bueno, aquí va la primera práctica que hice sobre listas enlazadas. Implementación de una clase Lista, clase Nodo y los siguientes métodos:
Añadir un elemento al inicio. Añadir un elemento al final Añadir un elemento de manera ordenada Llenar la lista por teclado Llenar la lista aleatoriamente Imprimir la lista Buscar un elemento Eliminar un elemento por dato Eliminar un elemento por posicion o índice Eliminar toda la lista Invertir una lista Ordernar una lista Cargar una lista desde archivo
Guardar la lista en un archivo Concatenar una lista a otra Intersección entre 2 listas
Podrán ver la variable *temp en casi todos los métodos , este es el puntero de tipo Nodo que me va a permitir moverme a través de la lista y que inicialmente es igual a la cabeza (head). Mientras exista algo en la lista, voy avanzado el puntero para que apunte al siguiente. Esto se consigue en casi todos los casos con un while.
While(temp)temp = temp->gte
Otra operación común en los métodos es preguntar si inicialmente la lista está vacía, es decir, si la cabeza no contiene algo o es igual a Null.
if(!head) o if(head==NULL)
Apliqué mis limitados conocimientos de templates para tener una lista genérica y así pueda funcionar con varios tipos de datos y de verdad funciona.
Ahí la definición e implementación de la clase, lista, clase nodo y el main para ver el funcionamiento. Cualquier crítica, sugerencia o comentarios son bienvenidos siempre.
Nodo.h
ver fuente
imprimir ?
01 #ifndef NODO_H02 #define NODO_H03 #include <iostream>
04
05 using namespace std;
06 template <class T>
07 class Nodo
08 {
09 public:
10 T dato;11 Nodo *sgte;
12 Nodo();
13 Nodo(T);14 ~Nodo();
15
16 void print();
17 void eliminar();
18 };
19
20 #endif // NODO_H
Nodo.cpp
ver fuente
imprimir ?
01 #include "Nodo.h"
02
03 //constructor por defecto
04 template<typename T>
05 Nodo<T>::Nodo()
06 {
07 dato = NULL;08 sgte = NULL;
09 }
1011 //constructor por parametro
12 template<typename T>
13 Nodo<T>::Nodo(T dato_)
14 {
15 dato = dato_;
16 sgte = NULL;
17 }
18
19 //imprimir un nodo
20 template<typename T>21 void Nodo<T>::print()
22 {
23 //cout << "Nodo-> " << "Dato: " << dato << " Direcion: " << this << " Siguiente: " << sgte << endl;
24 cout << dato << "-> ";
25 }
26
27 //eliminar todos los nodos
28 template<typename T>
29 void Nodo<T>::eliminar()
30 {
31 if(sgte)
32 sgte->eliminar();33 delete this;
34 }
35
36 template<typename T>37 Nodo<T>::~Nodo(){}
Lista.h
ver fuente
imprimir ?
01 #ifndef LISTA_H02 #define LISTA_H
03
04 #include <iostream>
05 #include "time.h"
06 #include <fstream>07 #include <string>08 #include "Nodo.h"09 #include "Nodo.cpp"
10
11 using namespace std;
12
13 template <class T>
14 class Lista
15 {
16 private:17 int dim,num_nodos;
18 T line;
19 string archivo;
20
21 public:
22 T ele;23 Nodo<T> *head;
24 Lista();
25 ~Lista();
26
27 void llenar_teclado(int);
28 void llenar_aleatorio(int);
29 void print();
30 void add_end(T);31 void add_head(T);32 void add_sort(T);
33 void search(T);
34 void del_dato(T);35 void del_pos(int);
36 void del_all();
37
38 void invertir();
39 void sort();
40 void load(string);41 void save(string);
42
43 void concat(Lista);
44 void interseccion(Lista);45 };
46
47 #endif // LISTA_H
Lista.cpp
ver fuente
imprimir ?
001 #include "Lista.h"
002
003 using namespace std;
004
005 //constructor por defecto
006 template<typename T>
007 Lista<T>::Lista()
008 {
009 num_nodos = 0;
010 head = NULL;
011 }
012013 //llenar la lista por teclado
014 template<typename T>
015 void Lista<T>::llenar_teclado(int dim)
016 {
017 for(int i=0;i<dim;i++){
018 cout << "Ingresa el elemento " << i + 1 << endl;
019 cin >> ele;
020 add_end(ele);021 }
022 }
023
024 //llenar la lista aleatoriamente para enteros
025 template<typename T>
026 void Lista<T>::llenar_aleatorio(int dim)
027 {
028 srand(time(NULL));
029 for(int i=0;i<dim;i++){
030 add_end(rand() % 100);031 }
032 }
033
034 //imprimir la lista
035 template<typename T>
036 void Lista<T>::print()
037 {
038 Nodo<T> *temp = head;
039 if(!head){
040 cout << "La lista esta vacia " << endl;
041 } else{
042 while(temp){
043 temp->print();
044 if(!temp->sgte) cout << "NULL";045 temp = temp->sgte;
046 }
047 }
048 cout << endl << endl;
049 }
050
051 //insertar al final
052 template<typename T>053 void Lista<T>::add_end(T dato_)
054 {
055 Nodo<T> *temp = head;
056 Nodo<T> *nuevo = new Nodo<T> (dato_);
057
058 if(!head){059 head = nuevo;
060 } else{
061 while(temp->sgte !=NULL){
062 temp = temp->sgte;
063 }
064 temp->sgte = nuevo;
065 }
066 num_nodos++;
067 }
068069 //insertar al inicio
070 template<typename T>
071 void Lista<T>::add_head(T dato_)
072 {
073 Nodo<T> *temp = head;
074 Nodo<T> *nuevo = new Nodo<T> (dato_);
075
076 if(!head){077 head = nuevo;
078 } else{
079 nuevo->sgte = head;
080 head = nuevo;
081 while(temp){
082 temp = temp->sgte;083 }
084 }
085 num_nodos++;
086 }
087
088 //insertar de manera ordenada
089 template<typename T>
090 void Lista<T>::add_sort(T dato_)
091 {
092 Nodo<T> *nuevo = new Nodo<T> (dato_);093 Nodo<T> *temp = head;
094
095 if(!head){
096 head = nuevo;
097 } else{
098 if(head->dato > dato_){099 nuevo->sgte = head;
100 head = nuevo;
101 } else{
102 while((temp->sgte != NULL) && (temp->sgte->dato < dato_)){103 temp = temp->sgte;
104 }
105 nuevo->sgte = temp->sgte;
106 temp->sgte = nuevo;
107 }
108 }
109 num_nodos++;
110 }
111
112 //buscar el dato de un nodo
113 template<typename T>
114 void Lista<T>::search(T dato_)
115 {
116 Nodo<T> *temp = head;117 int cont = 1;
118 int cont2=0;
119 while(temp){
120 if(temp->dato == dato_){
121 cout << "El dato se encuentra en la posicion: " << cont << " (Para seres humanos)" << endl;
122 cont2++;
123 }
124 temp = temp->sgte;125 cont++;
126 }
127 if(cont2 == 0){
128 cout << "No existe el dato " << endl;
129 }
130 cout << endl << endl;
131 }
132133 //eliminar por dato del nodo
134 template<typename T>
135 void Lista<T>::del_dato(T dato_)
136 {
137 Nodo<T> *temp = head;
138 Nodo<T> *temp1 = head->sgte;
139
140 int cont=0;
141
142 if(head->dato == dato_){143 head = temp->sgte;
144 } else {
145 while(temp1){
146 if(temp1->dato == dato_){
147 Nodo<T> *aux = temp1;
148 temp->sgte = temp1->sgte;149 delete aux;
150 cont++;
151 num_nodos--;
152 }
153 temp = temp->sgte;
154 temp1 = temp1->sgte;155 }
156 }
157 if(cont == 0){
158 cout << "No existe el dato " << endl;159 }
160 }
161
162 //eliminar por posicion del nodo
163 template<typename T>
164 void Lista<T>::del_pos(int pos)
165 {
166 Nodo<T> *temp = head;167 Nodo<T> *temp1 = temp->sgte;
168
169 if(pos < 1 || pos > num_nodos){
170 cout << "Fuera de rango " << endl;
171 } else if(pos==1){
172 head = temp->sgte;
173 } else{
174 for(int i=2;i<=pos;i++){
175 if(i==pos){
176 Nodo<T> *aux = temp1;177 temp->sgte = temp1->sgte;
178 delete aux;
179 num_nodos--;
180 }
181 temp = temp->sgte;
182 temp1 = temp1->sgte;183 }
184 }
185 }
186187 //eliminar todos los nodos
188 template<typename T>
189 void Lista<T>::del_all()
190 {
191 head->eliminar();
192 head = 0;
193 }
194
195 //invertir la lista
196 template<typename T>197 void Lista<T>::invertir()
198 {
199 Nodo<T> *temp = head;200 Nodo<T> *prev = NULL;201 Nodo<T> *next = NULL;
202
203 while(temp){
204 next = temp->sgte;205 temp->sgte = prev;
206 prev = temp;
207 temp = next;
208 }
209 head = prev;
210 }
211
212 //ordenar de manera ascendente
213 template<typename T>
214 void Lista<T>::sort()
215 {
216 T aux2;217 Nodo<T> *aux = head;218 Nodo<T> *temp = aux;
219
220 while(aux){
221 temp=aux;
222 while(temp->sgte){223 temp=temp->sgte;
224
225 if(aux->dato>temp->dato){
226 aux2=aux->dato;
227 aux->dato=temp->dato;
228 temp->dato=aux2;
229 }
230 }
231 aux=aux->sgte;
232 }
233 }
234235 //cargar una lista de un archivo
236 template<typename T>
237 void Lista<T>::load(string archivo)
238 {
239 ifstream in;
240 in.open(archivo.c_str());
241
242 if(!in.is_open()){
243 cout << "No se puede abrir el archivo: " << archivo << endl << endl;
244 } else{
245 while(in >> line){
246 add_end(line);
247 }
248 }
249 in.close();
250 }
251
252 //guardar una lista en un archivo
253 template<typename T>
254 void Lista<T>::save(string archivo)
255 {
256 Nodo<T> *temp = head;
257 ofstream out;
258 out.open(archivo.c_str());
259
260 if(!out.is_open()){261 cout << "No se puede guardar el archivo " << endl;
262 } else{
263 while(temp){
264 out << temp->dato;
265 out << " ";
266 temp = temp->sgte;267 }
268 }
269 out.close();
270 }
271
272 //concatenar a otra lista
273 template<typename T>
274 void Lista<T>::concat(Lista Lista2)
275 {
276 Nodo<T> *temp2 = Lista2.head;
277
278 while(temp2){279 add_end(temp2->dato);
280 temp2 = temp2->sgte;
281 }
282 }
283
284 //numeros que coinciden en 2 listas
285 template<typename T>
286 void Lista<T>::interseccion(Lista Lista2)
287 {
288 Nodo<T> *temp = head;289 Nodo<T> *temp2 = Lista2.head;//cabeza de la segunda lista
290 Lista lista_interseccion;//creo otra lista
291
292 int num_nodos2 = Lista2.num_nodos;//nodos de la segunda lista293 int num_inter=0;//numero de coincidencias
294
295 //creo 2 vectores dinamicos
296 T *v1 = new T[num_nodos];
297 T *v2 = new T[num_nodos2];
298
299 //lleno los vectores v1 y v2 con los datos de la lista original y segunda lista respectivamente
300 int i=0;
301 while(temp){
302 v1[i] = temp->dato;303 temp = temp->sgte;
304 i++;
305 }
306
307 int j=0;
308 while(temp2){309 v2[j] = temp2->dato;310 temp2 = temp2->sgte;311 j++;
312 }
313
314 //ordeno los vectores
315 insert_sort(v1,num_nodos);
316 insert_sort(v2,num_nodos2);
317
318 int v1_i= 0;//indice del 1er vector (v1)319 int v2_i= 0;//indice del 2do vector (v2)
320
321 //mientras no haya terminado de recorrer ambas listas
322 while (v1_i < num_nodos && v2_i < num_nodos2) {
323 if(v1[v1_i] == v2[v2_i]){//cuando los datos de ambas sean iguales
324 lista_interseccion.add_end(v1[v1_i]);//utilizo mi metodo add_end para llenar la lista de intersecciones
325 v1_i++;326 v2_i++;
327 num_inter++;
328 } else if(v1[v1_i] < v2[v2_i]){329 v1_i++;
330 } else{
331 v2_i++;
332 }
333 }
334
335 //Solo si hay alguna interseccion imprimo la nueva lista creada
336 if(num_inter > 0) {
337 cout << "Existen " << num_inter << " intersecciones " << endl;
338 lista_interseccion.print();
339 } else {
340 cout << "No hay interseccion en ambas listas" << endl;341 }
342 }
343
344 //usado por el metodo interseccion
345 template<typename T>
346 void insert_sort(T a[],int tam)
347 {
348 T temp;
349 for(int i=0;i<tam;i++){
350 for(int j=i-1;j >=0 && a[j+1] < a[j];j--){351 temp = a[j+1];352 a[j+1] = a[j];353 a[j] = temp;
354 }
355 }
356 }
357
358 template<typename T>359 Lista<T>::~Lista(){}
main.cpp
ver fuente
imprimir ?
01 #include <iostream>
02 #include "Lista.h"
03 #include "Lista.cpp" //por errores de linking de tipo "undefined reference to" (estudiando)
04
05 using namespace std;
06 int main()
07 {
08 Lista<int> l1;09 Lista<int> l2;
10
11 int dim,pos;
12 string archivo;
13
14 cout << "Ingresa la dimension de la lista " << endl;15 cin >>dim;
16
17 l1.llenar_aleatorio(dim);//llenar_teclado para otros tipos
18
19 cout << "Lista A al inicio " << endl;
20 l1.print();
21
22 cout << "Agrega un elemento por la cabeza" << endl;
23 cin >>l1.ele;
24 l1.add_head(l1.ele);25 l1.print();
26
27 cout << "Lista invertida " << endl;
28 l1.invertir();
29 l1.print();
30
31 cout << "Lista ordenada " << endl;
32 l1.sort();
33 l1.print();
34
35 cout << "Agrega un elemento (Sera ordenado)" << endl;
36 cin >>l1.ele;
37 l1.add_sort(l1.ele);
38 l1.print();
39
40 cout << "Busca un elemento" << endl;
41 cin >>l1.ele;
42 l1.search(l1.ele);
43
44 cout << "Elimina un elemento por dato" << endl;
45 cin >>l1.ele;
46 l1.del_dato(l1.ele);47 l1.print();
48
49 cout << "Elimina un elemento por posicion" << endl;
50 cin >>pos;
51 l1.del_pos(pos);
52 l1.print();
53
54 cout << "Cargar una lista desde archivo - Ingresa el nombre" << endl;
55 cin >> archivo;//debe estar en el mismo directorio que este
programa
56 l2.load(archivo);
57 cout << "Lista B" << endl;
58 l2.print();
59
60 cout << "Guardar la lista en un archivo - Ingresa el nombre" << endl;
61 cin >> archivo;//ingresa un nombre cualquiera *.*
62 l2.save(archivo);
63
64 cout << "Interseccion entre las listas A y B " << endl;65 l1.interseccion(l2);
66
67 cout << "Listas A y B concatenadas " << endl;
68 l1.concat(l2);
69 l1.print();
70
71 l1.del_all();
72 l1.print();
73
74 return 0;75 }
Un ejemplo de la salida del programa:
ver fuente
imprimir ?
01 Ingresa la dimension de la lista
02 10
03 Lista A al inicio
04 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL
05
06 Agrega un elemento por la cabeza
07 18
08 18-> 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL
09
10 Lista invertida11 62-> 68-> 27-> 9-> 51-> 4-> 5-> 31-> 60-> 55-> 18-> NULL
12
13 Lista ordenada
14 4-> 5-> 9-> 18-> 27-> 31-> 51-> 55-> 60-> 62-> 68-> NULL
15
16 Agrega un elemento (Sera ordenado)
17 45
18 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 60-> 62-> 68-> NULL
19
20 Busca un elemento
21 51
22 El dato se encuentra en la posicion: 8 (Para seres humanos)
23
24 Elimina un elemento por dato
25 60
26 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> 68-> NULL
27
28 Elimina un elemento por posicion:
29 11
30 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> NULL
31
32 Cargar una lista desde archivo - Ingresa el nombre33 prueba.txt // mi archivito prueba.txt tenia estos datos
34 Lista B
35 8-> 59-> 23-> 15-> 94-> 63-> 9-> 17-> 62-> 33-> NULL
36
37 Guardar la lista en un archivo - Ingresa el nombre
38 otralista.txt // abre tu archivo y mira el contenido39 Interseccion entre las listas A y B
40 Existen 2 intersecciones
41 9-> 62-> NULL
42
43 Listas A y B concatenadas
44 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> 8-> 59-> 23-> 15-> 94-> 63-> 9->17-> 62-> 33-> NULL
45
46 La lista esta vacia.