8 Listas Encadenadas 2a Parte

34
Implantación de listas en Implantación de listas en C++ C++ Apoyo SSD5 Apoyo SSD5

Transcript of 8 Listas Encadenadas 2a Parte

Implantación de listas en Implantación de listas en C++C++

Apoyo SSD5Apoyo SSD5

Mtl Lourdes CahuichMtl Lourdes Cahuich 22

Una Plantilla de la Clase ListaUna Plantilla de la Clase Lista

�� En esta sección examinaremos la En esta sección examinaremos la implantación de una clase de lista implantación de una clase de lista encadenada (encadenada (linkedlinked listlist classclass ).).

�� Iniciaremos examinando algunos Iniciaremos examinando algunos requerimientos importantes que queremos requerimientos importantes que queremos que nuestra clase soporte. que nuestra clase soporte.

Mtl Lourdes CahuichMtl Lourdes Cahuich 33

Lista encadenadaLista encadenada

�� Asumamos que la lista de la clase, que Asumamos que la lista de la clase, que llamaremos llamaremos LinkedListLinkedList, necesita soportar , necesita soportar solamente recorridos hacia adelante.solamente recorridos hacia adelante.

�� Por esta razón, podemos implantar la Por esta razón, podemos implantar la clase como una lista sencillamenteclase como una lista sencillamente--encadenada. encadenada.

Mtl Lourdes CahuichMtl Lourdes Cahuich 44

Lista encadenadaLista encadenada

�� También podemos asumir que la clase También podemos asumir que la clase LinkedListLinkedList necesita soportar la necesita soportar la inserción y eliminación de elementos del inserción y eliminación de elementos del frente y detrás de la lista. frente y detrás de la lista.

�� Para soportar este requerimiento, nuestra Para soportar este requerimiento, nuestra clase mantendrá apuntadores al inicio y al clase mantendrá apuntadores al inicio y al final de la lista. final de la lista.

Mtl Lourdes CahuichMtl Lourdes Cahuich 55

Lista encadenadaLista encadenada

�� Finalmente, nos gustaría usar esta clase Finalmente, nos gustaría usar esta clase para almacenar listas de enteros, cadenas para almacenar listas de enteros, cadenas de caracteres, o cualquier tipo de datos. de caracteres, o cualquier tipo de datos.

�� Esto requiere que la clase sea una Esto requiere que la clase sea una plantilla (plantilla (templatetemplate).).

Mtl Lourdes CahuichMtl Lourdes Cahuich 66

template <class T>template <class T>class class LinkedListLinkedList {{public:public:

LinkedListLinkedList (); // constructor default(); // constructor defaultLinkedList(constLinkedList(const LinkedListLinkedList <T>& <T>& srcsrc ); ); //constructor copy//constructor copy~~LinkedListLinkedList (); // Destructor(); // DestructorT& front(); //T& front(); // AccesarAccesar al primer al primer elementoelementoT& back(); //T& back(); // AccesarAccesar al al úúltimoltimo elementoelementointint size(); //Total de size(); //Total de elementoselementosboolbool empty(); //empty(); // SiSi estaesta vaciavacia la la listalistavoid void push_front(constpush_front(const T&); //T&); // InsertarInsertar al al inicioiniciovoid void push_back(constpush_back(const T&); //T&); // InsertarInsertar al finalal finalvoid void pop_frontpop_front (); //(); // QuitarQuitar elementoelemento del del inicioiniciovoid void pop_backpop_back (); //(); // QuitarQuitar elementoelemento del finaldel finalvoid dump(); //void dump(); // sacarsacar loslos elementoselementos de la de la listalista

};};

Mtl Lourdes CahuichMtl Lourdes Cahuich 77

Representación de NodosRepresentación de Nodos

�� Ahora que tenemos una idea de las Ahora que tenemos una idea de las funciones miembro que la clase implanta, funciones miembro que la clase implanta, enfoquémonos y pensemos en como enfoquémonos y pensemos en como podemos representar un nodo de la lista podemos representar un nodo de la lista encadenada.encadenada.

�� Sabemos que un nodo debe almacenar Sabemos que un nodo debe almacenar los datos de los elementos y cualquier los datos de los elementos y cualquier información necesaria para mantener la información necesaria para mantener la estructura de la lista encadenada.estructura de la lista encadenada.

Mtl Lourdes CahuichMtl Lourdes Cahuich 88

Lista encadenadaLista encadenada

�� Debido a se trata de la implantación de Debido a se trata de la implantación de una lista sencillamenteuna lista sencillamente--encadenada, la encadenada, la única información que requerimos única información que requerimos almacenar es un apuntador al siguiente almacenar es un apuntador al siguiente nodo de la listanodo de la lista

Mtl Lourdes CahuichMtl Lourdes Cahuich 99

template <class T>template <class T>

class class LinkedListLinkedList {{

private:private:

class Node {class Node {

T data;T data;

Node* next;Node* next;

};};

public:public:

// // aquaqu íí van van elementoselementos ppúúblicosblicos

......

Mtl Lourdes CahuichMtl Lourdes Cahuich 1010

Lista encadenadaLista encadenada

�� La clase anterior es una representación La clase anterior es una representación adecuada de un nodo para una lista adecuada de un nodo para una lista sencillamentesencillamente--encadenadaencadenada..

�� Contiene un elemento para almacenar los Contiene un elemento para almacenar los datos para el nodo y un apuntador al datos para el nodo y un apuntador al siguiente nodo. siguiente nodo.

Mtl Lourdes CahuichMtl Lourdes Cahuich 1111

Lista encadenadaLista encadenada

�� Dentro del contexto de nuestra clase de Dentro del contexto de nuestra clase de lista encadenada, la clase lista encadenada, la clase NodeNode requiere requiere de más características. de más características.

�� Primero, agregamos un constructor que Primero, agregamos un constructor que permite la inicialización de los datos permite la inicialización de los datos miembro de la clase.miembro de la clase.

Mtl Lourdes CahuichMtl Lourdes Cahuich 1212

Lista encadenadaLista encadenada

�� También añadimos un estatuto También añadimos un estatuto friendfriendque permite a las funciones miembro de la que permite a las funciones miembro de la clase clase LinkedListLinkedList acceder a los datos acceder a los datos miembro privados de la clase miembro privados de la clase NodeNode..

Mtl Lourdes CahuichMtl Lourdes Cahuich 1313

template <class T>template <class T>class class LinkedListLinkedList {{private:private:

class Node {class Node {friend class friend class LinkedListLinkedList <T>;<T>;

private:private:T data;T data;Node* next;Node* next;

public:public:Node(T d, Node* n = NULL) : Node(T d, Node* n = NULL) :

data(d), next(n) {}data(d), next(n) {} }}

; ;

Mtl Lourdes CahuichMtl Lourdes Cahuich 1414

Lista encadenadaLista encadenada

�� El listado anterior define completamente a El listado anterior define completamente a la clase la clase NodeNode dentro de la clase dentro de la clase LinkedListLinkedList . .

�� Esto se hace principalmente por Esto se hace principalmente por conveniencia, de manera que no conveniencia, de manera que no tengamos que especificar el tipo de la tengamos que especificar el tipo de la plantilla cada vez que declaramos un plantilla cada vez que declaramos un objeto de tipo objeto de tipo NodeNode

Mtl Lourdes CahuichMtl Lourdes Cahuich 1515

Lista encadenadaLista encadenada

�� La definición de la clase La definición de la clase NodeNode en este en este listado, agrega un constructor e incluye listado, agrega un constructor e incluye estatutos explícitos de los datos miembro estatutos explícitos de los datos miembro privados y públicos.privados y públicos.

�� También, el estatuto También, el estatuto friendfriend permite a los permite a los objetos de la clase objetos de la clase LinkedListLinkedList acceder acceder a los datos miembros de la clase a los datos miembros de la clase NodeNode

Mtl Lourdes CahuichMtl Lourdes Cahuich 1616

Lista encadenadaLista encadenada

�� Se requiere agregar otros datos miembro Se requiere agregar otros datos miembro privados a la clase privados a la clase LinkedListLinkedList . .

�� Se añaden apuntadores al inicio y al final Se añaden apuntadores al inicio y al final de la lista.de la lista.

�� La implantación de nuestra función La implantación de nuestra función miembro usa estos apuntadores para miembro usa estos apuntadores para manipular la lista; también se añade un manipular la lista; también se añade un dato miembro para almacenar el tamaño dato miembro para almacenar el tamaño de la lista.de la lista.

Mtl Lourdes CahuichMtl Lourdes Cahuich 1717

template <class T>template <class T>

class class LinkedListLinkedList {{

private:private:

class Node {class Node {

friend class friend class LinkedListLinkedList <T>;<T>;

private:private:

T data;T data;

Node* next;Node* next;

public:public:

Node(T d, Node* n = NULL) : data(d), next(n) Node(T d, Node* n = NULL) : data(d), next(n) {}}{}}

;;

Node* head; // Node* head; // inicioinicio de la de la listalista

Node* tail; // final de la Node* tail; // final de la listalista

intint count; // count; // númnúm. . ElementosElementos en la en la listalista

Mtl Lourdes CahuichMtl Lourdes Cahuich 1818

Funciones Miembro SencillasFunciones Miembro Sencillas

�� Ahora podemos implantar algunas de las Ahora podemos implantar algunas de las funciones miembro más sencillas de la funciones miembro más sencillas de la clase clase LinkedListLinkedList . .

�� El siguiente listado contiene El siguiente listado contiene implantaciones para el constructor implantaciones para el constructor defaultdefaulty las funciones miembro y las funciones miembro frontfront , back, , back, sizesize y y emptyempty . .

Mtl Lourdes CahuichMtl Lourdes Cahuich 1919

// // Constructor Constructor porpor defaultdefault

LinkedList(voidLinkedList(void ) : ) : head(NULLhead(NULL ), ), tail(NULLtail(NULL ), ), count(0) {}count(0) {}

// // RegresaRegresa la la referenciareferencia al 1er al 1er elementoelemento

T& T& front(voidfront(void ) {) {

assert (head != NULL);assert (head != NULL);

return headreturn head -- >data;}>data;}

// // RegresaRegresa la la referenciareferencia al al últimoúltimo elementoelemento

T& T& backback (( voidvoid ) {) {

assertassert (( tailtail != != NULL);NULL);

return tailreturn tail -- >data;}>data;}// // RegresaRegresa el el contadorcontador de de elementoselementos de la de la listalista

intint size(voidsize(void ) { return count;}) { return count;}

// // RegresaRegresa sisi la la listalista tienetiene o no o no elementoselementos

boolbool empty(voidempty(void ) { return count == 0;) { return count == 0; } }

Mtl Lourdes CahuichMtl Lourdes Cahuich 2020

Insertar y Remover desde el InicioInsertar y Remover desde el Inicio

�� Insertar un elemento al inicio de la lista Insertar un elemento al inicio de la lista es un proceso relativamente directo.es un proceso relativamente directo.

�� Las tareas involucradas son:Las tareas involucradas son:1.1. Crear un objeto nuevo Crear un objeto nuevo NodeNode..

2.2. Encadenar el nuevo nodo al inicio de la lista.Encadenar el nuevo nodo al inicio de la lista.3.3. Reposicionar el apuntador Reposicionar el apuntador headhead para reflejar para reflejar

el nuevo inicio de la lista.el nuevo inicio de la lista.

4.4. Incrementar el conteo de elementos en uno.Incrementar el conteo de elementos en uno.

Mtl Lourdes CahuichMtl Lourdes Cahuich 2121

Insertar y Remover desde el InicioInsertar y Remover desde el Inicio

�� Debido a que también debemos mantener Debido a que también debemos mantener un apuntador al final de la lista, existe un un apuntador al final de la lista, existe un caso especial cuando añadimos un caso especial cuando añadimos un elemento a una lista vacía.elemento a una lista vacía.

�� En este caso, el elemento que agregamos En este caso, el elemento que agregamos no sólo se convierte en el elemento inicial no sólo se convierte en el elemento inicial de la lista, también se convierte en el de la lista, también se convierte en el elemento final de la lista. elemento final de la lista.

Mtl Lourdes CahuichMtl Lourdes Cahuich 2222

Insertar y Remover desde el InicioInsertar y Remover desde el Inicio

�� Este caso especial es conocido como una Este caso especial es conocido como una condición de límitescondición de límites o o boundaryboundary conditioncondition. .

�� Una condición de límites es un punto o un Una condición de límites es un punto o un caso en un algoritmo, que debe ser caso en un algoritmo, que debe ser manejado de manera diferente. manejado de manera diferente.

Mtl Lourdes CahuichMtl Lourdes Cahuich 2323

Inserción en una lista vacíaInserción en una lista vacía

template <class T>template <class T>void void LinkedListLinkedList <T>::<T>:: push_front(Tpush_front(T d) {d) {

Node* Node* new_headnew_head = new = new Node(dNode(d , head);, head);if (thisif (this -- >empty()) {>empty()) {

head = head = new_headnew_head ;;tail = tail = new_headnew_head ;;

}}else {else {

head = head = new_headnew_head ;;}}count++count++ ;;

}}

Mtl Lourdes CahuichMtl Lourdes Cahuich 2424

Eliminar una lista con un elementoEliminar una lista con un elemento

�� La implantación del método La implantación del método pop_frontpop_front , , por razones similares al método por razones similares al método push_frontpush_front , también cuenta para una , también cuenta para una condición de límitescondición de límites..

�� En este método, el caso especial ocurre En este método, el caso especial ocurre cuando el tamaño de la lista es igual a cuando el tamaño de la lista es igual a uno.uno.

Mtl Lourdes CahuichMtl Lourdes Cahuich 2525

Eliminar una lista con un elementoEliminar una lista con un elementotemplate <class T>template <class T>void void LinkedListLinkedList <T>::<T>:: pop_front(voidpop_front(void ) {) {

assert(headassert(head != NULL);!= NULL);Node* Node* old_headold_head = head;= head;if (thisif (this -- >size() == 1) {>size() == 1) {

head = NULL;head = NULL;tail = NULL;tail = NULL;

}}else {else {

head = head = headhead -- >next;>next;}}deletedelete old_headold_head ;;countcount ---- ;;

} }

Mtl Lourdes CahuichMtl Lourdes Cahuich 2626

Insertar y Remover desde el FinalInsertar y Remover desde el Final

�� Insertar un elemento al final de la lista Insertar un elemento al final de la lista ((push_backpush_back ) es similar a insertarlo al ) es similar a insertarlo al inicio (inicio (push_frontpush_front ).).

�� La principal diferencia es el apuntador La principal diferencia es el apuntador utilizado en la operación. utilizado en la operación.

�� Al usar (Al usar (push_backpush_back ), insertamos un ), insertamos un elemento, encadenando un nodo nuevo al elemento, encadenando un nodo nuevo al apuntador apuntador tailtail ..

Mtl Lourdes CahuichMtl Lourdes Cahuich 2727

Insertar y Remover desde el FinalInsertar y Remover desde el Final

�� El método El método pop_backpop_back , por otro lado, no se , por otro lado, no se parece a ninguno de los métodos que parece a ninguno de los métodos que hemos implantado hasta ahora.hemos implantado hasta ahora.

�� Los pasos requeridos para completar esta Los pasos requeridos para completar esta operación son los siguientes.operación son los siguientes.�� Reposicionar el apuntador Reposicionar el apuntador tailtail al nodo al nodo

previo al último elemento. previo al último elemento.

�� Liberar la memoria usada para el último nodo Liberar la memoria usada para el último nodo de la lista.de la lista.

Mtl Lourdes CahuichMtl Lourdes Cahuich 2828

Insertar y Remover desde el FinalInsertar y Remover desde el Final

�� El primer paso mencionado anteriormente, El primer paso mencionado anteriormente, reposicionar el apuntador reposicionar el apuntador tailtail , añade , añade algo de complejidad a la implantación.algo de complejidad a la implantación.

�� Reposicionar requiere que regresemos un Reposicionar requiere que regresemos un nodo el apuntador nodo el apuntador tailtail

�� La única forma de mover un apuntador al La única forma de mover un apuntador al nodo justo antes del último nodo es nodo justo antes del último nodo es recorrer la lista recorrer la lista

Mtl Lourdes CahuichMtl Lourdes Cahuich 2929

El DestructorEl Destructor

�� El destructor para nuestra clase de lista El destructor para nuestra clase de lista encadenada debe liberar cualquier encadenada debe liberar cualquier memoria que pudimos haber asignado (en memoria que pudimos haber asignado (en los métodos los métodos push_frontpush_front y y push_backpush_back).).

�� Podemos nivelar nuestra implantación del Podemos nivelar nuestra implantación del método método pop_frontpop_front para brindar una para brindar una implantación del destructor simple y implantación del destructor simple y efectiva.efectiva.

Mtl Lourdes CahuichMtl Lourdes Cahuich 3030

// Destructor// Destructor

template <class T>template <class T>

LinkedListLinkedList <T>::~<T>::~ LinkedList(voidLinkedList(void ) ) {{

while (! thiswhile (! this -- >empty>empty ()) {()) {

thisthis-->>pop_frontpop_front();();

}}

} }

Mtl Lourdes CahuichMtl Lourdes Cahuich 3131

El Constructor El Constructor CopyCopy

�� Debido a que nuestra clase de lista encadenada Debido a que nuestra clase de lista encadenada asigna memoria dinámicamente, necesitamos asigna memoria dinámicamente, necesitamos implantar un constructor implantar un constructor copycopy . .

�� Esto es para asegurar que cuando se haga una Esto es para asegurar que cuando se haga una copia de la lista, también se haga una copia de copia de la lista, también se haga una copia de los datos de la lista.los datos de la lista.

�� De otra forma, podríamos tener dos De otra forma, podríamos tener dos apuntadores de los objetos de la lista (apuntadores de los objetos de la lista (headhead y y tailtail ) apuntando a los mismos nodos.) apuntando a los mismos nodos.

Mtl Lourdes CahuichMtl Lourdes Cahuich 3232

// // constructor copyconstructor copy

template <class T>template <class T>LinkedListLinkedList <T>::<T>:: LinkedList(constLinkedList(const

LinkedListLinkedList <T>& <T>& srcsrc ) :count(0), ) :count(0), head(NULLhead(NULL ), ), tail(NULLtail(NULL ))

{{

Node* current = Node* current = src.headsrc.head ;;

while (current != NULL) {while (current != NULL) {

thisthis -- >>push_back(currentpush_back(current -- >data);>data);

currentcurrent = = currentcurrent -- >>nextnext ;;

}}

} }

Mtl Lourdes CahuichMtl Lourdes Cahuich 3333

Cómo desplegar el contenido de la Cómo desplegar el contenido de la listalista

�� La última función miembro que La última función miembro que implantamos para la clase implantamos para la clase LinkedListLinkedListes el método es el método print_listprint_list . .

�� Este método despliega el contenido de la Este método despliega el contenido de la lista al flujo de salida estándar.lista al flujo de salida estándar.

Mtl Lourdes CahuichMtl Lourdes Cahuich 3434

// // MuestraMuestra el el contenidocontenido de la de la listalista

template <class T>template <class T>

void void LinkedListLinkedList <T>::<T>:: dump(voiddump(void ) {) {

coutcout << "(";<< "(";

Node* current = head;Node* current = head;

if (current != NULL) {if (current != NULL) {

while (currentwhile (current -- >next != NULL) {>next != NULL) {

coutcout << << currentcurrent -- >data << ", ";>data << ", ";

currentcurrent = = currentcurrent -- >>nextnext ;;

}}

coutcout << << currentcurrent -- >data;>data;

}}

coutcout << ")" << << ")" << endlendl ;;

}}