Implementación de Listas

Slides:



Advertisements
Presentaciones similares
Arreglos Unidimensionales y Bidimensionales ESTRUCTURAS DE DATOS I
Advertisements

Unidad 15 Características de C++ no relacionadas con el DOO.
BASE DE DATOS OBJETO RELACIONAL
Unidad 5 Listas Enlazadas Bibliografía: Algoritmos y Estructuras de datos de Aguilar y Martinez. Unidad 9 Autor: Ing Rolando Simon Titiosky.
Listas enlazadas c++ Prof. Franklin Cedeño.
Programación II Listas
Estructuras de datos y algoritmos
Programación I Teoría III
Programación, Algoritmos y Estructuras de Datos
Direcciones, Arreglos y Argumentos de Funciones
Funciones. Programación, Algoritmos y Estructuras de Datos.
Tipos de Datos Básicos y Estructurados
Punteros Universidad Nacional Mayor de San Marcos
POO en C++: Sintaxis En el .h debe aparecer la declaración de la clase: class NombreClase { private: // atributos y métodos privados public: // atributos.
Informática II Prof. Dr. Gustavo Patiño MJ
Tema 1. Introducción a la programación (Lenguaje java).
Tratamiento de listas en Java
Funcionamiento, programación
Informática II 1 Diego Fernando Serna RestrepoSemestre 2011/2.
Estructuras de Datos Cont. C++ y Tipos de Datos. Ejemplo: Vector de Objetos #include class estudiante { private: int aCarne; char aNombre[20]; float aNota;
Estructuras de Datos Punteros y algo más.
Estructuras de Datos Especificación formal de Listas.
Unidad 3 Punteros.
Herramientas para el acceso directo a memoria en C++

Material de apoyo Unidad 2 Estructura de datos
L ISTAS E NLAZADAS No son mas que un conjunto o lista de objetos que a diferencia de los vectores, estas poseen la capacidad de crecer o decrecer. Por.
COLAS, IMPLEMENTACIÓN A PARTIR DE LISTAS Y PARA PILAS
Tema 6: Clases Antonio J. Sierra.
C++ LISTAS C++ 11/04/2017 Ing. Edgar Ruiz Lizama.
Introducción a los punteros
Capítulo 5. Punteros y Cadenas de Caracteres
Índice. Revisando conceptos acerca de la memoria.
Programación Científica
TABLAS Definición. El tipo tabla permite definir objetos formados por un conjunto de elementos del mismo tipo. Ejemplos. El tipo tabla se utiliza para.
Clase 10: Estructuras de datos y arreglos.
Unidad VI Registros (estructuras, uniones y enumeraciones)
Programación I Técnico Universitario en Web Dpto. de Informática FCFMyN - UNSL -11-
PUNTEROS Ing Anghello Quintero.
Administración de Memoria
Informática Ingeniería en Electrónica y Automática Industrial
El lenguaje de programación C - Vectores y matrices -
Aplicación de estructuras de datos
1 Asignación Dinámica de Memoria Agustín J. González Versión original de Kip Irvine ELO 329.
Introducción a los punteros Prof. Domingo Hernández.
Manejo de Punteros y objetos en memoria dinámica en C++
Dinamismo y Contenedores Facultad de Ciencias Exactas y Naturales Universidad de Buenos Aires (C++ Avanzado) Depto. de Computación Algoritmos y Estructuras.
Unidad II Introducción a la programación en C++
FUNCIONES Conceptos básicos. Retorno de una función Clases de funciones. Paso de parámetros. Funciones y arrays.

Clase 10 Apuntadores & Memoria Dinámica
TEORIA DE LA INFORMACION INGENIERO ANYELO QUINTERO.
Programación en C para electrónicos
Listas Ligadas Simples. Definíción I  Es, en sencillas palabras. un grupo de datos organizados secuencialmente, pero a diferencia de los arreglos, la.
PUNTEROS Y REFERENCIAS
Constructor  Un constructor es un método que inicia un objeto inmediatamente después de su creación. De esta forma nos evitamos el tener que iniciar.
Punteros Recomendado: 1. Nivelación Funciones
Computación II Capitulo VII Punteros. Presentación de la unidad Objetivos: –Ser capaces de utilizar punteros. –Comprender las relaciones entre punteros,
1 Asignación Dinámica de Memoria Agustín J. González ELO 329.
INSTITUTO TECNOLOGICO DE APIZACO
Capitulo 4 Arreglos o Arrays Unidimensionales Bidimensionales Strings
LENGUAJE “C” Programación.
Laboratorio de programación
M.C. Meliza Contreras González
MEMORIA DINÁMICA.
Tema 1. Estructuras de datos Objetivo: Objetivo: El alumno resolverá problemas de almacenamiento, recuperación y ordenamiento de datos y las técnicas de.
1 ListaUna Lista se define como una serie de N elementos E 1, E 2,..., E N, ordenados de manera consecutiva, es decir, el elemento E k (que se denomina.
Prof. Manuel B. Sánchez. Declaración de Objetos Una vez que la clase ha sido implementada se pueden declarar objetos como variables locales de métodos.
Lenguaje de Programación II Prof. Rafael Montenegro B. Carrera: T.S.U en Informática Periodo: 2014-I.
LISTAS..
Transcripción de la presentación:

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

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)

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

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

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

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é?

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; }

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 ); }

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;

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); };

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"; }

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++;

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; }

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

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

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

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; }

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; }

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); };

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";

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

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

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

//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 

//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()

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;

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; }

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); }

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

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);

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; }

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

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

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);