Você está na página 1de 13

ESTRUCTURAS DINAMICAS

Conocemos algunas estructuras de datos como son los vectores y matrices. No son las nicas. Hay muchas situaciones donde utilizar alguna de estas estructuras nos proporcionar una solucin muy ineficiente (cantidad de espacio que ocupa en memoria, velocidad de acceso a la informacin, etc.) Ejemplo 1. Imaginemos que debemos realizar un procesador de texto, debemos elegir la estructura de datos para almacenar en memoria las distintas lneas que el operador ir tipeando. Una solucin factible es utilizar una matriz de caracteres. Pero como sabemos debemos especificar la cantidad de filas y columnas que ocupar de antemano. Podra ser por ejemplo 2000 filas y 200 columnas. Con esta definicin estamos reservando de antemano 800000 bytes de la memoria, no importa si el operador despus carga una lnea con 20 caracteres, igualmente ya se ha reservado una cantidad de espacio que permanecer ociosa. Tiene que existir alguna estructura de datos que pueda hacer ms eficiente la solucin del problema anterior. Ejemplo 2. Cmo estarn codificadas las planillas de clculo? Reservarn espacio para cada casilla de la planilla al principio? Si no la lleno, lo mismo se habr reservado espacio? Utilizar una matriz para almacenar todas las casillas de una planilla de clculo seguro ser ineficiente. Bien, todos estos problemas y muchos ms podrn ser resueltos en forma eficiente cuando conozcamos estas nuevas estructuras de datos (Listas, rboles)

LISTAS
Una lista es un conjunto de nodos, cada uno de los cuales tiene dos campos: uno de informacin y un apuntador al siguiente nodo de la lista. Adems un apuntador externo seala el primer nodo de la lista. Representacin grfica de un nodo:

La informacin puede ser cualquier tipo de dato simple, estructura de datos o inclusive uno o ms objetos. La direccin al siguiente nodo es un puntero. Representacin grfica de una lista:

Como decamos, una lista es una secuencia de nodos (en este caso cuatro nodos). La informacin de los nodos en este caso es un entero y siempre contiene un puntero que guarda la direccin del siguiente nodo. raiz es otro puntero externo a la lista que contiene la direccin del primer nodo. El estado de una lista vara durante la ejecucin del programa:

De esta forma representamos grficamente una lista vaca. Si insertamos un nodo en la lista quedara luego:

Si insertamos otro nodo al principio con el valor 9 tenemos:

Lo mismo podemos borrar nodos de cualquier parte de la lista. Esto nos trae a la mente el primer problema planteado: el desarrollo del procesador de texto. Podramos utilizar una lista que inicialmente estuviera vaca e introdujramos un nuevo nodo con cada lnea que tipea el operador. Con esta estructura haremos un uso muy eficiente de la memoria. Tipos de listas. Segn el mecanismo de insercin y extraccin de nodos en la lista tenemos los siguientes tipos: Listas tipo pila. Listas tipo cola. Listas genricas.

Una lista se comporta como una pila si las inserciones y extracciones las hacemos por un mismo lado de la lista. Tambin se las llama listas LIFO (Last In First Out - ltimo en entrar primero en salir) Una lista se comporta como una cola si las inserciones las hacemos al final y las extracciones las hacemos por el frente de la lista. Tambin se las llama listas FIFO (First In First Out primero en entrar primero en salir) Una lista se comporta como genrica cuando las inserciones y extracciones se realizan en cualquier parte de la lista. Podemos en algn momento insertar un nodo en medio de la lista, en otro momento al final, borrar uno del frente, borrar uno del fondo o uno interior, etc.

LISTAS TIPO PILAS


Una lista se comporta como una pila si las inserciones y extracciones las hacemos por un mismo lado de la lista. Tambin se las llama listas LIFO (Last In First Out - ltimo en entrar primero en salir) Importante: Una pila al ser una lista puede almacenar en el campo de informacin cualquier tipo de valor (int, char, float, vector de caracteres, un objeto, etc)

Para estudiar el mecanismo de utilizacin de una pila supondremos que en el campo de informacin almacena un entero (para una fcil interpretacin y codificacin) Inicialmente la PILA est vaca y decimos que el puntero raiz apunta a null (Si apunta a null decimos que no tiene una direccin de memoria):

Insertamos un valor entero en la pila: insertar(10)

Luego de realizar la insercin la lista tipo pila queda de esta manera: un nodo con el valor 10 y raiz apunta a dicho nodo. El puntero del nodo apunta a null ya que no hay otro nodo despus de este. Insertamos luego el valor 4: insertar(4)

Ahora el primer nodo de la pila es el que almacena el valor cuatro. raiz apunta a dicho nodo. Recordemos que raiz es el puntero externo a la lista que almacena la direccin del primer nodo. El nodo que acabamos de insertar en el campo puntero guarda la direccin del nodo que almacena el valor 10. Ahora qu sucede si extraemos un nodo de la pila. Cul se extrae? Como sabemos en una pila se extrae el ltimo en entrar. Al extraer de la pila tenemos: extraer()

La pila ha quedado con un nodo. Hay que tener cuidado que si se extrae un nuevo nodo la pila quedar vaca y no se podr extraer otros valores (avisar que la pila est vaca) Problema 1: Confeccionar una clase que administre una lista tipo pila (se debe poder insertar, extraer e imprimir los datos de la pila) Programa: using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace ListasTipoPila1

{ class Pila { class Nodo { public int info; public Nodo sig; } private Nodo raiz; public Pila() { raiz = null; } public void Insertar(int x) { Nodo nuevo; nuevo = new Nodo(); nuevo.info = x; if (raiz == null) { nuevo.sig = null; raiz = nuevo; } else { nuevo.sig = raiz; raiz = nuevo; } } public int Extraer() { if (raiz != null) { int informacion = raiz.info; raiz = raiz.sig; return informacion; } else { return int.MaxValue; } } public void Imprimir() { Nodo reco=raiz; Console.WriteLine("Listado de todos los elementos de la pila."); while (reco!=null) { Console.Write(reco.info+"-"); reco=reco.sig; } Console.WriteLine(); } static void Main(string[] args)

{ Pila pila1=new Pila(); pila1.Insertar(10); pila1.Insertar(40); pila1.Insertar(3); pila1.Imprimir(); Console.WriteLine("Extraemos de la pila:"+pila1.Extraer()); pila1.Imprimir(); Console.ReadKey(); } } } Analicemos las distintas partes de este programa: class Nodo { public int info; public Nodo sig; } private Nodo raiz; Para declarar un nodo debemos utilizar una clase. En este caso la informacin del nodo (info) es un entero y siempre el nodo tendr una referencia de tipo Nodo, que le llamamos sig. El puntero sig apunta al siguiente nodo o a null en caso que no exista otro nodo. Este puntero es interno a la lista. Para poder acceder a los atributos los definimos de tipo public. Tambin definimos un puntero de tipo Nodo llamado raiz. Este puntero tiene la direccin del primer nodo de la lista. En caso de estar vaca la lista, raiz apunta a null (es decir no tiene direccin) El puntero raiz es fundamental porque al tener la direccin del primer nodo de la lista nos permite acceder a los dems nodos. public Pila() { raiz = null; } En el constructor de la clase hacemos que raiz guarde el valor null. Tengamos en cuenta que si raiz tiene almacenado null la lista est vaca, en caso contrario tiene la direccin del primer nodo de la lista. public void Insertar(int x) { Nodo nuevo; nuevo = new Nodo(); nuevo.info = x; if (raiz == null) { nuevo.sig = null; raiz = nuevo; } else { nuevo.sig = raiz; raiz = nuevo; } } Uno de los mtodos ms importantes que debemos entender en una pila es el de Insertar un elemento en la pila. Al mtodo llega la informacin a insertar, en este caso en particular es un valor entero. La creacin de un nodo requiere dos pasos: - Definicin de un puntero o referencia a un tipo de dato Nodo: Nodo nuevo; - Creacin del nodo (creacin de un objeto):

nuevo = new Nodo(); Cuando se ejecuta el operador new se reserva espacio para el nodo. Realmente se crea el nodo cuando se ejecuta el new.

Paso seguido debemos guardar la informacin del nodo: nuevo.info = x; En el campo info almacenamos lo que llega en el parmetro x. Por ejemplo si llega un 5 el nodo queda:

Por ltimo queda enlazar el nodo que acabamos de crear al principio de la lista. Si la lista est vaca debemos guardar en el campo sig del nodo el valor null para indicar que no hay otro nodo despus de este, y hacer que raiz apunte al nodo creado (sabemos si una lista esta vaca si raiz almacena un null) if (raiz == null) { nuevo.sig = null; raiz = nuevo; }

Grficamente podemos observar que cuando indicamos raiz=nuevo, el puntero raiz guarda la direccin del nodo apuntado por nuevo. Tener en cuenta que cuando finaliza la ejecucin del mtodo el puntero nuevo desaparece, pero no el nodo creado con el operador new. En caso que la lista no est vaca, el puntero sig del nodo que acabamos de crear debe apuntar al que es hasta este momento el primer nodo, es decir al nodo que apunta raiz actualmente. else { nuevo.sig = raiz; raiz = nuevo; } Como primera actividad cargamos en el puntero sig del nodo apuntado por nuevo la direccin de raiz, y posteriormente raiz apunta al nodo que acabamos de crear, que ser ahora el primero de la lista. Antes de los enlaces tenemos:

Luego de ejecutar la lnea: nuevo.sig = raiz; Ahora tenemos:

Por ltimo asignamos a raiz la direccin que almacena el puntero nuevo. raiz = nuevo; La lista queda:

El mtodo Extraer: public int Extraer() { if (raiz != null) { int informacion = raiz.info; raiz = raiz.sig; return informacion; } else { return int.MaxValue; } } El objetivo del mtodo extraer es retornar la informacin del primer nodo y adems borrarlo de la lista. Si la lista no est vaca guardamos en una variable local la informacin del primer nodo: int informacion = raiz.info; Avanzamos raiz al segundo nodo de la lista, ya que borraremos el primero: raiz = raiz.sig; el nodo que previamente estaba apuntado por raiz es eliminado automticamente, al no tener ninguna referencia. Retornamos la informacin: return informacion; En caso de estar vaca la pila retornamos el nmero entero mximo y lo tomamos como cdigo de error (es decir nunca debemos guardar el entero mayor en la pila) return int.MaxValue; Es muy importante entender grficamente el manejo de las listas. La interpretacin grfica nos permitir plantear inicialmente las soluciones para el manejo de listas.

Por ltimo expliquemos el mtodo para recorrer una lista en forma completa e imprimir la informacin de cada nodo: public void Imprimir() { Nodo reco=raiz; Console.WriteLine("Listado de todos los elementos de la pila."); while (reco!=null) { Console.Write(reco.info+"-"); reco=reco.sig; } Console.WriteLine(); } Definimos un puntero auxiliar reco y hacemos que apunte al primer nodo de la lista: Nodo reco=raiz; Disponemos una estructura repetitiva que se repetir mientras reco sea distinto a null. Dentro de la estructura repetitiva hacemos que reco avance al siguiente nodo: while (reco!=null) { Console.Write(reco.info+"-"); reco=reco.sig; } Es muy importante entender la lnea: reco=reco.sig; Estamos diciendo que reco almacena la direccin que tiene el puntero sig del nodo apuntado actualmente por reco. Grficamente:

Al analizarse la condicin: while (reco!=null) se vala en verdadero ya que reco apunta a un nodo y se vuelve a ejecutar la lnea: reco=reco.sig; Ahora reco apunta al siguiente nodo:

La condicin del while nuevamente se vala en verdadera y avanza el puntero reco al siguiente nodo: reco=reco.sig;

Ahora s reco apunta a null y ha llegado el final de la lista (Recordar que el ltimo nodo de la lista tiene almacenado en el puntero sig el valor null, con el objetivo de saber que es el ltimo nodo) Para poder probar esta clase recordemos que debemos definir un objeto de la misma y llamar a sus mtodos: static void Main(string[] args) { Pila pila1=new Pila(); pila1.Insertar(10); pila1.Insertar(40); pila1.Insertar(3); pila1.Imprimir();

Console.WriteLine("Extraemos de la pila:"+pila1.Extraer()); pila1.Imprimir(); Console.ReadKey(); } Insertamos 3 enteros, luego imprimimos la pila, extraemos uno de la pila y finalmente imprimimos nuevamente la pila. Problema 2: Agregar a la clase Pila un mtodo que retorne la cantidad de nodos y otro que indique si esta vaca. Programa: using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace ListasTipoPila1 { class Pila { class Nodo { public int info; public Nodo sig; } private Nodo raiz; public Pila() { raiz = null; } public void Insertar(int x) { Nodo nuevo; nuevo = new Nodo(); nuevo.info = x; if (raiz == null) { nuevo.sig = null; raiz = nuevo; } else { nuevo.sig = raiz; raiz = nuevo; } } public int Extraer() { if (raiz != null) { int informacion = raiz.info; raiz = raiz.sig; return informacion;

} else { return int.MaxValue; } } public void Imprimir() { Nodo reco=raiz; Console.WriteLine("Listado de todos los elementos de la pila."); while (reco!=null) { Console.Write(reco.info+"-"); reco=reco.sig; } Console.WriteLine(); } public bool Vacia() { if (raiz == null) { return true; } else { return false; } } public int Cantidad() { int cant = 0; Nodo reco = raiz; while (reco != null) { cant++; reco = reco.sig; } return cant; } static void Main(string[] args) { Pila pila1=new Pila(); pila1.Insertar(10); pila1.Insertar(40); pila1.Insertar(3); pila1.Imprimir(); Console.WriteLine("La cantidad de nodos de la lista es:"+pila1.Cantidad()); while (pila1.Vacia()==false) { Console.WriteLine(pila1.Extraer()); } Console.ReadKey(); } }

} Para verificar si la pila esta vaca verificamos el contenido de la variable raiz, si tiene null luego la lista esta vaca y por lo tanto retornamos un true: public bool Vacia() { if (raiz == null) { return true; } else { return false; } } El algoritmo para saber la cantidad de nodos es similar al imprimir, pero en lugar de mostrar la informacin del nodo procedemos a incrementar un contador: public int Cantidad() { int cant = 0; Nodo reco = raiz; while (reco != null) { cant++; reco = reco.sig; } return cant; } Para probar esta clase en la main creamos un objeto de la clase Pila insertamos tres enteros: Pila pila1=new Pila(); pila1.Insertar(10); pila1.Insertar(40); pila1.Insertar(3); Imprimimos la pila (nos muestra los tres datos): pila1.Imprimir(); Llamamos al mtodo Cantidad (nos retorna un 3): Console.WriteLine("La cantidad de nodos de la lista es:"+pila1.Cantidad()); Luego mientras el mtodo Vacia nos retorne un false (lista no vaca) procedemos a llamar al mtodo extraer: while (pila1.Vacia()==false) { Console.WriteLine(pila1.Extraer()); } Problemas propuestos 1. Agregar un mtodo a la clase Pila que retorne la informacin del primer nodo de la Pila sin borrarlo.

FUNCIONES
public int Maximo (int x, int y) { int mayor;

if (x==y) return -1; else if (x>y) return x; else return y; } En la primera parte de la declaracin public int Maximo (int x, int y) public, es el nivel de acceso, indica que puede ser accedida desde cualquier scrip, dentro o fuera del archivo donde se declar. int, es el valor que retornar la funcin, en este caso como es un numero el que tiene que retornar, pero no siempre es as, algunas veces, hay funciones que piden de argumento un string y retornan un bool u otro tipo de datos. Maximo, es el nombre de la funcin (int x, int y) son los argumentos de la funcin, los valores que necesita para operar, en este caso son dos, siempre se separan con una coma y se debe de definir el nombre y el tipo de datos. Y dentro de esta funcin utiliza los argumentos que pide y realiza la comparacin, lo de adentro es un simple if...

Você também pode gostar