miércoles, 30 de noviembre de 2011

Ordenamiento

Uno de los procedimientos más comunes y útiles en el procesamiento de datos, es la clasificación u ordenación de los mismos. Se considera ordenar al proceso de reorganizar un conjunto dado de objetos en una secuencia determinada. Cuando se analiza un método de ordenación, hay que determinar cuántas comparaciones e intercambios se realizan para el caso más favorable, para el caso medio y para el caso más desfavorable.

Ordenamiento de burbuja

El primer ordenamiento que presentamos es quizá el más ampliamente conocido entre los estudiantes que se inician en la programación. Una de las características de este ordenamiento es que es fácil de entender y programar. Aunque, es uno de los algoritmos mas ineficiente.

La idea básica subyacente en el ordenamiento de burbuja es pasar a través del arreglo de datos varias veces en forma secuencial. Cada paso consiste en la comparación de cada elemento en el arreglo con su sucesor (x[i] con  x[i+1]) y el intercambio de los dos elementos si no están en el orden correcto. Considérese el siguiente arreglo de datos:


25 57 48 37 12 92 86 33

En el primer paso se realizan las siguientes operaciones:

x[0] con x[1] (25 con 57)  no intercambio.
x[1] con x[2] (57 con 48)      intercambio.
x[2] con x[3] (57 con 32)      intercambio.
x[3] con x[4] (57 con 12)      intercambio.
x[4] con x[5] (57 con 92)  no intercambio.
x[5] con x[6] (92 con 86)      intercambio.
x[6] con x[7] (92 con 33)      intercambio.

Así después del primer paso, el arreglo está en el siguiente orden:

25 48 37 12 57 86 33 92

Obsérvese que después del primer paso, el elemento mayor (en este caso 92) está en la posición correcta dentro del arreglo. En general x[n-i] estará en su posición correcta después de la iteración i. El método se lama ordenamiento de burbuja porque cada número “burbujea” con lentitud hacia su posición correcta. El conjunto completo de iteraciones es:

iteración 0 :                     25 57 48 37 12 92 86 33
iteración 1:                       25 48 37 12 57 86 33 92
iteración 2:                       25 37 12 48 57 33 86 92
iteración 3:                       25 12 37 48 33 57 86 92
iteración 4:                       12 25 37 33 48 57 89 92
iteración 5:                       12 25 33 37 48 57 89 92

La implementación de este algoritmo en Java queda como:

   void Burbuja(int x[], int n)
  {
    int b, j, t;
    do
    {
      b = 0;
      for(j=0; j<n; j++)
      {
         if(x[j] > x[j+1])
         {
           t = x[j];
           x[j] = x[j+1];
           x[j+1] = t;
           b++;
         }
      }
      n--;
    }
    while(b > 0);
  }


Ordenamiento "Quicksort".

El método de ordenamiento Quick Sort es actualmente el más eficiente y veloz de los métodos de ordenación interna. Es también conocido con el nombre del método rápido y de ordenamiento por partición, en el mundo de habla hispana.
Este método es una mejora sustancial del método de intercambio directo y recibe el nombre de Quick Sort por la velocidad con que ordena los elementos del arreglo. Su autor C.A. Hoare lo bautizó así.
La idea central de este algoritmo consiste en los siguiente:
Se toma un elemento x de una posición cualquiera del arreglo.
Se trata de ubicar a x en la posición correcta del arreglo, de tal forma que todos los elementos que se encuentran a su izquierda sean menores o iguales a x y todos los elementos que se encuentren a su derecha sean mayores o iguales a x.
Se repiten los pasos anteriores pero ahora para los conjuntos de datos que se encuentran a la izquierda y a la derecha de la posición correcta de x en el arreglo.
Ejemplo:
A: 15,67,08,16,44,27,12,35
Se selecciona A[i]  x=15

Primera pasada (DER-IZQ)
A[8] >= x 35 >= 15 No hay intercambio
A[7] >= x 12 >= 15 Si hay intercambio

A: 12,67,08,16,44,27,15,35

(IZQ-DER)
A[2] < = X 67 < = 15 Si hay intercambio

A:12,15,08,16,44,27,67,35

2da. Pasada (DER-IZQ)
A[6] >= x 27 >= 15 No hay intercambio
A[5] >= x 44 >= 15 No hay intercambio
A[4] >= x 16 >= 15 No hay intercambio
A[3] >= x 08 >= 15 Si hay intercambio

A: 12,08,15,16,44,27,67,35

Como el recorrido de izquierda a derecha debería iniciarse en la misma posición 
donde se encuentra el elemento x, el proceso se termina ya que el elemento x, se 
encuentra en la posición correcta.

A: 12, 08, 15, 16, 44, 27, 67, 35
1er 2do Conjunto
Conjunto
16, 44, 27, 67, 35
x16

(DER-IZQ)
A[8]>=x No hay intercambio
A[7]>=x No hay intercambio
A[6]>=x No hay intercambio
A[5]>=x No hay intercambio

A: 12, 08, 15, 16, 44, 27, 67, 35
xß44

(DER-IZQ)
A[8]>= x Si hay intercambio

A: 12, 08, 15, 16, 35, 27, 67, 44

(IZQ-DER)
A[6] < = x No hay intercambio
A[7] < = x Si hay intercambio
12, 08, 15, 16, 35, 27, 44, 67
12, 08, 15, 16, 35, 27, 44, 67
35, 27, 44, 67
xß35

(DER-IZQ)
A[8] >= x No hay intercambio
A[7] >= x No hay intercambio
A[6] >= x Si hay intercambio
12, 08, 15, 16, 27, 35, 44, 67
12,08
xß12

(DER-IZQ)
A[2]>=x Si hay intercambio

EL VECTOR ORDENADO:
08,12,15,16,27,35,44,67
 
 
Ordenamiento "Shell Sort".
 
  1. Shell Sort
  2. Pedirle a un ordenador que haga algo intuitivamente es, de momento, bastante complicado, así que sustituiremos la intuición por un procedimiento mecánico más o menos ingenioso. Veamos el siguiente arreglo:
  3. 74, 14, 21, 44, 38, 97, 11, 78, 65, 88, 30
  4. Shell nos propone que hagamos sobre el arreglo una serie de ordenaciones basadas en la inserción directa, pero dividiendo el arreglo original en varios sub-arreglo tales que cada elemento esté separado k elementos del anterior (a esta separación a menudo se le llama salto o gap )... Se debe empezar con k=n/2 , siendo n el número de elementos de arreglo, y utilizando siempre la división entera.... después iremos variando k haciéndolo más pequeño mediante sucesivas divisiones por 2, hasta llegar a k=1. Pero vamos a ello... En nuestro ejemplo, n=11 (porque hay 11 elementos). Así que k=n/2=11/2=5
  5. Empezamos con k=5. Así pues, vamos a dividir nuestro arreglo original en 5 sub-arreglo, en los cuales, sus elementos estarán separados por 5 lugares del arreglo original (el salto o gap es 5). Vamos a hacerlo con colores. Tomamos el primer elemento (el 74) contamos 5 lugares y tomamos también otro elemento (el 97) volvemos a contar 5 y tomamos otro (el 30) y acabamos porque se nos acaba el arreglo. El primer sub-arreglo con k=5 es el formado por 74, 97 y 30. Vamos a pintarlos en rojo
  6. 74 , 14, 21, 44, 38, 97 , 11, 78, 65, 88, 30
  7. Ahora, ordenaremos los elementos del sub-arreglo rojo pero sólo entre ellos, utilizando el algoritmo de Inserción directa.   30 , 14, 21, 44, 38, 74 , 11, 78, 65, 88, 97   Fíjate qué curioso. El 30, un elemento relativamente pequeño se ha ido hacia el principio y el 97 hacia el final... ¡pero dando saltos ( gap ) de 5 en 5 lugares! Cada uno ha avanzado en saltos de 5 hacia una posición cercana a su ubicación definitiva.
  8. Fíjate qué curioso. El 30, un elemento relativamente pequeño se ha ido hacia el principio y el 97 hacia el final... ¡pero dando saltos ( gap ) de 5 en 5 lugares! Cada uno ha avanzado en saltos de 5 hacia una posición cercana a su ubicación definitiva. Formemos ahora otro sub-arreglo con salto k=5... partiendo del segundo elemento (el 14) y contando 5 (tomamos también el 11) y ya está, porque se acaba el arreglo.   30 , 14 , 21, 44, 38, 74 , 11 , 78, 65, 88, 97
  9. Vamos a ordenarlos entre ellos con Inserción directa... el 11 primero y el 14 después.   30 , 11 , 21, 44, 38, 74 , 14 , 78, 65, 88, 97
  10. Ahora a por otro... el 21 y el 78     30 , 11 , 21 , 44, 38, 74 , 14 , 78 , 65, 88, 97   Están en orden entre ellos, así que se quedan como están.
  11. Ahora le toca al sub-arreglo formado por el 44 y el 65    30 , 11 , 21 , 44 , 38, 74 , 14 , 78 , 65 , 88, 97   Que también están en orden entre ellos... y finalmente el 38 y el 88, que también están en orden. 30 , 11 , 21 , 44 , 38 , 74 , 14 , 78 , 65 , 88 , 97
  12. Hemos formado 5 sub-arreglos en los cuales los elementos están separados por 5 lugares (porque k=5). Hemos ordenado cada sub-arreglo por separado utilizando inserción directa, y hemos logrado que cada elemento se dirija hacia su ubicación definitiva en pasos de 5 lugares. Por supuesto, no hemos terminado todavía, pero resulta evidente que algunos elementos, como el 30, el 97 o el 11 han dado un gran salto y que no deben andar muy lejos de su sitio final.
  13. Decimos ahora que el arreglo está 5-ordenado.   Para continuar con el algoritmo, debemos ir reduciendo progresivamente k dividiéndolo sucesivamente por 2 y k-ordenando los sub-arreglos que nos salgan (recuerda que nos salen k sub-arreglo). Cuando lleguemos a k=1 habremos terminado.   Pero de momento, nuestra k valía 5, así que ahora k←k/2=5/2=2   Nuestra nueva k vale 2. Repetimos todo el tinglado, pero ahora nos saldrán 2 sub-arreglo cuyos elementos están separados por 2 lugares.
  14. El primero (en marrón) y el segundo (en verde): 30 , 11 , 21 , 44 , 38 , 74 , 14 , 78 , 65 , 88 , 97
  15. Ordenamos por un lado los marrones entre ellos y los verdes entre ellos... es decir, 2-ordenamos el arreglo (curiosamente, los verdes ya están ordenados.... probablemente ha contribuido a ello la 5-ordenación que ya hemos hecho. En ese caso, la ordenación ha requerido muy poco esfuerzo)   14 , 11 , 21 , 44 , 30 , 74 , 38 , 78 , 65 , 88, 97
  16. Ahora, cada número está mucho más cerca de su posición definitiva... El arreglo está 2-ordenado... pero sigue también 5-ordenado. No hemos perdido el trabajo que hicimos cuando k era 5.   Finalmente, calculamos un nuevo k dividiendo el que tenemos entre 2. k←k/2=2/2=1 Hemos llegado a k=1. Cuando k es 1 sólo podemos obtener 1 sub-arreglo cuyos elementos están separados 1 posición: el propio arreglo original. Dicho de otra manera... cuando k es 1, el algoritmo de Shell se comporta exactamente igual que el de inserción directa sobre todo el arreglo .
  17. Sin embargo, las k-ordenaciones que hemos hecho (con k=5 y k=2) han hecho que cada elemento se aproximase con saltos de 5 y luego de 2 posiciones hacia su ubicación definitiva. Ahora que k=1 y que vamos a aplicar el algoritmo de inserción directa tal cual, haremos muchas menos comparaciones e intercambios que si lo hubiéramos aplicado con en arreglo tal como lo teníamos al empezar. El algoritmo de inserción directa se comporta tanto mejor cuanto más cerca está cada elemento de su sitio definitivo.   Finalmente, el arreglo queda de ésta manera:   11, 14, 21, 30, 38, 44, 65, 74, 78, 88, 97   Cada elemento descolocado ha tenido que moverse pocos lugares. Muchos de ellos ni siquiera se han movido.


Busqueda


La búsqueda es una operación que tiene por objeto la localización de un elemento dentro de la estructura de datos. A menudo un programador estará trabajando con grandes cantidades de datos almacenados en arreglos y pudiera resultar necesario determinar si un arreglo contiene un valor que coincide con algún valor clave o buscado.
Siendo el array de una dimensión o lista una estructura de acceso directo y a su vez de acceso secuencial, encontramos dos técnicas que utilizan estos dos métodos de acceso, para encontrar elementos dentro de un array: búsqueda lineal y búsqueda binaria.

Búsqueda Secuencial:

La búsqueda secuencial es la técnica más simple para buscar un elemento en un arreglo. Consiste en recorrer el arreglo elemento a elemento e ir comparando con el valor buscado (clave). Se empieza con la primera casilla del arreglo y se observa una casilla tras otra hasta que se encuentra el elemento buscado o se han visto todas las casillas. El resultado de la búsqueda es un solo valor, y será la posición del elemento buscado o cero. Dado que el arreglo no está en ningún orden en particular, existe la misma probabilidad de que el valor se encuentra ya sea en el primer elemento, como en el último. Por lo tanto, en promedio, el programa tendrá que comparar el valor buscado con la mitad de los elementos del arreglo.
El método de búsqueda lineal funciona bien con arreglos pequeños o para arreglos no ordenados. Si el arreglo está ordenado, se puede utilizar la técnica de alta velocidad de búsqueda binaria, donde se reduce sucesivamente la operación eliminando repetidas veces la mitad de la lista restante.

Búsqueda Binaria.

La búsqueda binaria es el método más eficiente para encontrar elementos en un arreglo ordenado. El proceso comienza comparando el elemento central del arreglo con el valor buscado. Si ambos coinciden finaliza la búsqueda. Si no ocurre así, el elemento buscado será mayor o menor en sentido estricto que el central del arreglo. Si el elemento buscado es mayor se procede a hacer búsqueda binaria en el subarray superior, si el elemento buscado es menor que el contenido de la casilla central, se debe cambiar el segmento a considerar al segmento que está a la izquierda de tal sitio central.

Busqueda Hash

Hasta ahora las técnicas de localización de registros vistas, emplean un proceso de búsqueda que implica cierto tiempo y esfuerzo. El siguiente método nos permite encontrar directamente el registro buscado.
 

    La idea básica de este método consiste en aplicar una función que traduce un conjunto de posibles valores llave en un rango de direcciones relativas. Un problema potencial encontrado en este proceso, es que tal función no puede ser uno a uno; las direcciones calculadas pueden no ser todas únicas, cuando R(k1 )= R(k2)

Pero : K1 diferente de K2 decimos que hay una colisión. A dos llaves diferentes que les corresponda la misma dirección relativa se les llama sinónimos.

 

A las técnicas de calculo de direcciones también se les conoce como :

  • Técnicas de almacenamiento disperso
  • Técnicas aleatorias
  • Métodos de transformación de llave - a- dirección
  • Técnicas de direccionamiento directo
  • Métodos de tabla Hash
  • Métodos de Hashing
    Pero el término mas usado es el de hashing. Al cálculo que se realiza para obtener una dirección a partir de una llave se le conoce como función hash.
 
 
Ventaja
  1. Se pueden usar los valores naturales de la llave, puesto que se traducen internamente a direcciones fáciles de localizar
  2. Se logra independencia lógica y física, debido a que los valores de las llaves son independientes del espacio de direcciones
  3. No se requiere almacenamiento adicional para los índices.
Desventajas
  1. No pueden usarse registros de longitud variable
  2. El archivo no esta clasificado
  3. No permite llaves repetidas
  4. Solo permite acceso por una sola llave
Costos
  • Tiempo de procesamiento requerido para la aplicación de la función hash
  • Tiempo de procesamiento y los accesos E/S requeridos para solucionar las colisiones.
La eficiencia de una función hash depende de:
  1. La distribución de los valores de llave que realmente se usan
  2. El numero de valores de llave que realmente están en uso con respecto al tamaño del espacio de direcciones
  3. El numero de registros que pueden almacenarse en una dirección dad sin causar una colisión
  4. La técnica usada para resolver el problema de las colisiones
Las funciones hash mas comunes son:
  • Residuo de la división
  • Medio del cuadrado
  • Pliegue


viernes, 4 de noviembre de 2011

Arboles

Definicion: Un árbol es una estructura de datos ampliamente usada que imita la forma de un árbol (un conjunto de nodos conectados). Un nodo es la unidad sobre la que se construye el árbol y puede tener cero o más nodos hijos conectados a él. Se dice que un nodo a es padre de un nodo b si existe un enlace desde a hasta b (en ese caso, también decimos que b es hijo de a). Sólo puede haber un único nodo sin padres, que llamaremos raíz. Un nodo que no tiene hijos se conoce como hoja. Los demás nodos (tienen padre y uno o varios hijos) se les conoce como rama.



Tipos de arboles.

Un árbol ordenado se define como un árbol en el que los subárboles de cada nodo forman un conjunto ordenado. En un árbol ordenado, podemos hablar del primero, segundo o último hijo de un nodo en particular. El primer hijo de un nodo en un árbol ordenado se denomina con frecuencia el hijo más viejo de este nodo y el último se denomina el hijo más joven. Un bosque es un conjunto ordenado de árboles ordenados.

 El árbol de la izquierda es ordenado y el árbol de la derecha es un árbol no ordenado.
Image arbolesord
 
Arboles de expresion: Representan un orden de ejecucion.
 
 
 
Arboles Similares:Los que tienen la misma estructura (forma).
 
 
 Arboles equivalentes: Son los árboles similares y sus nodos contienen la misma información.
 
Arboles binarios: un árbol binario es una estructura de datos en la cual cada nodo siempre tiene un hijo izquierdo y un hijo derecho. No pueden tener más de dos hijos (de ahí el nombre "binario"). Si algún hijo tiene como referencia a null, es decir que no almacena ningún dato, entonces este es llamado un nodo externo. En el caso contrario el hijo es llamado un nodo interno. Usos comunes de los árboles binarios son los árboles binarios de búsqueda, los montículos binarios y Codificación de Huffman.
 
 
 
nLos hermanos se enlazan en forma horizontal (lineal)
nSe enlaza en forma vertical el padre con el hijo que se encuentra mas a la izquierda y se elimina el enlace de este padre con los demás hijos.
nSe rota el diagrama resultante 45 grados hacia la izquierda.
 
Conversion de un arbol general a un arbol binario.
 
 

Recursividad

 Recursividad.


Introducción.
La recursividad consiste en realizar una definición de un
concepto en términos del propio concepto que se está definiendo.


Ejemplos:
·
0 es un Número natural y el sucesor de un número natural
es también un número natural.
Los números naturales se pueden definir de la siguiente forma:
·
o n multiplicado por el factorial del número n-1, en caso
contrario.
El factorial de un número natural n, es 1 si dicho número es 0,
·
producto de x por la potencia (n-1)-ésima de x, cuando n es
mayor que 0.
En todos estos ejemplos se utiliza el concepto definido en la
propia definición.
La n-ésima potencia de un número x, es 1 si n es igual a 0, o el


Solución de problemas recursivos:
·
pequeños, del mismo tipo que el inicial.
División sucesiva del problema original en uno o varios más
·
Se van resolviendo estos problemas más sencillos.
·
problemas más complejos.
O lo que es lo mismo:
1.Un problema P se puede resolver conociendo la solución de
otro problema Q que es del mismo tipo que P, pero más
pequeño.
2.Igualmente, supongamos que pudiéramos resolver Q
mediante la búsqueda de la solución de otro nuevo
problema, R, que sigue siendo del mismo tipo que Q y P,
pero de un tamaño menor que ambos.
3.Si el problema R fuera tan simple que su solución es obvia o
directa, entonces, dado que sabemos la solución de R,
procederíamos a resolver Q y, una vez resuelto, finalmente
se obtendría la solución definitiva al primer problema, P.
Con las soluciones de éstos se construyen las soluciones de los

Ejemplos simples de
recursividad.
A) Cálculo del factorial de un número, por ejemplo, 5.
5! = 5 * 4!
4! = 4 * 3!
3!= 3 * 2!
2! = 2 * 1!
DESCOMPOSICIÓN
DEL PROBLEMA
1! = 1 * 0!
SOLUCIÓN CONOCIDA O DIRECTA
0! = 1
1! = 1 * 0! = 1
2! = 2 * 1! = 2
3! = 3 * 2! = 6 RESOLUCIÓN DE
PROBLEMAS MÁS
COMPLEJOS A PARTIR
4! = 4 * 3! = 24 DE OTROS MÁS
SIMPLES
5! = 5 * 4! = 120
B) Búsqueda de una palabra en un diccionario.
Características de los problemas que pueden ser
resueltos de manera recursiva:
4.Los problemas pueden ser redefinidos en términos de uno o
más subproblemas, idénticos en naturaleza al problema
original, pero de alguna forma menores en tamaño.
5.Uno o más subproblemas tienen solución directa o conocida,
no recursiva.
6.Aplicando la redefinición del problema en términos de
problemas más pequeños, dicho problema se reduce
sucesivamente a los subproblemas cuyas soluciones se
conocen directamente.
7.La solución a los problemas más simples se utiliza para
construir la solución al problema inicial.
Algoritmos recursivos:
diseño de la solución de un problema de manera recursiva
El algoritmo se llamará a sí mismo varias veces
¡Ojo al diseñar algoritmos recursivos!
pueden ser menos eficientes que que su solución iterativa
Algoritmo recursivo
nivel que permita recursividad (en nuestro caso, en Java).
Implementación en un lenguaje de alto

jueves, 8 de septiembre de 2011

Estructura de datos y organizacion de datos 09110936 Israel Calderon Romero




Concepto de LISTA. Una lista es una estructura de datos homogénea y dinámica, que va a estar formada por una secuencia de elementos, donde cada uno de ellos va seguido de otro o de ninguno.
Homogénea: Todos los elementos que la forman tienen el mismo tipo base.
Dinámica: Puede crecer o decrecer en tiempo de ejecución según nuestras necesidades.
dos listas pueden ser diferentes si:

No tienen el mismo número de elementos:
L1: gato, perro.
L2: gato, canario, cerdo.
Cuando, aun teniendo el mismo número de elementos, estos son distintos:
L1: gato, perro.
L2: gato, cerdo.
Cuando, aun teniendo el mismo número de elementos y siendo estos los mismos, no están dispuestos en el mismo orden.
L1: gato, perro.
L2: perro, gato.
Hay varios criterios para clasificar las listas: según su modo de acceso o según su información de acceso.

Modo De Acceso.
Atendiendo a este, se dividen en densas y enlazadas. El modo de acceso es independiente de la implementación realizada.
Listas densas
Se caracterizan porque los elementos siguen una secuencia física. Sabemos cuales es el siguiente elemento porque para acceder a él hemos tenido que pasar por todos los anteriores.
La localización de un elemento cualquiera será:
El primero si es el primer elemento de la lista.
N-esimo si para llegar a el hemos pasado por N-1 elementos.
Siguen una estructura física secuencial luego se pueden implementar utilizando ficheros, ARRAYS y punteros.


Listas enlazadas
Son aquellas en las que cada elemento que los compone contiene la información necesaria para acceder al elemento siguiente. La localización de un elemento cualquiera será:
Un elemento de la lista tendrá la dirección K si K es el primero y K es conocido (dirección de inicio).
Estará en la dir. J si J está contenida en el elemento anterior.
Informacion de acceso.

Listas ordinales
Los elementos se van colocando en la lista a medida que llegan y se identifican por el orden de llegada.El acceso a un elemento es por su orden o posición relativa dentro de la lista.
Listas calificadas
Los elementos se clasifican por una clave y pueden estar ordenados o no estarlo. A un elemento se accede por la información contenida en un campo clave.
Diferencias: En la primera clase importa en orden de llegada, mientras que en la segunda depende de la clave.



Pilas.
Una pila es una lista ordinal en la que el modo de acceso a sus elementos es del tipo LIFO. Los añadidos y extracciones de elementos de una estructura se realizan solo por un extremo, luego el único elemento accesible de la pila es el que se encuentre en la cima. Esto exigirá que la manipulación sobre un elemento, necesite que el mismo ocupe la posición de cima.
Sobre una estructura de tipo pila, surgen de forma natural las operaciones que permiten añadir elementos y quitar elementos.
Implementación utilizando tablas
Esta realización consiste en ir guardando consecutivamente los elementos de la pila en un vector de tamaño fijo. Un índice marcará la posición del último elemento que se ha añadido a la pila. Por tanto, las inserciones en la estructura se realizarán en la posición inmediatamente siguiente a la posición marcada como cima, pasando a ser esta nueva posición ocupada la nueva cima de la pila.
El hecho de utilizar un vector para almacenar los elementos, puede conducir a la situación en que la pila esté llena, es decir, que no quepa ningún elemento más. Esto se producirá cuando el índice que señala la cima de la pila sea igual al tamaño del vector.


Otros Tipos De Listas

Listas reorganizables.- Son aquellas listas en las que el último elemento consultado se sitúa al principio.
Listas circulares.- En ellas el último elemento apunta al primero.
Listas doblemente enlazadas.- Cada elemento tiene dos punteros, uno de los cuales apunta al elemento siguiente y otro al anterior.
Listas circulares doblemente enlazadas

PROGRAMAS Y ANALISIS         LISTA SIMPLEMENTE ENLAZADA



Cuando utilizamos listas enlazadas podemos realizar la siguientes operaciones:



Podemos añadir información a la lista insertando un nuevo nodo en un determinado


lugar dentro de la lista.



Podemos eliminar un nodo especifico dentro de la lista que contenga información.



Podemos recuperar la información almacenada en un nodo especifico o encontrar


la posición de un determinado nodo que contenga alguna información especifica.

A continuación implementaremos un ejercicio en donde almacenaremos en cada nodo de

la lista información referente a una persona. Para esto declararemos la clase

TPersona y


en los elementos de la lista almacenaremos objetos de la clase persona.

Para la implementación del ejercicio crearemos un nuevo proyecto y crearemos además

de la clase TForm que se crea por defecto, dos unidades para implementar el código de

las clases

TPersona y TListaPersona. La unidad en donde esta la clase TForm se


guardara con el nombre

UVentanaLista.


Datos

Información Enlace


Nodo de una lista


Pedro enlace Juan enlace Luis enlace Carlos nulo


Unidad UPersona en donde se implementa el código de la clase TPersona:


unit UPersona;

{$mode objfpc}{$H+}

interface

uses

Classes, SysUtils;

type


//Definición de la clase para la información de un nodo dentro de la lista enlazada simple.


{ TPersona }

TPersona = class

private

cedula:integer;

apellido:string;

nombre:string;

sexo:char;

edad:byte;


//Este atributo corresponde al apuntador que permite enlazar el nodo con el siguiente nodo de la lista.


siguiente:TPersona;

public


//método constructor de la clase.


constructor Create;


//Declaración de los métodos modificadores de los atributos declarados en la clase.


procedure setCedula(ced:integer);

procedure setApellido(ape:string);

procedure setNombre(nom:string);

procedure setSexo(sex:char);

procedure setEdad (ed:byte);

procedure setSiguiente(sig:TPersona);


//Declaración de los métodos selectores de los atributos declarados en la clase.


function getCedula:integer;

function getApellido:string;

function getNombre:string;

function getSexo:char;

function getEdad:byte;

function getSiguiente:TPersona;

end;

implementation

{ TPersona }

constructor TPersona.Create;

begin

cedula:=0;

apellido:='';

nombre:='';

sexo:=#0;

//El símbolo # permite hacer referencia a un carácter por su código ASCII.


siguiente:=nil;

//se asigna el valor de nulo inicialmente al apuntador de primer nodo de la lista.


end;

procedure TPersona.setCedula(ced: integer);

begin

cedula:=ced;

end;

procedure TPersona.setApellido(ape: string);

begin

apellido:=ape;

end;

procedure TPersona.setNombre(nom: string);

begin

nombre:=nom;

end;

procedure TPersona.setSexo(sex: char);

begin

sexo:=sex;

end;

procedure TPersona.setEdad(ed: byte);

begin

edad:=ed;

end;

procedure TPersona.setSiguiente(sig: TPersona);

begin

siguiente:=sig;

end;

function TPersona.getCedula: integer;

begin

Result:=cedula;

end;

function TPersona.getApellido: string;

begin

Result:=apellido;

end;

function TPersona.getNombre: string;

begin

Result:=nombre;

end;

function TPersona.getSexo: char;

begin

Result:=sexo;

end;

function TPersona.getEdad: byte;

begin

Result:=edad;

end;

function TPersona.getSiguiente: TPersona;

begin

Result:=siguiente;

end;

end.


Unidad UDeclararLista en donde se implementa el código de la clase TListaPersona:


unit UDeclararLista;

{$mode objfpc}{$H+}

interface

uses

Classes, SysUtils, UPersona, Dialogs;

type

{ TListaPersona }

TListaPersona = class

private


//Declaramos el atributo correspondiente al primer nodo de la lista (cabecera), el cual tendrá un objeto de la

//clase TPersona.


cabeza:TPersona;

public

constructor Create;

//método constructor de la clase.


//Declaración de los métodos selectores y modificadores para asignar al nodo de cabecera un elemento de

//la clase TPersona o para obtener un elemento de la clase TPersona del nodo cabecera.


procedure setCabeza(cab:TPersona);

function getCabeza:TPersona;


//Este método recorre la lista y devuelve el apuntador del ultimo nodo de la lista.


function ultimo:Tpersona;


//Declaración de los métodos, correspondientes a las diferentes operaciones que se pueden realizar sobre la

//lista.


procedure agregar(per:TPersona);


//Declaración del método que permite buscar un elemento en la lista pasando como parámetro la cedula de

//la persona.


function buscar(ced:integer):TPersona;


//Declaración del método que me permite eliminar un nodo con al información de una persona especifica.


procedure eliminar(per:TPersona);


//Declaración del método que borra el nodo recibiendo como parámetro la cedula de una persona especifica.


procedure eliminarNodo(ced:integer);


//Declaración del método que borra todos los nodos de la lista.


procedure limpiar;


//Declaración del método que recoge la basura de la memoria, debe ser sobre escrito (override) para que

//haga lo de su clase padre.


destructor Destroy;override;

end;

implementation

{ TListaPersona }


//inicial izamos la lista en blanco o en vacío, asignando al primer nodo que se crea (cabeza) el valor de nulo.


constructor TListaPersona.Create;

begin

cabeza:=nil;

end;

procedure TListaPersona.setCabeza(cab: TPersona);

begin

cabeza:=cab;

end;

function TListaPersona.getCabeza: TPersona;

begin

Result:=cabeza;

end;


//Implementación del método que permite recorrer la lista hasta su ultimo elemento (nodo)

//y devuelve el apuntador del ultimo nodo de la lista junto con su información.


function TListaPersona.ultimo: Tpersona;

var


//Declaramos una variable temporal para que apunte al primer nodo de la lista.


temp:TPersona;

begin

temp:=cabeza;

//a la variable temporal le asigno el primer nodo de la lista (cabeza).


//mientras que la cabeza sea diferente de nulo, es decir que la lista no este vacía y no se haya llegado a su

//ultimo elemento entonces temporal apunta al primer nodo de la lista, luego preguntamos si el siguiente del

//primer nodo (cabeza), es nulo, esto quiere decir que ese primer nodo es el único nodo de la lista y se

//rompe el ciclo, porque el ultimo nodo siempre tiene como nulo a su siguiente.


while temp <> nil do

begin

if temp.getSiguiente = nil then

break

else


//si no se da la primera condición hacemos que el apuntador del nodo temporal, apunte al siguiente nodo de

//la lista.


temp:=temp.getSiguiente;

end;

Result:=temp;

end;


//Implementación del método que permite agregar la información de una persona (per) en un nuevo nodo al

//final de la lista. Este método recibe como parámetro un objeto de la clase TPersona.


procedure TListaPersona.agregar(per: TPersona);

begin


//si no existe ningún nodo en la lista, es decir que la lista este vacía, entonces inserto un primer nodo y le

//asigno la información de la persona.


if cabeza = nil then

begin

cabeza:=per;

end

else

begin


//si no es el primer nodo que se agrega, entonces al ultimo nodo que ya existe en la lista, le decimos que

//apunte su siguiente, que es el nuevo nodo que se agregara con al información de la persona.


ultimo.setSiguiente(per);

end;

end;


//Implementación del método que busca la información de una persona en la lista, pasando la cedula de una

//persona como parámetro.


function TListaPersona.buscar(ced: integer): TPersona;

var

temp:TPersona;

begin

temp:=cabeza;


//Mientras no este vacía la lista y no se haya llegado al final de la lista.


while temp <> nil do

begin


//si el nodo temporal tiene la información que se busca, quiere decir que se ha encontrado el nodo con la

//información y se rompe el ciclo.


if temp.getCedula = ced then

break

else


//Pero si no, pasamos al siguiente nodo de la lista, asignando a la variable temporal el nuevo nodo.


temp:=temp.getSiguiente;

end;

Result:=temp;

end;


//Este método permite eliminar un nodo de la lista con la información referente a una persona. Para la

//Implementación de este método se pueden dar dos posibilidades, una que el nodo que se busca para

//eliminar este en la primera posición de la lista o que el nodo a eliminar este en los próximos elementos de

//la lista, incluso en el ultimo.


procedure TListaPersona.eliminar(per: TPersona);

var

temp:TPersona;

//la variable temporal apuntara al nodo anterior al que se esta buscando.


begin


//Si el nodo a eliminar es el primero de la lista, entonces movemos el apuntador (cabeza) a su siguiente.


if cabeza = per then

begin

cabeza:=cabeza.getSiguiente;

//movemos el apuntador (cabeza) a su su siguiente nodo inmediato.


end

else


//Si el primero no es el nodo que quiero eliminar de la lista entonces quiere decir que puede ser el ultimo o

//un nodo intermedio, entonces necesitamos recorrer la lista y conocer cual es el nodo anterior al que quiero

//borrar, para pasar el apuntador del anterior al siguiente nodo del que quiero borrar.


begin

temp:=cabeza;


//mientras que el siguiente nodo del nodo en el que estoy no tenga como siguiente al nodo que se esta

//buscando (per) entonces asigno a la variable temporal el siguiente nodo de la lista.


while temp.getSiguiente <> per do

begin

temp:= temp.getSiguiente;

end;


//pero si el apuntador del nodo actual (temp) apunta al nodo que estoy buscando, entonces quiere decir que

//me encuentro en el nodo anterior al nodo que se busca. El apuntador siguiente del nodo (temp), lo coloco

//como igual al apuntador siguiente del nodo buscado (per). Es decir el apuntador del nodo anterior al

//buscado pasa a apuntar al nodo que sigue después de nodo que se busca.


temp.setSiguiente(per.getSiguiente);

end;

per.setSiguiente(nil);

//Cortamos el enlace del nodo que vamos a borrar, hacia su nodo siguiente.


per.Free;

//Destruimos el nodo que estamos borrando.


end;


//Implementación de otro método para eliminar un nodo.


procedure TListaPersona.eliminarNodo(ced: integer);

var

temp:TPersona;

begin


//Buscamos el nodo con la información de la cedula igual al numero de cedula pasado como parámetro.


temp:=buscar(ced);


//si el nodo buscado es diferentes de nil quiere decir que se encontró el nodo el la lista y lo elimino.


if temp <> nil then

begin

eliminar(temp);

end

else

begin

ShowMessage('La persona con cedula '+IntToStr(ced)+' NO se encuentra en la lista');

end;

end;

procedure TListaPersona.limpiar;

begin


//Borramos siempre el primer nodo de la lista, o borramos uno a uno los elementos de la lista hasta que este

//vacía.


while cabeza <> nil do

begin

eliminar(cabeza);

//Eliminamos el primer nodo y así sucesivamente si existen varios nodos en la lista.


end;

end;

destructor TListaPersona.Destroy;

begin

limpiar;

//Destruimos todos los nodos que pueda tener la lista.


inherited Destroy;

//Llamamos al destructor de la clase padre (implícita en la clase TObject).


end;

end.


Además de los métodos implementados anteriormente con las operaciones básicas que

se puede hacer sobre las listan, también podemos declarar de métodos que permiten

recorrer la lista y realizar operaciones de búsquedas especificas sobre la lista.

Para complementar el ejercicio anterior podemos agregar los siguientes métodos en la

declaración de clase

TListaPersona, para implementarlos:


//Declaración del método que permite saber el número de personas registradas en la lista, es decir el

//número de nodos de la lista.


function totalPersona:integer;


//Declaración del método que calcula el número de personas aptas para votar.


function totalVotantes:integer;


//Declaración del método que calcula el promedio de edad de las personas de la lista.


function promedioEdad:real;


//-------------> Implementación de los métodos declarados en la parte publica de la clase TListaPersona.

//Implementación del método que recorre la lista y cuenta el número de nodos (personas) agregados a esta.


function TListaPersona.totalPersona: integer;

var

temp:TPersona;

contPer:integer;

begin

contPer:=0;

temp:=cabeza;


//Siempre que no haya llegado al final de la lista, se cuenta el nodo con al información de la persona y se

//pasa al próximo nodo, si este existe, sino se sale del siclo while.


while temp <> nil do

begin

contPer:=contPer+1;

temp:=temp.getSiguiente;

end;

Result:=contPer;

end;


//Implementación del método que recorre la lista y cuenta el número de personas aptas para votar, osea las

//mayores de 18 años.


function TListaPersona.totalVotantes: integer;

var

votantes:integer;

temp:TPersona;

begin

votantes:=0;

temp:=cabeza;


//Siempre que no haya llegado al final de la lista, se pregunta que la persona sea mayor de 18 años, si esto

//se cumple la persona es apta para botar y se cuenta.


while temp <> nil do

begin

if temp.getEdad>=18 then

begin

votantes:= votantes + 1;

end;

temp:=temp.getSiguiente;

end;

Result:=votantes;

end;


//Implementación del método que calcula el promedio de edad de las personas de la lista.


function TListaPersona.promedioEdad: real;

var


//Declaramos dos variables, una para contar el numero de personas (cp) y otra para sumar la edades(se).


se, cp: integer;

temp:TPersona;

begin

cp:=0;

se:=0;

temp:=cabeza;

while temp <> nil do

//Siempre que no haya llegado al final de la lista.


begin

cp:=cp+1;

//Contador para el número de personas.


se:=se+temp.getEdad;

//Sumador de las edades.


temp:=temp.getSiguiente;

//pasamos al próximo nodo de la lista.


end;

if cp > 0 then

Result:=se/cp

else

Result:=0;

end;


Cuando creamos el nuevo proyecto para implementar el ejercicio, automáticamente se

crea una unidad con la clase TForm1. Se procedió a guardar esta unidad con el nombre




Unidad UVentanaLista en donde se implementa el código de la clase TListaPersona:


unit UVentanaLista;

{$mode objfpc}{$H+}

interface

uses

Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, UDeclararLista, UPersona, StdCtrls;

type

{ TForm1 }

TForm1 = class(TForm)

bAgregar: TButton;

bBuscar: TButton;

bEliminar: TButton;

bMostar: TButton;

bLimpiar: TButton;

bSalir: TButton;

bEliminardos: TButton;

bCalcular: TButton;

ced: TEdit;

ape: TEdit;

op: TComboBox;

eda: TEdit;

Label5: TLabel;

Label6: TLabel;

Label7: TLabel;

verdatos: TListBox;

sex: TComboBox;

Label4: TLabel;

nom: TEdit;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);

procedure FormCreate(Sender: TObject);

procedure FormShow(Sender: TObject);

procedure bAgregarClick(Sender: TObject);

procedure bBuscarClick(Sender: TObject);

procedure bCalcularClick(Sender: TObject);

procedure bEliminarClick(Sender: TObject);

procedure bEliminardosClick(Sender: TObject);

procedure bLimpiarClick(Sender: TObject);

procedure bMostarClick(Sender: TObject);

procedure bSalirClick(Sender: TObject);

private


//Declaramos un atributo (instancia) global para la clase TListaPersona; para toda la ventana.


lis:TListaPersona;


//Declaración del Método para llenar una instancia de persona con datos desde la ventana.


procedure llenar(per:TPersona);


//Declaración del Método para mostrar los atributos de una instancia de persona hasta la ventana


procedure mostrar(per:TPersona);


//Declaración del Método para limpiar los controles (TEdit) de la ventana.


procedure Limpiar;

public

{ public declarations }

end;

var

Form1: TForm1;

implementation

{ TForm1 }

procedure TForm1.FormShow(Sender: TObject);

begin

ced.SetFocus;

end;


//Programar el evento del botón que agrega la información a cada nodo de la lista.


procedure TForm1.bAgregarClick(Sender: TObject);

var

per:TPersona;

//se declara la Instancia (per) para la nueva persona que se va a crear.


begin


//Buscamos la cedula para ver si no esta en alguno de los nodos, si es así agregamos la información a un

//nuevo nodo.


if lis.buscar(StrToInt(ced.Text)) = nil then

begin

per:=TPersona.Create;

//Creamos una nueva instancia de la clase TPersona.


llenar(per);

//Llenamos esta nueva persona con los datos de la ventana.


lis.agregar(per);

//Agregamos a la lista la información de una nueva persona.


ShowMessage('La información se agrego correctamente');

Limpiar;

//Limpiamos los controles de la ventana.


end;

end;


//Programar el evento del botón que busca la información de la persona en uno de los nodos de la lista,

//pasando como parámetro el número de la cedula de la persona.


procedure TForm1.bBuscarClick(Sender: TObject);

var

per:TPersona;

begin


//Buscamos el nodo con la información de persona con la cedula digitada en el TEdit de nombre ced.


per:=lis.buscar(StrToInt(ced.Text));

if per <> nil then

//Si la variable per es distinta de nil, entonces encontramos la información en un nodo.


begin

mostrar(per);

//Llenamos los controles de la ventana con los datos de la persona.


end


//Si per es igual a nil quiere decir que no se encontró el nodo buscado y mandamos un mensaje.


else

begin

ShowMessage('La persona con cedula '+ced.Text+' No existe');

Limpiar;

//Limpiamos los controles de la ventana.


end;

end;


//Programar el evento del botón que llama a los métodos que recorren la lista y realizan operaciones de

//búsquedas especificas sobre la información de la persona en cada uno de los nodos de ls lista.

//Teniendo en cuenta la opción ItemIndex del TComboBox de nombre op, se llama al método requerido para

//realizar la operación y se muestran los resultados en el TListBox de nombre verdatos.


procedure TForm1.bCalcularClick(Sender: TObject);

begin

if op.ItemIndex = 0 then

begin

verdatos.Clear;

verdatos.Items.Add('El numero de personas en la lista es: '+IntToStr(lis.totalPersona));

end

else

if op.ItemIndex = 1 then

begin

verdatos.Clear;

verdatos.Items.Add('El numero de personas aptas para votar es: '+IntToStr(lis.totalVotantes));

end

else

begin

verdatos.Clear;

verdatos.Items.Add('El promedio de edad de las personas es: '+FloatToStr(lis.promedioEdad));

end;

end;


//Programar el evento del botón para eliminar la información de una persona.


procedure TForm1.bEliminarClick(Sender: TObject);

var

per:TPersona;

begin


//Buscamos la persona que vamos a eliminar y como parámetro se pasa la cedula digitada en el TEdit de

//nombre ced.


per:=lis.buscar(StrToInt(ced.Text));

if per <> nil then

//Si per es distinto de nil, entonces encontramos el nodo a eliminar con la información.


begin

lis.eliminar(per); /

/Borramos la instancia de la persona encontrada.


ShowMessage('Persona eleiminada exitosamente');

end

else

begin

ShowMessage('Esta cedula no existe');

end;

Limpiar;

//Limpiamos los controles de la ventana.


end;


//Programar el evento del otro botón para eliminar la información de una persona. Recuerden que en la

//clase TListaPersona declaramos dos métodos que realizaban esta función. Entonces podemos utilizar

//cualquiera de los dos metodos para eliminar.


procedure TForm1.bEliminardosClick(Sender: TObject);

begin

lis.eliminarNodo(StrToInt(ced.Text));

Limpiar;

end;


//Implementación del evento para el botón que borra todos los nodos de la lista y limpia los controles de la

//ventana.


procedure TForm1.bLimpiarClick(Sender: TObject);

begin

lis.limpiar;

Limpiar;

end;


//Implementación del evento para el botón que muestra al información de todos los nodos de la lista

//(información de las personas), en el TListBox de nombre verdatos.


procedure TForm1.bMostarClick(Sender: TObject);

var

per:TPersona;

begin

verdatos.Clear;

//Limpiamos los datos actuales de la lista o cualquier información del TListBox.


Per:=Lis.getCabeza;

//Empezamos a recorrer desde la cabeza, es decir el primer nodo de la lista.


while(per<>nil) do

//Mientras que no lleguemos al final de la lista.


begin


//Vamos mostrando los datos de cada persona de la lista en el TListBox de nombre verdatos.


verdatos.Items.Add(IntToStr(per.getCedula) + #32 + per.getApellido + #32 + per.getNombre + #32 +

IntToStr(per.getedad) + #32 + per.getsexo);

per:=per.getSiguiente;

//Y pasamos al siguiente nodo de la lista.


end;

end;

procedure TForm1.bSalirClick(Sender: TObject);

begin

Close;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin


//Inicializamos las instancias para las clases TListaPersona.


lis:=TListaPersona.Create;

end;

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);

begin

lis.Free;

end;


//Implementación del método que llena una instancia de la persona, con los datos digitados en la ventana.


procedure TForm1.llenar(per: TPersona);

begin

per.setCedula(StrToInt(ced.Text));

per.setApellido(ape.Text);

per.setNombre(nom.Text);

per.setSexo(sex.Text[1]);

//Del texto del sexo tomamos solo el primer carácter (1).


per.setEdad(StrToInt(eda.Text));

end;


//Implementación del método que muestra en los controles de la ventana la información correspondiente a

//una persona especifica.


procedure TForm1.mostrar(per: TPersona);

begin

ced.Text:=IntToStr(per.getCedula);

ape.Text:=per.getApellido;

nom.Text:=per.getNombre;

sex.Text:=per.getSexo;

eda.Text:=IntToStr(per.getEdad);

end;


//Implementación del método que limpia los controles de la ventana.


procedure TForm1.Limpiar;

begin

ced.Clear;

ape.Clear;

nom.Clear;

sex.Text:='';

eda.Clear;

verdatos.Clear;

ced.SetFocus;

end;

initialization

{$I uventanalista.lrs}

end.