La descarga está en progreso. Por favor, espere

La descarga está en progreso. Por favor, espere

Implementación de Listas

Presentaciones similares


Presentación del tema: "Implementación de Listas"— Transcripción de la presentación:

1 Implementación de Listas
Estructuras de Datos Implementación de Listas

2 Alternativas 1. Mediante arreglos de tamaño fijo
2. Mediante arreglos de tamaño variable 3. Mediante listas ligadas En todos los casos los elementos de la lista son de tipo stdelement (elementos con campo clave que los hace únicos)

3 Alternativas 1 y 2: En cada posición del arreglo se guarda un elemento de tipo stdelement En el caso del arreglo estático se define (reserva) un número de elementos suficiente desde el inicio del programa En el caso del arreglo dinámico, por medio de las función realloc() se puede expandir (debido a una inserción) y contraer (debido a un borrado) el arreglo a medida que se requiera

4 Ambas alternativas implican que se realicen “corrimientos” de elementos tanto en inserciones como en borrados Las operaciones de navegación con el cursor son bastante simples (se utiliza el índice del arreglo) Nos concentraremos en la alternativa 3 aunque a continuación se verán los fundamentos de la alternativa 2

5 Función Realloc() Es una potente función para el manejo de memoria dinámica que permite crear y manipular arreglos dinámicos (arreglos que cambian de tamaño durante la ejecución), su sintaxis es: puntero = (tipo_de_variable *) realloc( direccion_de_mem, numero_de_bytes ); Está en stdlib.h

6 dirección_de_mem es la dirección del espacio de memoria cuyo tamaño se desea modificar, si dirección_de_mem es nulo, realloc() reservará un nuevo espacio de memoria El argumento numero_de_bytes es el nuevo tamaño que se desea asignar al bloque referenciado por dirección_de_mem. Si numero_de_bytes es 0 (cero) este bloque es liberado. realloc() devuelve la dirección del espacio de memoria ya contraído o expandido  Esta dirección puede ser diferente a dirección_mem ¿por qué?

7 int *cambiar_tamano( int *arreglo, int n ) { int *r;
Dirección inicial Número de elementos deseados Veamos un ejemplo: int *cambiar_tamano( int *arreglo, int n ) { int *r; r = (int *)realloc(arreglo, n*sizeof(int)); return r; }

8 void main() { int *arreglo; //Se crea arreglo = cambiar_tamano( NULL, 5 ); arreglo[2] = 4; //Se expande arreglo = cambiar_tamano( arreglo, 10 ); // Se destruye arreglo = cambiar_tamano( arreglo, 0 ); }

9 Supóngase que se va a manejar una lista de estudiantes:
class estudiante { public: int aCarne; estudiante(); // Constructor por defecto estudiante(int carne); }; estudiante::estudiante() { aCarne = 0; } estudiante::estudiante(int carne) { aCarne = carne;

10 class lista { public: estudiante *primero; // Puntero para el manejo del vector que // representa la lista de estudiantes int n; // Número de estudiantes int cursor; // Posición del elemento actual //Constructor lista(); //Destructora void destruir_lista(lista *l); //Inserción void inserte_antes(estudiante e); };

11 lista::lista() { primero = NULL; n = 0; cursor = 0; } void lista::destruir_lista(lista *l) { if(n == 0) delete l; else cout<<"La lista debe ser vacia"; }

12 void lista::inserte_antes(estudiante e)
{ int i; primero=(estudiante*)realloc((primero), (n+1)*sizeof(estudiante)); if(n == 0) { primero[0] = e; cursor++; // El cursor queda valiendo 1 pero se ocupa la // posición 0 } else { for(i=0; i<=(n-cursor); i++){ primero[(n-i)] = primero[((n-1)-i)]; primero[cursor-1] = e; n++;

13 void main() { estudiante e1(100); lista milista; cout << milista.n << milista.cursor; milista.inserte_antes(e1); cout<< milista.primero[0].aCarne; estudiante e2(200); milista.inserte_antes(e2); cout<< milista.primero[1].aCarne; }

14 Alternativa 3 Las listas pueden ser:
Simplemente ligadas Simples circulares Doblemente ligadas Dobles circulares Todas las anteriores y con registro cabeza Nos concentraremos en las listas doblemente ligadas no circulares sin registro cabeza

15 En la implementación doblemente ligada, cada elemento de la lista está representado por un nodo
Un nodo contiene, además del stdelement que se desea almacenar en la lista un par de punteros, uno de ellos apunta al siguiente nodo de la lista y el otro al nodo anterior Una lista doblemente enlazada es un conjunto de nodos conectados entre sí Cada nodo tiene asociado una dirección de memoria Los nodos no necesariamente tienen que estar en posiciones contiguas de memoria

16 Una lista doblemente enlazada de estudiantes:
e1,e2, e3 son estudiantes NULL e1 [76] [43] e2 [81] [76] e3 NULL [43] [76] [81] Direcciones de los nodos

17 El operador flecha ->
#include <iostream.h> struct persona{ int ced; }; void main(void) { struct persona p1,*p2; p1.ced=4; p2 = &p1; cout<< p2->ced; cout<< (*p2).ced; }

18 La clase nodo class nodo { public: nodo *siguiente; nodo *anterior;
estudiante e; public: //Constructor nodo(nodo *sig, nodo *ant, estudiante e1); }; //Implementación Constructor nodo::nodo(nodo *sig, nodo *ant, estudiante e1) siguiente=sig; anterior=ant; e=e1; }

19 class lista { public: nodo *primero; // Apunta al primer elemento de la lista nodo *cursor; // Apunta a un nodo de la lista int n; // Número de elementos de la lista //Constructor lista(); //Destructora void destruir_lista(lista *l); //Construcción void inserte_antes(estudiante e); };

20 lista::lista() { primero = NULL; n = 0; cursor = NULL; } void lista::destruir_lista(lista *l) if(l->cursor == NULL) delete l; else cout<<"Error: la lista debe ser vacia";

21 void lista::inserte_antes(estudiante e) { nodo *nnodo;
nnodo = new nodo(NULL, NULL, e); int cmb_primero = 0; if(cursor !=NULL && cursor->anterior != NULL)//Si hay anterior nnodo->anterior=cursor->anterior; (cursor->anterior)->siguiente=nnodo; } else //Ya sea que cursor = NULL o que cursor esté en el primero nnodo->anterior=NULL; cmb_primero=1; //Activa bandera para primero CONTINUA

22 if(primero != NULL) //Si la lista era no vacía
{ nnodo->siguiente=cursor; cursor->anterior=nnodo; } else //Si la lista era vacía nnodo->siguiente=NULL; cmb_primero=1; if( cmb_primero){ primero=nnodo; //Cambio de primero cursor=nnodo; //El cursor queda en el actual n++; //Incrementa el número de elementos

23 Imprime: 100 1 200 2 void main() { estudiante e1(100); lista milista;
cout << milista.n <<endl; milista.inserte_antes(e1); cout << (milista.primero)->e.aCarne<<endl; cout << (milista.cursor)->e.aCarne<<endl; cout << milista.n << endl; estudiante e2(200); milista.inserte_antes(e2); cout << milista.n<<endl; } Imprime: 100 1 200 2

24 //Veamos otro main() que hace uso de la lista anterior: void main() {
estudiante eaux; lista milista; int carnet, n; cout<< "Nro de estudiantes a ingresar: "; cin >> n; for(int k=1; k<=n; k++) cout<<"Carnet: " << endl; cin>> carnet; eaux.aCarne = carnet; milista.inserte_antes(eaux); } El main() Continúa 

25 //Recorrer la lista desde el primero hasta el final: nodo *ptnodo;
ptnodo = milista.primero; while(ptnodo != NULL) { cout << ptnodo->e.aCarne << endl; ptnodo = ptnodo ->siguiente; } /*Este ciclo imprime los datos en el orden inverso a la entrada...*/ Fin del main()

26 Ahora se va a añadir a la clase lista la función ultimo():
Se agrega a la clase la siguiente función: nodo *ultimo(); Y la implementación correspondiente es: nodo *lista::ultimo() { nodo *ult=NULL,*aux=primero; //aux también podría iniciarse en el cursor... while (aux != NULL) { ult = aux; aux = aux ->siguiente; } return ult;

27 Ahora se puede recorrer la lista desde el último hasta el primero así:
cout<<"Del último al primero"<<endl; ptnodo = milista.ultimo(); while(ptnodo != NULL) { cout << ptnodo->e.aCarne << endl; ptnodo = ptnodo->anterior; }

28 Se pueden crear igualmente funciones recursivas
para el recorrido por ejemplo: void imprimir1(nodo *ptnodo) { if (ptnodo != NULL ) cout << ptnodo ->e.aCarne << endl; imprimir1(ptnodo ->siguiente); }

29 void imprimir2(nodo *ptnodo)
{ if (ptnodo != NULL ) imprimir2(ptnodo ->siguiente); cout << ptnodo ->e.aCarne << endl; }

30 Desde el main() se pueden invocar así:
void main() { estudiante eaux; lista milista; int carnet, n; cout<< "Nro de estudiantes a ingresar: "; cin >> n; for(int k=1; k<=n; k++) { cout<<"Carnet: " << endl; cin>> carnet; eaux.aCarne = carnet; milista.inserte_antes(eaux); } imprimir1(milista.primero); imprimir2(milista.primero);

31 estudiante(int carne); int clave(); }; int estudiante::clave()
Ahora agregará a la lista la función existe(k), se asumirá el carnet como la clave. Pero primero se agrega a la clase estudiante la función clave() así: class estudiante { public: int aCarne; estudiante(); estudiante(int carne); int clave(); }; int estudiante::clave() { return aCarne; }

32 Ahora se agrega a la clase lista la función existe(k) así:
int existe(int k); Y la implementación es: lista::existe(int k) { nodo *pt=primero; while(pt != NULL){ if(pt ->e.clave() == k ){ return 1; } //verdadero, encontrado pt=pt->siguiente; } return 0; // no encontrado

33 Agregar a la clase la siguiente función y su correspondiente implementación:
lista::existe(int k) { nodo *pt=primero; while(pt != NULL){ if(pt ->e.clave() == k ){ return 1; //Verdadero, encontrado } pt=pt->siguiente; return 0; // No encontrado

34 El main() para ejemplificar la invocación es:
void main() { estudiante eaux; lista milista; int carnet, n; cout<< "Nro de estudiantes a ingresar: "; cin >> n; for(int k=1; k<=n; k++) { cout<<"Carnet: " << endl; cin>> carnet; eaux.aCarne = carnet; milista.inserte_antes(eaux); } cout << milista.existe(3); cout << milista.existe(8);


Descargar ppt "Implementación de Listas"

Presentaciones similares


Anuncios Google