SlideShare una empresa de Scribd logo
1 de 143
Descargar para leer sin conexión
1
Auditoria II
ALGORITMOS II
INGENIERÍA DE SISTEMAS
sfs
Algoritmos II
2
© Corporación Universitaria
Remington
Medellín, Colombia
Derechos Reservados ©2011
Primera edición
2020
Algoritmos II
José Antonio Polo
Facultad de Ingenierías
Comité académico
Jorge Mauricio Sepúlveda Castaño
Decano de la Facultad de Ingenierías
jsepulveda@uniremington.edu.co
David Ernesto González Parra
Director de Educación a Distancia y Virtual
dgonzalez@unireminton.edu.co
Francisco Javier Álvarez Gómez
Coordinador CUR-Virtual
falvarez@uniremington.edu.co
Edición y Montaje
Dirección de Educación a Distancia y Virtual
Equipo de diseño gráfico
www.uniremington.edu.co
virtual@uniremington.edu.co
Derechos reservados: El módulo de estudio del curso de
ALGORITMOS II es propiedad de la Corporación Universitaria
Remington; las imágenes fueron tomadas de diferentes fuentes que
se relacionan en los derechos de autor y las citas en la bibliografía. El
contenido del módulo está protegido por las leyes de derechos de autor
que rigen al país. Este material tiene fines educativos y no puede
usarse con propósitos económicos o comerciales. El autor(es) certificó
(de manera verbal o escrita) No haber incurrido en fraude científico,
plagio o vicios de autoría; en caso contrario eximió de toda
responsabilidad a la Corporación Universitaria Remington y se declaró
como el único responsable.
Esta obra es publicada bajo la licencia Creative Commons.
Reconocimiento-No Comercial-Compartir Igual 2.5 Colombia
sfs
Algoritmos II
3
TABLA DE CONTENIDO
Pág.
1 UNIDAD 1 ALGORITMOS DE ORDENAMIENTO Y BÚSQUEDA 7
1.1.1 OBJETIVO GENERAL 7
1.1.2 OBJETIVOS ESPECÍFICOS 7
1.1.3 PRUEBA INICIAL 8
1.2 TEMA 1 BÚSQUEDA SECUENCIAL, BINARIA Y TRANSFORMACIÓN DE CLAVES 8
1.2.1 BÚSQUEDA SECUENCIA 8
1.2.2 BÚSQUEDA BINARIA 10
1.2.3 BÚSQUEDA POR TRANSFORMACIÓN DE CLAVES 14
1.2.4 EJERCICIO DE APRENDIZAJE 14
1.2.5 TALLER DE ENTRENAMIENTO 15
1.3 TEMA 2 ORDENAMIENTO POR BURBUJA, INSERCIÓN Y SELECCIÓN (MARGE SORT, QUICK SORT, COCKTAIL
SORT) 16
1.3.1 ORDENAMIENTO ASCENDENTE POR MÉTODO BURBUJA 16
1.3.2 PROCESO DE INSERCIÓN EN UN VECTOR ORDENADO ASCENDENTEMENTE 20
1.3.3 ORDENAMIENTO POR SELECCIÓN 23
1.3.4 MARGE SORT, QUICK SORT, COCKTAIL SORT 28
1.3.5 EJERCICIO DE APRENDIZAJE 31
1.3.6 TALLER DE ENTRENAMIENTO 32
1.4 TEMA 3 ANÁLISIS DE EFICIENCIA DE ORDENAMIENTO Y BÚSQUEDA 33
1.4.1 EJERCICIO DE APRENDIZAJE 35
1.4.2 TALLER DE ENTRENAMIENTO 36
2 UNIDAD 2 MANEJO DE ESTRUCTURAS DINÁMICAS EN MEMORIA (LISTAS LIGADAS) 38
2.1.1 OBJETIVO GENERAL 38
2.1.2 OBJETIVOS ESPECIFICOS 38
2.1.3 PRUEBA INICIAL 39
2.2 TEMA 1 CONCEPTOS BÁSICOS Y LISTAS SIMPLEMENTE LIGADAS 39
2.2.1 TEMA 1 PUNTEROS 39
2.2.2 CLASE NODOSIMPLE 40
2.2.3 LISTAS SIMPLEMENTE LIGADAS 45
2.2.4 DIFERENTES TIPOS DE LISTAS SIMPLEMENTE LIGADAS Y SUS CARACTERÍSTICAS 64
2.2.5 EJERCICIO DE APRENDIZAJE 65
2.2.6 TALLER DE ENTRENAMIENTO 65
2.3 TEMA 2 LISTAS DOBLEMENTE LIGADAS Y OTROS TIPOS DE TOPOLOGÍAS DE LISTAS 66
2.3.1 LISTA DOBLEMENTE LIGADAS 66
2.3.2 EJERCICIO DE APRENDIZAJE 70
2.3.3 TALLER DE ENTRENAMIENTO 72
2.4 TEMA 3 PILAS Y COLAS (Estáticas y Dinámicas) 73
sfs
Algoritmos II
4
2.4.1 RELACIÓN DE CONCEPTOS 73
2.4.2 DEFINICIÓN 75
2.4.3 PILAS CON VECTORES Y LISTAS 75
2.4.4 TEMA 3 COLAS CON VECTORES Y LISTAS 86
2.4.5 EJERCICIO DE APRENDIZAJE 95
2.4.6 TALLER DE ENTRENAMIENTO 95
3 UNIDAD 3 CONCEPTUALIZACIÓN DE RECURSIVIDAD, ARBOLES Y GRAFOS 97
3.1.1 OBJETIVO GENERAL 97
3.1.2 OBJETIVOS ESPECÍFICOS 98
3.1.3 PRUEBA INICIAL 98
3.2 TEMA 1 DEFINICIÓN Y APLICACIÓN DE LA RECURSIVIDAD 98
3.2.1 EJERCICIO DE APRENDIZAJE 99
3.2.2 TALLER DE ENTRENAMIENTO 100
3.3 TEMA 2 DEFINICIÓN, CONCEPTOS, REPRESENTACIÓN Y RECORRIDOS DE ARBOLES 101
3.3.1 RELACIÓN DE CONCEPTOS 101
3.3.2 ARBOLES 101
3.3.3 ARBOLES BINARIOS Y SU REPRESENTACIÓN 106
3.4 LISTAS GENERALIZADAS 115
3.4.1 DEFINICIÓN DE LISTAS GENERALIZADAS (ESTILO TÍTULO 3) 116
3.4.2 EJERCICIO DE APRENDIZAJE 119
3.4.3 TALLER DE ENTRENAMIENTO 121
3.5 TEMA 3 DEFINICIÓN, CONCEPTOS, REPRESENTACIÓN Y RECORRIDOS DE GRAFOS 122
3.5.1 RELACIÓN DE CONCEPTOS 122
3.6 GRAFOS 122
3.6.1 DEFINICIÓN Y TERMINOLOGÍA BÁSICA SOBRE GRAFOS 122
3.6.2 EJERCICIO DE APRENDIZAJE 136
3.6.3 TALLER DE ENTRENAMIENTO 136
4 PISTAS DE APRENDIZAJE 137
5 GLOSARIO 141
6 BIBLIOGRAFÍA 143
sfs
Algoritmos II
5
P R O P Ó S I T O G E N E R A L
Que el estudiante pueda identificar las diferentes estructuras de almacenamiento y
aplicarlas de forma óptima en la solución de problemas.
ALGORITMOS II
sfs
Algoritmos II
6
a
O B J E T I V O G E N E R A L
Entrenar a los estudiantes en las técnicas de programación para el
almacenamiento de datos tanto a nivel de memoria como en disco,
para el desarrollo de algoritmos aplicables a diversos retos, que
permita la generación de una capacidad analítica y creativa en la
solución e implementación.
O B J E T I V O S E S P E C Í F I C O S
➢ Reconocer los diferentes algoritmos de ordenamiento y búsqueda
y realizar operaciones a nivel de programación.
➢ Identificar las estructuras de almacenamiento de información como
piolas y colas, representadas de forma estática y dinámica
➢ Aplicar soluciones a problemas a partir de árboles y grafos
U N I D A D 1 U N I D A D 2
Manejo de estructuras
dinámicas en Memoria
(listas ligadas)
Algoritmos de
ordenamiento y
búsqueda
ALGORITMOS II
U N I D A 3
Conceptualización de
recursividad, árboles y
grafos
sfs
Algoritmos II
7
1 UNIDAD 1 ALGORITMOS DE ORDENAMIENTO Y
BÚSQUEDA
1.1.1 OBJETIVO GENERAL
➢Realizar operaciones de ordenamiento y búsqueda sobre grupos de datos, que pueden
estar representados en arreglos; permitiendo mejorar la eficiencia de los algoritmos.
1.1.2 OBJETIVOS ESPECÍFICOS
➢ Aplicar algoritmos de búsqueda con sus diferentes esquemas de representación y realizar
comparativos de eficiencia entre ellos.
sfs
Algoritmos II
8
➢ Aplicar los diferentes algoritmos de búsqueda que permitan encontrar un valor
determinado dentro de un grupo de valores dados que pueden estar almacenados en un
arreglo.
➢ Aplicar los diferentes algoritmos de ordenamiento que permitan a un grupo de datos
ordenarse de forma ascendente o descendente según la necesidad los datos pueden estar
almacenados en un arreglo.
➢ Aplicar en análisis de algoritmos para determinar la eficiencia de los procesos de
ordenamiento y búsqueda y efectuar la comparación para determinar cuál algoritmo es el
de mejor rendimiento.
1.1.3 PRUEBA INICIAL
• ¿Cuál es la diferencia entre arreglos unidimensionales y arreglos bidimensionales?
• ¿Porque es importante tener los datos ordenados en todo momento?
• ¿Qué es la eficiencia en un algoritmo?
1.2 TEMA 1 BÚSQUEDA SECUENCIAL, BINARIA Y
TRANSFORMACIÓN DE CLAVES
➢Video: ” Búsqueda Lineal VS Búsqueda Binaria”
➢” Ver Video”: https://www.youtube.com/watch?v=HmUpRHn31FU ”
1.2.1 BÚSQUEDA SECUENCIA
Cuando tenemos un grupo de datos almacenados secuencialmente en un arreglo y se necesita
determinar si un dato D está dentro de eses grupo, debemos construir un algoritmo que nos
permita aplicar la búsqueda secuencial: se debe recorrer el vector con un ciclo hasta su tamaño
(cantidad de datos de la estructura), se debe pedir el dato a buscar fuera del ciclo (puede ser un
parámetro si es un método o una simple lectura por teclado. Se debe comparar ese dato con el
contenido de cada una de las posiciones del vector y el objetivo es encontrar el dato dentro de
una de ellas, si lo encuentra debe devolver el índice o la posición donde lo encontró, pero, sino lo
encuentra debe devolver un mensaje que diga que el dato no se encuentra en el vector. Algoritmo
que realiza este proceso.
Búsqueda Secuencial
sfs
Algoritmos II
9
1. i = 1 1
2. While ((i <= n) and (V[j] <> x) do n + 1
3. i = i - 1 n
4. End (while) n
5. If (i <= n) then return i 1
6. Else write(“el dato” , x , “no existe”) 1
Contador de frecuencia = 3(n + 4)
Y el orden de magnitud es O(n)
Sea el siguiente vector de tamaño 10, que contiene los preciso de 10 artículos distintos (el vector
no se encuentra ordenado). Si el administrador necesita determinar si existe dentro del vector
un producto con un valor igual a 80.000 pesos como se podría ilustrar este proceso de búsqueda:
D=80000
sfs
Algoritmos II
10
Al comparar en este paso encuentra que el valor almacenado al dato con el se realiza la búsqueda,
el algoritmo inmediatamente debe parar la búsqueda y debe devolver el índice o la posición del
vector don se encuentra ese dato.
Un caso particular en esta búsqueda se da por ejemplo cunado busca el dato igual a 60000 dentro
del vector anterior
Como el dato no está en ninguna de las posiciones del vector el algoritmo de búsqueda debe
devolver un mensaje que indique que el dato no fue encontrado dentro de la estructura (se debe
notar que primero debe haber recorrido todo el vector buscando el dato). El orden de magnitud
de este algoritmo que tiene un ciclo para poder trabajar es normalmente O(n); puesto que el peor
de los casos el algoritmo recorre todo el vector.
1.2.2 BÚSQUEDA BINARIA
El proceso de búsqueda binaria utiliza el hecho de que los datos se encuentran ordenados en
forma ascendente o descendente. La primera comparación se hace con el dato de la mitad del
vector. Si se tiene suerte, ese es el dato que se está buscando y no hay que hacer más
comparaciones; si no lo es, es porque el dato que se está buscando es mayor o menor que el dato
de la mitad del vector. Si el dato que se está buscando es mayor que el dato de la mitad del vector,
significa que, si el dato se halla en el vector, está a la derecha del dato de la mitad, o sea que no
abra necesidad de comparar el dato que se está buscando con todos los datos que están a la
izquierda del dato de la mitad del vector. Luego de que hemos descartado la mitad de los datos,
la siguiente comparación se hará con el dato de la mitad, de la mitad en la cual posiblemente este
el dato a buscar. Así continuamos con este proceso hasta que se encuentre el dato, o se detecte
que el dato no está en el vector. Si tuviéramos un millón de datos, con una sola comparación
estamos ahorrando 500.000 comparaciones, con la segunda comparación se ahorran 250.000
comparaciones, con la tercera se ahorran 125.000 comparaciones y así sucesivamente. Como se
puede ver, la reducción del número de comparaciones es notable.
A continuación, se presenta el método con el cual se efectúa este proceso:
sfs
Algoritmos II
11
1. PUBLICO ESTATICO ENTERO BusquedaBinaria (V, n, d)
2. VARIABLES: li, ls, m (ENTEROS)
3. li = 1
4. ls = n
5. MQ (li <= ls)
6. m = (li + ls) / 2
7. SI (V[m] == d)
8. RETORNE (m)
9. SINO
10. SI (V[m] < d)
11. li = m + 1
12. SINO
13. ls = m – 1
14. FINSI
15. FINSI
16. FINMQ
17. RETORNE (n + 1)
18. FIN(Método)
En la instrucción 1 se define el método BúsquedaBinaria, cuyos parámetros son: V, en el cual hay
que efectuar la búsqueda; n, el tamaño del vector; y d, el dato a buscar.
En la instrucción 2 se definen las variables de trabajo: li, para guardar el límite inferior del rango
en el cual hay que efectuar la búsqueda; ls, para guardar el límite superior del rango en el que se
efectuará la búsqueda; y m, para guardar la posición de la mitad del rango entre li y ls.
En las instrucciones 3 y 4 se asignan los valores iníciales a las variables li y ls. Estos valores iníciales
son 1 y n, respectivamente, ya que la primera vez el rango sobre el cual hay que efectuar la
búsqueda es desde la primera posición hasta la última del vector.
En la instrucción 5 se plantea el ciclo MIENTRAS_QUE (MQ), con la condición de que li sea menor
o igual que ls. Es decir, si el límite inferior (li) es mayor o igual que el límite superior (ls), aún
existen posibilidades de que el dato que se está buscando se encuentre en el vector. Cuando li
sea mayor que ls significa que el dato no está en el vector y retornara n+1.
Cuando la condición de la instrucción 5 sea verdadera se ejecutan las instrucciones del ciclo.
En la instrucción 6 se calcula la posición de la mitad entre li y ls, llamamos a esta posición m.
En la instrucción 7 se compara el dato de la posición m con el dato d. si el dato de la posición m
es igual al dato d que se está buscando (V[m] == d), ejecuta la instrucción 8: termina el proceso
de búsqueda retornando m, la posición en la cual se halla el dato d en el vector.
sfs
Algoritmos II
12
Si el dato que se encuentra en la posición m no es el que buscamos, pasamos a la instrucción 10.
En caso de que la condición de la instrucción 10 sea verdadera, significa que, si el dato está en el
vector, se halla a la derecha de la posición m; por consiguiente, el límite inferior del rango en el
cual se debe efectuar la búsqueda es m+1, y por tanto ejecuta la instrucción 11 en el cual a la
variable li se le asigna m+1.
Si el resultado de la comparación de la instrucción 10 es falso, significa que, si el dato está en el
vector, se halla a la izquierda de la posición m; por consiguiente, el límite superior del rango en el
cual se debe efectuar en la búsqueda es m–1, y por tanto ejecuta la instrucción 13 en la cual a la
variable ls se le asigna m–1.
Habiendo actualizando el límite inferior o el límite superior, se llega a la instrucción 16, la cual
retorna la ejecución a la instrucción 5, donde se efectúa de nuevo la comparación entre li y ls.
Cuando la condición sea falsa se sale del ciclo y ejecuta la instrucción 17, la cual retorna n+1,
indicando que el dato no se halla en el vector.
Fíjese que la única manera de que se ejecute la instrucción 17 es que no haya encontrado el dato
que se está buscando, ya que si lo encuentra ejecuta la instrucción 8, la cual termina el proceso.
Consideremos, como ejemplo, el siguiente vector, y que se desea buscar el número 38 en dicho
vector:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
Al ejecutar nuestro algoritmo de búsqueda binaria, cuando se esté en la instrucción 5 por primera
vez, li se situará en 1 y ls en n, como vemos en la siguiente figura:
Al ejecutar la instrucción 7, la cual compara el dato de la posición m (28) con d (38), se determina
que el dato d, si está en el vector, se halla a la derecha de la posición m, por consiguiente, el valor
de li deberá ser 9. En constancia, al ejecutar la instrucción 11, el límite inferior del rango sobre el
li M Ls
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
sfs
Algoritmos II
13
cual hay que efectuar la búsqueda es 9, por lo tanto, el rango sobre el cual hay que efectuar dicha
búsqueda es entre 9 y 15.
Al ejecutar el ciclo por segunda vez el valor de m será 12, como muestra la figura siguiente:
Luego, al comparar d (38) con V[m] (52), se determina que el dato que se está buscando, si está
en el vector, debe hallarse a la izquierda de m, es decir, entre las posiciones 9 y 11, por
consiguiente, el valor de j será 11 (j = m – 1).
Al ejecutar el ciclo por tercera vez, las variables quedarán de la siguiente forma:
li m ls
n
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
En esta pasada se detecta que el dato debe estar a la derecha de m, por consiguiente el valor de
li deberá ser 11, y en consecuencia el valor de m también. La situación en el vector queda así:
En este punto la comparación de d con V[m] indica que si el dato d está en el vector, debe estar
a la izquierda de m, por tanto el valor de ls será 10, y al regresar a la instrucción 5 y evaluar la
condición del ciclo (li <= ls), esta será falsa, por consiguiente termina el ciclo y retorna como
posición el valor de 16 (n+1), indicando que el 38 no se encuentra en dicho vector.
li m ls
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
li m Ls
n
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
sfs
Algoritmos II
14
1.2.3 BÚSQUEDA POR TRANSFORMACIÓN DE CLAVES
Cuando se utiliza métodos de búsqueda por transformación de claves permiten aumentar la
velocidad de búsqueda, con una condición importante y es que los elementos no tienen que esta
ordenados, es decir, que la ventaja es que el tiempo de búsqueda es totalmente independiente
al número componentes del arreglo (vector).
Supongamos que se tiene una colección de datos donde cada uno de ellos identificado por una
clave donde resulta atractivo tener acceso a ellos de forma directa.
Se tiene que tener en cuenta que dos claves diferentes pueden apuntar a una misma dirección
dentro del arreglo a esto se le llama colisiones.
Cuando se quiere trabajar con este método de búsqueda se debe seleccionar previamente:
Una función Hash que sea fácil de calcular y que distribuya uniformemente las claves
Un método para resolver las colisiones, si estas se presentan, se contará con algún método que
genere posiciones alternativas.
1.2.3.1 FUNCIÓN HASH POR MODULO:
Consiste en tomar el residuo de la división de la clave entre el número de componentes del arreglo
ejemplo: se tiene un arreglo de N elementos y K es la clave del dato a buscar. La función hash
correspondiente es:
H(K)=(K*ModN)+1
Se observa en la fórmula que al residuo de la división se le suma 1, con el objetivo de tener un
valor comprendido entre 1 y N siendo N el tamaño del Arreglo.
Para lograr una mayor uniformidad en la distribución es importante que N sea un numero primo
o divisible entre muy pocos números, en caso de que N no sea un numero primo, se debe buscar
el número primo más cercano a N.
1.2.4 EJERCICIO DE APRENDIZAJE
Supongamos que N es igual a 100 es el tamaño del Arreglo y las direcciones que se le deben
asignar a los elementos (al guardarlo o recuperarlo) son los números del 1 al 100y además
sfs
Algoritmos II
15
contamos con las siguientes claves K1=7259 y K2=9359 son las que se les debe asignar posiciones
dentro el arreglo, las direcciones correspondientes para K1 y K2
H(K1)=(7259*Mod 100) +1= 60
H(K2)=(9359*Mod 100) +1= 60
Nota: se observa que dos claves distintas apuntan a una misma posición en el arreglo, lo que
generó una colisión y este problema se resuelve asignando el primo más cercan para N=100 que
es 97.
Aplicando las fórmulas con este valor observamos:
H(K1)=(7259*Mod 97) +1= 82
H(K2)=(9359*Mod 97) +1= 48
Con N=97 se ha eliminado la colisión.
1.2.5 TALLER DE ENTRENAMIENTO
Supongamos que N es igual a 200 es el tamaño del Arreglo y las direcciones que se le deben
asignar a los elementos (al guardarlo o recuperarlo) son los números del 1 al 200 y además
contamos con las siguientes claves K1=5526 y K2=2850 son las que se les debe asignar posiciones
dentro el arreglo, encontrar las direcciones asociadas a las direcciones K1 y K2 para la búsqueda
hashing y en caso de que se den colisiones resolverlas (recuerde que se debe tomar el primo más
cercano al valor de N).
TIPS
El hashing usa las claves para asociar y encontrar los datos de un arreglo
mayor velocidad.
sfs
Algoritmos II
16
1.3 TEMA 2 ORDENAMIENTO POR BURBUJA, INSERCIÓN Y
SELECCIÓN (MARGE SORT, QUICK SORT, COCKTAIL SORT)
➢Video: ” ALGORITMOS - METODOS DE ORDENAMIENTO”
➢” Ver Video”: https://www.youtube.com/watch?v=VJ_EUuURRg4 ”
1.3.1 ORDENAMIENTO ASCENDENTE POR MÉTODO BURBUJA
El método de ordenamiento por burbuja consiste en comparar dos datos consecutivos y
ordenarlos ascendentemente, es decir, si el primer dato es mayor que el segundo se intercambia
dichos datos, de lo contrario se dejan tal cual están. Cualquiera de las dos situaciones que se
hubiera presentado se avanza en el vector para comparar los siguientes dos datos consecutivos.
En general, el proceso de comparaciones es: el primer dato con el segundo, el segundo dato con
el tercero, el tercer dato con el cuarto, el cuarto con el dato quinto, y así sucesivamente, hasta
comparar el penúltimo dato con el último. Como resultado de estas comparaciones, y los
intercambios que se hagan, el resultado es que en la última posición quedara el mayor dato en el
vector. La segunda vez se compara nuevamente los datos consecutivos, desde el primero con el
segundo, hasta que se comparan el antepenúltimo dato con el penúltimo, obteniendo como
resultado que el segundo dato mayor queda de penúltimo. Es decir, en cada pasada de
comparaciones, de los datos que faltan por ordenar, se ubica el mayor dato en la posición que le
corresponde, o sea de ultimo en el conjunto de datos que faltan por ordenar. Veamos el método
que efectúa dicha tarea
1. PUBLICO ESTATICO VOID OrdenamientoAscendenteBurbuja (V, n)
2. VARIABLES: i, j (ENTEROS
3. PARA (i= 1, n-1, 1)
4. PARA (j= 1, n-i, 1)
5. SI (V[j] > V[j+1])
6. INTERCAMBIAR (V, j, j+1)
7. FINSI
8. FINPARA
9. FINPARA
10. FIN(Método)
Como ejemplo vamos a considerar el siguiente vector:
sfs
Algoritmos II
17
1 2 3 4 5 6
V 3 1 6 2 8 4
Nuestro interés es ordenar los datos de dicho vector en forma ascendente, utilizando el método
que llamamos burbuja.
1 2 3 4 5 6
Parte 1 3 1 6 2 8 4
Primera pasada: cinco comparaciones
Parte 4 1 3 2 6 8 4
En la figura anterior se presentan los cincos comparaciones que se efectúan en la primera pasada.
La comparación correspondiente a cada pasada se ve resaltada en cada vector. A cada
comparación la llamaremos parte con el fin de evitar redundancias.
• En la primera parte se compara el dato de la posición 1 con el dato de la posición 2. Como
el dato de la posición 1 es mayor que el dato de la posición 2, se intercambian dichos
datos, quedando el vector como se ve en la parte 2.
• En la parte 2 se compara el dato de la posición 2 con el dato de la posición 3. Como el dato
de la posición 3 es mayor que el dato de la posición 2, los datos se dejan intactos.
• En la parte 3 se compara el dato de la posición 3 con el dato de la posición 4. Como el dato
de la posición 3 es mayor que el dato de la posición 4, se intercambian dichos datos,
quedando el vector como se ve en la parte 4.
• En la parte 4 se compara el dato de la posición 4 con el dato de la posición 5. Como el dato
de la posición 4 es menor que el dato de la posición 5, los datos permanecen intactos.
• En la parte 5 se compara el dato de la posición 5 con el dato de la posición 6. Como el dato
de la posición 5 es mayor que el dato de la posición 6, se intercambian dichos datos.
Parte 2 1 3 6 2 8 4
Parte 3 1 3 6 2 8 4
Parte 5 1 3 2 6 8 4
sfs
Algoritmos II
18
Luego de realizar estas comparaciones y estos intercambios, el vector queda de la siguiente
forma:
En esta figura se ha resaltado el dato de la posición 6, puesto que este ha quedado en el sitio que
le corresponde.
En la segunda pasada se harán nuevamente comparaciones de datos consecutivos desde la
posición 1 hasta la posición 5, ya que la posición 6 ya está en orden.
Las comparaciones e intercambios correspondientes a esta segunda pasada se presentan en la
figura 31.4
1 2 3 4 5 6
Parte 1 1 3 2 6 4 8
Segunda pasada: cuatro comparaciones
Como resultado final de esta segunda pasada el vector quedará de la siguiente forma:
1 2 3 4 5 6
1 2 3 4 6 8
En esta figura se resaltan las dos últimas posiciones, indicando que esta parte del vector ya está
ordenada.
En la siguiente figura se muestra como es el proceso de comparaciones e intercambios
correspondientes a la tercera pasada. Fíjese que las comparaciones solo se efectúan hasta la
posición 4, ya que los datos de las posiciones 5 y 6 ya están ordenados y ubicados en sus
correspondientes lugares.
1 2 3 4 5 6
1 3 2 6 4 8
Parte 2 1 3 2 6 4 8
Parte 3 1 2 3 6 4 8
Parte 4 1 2 3 6 4 8
sfs
Algoritmos II
19
1 2 3 4 5 6
Tercera pasada: tres comparaciones
Ahora veamos el estado actual de nuestro vector después de la tercera pasada:
1 2 3 4 5 6
1 2 3 4 6 8
En la siguiente figura se muestra las dos comparaciones correspondientes a la cuarta pasada:
Cuarta pasada: dos comparaciones
Luego de la cuarta pasada el vector quedará de la siguiente forma:
1 2 3 4 5 6
1 2 3 4 6 8
En la siguiente figura se muestra la comparación que se hará en la quinta pasada:
Quinta pasada: una comparación
Después de la quinta pasada nuestro vector quedará así:
1 2 3 4 5 6
1 2 3 4 6 8
Observe que al concluir la tercera pasada los datos del vector ya estaban ordenados; es decir, las
comparaciones correspondientes a las pasadas cuarta y quinta no eran necesarias. Esta situación
se puede detectar en el algoritmo si utilizamos una variable auxiliar y le asignamos un valor antes
de comenzar el ciclo interno. Si ocurrió algún intercambio, modificamos el valor inicial de dicha
1 2 3 4 6 8
1 2 3 4 6 8
1 2 3 4 6 8
1 2 3 4 5 6
1 2 3 4 6 8
1 2 3 4 6 8
1 2 3 4 5 6
1 2 3 4 6 8
sfs
Algoritmos II
20
variable auxiliar. Al terminar el ciclo interno averiguamos cual es el contenido de dicha variable
auxiliar. Si es el mismo que se le asigno inicialmente, significa que no hubo intercambios en el
ciclo interno, por consiguiente, los datos del vector ya están ordenados y no hay necesidad de
hacer más comparaciones. Para nuestro ejemplo llamaremos a esa variable auxiliar sw.
Nuestro algoritmo queda:
1. PUBLICO ESTATICO VOID OrdenamientoAscendenteBurbujaSW (V, n)
2. VARIABLES: i, j, sw (ENTEROS)
3. PARA (i= 1, n-1, 1)
4. Sw = 0
5. PARA (j= 1, n-i, 1)
6. SI (V[j] > V[j+1])
7. INTERCAMBIAR (V, j, j+1)
8. sw = 1
9. FINSI
10. FINPARA
11. SI (sw == 0)
12. i = n
13. FINSI
14. FINPARA
15. FIN(Método)
El algoritmo anterior es similar al primero que hicimos de ordenamiento ascendente con el
método de burbuja, la diferencia está en que agregamos una variable llamada sw con la cual
sabremos si el vector está completamente ordenado sin haber hecho todos los recorridos.
Cuando la variable sw no cambie de valor significa que el vector ya está ordenado y asignaremos
a la variable i el valor de n para salir del ciclo externo.
1.3.2 PROCESO DE INSERCIÓN EN UN VECTOR ORDENADO
ASCENDENTEMENTE
Si queremos insertar un dato en un vector ordenado ascendentemente, sin dañar su
ordenamiento, primero debemos buscar la posición en la que debemos insertar. Para buscar la
posición donde vamos a insertar un nuevo dato en el vector ordenado ascendentemente
debemos recorrer el vector e ir comparando el dato de cada posición con el dato a insertar. Como
los datos están ordenados ascendentemente, cuando se encuentre en el vector un dato mayor
que el que se va a insertar esa es la posición en la cual deberá quedar el nuevo dato.
sfs
Algoritmos II
21
Si el dato a insertar es mayor que todos los datos del vector, entonces el dato a insertar quedara
de último.
El método siguiente ejecuta esta tarea y retorna en la variable i La posición en la cual debe
quedar el dato a insertar:
1. PUBLICO ESTATICO ENTERO BuscarDondeInsertar (V, m, d)
2. VARIABLES: i (ENTERO)
3. i = 1
4. MQ ((i <= m) ^ (V[i] < d))
5. i = i + 1
6. FINMQ
7. RETORNE (i)
8. FIN(Método)
En la instrucción 1 se define el nombre del programa con sus parámetros: V, variable que contiene
el nombre del vector en el cual hay que efectuar el proceso de búsqueda; m, variable que contiene
el número de posiciones utilizadas en el vector; y d, variable que contiene el dato a insertar.
En la instrucción 2 se define la variable i, que es la variable con la que recorre el vector y se va
comparando el dato de la posición i del vector (V[i]) con el dato a insertar (d).
En la instrucción 3 se inicializa la variable i en 1, ya que esta es la posición a partir de la cual se
comienza a almacenar la posición donde se va a insertar el dato.
En la instrucción 4, la instrucción del ciclo, se controlan dos situaciones: una, que no se haya
terminado de comparar los datos del vector, (i <= m), y dos, que el dato de la posición i sea mayor
que d (V[i] < d).
Si ambas condiciones son verdaderas se ejecutan las construcciones 5 y 6, es decir, se incrementa
la i en 1 y se regresa a la instrucción 4 a evaluar nuevamente las condiciones.
Cuando una de las condiciones sea falsa (i>m o V[i]>=d), se sale del ciclo y ejecuta la instrucción
7, es decir, retorna al programa llamante el valor de i: la posición en la cual hay que insertar el
dato d.
Como ejemplo, consideremos el vector de la siguiente figura, y que se desea insertar el número
10 (d==10).
sfs
Algoritmos II
22
Al ejecutar el método
BuscarDondeInsertar, este retorna i valiendo 4, es decir, en la posición 4 del vector V debe quedar
el dato 10.
Ahora veamos Conocimos que el dato debe quedar en una posición i, veamos cómo se efectúa
este proceso. Si el vector no está lleno (m == n), debemos mover todos los datos desde la posición
i del vector hacia la derecha.
1. PUBLICO ESTATICO VOID Insertar (V, m, n, i, d)
2. VARIABLES: j (ENTERO)
3. SI (m == n)
4. IMPRIMA (“vector lleno”)
5. RETORNE
6. SINO
7. PARA (j= m, i, -1)
8. V[j+1] = V[j]
9. FINPARA
10. V[i] = d
11. m = m + 1
12. FINSI
13. FIN(Método)
Es la instrucción 1 se define el método con sus parámetros: V, variable que contiene el nombre
del vector en el cual hay que efectuar el proceso de inserción; m, variable que contiene el número
de posiciones utilizadas en el vector; n, tamaño del vector; i, variable que contiene la posición en
la cual se debe insertar el dato contenido en d; y d, variable que contiene el dato a insertar. Es
bueno resaltar que los parámetros V y m deben ser parámetros por referencia, mientras que n, i
y d son por valor.
En la instrucción 2 se define la variable j, la cual se utilizará para mover los datos del vector en
caso de que sea necesario.
m n
1 2 3 4 5 6 7 8 9 10
V 3 5 7 11 18 23 36
sfs
Algoritmos II
23
En la instrucción 3 se controla que el vector no esté lleno. En caso de que el vector este lleno (m
== n), se ejecuta la instrucción 4, la cual produce el mensaje de que el vector está lleno y finaliza
el método sin realizar más acciones, la instrucción 5 indica que el método puede retornar en
donde fue invocado.
En caso de que el vector no esté lleno se ejecuta la instrucción 7, en la cual se plantea la
instrucción PARA, la cual inicializa el valor de j con el contenido de m, compara el valor de j con
el valor de i y define la forma como variara el de j. la variación de la variable j será restándole 1
cada vez que llegue a la instrucción fin del PARA. Cuando el valor de j sea menor que i se sale del
ciclo. En caso de que el valor inicial de j sea menor que i, no ejecutara la instrucción 8 y continuara
con la instrucción 10.
En la instrucción 8 se mueve el dato que está en la posición j a la posición siguiente (j + 1).
En la instrucción 9, que es el fin de la instrucción PARA, disminuye el valor de j, ejecutara
nuevamente las instrucciones 8 y 9, hasta que j sea menor que i.
Cuando se sale del ciclo, ejecuta la instrucción 10, en la cual se asigna a la posición i del vector el
dato d y continua con la instrucción 11 en la cual se incrementa el valor de m en 1, indicando que
el vector ha quedado con un elemento más.
Veamos cómo queda nuestro vector después de haber insertado el dato:
1.3.3 ORDENAMIENTO POR SELECCIÓN
Como ya hemos visto, el hecho de trabajar los datos ordenados hace que los algoritmos sean más
eficientes. Para ejecutar el proceso de ordenamientos se han desarrollado múltiples métodos,
buscando que este proceso sea lo más eficiente posible. Ahora veamos un método que ordena
los datos de un vector. El método utilizado en este algoritmo se denomina ordenamiento por
selección. Este método se enuncia así: de los datos que faltan por ordenar, determinar el menor
de ellos y ubicarlo de primero en ese conjunto de datos.
i m n
1 2 3 4 5 6 7 8 9 10
V 3 5 7 10 11 18 23 36
sfs
Algoritmos II
24
Con base en este enunciado se presenta el método:
1. PUBLICO ESTATICO VOID OrdenamientoAscendenteSeleccion (V, m)
2. VARIABLES: i, j, k (ENTEROS)
3. PARA (i= 1, m-1, 1)
4. k = i
5. PARA (j= i+1, m, 1)
6. SI (V[j] < V[k])
7. k = j
8. FINSI
9. FINPARA
10. OrdenamientoAscendenteSeleccion .Intercambiar (V, k, i)
11. FINPARA
12. FIN(Método)
• En la instrucción 1 se define el método con sus parámetros: V, variable en la cual se
almacena el vector que desea ordenar, y m, el número de elementos a ordenar. V es un
parámetro por referencia, ya que se modificará al cambiar de posición los datos dentro
del vector.
• En la instrucción 2 se define las variables necesarias para efectuar el proceso de
ordenamiento. La variable i se utiliza para identificar a partir de cual posición es que faltan
datos por ordenar. Inicialmente el valor de i es 1, ya que inicialmente faltan todos los datos
por ordenar y los datos comienzan en la posición 1. Cuando el contenido de la variable i
sea 2, significa que faltan por ordenar los datos que hay a partir de la posición 2 del vector;
cuando el contenido de la variable i sea 4, significa que faltan por ordenar los datos que
hay a partir de la posición 4; cuando el contenido de la variable i sea m, significa que
estamos en el último elemento del vector, el cual obviamente estará en su sitio, pues no
hay más datos con los cuales se puede comparar. Esta es la razón por la cual en la
instrucción 3 se pone a variar la i desde 1 hasta m–1.
NOTA: Si deseamos ordenar el vector de forma descendente, simplemente
cambiamos el símbolo menor que (<) por el de mayor que (>) en la instrucción
6.descubre el valor propio de las cosas.
sfs
Algoritmos II
25
• En la instrucción 3 se plantea el ciclo de la variable i, que varían desde 1 hasta m–1, tal
como explicamos en el párrafo anterior.
• En la instrucción 4 se le asigna a k el contenido de la variable i. la variable k se utiliza para
identificar la posición en la que se halla el menor dato. Inicialmente suponemos que el
menor dato se encuentra en la posición i del vector, es decir, suponemos que el primero
del conjunto de datos que faltan por ordenar.
• En la instrucción 5 se plantea el ciclo con el cual se determina la posición en la cual se halla
el dato menor del conjunto de datos que faltan por ordenar. En este ciclo se utiliza la
variable j, que tiene un valor inicial de i + 1 y varia hasta m.
• En la instrucción 6 se compara el dato que se halla en la posición j del vector con el dato
que se halla en la posición k. si el contenido de la posición j es menor que el contenido de
la posición k, se actualiza el contenido de la variable k con el contenido de j, de esta
manera en la variable k siempre estará la posición en la cual encuentra el menor dato.
• Al terminar la ejecución 10 se intercambia el dato que se halla en la posición k con el dato
que se halla en la posición i, logrando de esta manera ubicar el menor dato al principio del
conjunto de datos que faltan por ordenar. Nótese que invocamos al método Intercambiar
y lo hicimos con el nombre del método que invoca. El nombre del método invocado
• Al llegar a la instrucción 11 continúa con el ciclo externo incrementado a i, que es a partir
de esa posición que faltan los por ordenar.
Como ejemplo, consideramos el siguiente vector:
Al ejecutar por primera vez las instrucciones 3, 4 y 5, los valores de i, k y j son 1, 1 y 2,
respectivamente, lo cual indica que faltan por ordenar los datos a partir de la posición 1, en donde
se halla el menor dato de los que faltan por ordenar y se va a comenzar a comparar los datos del
vector, a partir de la siguiente posición, es decir, 2. Gráficamente se presenta esta situación en la
siguiente figura.
1 2 3 4 5 6
V 3 1 6 2 8 4
sfs
Algoritmos II
26
Al ejecutar la instrucción 6, por primera vez, comparará el dato de la posición 2 (j == 2) con el dato
de la posición 1 (k == 1), obteniendo como resultado que la condición es verdadera; por tanto,
ejecuta la instrucción 7, la cual asigna a k el valor de j, indicando que el menor dato se halla en la
posición 2 del vector.
Al ejecutar la instrucción 9, incrementa el contenido de j en 1, quedando j con el valor de 3. Esta
nueva situación se presenta a continuación.
Se ejecuta de nuevo la instrucción 6 y compara el dato de la posición 3 con el dato de la posición
2, obteniendo como resultado que la condición es falsa; por tanto, no ejecuta la instrucción 7, y
continúa en la instrucción 9, es decir, incrementa nuevamente el contenido de j en 1, la cual
queda valiendo 4.
Se continúan ejecutando las instrucciones del ciclo interno (instrucciones 6 a 9), comparando el
contenido de la posición j del vector con el contenido de la posición k, obteniendo siempre falso
como resultado, hasta que el contenido de la variable j es 7. Cuando esto sucede, pasa ejecutar
la instrucción 10, en la cual se intercambia el dato que se halla en la posición i con el dato que se
halla en la posición k. En este momento el vector se encuentra así:
i k j
1 2 3 4 5 6
V 3 1 6 2 8 4
i k j
1 2 3 4 5 6
V 3 1 6 2 8 4
i K J
sfs
Algoritmos II
27
El contenido de la posición 1 lo resaltamos indicando que el dato de esa posición ya está ubicado
en la posición que le corresponde.
Continúa con la ejecución de la instrucción 11, en la cual incrementa el contenido de i en 1, y
regresa a continuación con el ciclo externo. Se asigna nuevamente a k el contenido de i y se
comienza de nuevo la ejecución del ciclo interno, con valor inicial de j en 3, así:
Al terminar la ejecución del ciclo interno, por segunda vez, el contenido de la variable k será 4,
indicando que en esta posición se encuentra el menor de los datos que faltan por ordenar, es
decir, de los datos que hay a partir de la posición 2 del vector.
Terminando la ejecución del ciclo interno continúa con la instrucción 10 en la cual intercambia el
dato que está en la posición i (2) con el dato que está en la posición k (4) del vector. Ahora nuestro
vector se ve así:
1 2 3 4 5 6
V 1 3 6 2 8 4
i k j
1 2 3 4 5 6
V 1 3 6 2 8 4
i k j
1 2 3 4 5 6
V 1 3 6 2 8 4
sfs
Algoritmos II
28
Aquí resaltamos el contenido de las dos primeras posiciones indicando que esos dos datos ya
están ordenados y en el sitio que les corresponde.
Al ejecutar la instrucción 11 incrementa la i en 1, indicando que ya faltan por ordenar sólo los
datos que se encuentran a partir de la posición 3, y regresa a ejecutar nuevamente las
instrucciones 4 y56, en las cuales al valor de k le asigna el contenido de i, y a j la inicializamos en
4. Veámoslo gráficamente:
El proceso de ordenamiento continuara de esta manera hasta que el valor i sea 6. Cuando el valor
de i es 6 el proceso termina y los datos del vector están ordenados en forma ascendente.
Finalmente, el vector se verá así:
1.3.4 MARGE SORT, QUICK SORT, COCKTAIL SORT
Método de ordenamiento QUICK SORT
Es el método de ordenamiento más eficiente estadísticamente, en el caso promedio para ordenar
los datos de un vector. El Método consiste básicamente en elegir un dato del vector y ubicarlo en
el sitio que le corresponde, es decir, los anteriores serán todos menores que ese dato y los
i k j
1 2 3 4 5 6
V 1 2 6 3 8 4
i k j
1 2 3 4 5 6
V 1 3 6 2 8 4
1 2 3 4 5 6
V 1 2 3 4 6 8
sfs
Algoritmos II
29
siguientes serán todos mayores que ese dato. Luego de efectuar esta operación se procede a
ordenar los datos que quedaron antes y los que quedaron después usando la misma técnica.
Algoritmo Quicksort
Void quickSort (entero m, entero n)
Entero i, j
If (m<n) then
i=m
j=j+1
while (i<j) do
do
i=i+1
while ((i<=n) and (V[i]>=V[m]))
do
j=j-1
while ((j!=m) and (V[j]>=V[m]))
if (i<j) then
intercambia(i,j)
end(if)
end(while)
intercambia(j,m)
Quicksort(m,j-1)
quicksort (j+1, n)
end(if)
End(quinksort)
Método de ordenamiento MERGE SORT
Este método de ordenamiento no busca ubicar inicialmente un dato en la posición que le
corresponde. Simplemente divide el vector en dos subvectores de igual tamaño, los ordena por
separado y luego los intercala. Este método tiene la inconveniencia de que requiere memoria
adicional para ejecutarse.
El algoritmo para sortMerge se escribe a continuación:
sfs
Algoritmos II
30
Void sortMerge(entero primero, entero ultimo)
entero mitad
if (primero < ultimo) then
mitad=(primero+ultimo)/2
sortMerge(primero, mitad)
sortMerge(mitad + 1, ultimo)
intercalar(primero, mitad,ultimo)
end(if)
End(sortMerge)
El algoritmo para el método intercalar es:
Void intercalar(entero primero, entero mitad, entero ultimo)
Entero i, j, k, b[]
B=new entero[V[0]]
If (primero > mitad) or (mitad + 1 > ulimo) then return
For (k=primero; k <= ultimo; k++) do
b.asigneDato(V[k], k)
end(for)
i=primero
j=mitad + 1
k=primero – 1
while ((i<=mitad) and (j<=ultimo)) do
k=+1
if (b.datoEnPosicion(i)<=b.datoEnPosicion(j)) then
V[k]=b.datoEnPosicion(i)
i=i+1
else
V[k]=b.datoEnPosicion(j)
j=j+1
end(if)
end(while)
while (i<=mitad) do
k=k+1
V[k]=b.datoEnPosicion(i)
i=i+1
sfs
Algoritmos II
31
end(while)
while (j<=ultimo) do
k=k+1
V[k]=b.datoEnPosicion(j)
j=j+1
end(while)
Fin(intercalar)
Ordenam
Método de ordenamiento COCKTAIL SORT
Es un algoritmo de ordenamiento que surge como una mejora al algoritmo de ordenamiento de
burbuja. Funciona observando que los números grandes se están moviendo rápidamente hasta
el final de la lista (estas son las liebres), pero que los números pequeños (las tortugas) se mueven
solo muy lentamente al inicio de la lista.
La solución plantea ordenar por el método de burbuja y cuando llegamos al final de la primera
iteración, no volver a realizar el cálculo desde el principio, sino, que empecemos desde el final
hasta el inicio. De esa manera siempre se consigue que tanto los números pequeños como los
grandes se desplacen a los extremos de la lista lo más rápido posible
1.3.5 EJERCICIO DE APRENDIZAJE
1. PROCEDIMIENTO cocktail_sort ( VECTOR a[1:n])
2. dirección ← 'frontal', comienzo ← 1, fin ← n-1, actual ← 1
3. REPETIR
4. permut ← FALSO
5. REPETIR
6. SI a[actual] > a[actual + 1] ENTONCES
7. intercambiar a[actual] Y a[actual + 1]
8. permut ← VERDADERO
9. FIN SI
10. SI (dirección='frontal') ENTONCES
11. actual ← actual + 1
12. SI NO
13. actual ←actual - 1
14. FIN SI
sfs
Algoritmos II
32
15. MIENTRAS
QUE ((dirección='frontal') Y (actual<fin)) OU ((dirección='final) O (actual>comienzo))
16. SI (dirección='frontal') ENTONCES
17. dirección ← 'final'
18. fin ← fin - 1
19. SI NO
20. dirección ← 'frontal'
21. comienzo ← comienzo + 1
22. FIN SI
23. MIENTRAS permut = VERDADERO
24.
25. FIN PROCEDIMIENTO
1.3.6 TALLER DE ENTRENAMIENTO
Void quickSort (entero m, entero n)
Entero i, j
If (m<n) then
i=m
j=j+1
while (i<j) do
do
i=i+1
while ((i<=n) and (V[i]>=V[m]))
do
j=j-1
while ((j!=m) and (V[j]>=V[m]))
if (i<j) then
intercambia(i,j)
end(if)
end(while)
intercambia(j,m)
Quicksort(m,j-1)
quicksort (j+1, n)
end(if)
End(quinksort)
sfs
Algoritmos II
33
1.4 TEMA 3 ANÁLISIS DE EFICIENCIA DE ORDENAMIENTO Y
BÚSQUEDA
➢Video: ” Análisis de Algoritmos , Complejidad de algoritmos (Actualizado)”
➢” Ver Video”: https://www.youtube.com/watch?v=Sibd8jSTdUQ&t=256s ”
A continuación de mostrara y se realzara un análisis de los algoritmos de ordenamiento y
búsqueda para encintar su contador de frecuencias y su respectivo orden de magnitud con el
objetivo de realizar un comparativo de cual algoritmo en búsqueda y en ordenamiento
respectivamente es el más eficiente:
Análisis del algoritmo Ordenamiento por selección
1. Void selección() 1
2. Entero i, j, k 1
3. For (i = 1; i < n; i++) do n
4. K = i n - 1
5. For (j= j+1; j<=n; j++) do n(n -1)/2 +(n – 1)
6. If v[j] < V[k] then n(n -1)/2
Nota: Realice una prueba de escritorio para un vector de 10 posiciones, la
información en el vector está inicialmente desordenada; después de realizar la
prueba, desde su punto de vista escriba que tan eficiente es el método.
TIPS
La implementación de los métodos de ordenamiento y búsqueda
permiten mejorar el rendimiento en colecciones de datos de grandes
volúmenes que requieren de esos procesos.
sfs
Algoritmos II
34
7. K= j n(n -1)/2
8. End (if) n(n -1)/2
9. End (for) n(n -1)/2
10. Intercambia(i,k) n - 1
11. End (for) n – 1
12. End (selección) 1
Contador de frecuencia = 5n(n – 1)/2 + 5n -1
Y el orden de magnitud es O(n2)
Análisis del algoritmo Ordenamiento por inserción
1. Void Inserción() 1
2. Entero i, j, d 1
3. For (i = 2; i < n; i++) do n
4. d = V[i] n - 1
5. j = i - 1 n(n -1)/2 +(n – 1)
6. While ((j > 0) and (d <[j])) do n(n -1)/2
7. V[j + 1] = V[j] n(n -1)/2
8. j = j - 1 n(n -1)/2
9. End (while) n(n -1)/2
10. V[j + 1] = d n - 1
11. End (for) n – 1
12. End (Inserción) 1
Contador de frecuencia = 4n(n – 1)/2 + 5n - 2
Y el orden de magnitud es O(n2)
Análisis del Algoritmo Búsqueda Binaria
1. primero = 1 1
2. ultimo = n 1
3. while (primero <= ultimo) do log2n + 1
4. Medio = (primero + ultimo) /2 log2n
sfs
Algoritmos II
35
5. If (V[medio] == x) then return medio log2n
6. If (V[medio] > x) then ultimo = medio - 1 log2n
7. else primero = medio + 1 log2n
8. End (while) log2n
9. write(“el dato” , x , “no existe”) 1
Contador de frecuencia = 6(log2n) + 4
Y el orden de magnitud es O(log2n)
Análisis del algoritmo de Búsqueda Secuencial
1. i = 1 1
2. While ((i <= n) and (V[j] <> x) do n + 1
3. i = i - 1 n
4. End (while) n
5. If (i <= n) then return i 1
6. Else write(“el dato” , x , “no existe”) 1
Contador de frecuencia = 3(n + 4)
Y el orden de magnitud es O(n)
1.4.1 EJERCICIO DE APRENDIZAJE
Análisis del algoritmo Ordenamiento por burbuja
1. Void burbuja() 1
2. Entero i, j 1
3. For (i = 1; i < n; i++) do N
4. For (j= 1; j<=n-i; j++) do n(n -1)/2 +(n – 1)
5. If v[j] > V[j + 1] then n(n -1)/2
6. Intercambia(i, j + 1) n(n -1)/2
7. End (if) n(n -1)/2
8. End (for) n(n -1)/2
9. End (for) n – 1
10. End (burbuja) 1
sfs
Algoritmos II
36
Contador de frecuencia = 5n(n – 1)/2 + 3n + 1
Y el orden de magnitud es O(n2)
1.4.2 TALLER DE ENTRENAMIENTO
Al siguiente algoritmo coloque al frente cada instrucción el número de veces que se ejecuta cada
una de ellas, además, hallar el contador de frecuencia y el orden de magnitud.
Análisis del algoritmo Ordenamiento por Burbuja mejorado
1. Void burbujaMejorado ()
2. Entero i, j, sw
3. For (i = 1; i < n; i++) do
4 Sw = 0
5. For (j= 1; j<=n-i; j++) do
6. If (V[j] > V[j + 1]) then
7. Intercambia(i, j + 1)
8. sw= 1
9. End (if)
10. End (for)
11. If (sw == 0) then return
12. End (for)
13. End (burbuja)
Contador de frecuencia = ¿?
Y el orden de magnitud es ¿?
TIPS
Los rendimientos de los algoritmos de ordenamiento y búsqueda
alcanzan a llegar a niveles de logarítmicos y semilogarítmicos,
mejorando los órdenes de los lineales y cuadráticos.
sfs
Algoritmos II
37
38
Algoritmos II
2 UNIDAD 2 MANEJO DE ESTRUCTURAS DINÁMICAS EN
MEMORIA (LISTAS LIGADAS)
2.1.1 OBJETIVO GENERAL
➢ Reconocer el concepto de nodos, el manejo de listas simples, listas dobles y las
operaciones con pilas y colas.
2.1.2 OBJETIVOS ESPECIFICOS
➢ Configurar la estructura nodo tanto simple como doble
➢ Realizar operaciones (buscar, insertar, borrar) con listas simples y dobles
➢ Realizar las operaciones de apilar, desapilar, encolar, desencolar tanto en vectores como
en listas simples.
39
Algoritmos II
2.1.3 PRUEBA INICIAL
• ¿Qué es un nodo?
• ¿Qué es un puntero?
• ¿Qué es una lista simplemente ligada?
• ¿Qué es una lista doblemente ligada?
• ¿Qué es un nodo cabeza?
• ¿Qué es una pila?
• ¿Qué es una cola?
2.2 TEMA 1 CONCEPTOS BÁSICOS Y LISTAS SIMPLEMENTE
LIGADAS
➢Video: ” Conceptos basicos de listas lineales”
➢” Ver Video”: https://www.youtube.com/watch?v=1sObs2NdjrY”
2.2.1 TEMA 1 PUNTEROS
Los punteros son direcciones de memoria que indica una posición de memoria dentro de la
RAM, son muy utilizados con cuando se trabaja con memoria dinámica.
Para representar el concepto de puntero se mostrará una lista.
Donde cada cuadro contiene dos campos, uno para el dato y otro para la liga. Técnicamente, cada
cuadro se denomina nodo, donde cada nodo posee una dirección de memoria.
40
Algoritmos II
Ejemplo: el primer cuadro tiene la dirección 1F, el segundo 2F y el tercero 3F.
2.2.2 CLASE NODOSIMPLE
Como nuestro objetivo es trabajar PROGRAMACIÓN ORIENTADA A OBJETOS, y para ello usamos
clases con sus respectivos métodos, comencemos definiendo la clase en la cual manipulamos el
nodo que acabamos de definir. A dicha clase la denominaremos nodoSimple:
1. CLASE nodoSimple
2. Privado
3. Objeto dato
4. nodoSimple liga
5. publico
6. nodoSimple() // constructor
7. objeto retornaDato()
8. nodoSimple retornaLiga()
9. void asignaDato(Objeto d)
10. void asignaLiga(nodoSimple x)
11. end(Clase nodoSimple)
Los algoritmos correspondientes a los métodos definidos son:
1. nodoSimple(objeto d) // constructor
2. dato = d
3. liga = null
4. end(nodoSimple)
1. objeto retornaDato()
2. return dato
3. end(retornaDato)
41
Algoritmos II
1. nodoSimple retornaLiga()
2. return liga
3. end(retornaLiga)
1. void asignaDato(objeto d)
2. dato = d
3. end(asignaDato)
1. void asignaLiga(nodoSimple x)
2. liga = x
3. end(asignaLiga)
Para usar esta clase consideremos el siguiente ejemplo:
1. nodoSimple x
2. d = 3.1416
3. x = new nodoSimple(d)
Al ejecutar la instrucción 3 el programa se comunica con el sistema operativo y este le asigna una
posición de memoria a nuestro programa, el cual identifica esta posición de memoria con la
variable x. el resultado obtenido es:
En el cual 19 es la dirección del nodo en la que se almacenan los campos de dato y liga. Dicha
dirección la suministra el sistema operativo de una forma transparente para el usuario.
Si queremos acceder los campos del nodo x, lo haremos así:
d = x.retornaDato() // d queda valiendo 3.1416
z = x. retornaLiga() // z queda valiendo nulo
42
Algoritmos II
A continuación, presentamos un ejemplo más completo de la utilización de la clase nodo Simple.
Supongamos que tenemos el conjunto de datos a, b, c, f y que se procesan con el siguiente
algoritmo:
1. nodoSimple x, y, z, p
2. read(d) // lee la letra “a”
3. x = new nodoSimple(d) // digamos que envió el nodo 4
4. read(d) // lee la letra “b”
5. y = new nodoSimple(d) // digamos que envió el nodo 8
6. read(d) // lee la letra “c”
7. z = new nodoSimple(d) // digamos que envió el nodo 3
El resultado grafico al ejecutar estas instrucciones es:
Ahora, si ejecutamos las instrucciones:
8. x.asignaLiga(y)
9. y.asignaLiga(z)
Los nodos quedaran conectados así:
Si ejecutamos las siguientes instrucciones:
10. read(d) // lee la letra “f”
11. y = new nodoSimple(d) // digamos que envió el nodo 7
Nuestros nodos quedan así:
43
Algoritmos II
Ahora, ejecutemos estas instrucciones:
12. p= x.retornaLiga()
13. write(p.retornaDato())
La variable p queda valiendo 8 y escribe la letra “b”.
Y si ejecutamos esta otra instrucción:
14. x.retornaLiga().asignaLiga(y)
Nuestros nodos quedan así:
Observe que cuando se ejecuta x.retornaLiga() se está obteniendo el contenido del campo de liga
del nodo x, el cual es el nodo 8 en nuestro ejemplo. Entonces. El nodo 8 invoca el método
asignaLiga() y le estamos enviando como parámetro el nodo y, que en este momento vale 7.
Podemos reorganizar el dibujo de nuestros nodos así:
Ahora, si ejecutamos las siguientes instrucciones:
15. y.asignaLiga(z)
16. y = null
17. z = null
18. p = x
44
Algoritmos II
Nuestra lista queda así:
Y ahora ejecutemos estas instrucciones:
19. while (p != null) do
20. write(p.retornaDato())
21. p = p.retornaLiga()
22. end(while)
En la instrucción 20, la primera vez que entra al ciclo escribe la letra “a”, puesto que p vale 4. En
la instrucción 21 modifica el valor de p: a p le asigna lo que hay en el campo de liga del nodo 4,
es decir, 8. Nuestra lista está así:
La segunda vez que entra al ciclo escribe la letra “b” y la p queda valiendo 7. Nuestra lista está
así:
La tercera vez que entra al ciclo escribe la letra “f” y la p queda valiendo 3:
45
Algoritmos II
La cuarta vez que entra al ciclo escribe la letra “c” y la p queda valiendo null; por consiguiente,
termina el ciclo. Este ciclo, instrucciones 19 a 22, tiene orden de magnitud O(n), siendo n el
número de nodos de la lista.
Ahora, si por último ejecutamos estas instrucciones:
23. x.asignaLiga(x.retornaLiga().retornaLiga())
La lista queda así:
Observe que no hemos dibujado el nodo 8 ya que no está conectado con los otros, pues se ha
desconectado de la lista con la instrucción 23. Lo que hace la instrucción 23 se puede escribir
también con las siguientes instrucciones:
23a. y = x.retornaLiga()
23b. x.asignaLiga(y.retornaLiga())
o
23a. y = x.retornaLiga()
23b. y = y.retorna.Liga()
23c. x.asignaLiga(y)
2.2.3 LISTAS SIMPLEMENTE LIGADAS
Las listas simplemente ligadas son estructuras donde se maneja la información de forma
dinámica, donde el espacio donde se la guarda la información es un nodo, donde este se
subdivide en dos espacios un espacio para guardar la información y otro para guardar la dirección
de memoria al siguiente nodo, con estas listas se pueden realizar las operaciones de insertar,
ordenar, buscar, borrar y todo esto bajo el concepto de memoria dinámica.
Es supremamente importante que entienda bien este ejemplo de aplicación de la
clase nodoSimple.
46
Algoritmos II
2.2.3.1 CLASE LISTAS SIMPLEMENTE LIGADA
Es un conjunto de nodos conectados cuyo elemento básico son objetos de la clase nodoSimple.
Con el fin de poder operar sobre este conjunto de nodos es necesario conocer el primer nodo del
conjunto de nodos que están conectados, y en muchas situaciones el último nodo del conjunto.
Con base en esto vamos a definir la clase llamada LSL (lista simplemente ligada), la cual tendrá
dos datos privados de la clase nodoSimple, que llamaremos primero y último: primero apuntara
hacia el primer nodo de la lista y último apuntará hacia el último nodo de la lista. Además,
definiremos las operaciones que podremos efectuar sobre objetos de dicha clase.
1. CLASE LSL
2. Privado
3. nodoSimple primero, ultimo
4. Publico
5. LSL() // constructor
6. boolean esVacia()
7. nodoSimple primerNodo()
8. nodoSimple ultimoNodo()
9. nodoSimple anterior(nodoSimple x)
10. boolean finDeRecorrido(nodoSimple x)
11. void recorre()
12. nodoSimple buscaDondeInsertar(Objeto d)
13. void insertar(Objeto d, nodoSimple y)
14. void conectar(nodoSimple x, nodoSimple y)
15. nodoSimple buscarDato(Objeto d, nodoSimple y)
16. void borrar(nodoSimple x, nodoSimple y)
17. void desconectar(nodoSimple x, nodoSimple y)
18. void ordenaAscendentemente()
19. end(Clase)
47
Algoritmos II
Expliquemos brevemente cada uno de los métodos definidos. Comencemos con el constructor:
cuando se ejecuta el constructor lo único que se hace es crear una nueva instancia de la clase LSL
con sus correspondientes datos privados en null. Ejemplo: si tenemos estas instrucciones:
1. LSL a, b
2. a = new LSL()
3. b = new LSL()
Lo que se obtiene es:
Para explicar que es lo que hace cada uno de los métodos definidos en la clase LSL consideremos
el siguiente objeto, perteneciente a la clase LSL y que llamamos a:
La función esVacia() retorna verdadero si la lista que invoca el método está vacía; de lo contrario,
retorna falso. Una lista está vacía cuando la variable primero es null.
La función primerNodo() retorna el nodo que esta de primero en la lista. Si efectuamos la
instrucción p = a.primerNodo(), entonces p quedara valiendo 4.
La función ultimoNodo(), retorna el nodo que esta de ultimo en la lista. Si ejecutamos la
instrucción p = a.ultimoNodo(), entonces p quedara valiendo 5.
La función finDeRecorrido(p) retorna verdadero si el nodo p enviado como parámetro es null; de
lo contrario, retorna falso.
48
Algoritmos II
La función anterior(x) retorna el nodo anterior al nodo enviado como parámetro. Si tenemos que
x = 7 y ejecutamos la instrucción p = a.anterior(x), entonces p quedara valiendo 8.
El método recorre(), como su nombre lo dice, simplemente recorre y escribe los datos de una
lista simplemente ligada. Si ejecutamos la instrucción a.recorre(), el resultado que se obtiene es
la escritura de b, e, i, o, u.
La función buscaDondeInsertar(d) retorna el nodo a continuación del cual se debe insertar un
nuevo nodo con dato d en una lista simplemente ligada en la que los datos están ordenados
ascendentemente y deben continuar cumpliendo esta característica después de insertarlo.
Presentemos algunos ejemplos:
y = a.buscaDondeInsertar(“f”) entonces y queda valiendo 8.
y = a.buscaDondeInsertar(“z”) entonces y queda valiendo 5.
y = a.buscaDondeInsertar(“a”) entonces y queda valiendo null.
El método insertar(d, y) consigue un nuevo nodoSimple, lo carga con el dato d e invoca el método
conectar con el fin de conectar el nuevo nodo (llamémoslo x) a continuación del nodo y. Si
ejecutamos las siguientes instrucciones:
d = “f”
y = a.buscaDondeInsertar(d)
a.insertar(d, y)
El objeto a, quedara así:
El método conectar simplemente conecta el nodo x a continuación del nodo y, tal como se ve en
la figura anterior.
La función buscarDato(d, y), como su nombre lo dice, busca el dato d en la lista invoca el método:
si lo encuentra, retorna el nodo en el cual lo encontró; de lo contrario, retorna null. En el
49
Algoritmos II
parámetro y, el cual debe ser un parámetro por referencia, retorna el nodo anterior al nodo en
el cual encontró el dato d. algunos ejemplos son:
x = a.buscarDato(“f”, y) entonces x queda valiendo 9 y y queda valiendo 8.
x = a.buscarDato(“u”, y) entonces x queda valiendo 5 y y queda valiendo 3.
x = a.buscarDato(“b”, y) entonces x queda valiendo 4 y y queda valiendo null.
x = a.buscarDato(“m”, y) entonces x queda valiendo null y y queda valiendo último, es
decir 5.
El método borrar(x, y) controla que el parámetro x sea diferente de null: si x es null produce el
mensaje de que el dato d (el dato buscado con el método buscarDato) no se halla en la lista y
retorna; si x es diferente de null, invoca el método desconectar(x, y).
El método desconectar(x, y) simplemente desconecta el nodo x de la lista que invoca el método.
Para desconectar un nodo de una lista se necesita conocer cuál es el nodo anterior. Por lo tanto,
el nodo y, el segundo parámetro, es el nodo anterior a x. si ejecutamos las siguientes
instrucciones:
d = “i”
x = a. buscarDato(d, y) // x queda valiendo 7 y y queda valiendo 9
a.borrar(x, y) // desconecta el nodo x
Esta queda así:
El método ordenaAscendentemente(), como su nombre lo dice, reorganiza los nodos de una lista
simplemente ligada, de tal manera que los datos en ella queden ordenados ascendentemente.
50
Algoritmos II
Si tenemos la siguiente lista:
Y ejecutamos la instrucción a.ordenaAscendentemente(), la lista quedara así:
Observe que los datos no se han movido, son los nodos los que han cambiado de posición y por
consiguiente primero y último han variado.
Asegúrese de entender bien que es lo que hace cada método. Si usted conoce bien lo que hace
cada método, podrá usarlos apropiadamente; de lo contrario, no.
2.2.3.2 IMPLEMENTACIÓN DE LOS MÉTODOS DE LA CLASE LISTA SIMPLEMENTE
LIGADA
El constructor:
LSL()
Primero = ultimo = null
end(LSL)
Simplemente inicializa los datos privados primero y último en null.
Como ingeniero de sistemas, debe saber cómo usar los métodos de una clase y
además como implementarlos.
51
Algoritmos II
Boolean esVacia()
Return primero == null
end(esVacia)
Recuerde que tanto C como en java la instalación
return x == y
Es equivalente a:
if (x == y)
return true
else
return false
nodoSimple primerNodo()
return primero
end(primero)
nodoSimple ultimoNodo()
return ultimo
end(ultimo)
boolean finDeRecorrido(nodoSimple x)
return x == null
end(finDeRecorrido)
1. void recorre()
2. nodoSimple p
3. p = primerNodo()
4. while no finDeRecorrido(p) do
52
Algoritmos II
5. Write(p.retornaDato())
6. p = p.retornaLiga()
7. end(while)
8. end(Método)
Para recorrer y escribir los datos de una lista simplemente ligada se requiere una variable
auxiliar, la cual llamamos p. dicha variable se inicializa con el primer nodo de la lista simplemente
ligada(instrucción 3 del método anterior) y luego planteamos un ciclo (instrucciones 4 a 7), el cual
se ejecuta mientras p sea diferente a null (método finDeRecorrido()). Cuando p sea null se sale
del ciclo y termina la tarea.
Simplemente no escribe nada. Es decir, la instrucción 4 se controlan dos situaciones: lista vacía y
fin de recorrido.
2.2.3.3 PROCESO DE INSERCIÓN DE UN DATO EN UNA LISTA SIMPLEMENTE
LIGADA
Para insertar un dato d en una lista ligada hemos definido tres métodos en nuestra clase LSL:
buscarDondeInsertar(d), insertar(d, y) y conectar(x, y). Analicemos cada uno de ellos. Es
importante recordar que en este proceso de inserción se requiere que los datos de la lista se
hallen ordenados en forma ascendente.
Consideremos la siguiente lista y que se desea insertar el dato “g”. Lo primero que se debe hacer
es determinar en qué sitio debe quedar la letra “g” para que se cumpla que los datos continúen
ordenados en forma ascendente. Por observación, nos damos cuenta de que la “g” debe quedar
entre la “f” y la “o”, es decir, a continuación del nodo 9.
Observe que, si por alguna razón el objeto que invoca este método tiene la lista
vacía, nuestro método funciona correctamente.
53
Algoritmos II
Nuestro primer método, buscaDondeInsertar(d), efectúa la tarea que determina a continuación
de cual nodo debe quedar el dato a insertar. El método para esta tarea es:
1. nodoSimple buscaDondeInsertar(Objeto d)
2. nodoSimple p, y
3. p = primerNodo()
4. y = anterior(p)
5. while (no finDeRecorrido(p) and p.retornaDato() < d) do
6. y = p
7. p = p.retornaLiga()
8. end(while)
9. return y
10. end(buscaDondeInsertar)
En este método se requieren dos variables auxiliares, las cuales llamamos p y y. con la variable
p se recorre y a medida que la vamos recorriendo se va comparando el dato de p (p.retornaDato())
con el dato d que se desea insertar. Mientras que el dato de p sea menor que d se avanza en la
lista con p y con y. la variable y siempre estará apuntando hacia a p. como inicialmente p es el
primer nodo, inicialmente y es null. Fíjese que si el dato d a insertar es menor que el dato del
primer nodo de la lista simplemente ligada nuestro método retorna null. El hecho de que nuestro
método retorne null significa que el dato a insertar va a quedar de primero en la lista.
Veamos ahora como es el algoritmo para nuestro método Insertar(d, y):
1. void insertar(Objeto d, nodoSimple y)
2. nodoSimple x
3. x = nodoSimple(d)
4. conectar(x, y)
5. end(Método)
Nuestro método insertar consigue simplemente un nuevo nodo, lo carga con el dato d e invoca
el método conectar. El parámetro y se refiere al nodo a continuación del cual habrá que conectar
el nuevo x.
Ocupémonos del método conectar(x, y):
• Caso 1:
Al ejecutar y = buscaDondeInsertar(d) con d = “g” en el objeto de la figura anterior y el método
insertar(d, y), estamos en la situación mostrada en la figura siguiente:
54
Algoritmos II
Conectar el nodo x a continuación del nodo y implica que cuando lleguemos al nodo y
debemos trasladarlo hacia el nodo x, o sea que el campo de liga del nodo y debe quedar
valiendo 6, y cuando estemos en el nodo x debemos trasladarnos hacia el nodo 3, es decir,
que el campo liga del nodo x debe quedar valiendo 3. O sea que, hay que modificar dos
campos de liga: el campo de liga del nodo y y el campo de liga del nodo x. para lograr esto
debemos ejecutar las siguientes instrucciones:
x.asignaLiga(y.retornaLiga()) // modifica el campo de liga del nodo x
y.asignaLiga(x) // modifica el campo de liga del nodo y
Y la lista queda así:
Y como se podrá observar, se ha insertado el nodo x a continuación del nodo y
• Caso 2:
Consideremos que el dato a insertar es d = “z”. Al ejecutar y=buscaDondeInsertar(d), y el
método insertar(d, y), estamos en la siguiente situación:
55
Algoritmos II
Conectar x a continuación de y se logra con las mismas instrucciones del caso 1, teniendo en
cuenta que como el dato que se inserta queda de ultimo hay que actualizar la variable último.
Lo anterior significa que las instrucciones para conectar x a continuación de y serán:
x.asignaLiga(y.retornaLiga()) // modifica el campo de liga del nodo x
y.asignaLiga(x) // modifica el campo de liga del nodo y
if (y == ultimo) then
ultimo = x
end(if)
Y la lista queda así:
• Caso 3:
Consideremos que el dato a insertar es d = “a”. al ejecutar y=buscaDondeInsertar(d) y el
método insertar(d, y), estamos en la situación mostrada:
56
Algoritmos II
En esta situación, cuando la y es null, es decir que el dato a insertar quedara de primero, hay
que modificar el campo de la liga x y la variable primero:
x.asignaLiga(primero)
primero = x
Pero hay que tener en cuenta que la lista pudo haber estado vacía. Si esa fuera la situación
habría que actualizar también la variable última. Considerando estas situaciones, las
instrucciones completas para conectar un nodo x al principio de la lista son:
x.asignaLiga(primero)
if (primero == null) then
ultimo = null
end(if)
primero = x
El algoritmo completo para el método conectar consiste simplemente en agrupar las
instrucciones descritas para cada uno de los casos en un solo método. Dicho método se
presenta a continuación: en las instrucciones 2 a 7 se consideran los casos 1 y 2, mientras que
en las instrucciones 9 a 13 se considera el caso 3:
1. void conectar(nodoSimple x, nodoSimple y)
2. if (y != null) then
3. x.asignaLiga(y.retornaLiga())
4. y.asignaLiga(x)
5. if (y == ultimo) then
6. ultimo = x
7. end(if)
8. Else
9. x.asignaLiga(primero)
10. if (primero == null) then
11. ultimo = x
12. end(if)
13. primero = x
14. end(if)
15. end(Método)
57
Algoritmos II
2.2.3.4 PROCESO DE BORRADO DE UN DATO EN UNA LISTA SIMPLEMENTE LIGADA
Borrar un dato de una lista simplemente ligada consiste en ubicar el nodo en el cual se halla el
dato y desconectarlo de lista. Para ello hemos definido tres métodos que hemos llamado
buscarDato(d, y), borrar(x, y) y desconectarlo(x, y).
Si tenemos la siguiente lista:
Y queremos borrar el nodo que contiene la letra “f”, lo primero que debemos hacer es determinar
en cual nodo se halla la letra “f” y cuál es su nodo anterior. Esta tarea se efectúa con el método
buscarDato(d, y): ejecutamos la instrucción
x = a.buscarDato(d, y)
Y estamos en esta situación:
El algoritmo correspondiente al método buscarDato(d, y) es similar al método
buscarDondeInsertar(d) y lo presentamos a continuación.
1. nodoSimple buscarDato(Objeto d, nodoSimple y)
2. nodoSimple x
3. x = primerNodo()
4. y = anterior(x)
5. while (no finDeRecorrido(x) and x.retornaDato()) != d do
6. y = x
7. x = x.retornaLiga()
8. end(while)
58
Algoritmos II
9. return x
10. end(buscarDato)
Utilizamos la variable x para recorrer la lista e ir comparando el dato del nodo x con d. de este
ciclo, instrucciones 5 a 8, se sale cuando encuentre o cuando haya terminado de recorrer la lista.
Observe que cuando el dato que se busca no se halla en la lista el parámetro y queda valiendo
último. Además, cuando el dato que se busca es el primer dato de la lista, la variable y queda
valiendo null.
Nuestro método borrar(x, y) consiste simplemente en controlar que el nodo x sea diferente de
null. Si el nodo x es null significa que el dato no se encontró en la lista; por consiguiente no hay
ningún nodo para desconectar, entonces produce el mensaje correspondiente y retorna al
programa llamante puesto que no hay nada más que hacer. Si x es diferente de null se invoca el
método desconectar. El algoritmo correspondiente a dicho método se presenta a continuación:
void borrar(nodoSimple x, nodoSimple y)
if x == null then
write(“dato no existe”)
return
end(if)
desconectar(x, y)
end(Método)
Analicemos ahora las instrucciones correspondientes al método desconectar (x, y).
• Caso 1:
Es la situación mostrada en la figura anterior. Lo único que hay que hacer para desconectar el
nodo x es modificar el campo de liga del nodo y, asignándole lo que hay en el campo liga del
nodo x. esto se logra con la siguiente instrucción:
y.asignaLiga(x.retornaLiga())
59
Algoritmos II
• Caso 2:
Si el dato a borrar es d = “z”, al ejecutar la instrucción
x = a.buscarDato(d, y)
La situación es:
Por consiguiente, cuando se desconecte el nodo x la variable última debe quedar valiendo y y
las instrucciones serán:
y.asignaLiga(x.retornaLiga())
if (x == ultimo) then
ultimo = y
end(if)
• Caso 3:
Si el dato a borrar es d = “b” al ejecutar la instrucción
x = a.buscarDato(d, y)
La situación es:
Con la variable y valiendo null.
En esta situación lo que hay que hacer es actualizar la variable primero: a primero se le asigna
lo que haya en el campo de liga primero. Hay que tener en cuenta que puede suceder que la lista
solo hubiera tenido un nodo; en este caso la variable primero quedará valiendo null, y por lo tanto
60
Algoritmos II
la variable ultimo también deberá quedar valiendo null. Las instrucciones para resolver este caso
son:
primero = primero.retornaLiga()
if (primero == null) then
ultimo = null
end(if)
Agrupando las instrucciones correspondientes a los tres casos en un solo algoritmo obtenemos:
1. void desconectar (nodoSimple x, nodoSimple y)
2. if (x != primero) then
3. y.asignaLiga(x.retornaLiga())
4. if (x == ultimo) then
5. ultimo = y
6. end(if)
7. else
8. primero = primero.retornaLiga()
9. if (primero == null) then
10. ultimo = null
11. end(if)
12. end(if)
13. end(Método)
En las instrucciones 2 a 6 se resuelve para los casos 1 y 2, mientras que en las instrucciones 8 a 11
se resuelve para el caso 3.
Los métodos para conectar y desconectar son métodos con orden de magnitud 0(1), lo cual
mejora sustancialmente estas operaciones con respecto a la representación de datos en un
vector.
61
Algoritmos II
2.2.3.5 ORDENAMIENTO DE DATOS EN UNA LISTA SIMPLEMENTE LIGADA
Presentemos a continuación un método que utiliza el método selección, el cual, se enuncia así:
“de los datos que faltan por ordenar, determine cuál es el menor y colocarlo de primero en ese
conjunto de datos”.
1. void OrdenaAscendentemente()
2. nodoSimple p, ap, menor, amenor, q, aq
3. p = primerNodo()
4. ap = anterior(p)
5. while (p != ultimoNodo())
6. menor = p
7. amenor = ap
8. q = p.retornaLiga
9. aq =p
10. while (no finDeRecorrido(q))
11. if (q.retornaDato() < menor.retornaDato())
12. menor = q
13. amenor = aq
14. end(if)
15. aq =q
16. q = q.retornaLiga()
17. end(while)
18. if(menor == p)
19. ap = p
20. p = p.retornaLiga()
21. else
22. desconectar(menor, amenor)
23. conectar(menor, ap)
24. ap = menor
25. end(if)
26. end(while)
27. end(Método)
Con base en este enunciado definimos las variables necesarias para elaborar el método. Se
requiere una variable que indique a partir de cual nodo faltan datos por ordenar. Dicha variable
la llamamos p. inicialmente p apunta hacia el primer nodo ya que al principio faltan todos los
datos por ordenar. Se requiere otra variable para recorrer la lista e ir comparando los datos para
62
Algoritmos II
determinar en cual nodo se halla el menor dato. Esta variable la llamamos q. y por último
requerimos otra variable que apunte hacia el nodo que tiene el menor dato. Esta variable la
llamamos menor.
Como ya hemos visto, para efectuar las operaciones de conexión y desconexión se requiere
conocer los registros anteriores a los nodos con los cuales se desean ejecutar dichas
operaciones; por lo tanto, definimos otras tres variables que llamaremos ap, aq y amenor, las
cuales apuntan hacia los nodos anteriores a p, q y menor respectivamente.
En la instrucción 5 definimos el ciclo principal del ciclo. El método terminara cuando p este
apuntando hacia el último nodo de la lista, puesto que cuando p este apuntando hacia ese nodo
significa que solo falta un dato por ordenar, y un solo dato esta ordenado.
En las instrucciones 6 y 7 asignamos los valores iniciales de menor y amenor. Inicialmente
consideramos que el menor dato es el principio del conjunto de datos que faltan por ordenar, es
decir, p.
En las instrucciones 8 y 9 se asignan los valores iniciales de q y aq.
En las instrucciones 10 a 17 se efectúa el ciclo para determinar cuál es el nodo que contiene el
menor dato. Se compara el dato de nodo q con el dato del nodo menor. Si el dato de q es menor
que el dato de menor, actualizaremos menor y su interior. Cualquiera que hubiera sido el
resultado avanzamos con q y su anterior.
En la instrucción 18 confrontamos en cual posición está el nodo de tiene el menor dato. Si el
menor dato estaba de primero en ese conjunto de datos, es decir, en p, simplemente avanzamos
con p y su anterior (instrucciones 19 y 20); de lo contrario, desconectamos el nodo menor, cuyo
anterior es amenor, y lo conectamos a continuación de ap (instrucciones 22 y 23). De haber
ocurrido esto último, el anterior a p, es decir ap, ya es menor (instrucción 24).
Nuestro método consistirá entonces en determinar cuál es el nodo que tiene el
menor dato entre los datos que faltan por ordenar; desconectamos el nodo de ese
sitio y lo conectamos al principio de ese conjunto de datos.
63
Algoritmos II
2.2.3.6 MÉTODO ANTERIOR(X)
Ya hemos definido que nuestro método denominado anterior(x) retornara el nodo anterior al
nodo x enviado como parámetro. Para ello bastara con recorrer la lista simplemente ligada
utilizando dos variables auxiliares: una (llamémosla p) que se va comparando con x, y otra que
siempre apuntara hacia el nodo anterior a x (llamémosla y). cuando p sea igual a x, simplemente
se retorna y. inicialmente será el primer nodo y y será null. Nuestro método es el siguiente:
nodoSimple anterior(x)
nodoSimple p, y
p = primerNodo()
y = null
while (p != x) do
y = p
p = p.retornaLiga()
end(while)
return y
end(anterior)
2.2.3.7 CONSTRUCCIÓN DE LISTAS SIMPLEMENTE LIGADAS
Pasemos ahora a considerar como construir listas simplemente ligadas. Básicamente hay tres
formas de hacerlo: una, que los datos queden ordenados ascendentemente a medida que la lista
se va construyendo; otra, insertando nodos siempre al final de la lista; y una tercera, insertando
los nodos siempre al principio de la lista.
Para la primera forma de construcción (que los datos queden ordenados ascendentemente a
medida que se va construyendo la lista), un método general es:
LSL a
a = new LSL()
64
Algoritmos II
Mientras haya datos por leer haga
Lea(d)
y = a.buscaDondeInsertar(d)
a.insertar(d, y)
end(mientras)
Es decir, basta con plantear un ciclo para la lectura de datos e invocar los métodos para buscar
donde insertar e insertar desarrollados previamente.
Para la segunda forma de construcción (insertando nodos siempre al final de la lista), un método
es:
LSL a
nodoSimple
a = new LSL()
mientras haya datos por leer haga
lead(d)
y = a.ultimoNodo()
a.insertar(d, y)
end(mientras)
Nuevamente se plantea un ciclo para la lectura de datos y cada vez que se lea un dato se
determina el último y se invoca el método para insertar.
2.2.4 DIFERENTES TIPOS DE LISTAS SIMPLEMENTE LIGADAS Y SUS
CARACTERÍSTICAS
Comencemos presentando gráficamente los diferentes tipos de lista que se pueden construir:
• Listas simplemente ligadas:
65
Algoritmos II
• Listas simplemente ligadas circulares:
• Listas simplemente ligadas circulares con nodo cabeza:
• Listas simplemente ligadas con nodo cabeza:
2.2.5 EJERCICIO DE APRENDIZAJE
En cada tema anterior se muestra los ejercicios de aprendizaje.
2.2.6 TALLER DE ENTRENAMIENTO
Esta es la tercera forma de construcción de lista (insertando nodos siempre al principio de la lista),
nuestro método es:
66
Algoritmos II
LSL a
a = new LSL
Mientras haya datos por leer haga
lead(d)
a.insertar(d, null)
end(mientras)
Aquí, basta con plantear el ciclo para lectura de datos e invocar el método insertar enviado como
segundo parámetro null. Recuerde que nuestro método insertar(d, y) inserta un nodo con dato d
a continuación de y: si y es null significa que el dato d quedara de primero.
2.3 TEMA 2 LISTAS DOBLEMENTE LIGADAS Y OTROS TIPOS DE
TOPOLOGÍAS DE LISTAS
➢Video: ” Lista Doblemente Ligada”
➢” Ver Video”:
https://www.youtube.com/watch?v=6C8_tKeGp6I&ab_channel=EdwinGonz%C3%A1lezTer%C3
%A1n ”
2.3.1 LISTA DOBLEMENTE LIGADAS
Las listas doblemente ligadas son estructuras que permiten manejar la información de forma
dinámica, donde el espacio donde se guarda la información es un nodo, que es una dirección de
memoria dividida en tres partes, una parte para guardar la información, otra para la dirección al
Nota: realice una prueba de escritorio para que visualice el proceso.
TIPS
El manejo dinámico de la memoria nos permite optimizar este recurso.
67
Algoritmos II
siguiente nodo y la otra para apuntar al nodo anterior, con estas listas se pueden realizar las
operaciones de insertar, borrar, buscar, ordenar y todo bajo el concepto de memoria dinámica.
2.3.1.1 DEFINICIÓN DE CARACTERÍSTICAS
Un nodo doble es un registro que tiene dos campos de liga: uno que llamaremos Li (Liga izquierda)
y otro que llamaremos Ld (Liga derecha). Un dibujo para representar dicho nodo es:
Liga izquierda Área de datos Liga derecha
Donde:
Li: apunta hacia el nodo anterior.
Ld: apunta hacia el nodo siguiente.
Con base en esto vamos a definir una clase que llamaremos nodoDoble:
1. CLASE nodoDoble
2. Privado
3. Objeto dato
4. nodoDoble Li, Ld
5. publico
6. nodoDoble(objeto d) // constructor
7. void asignaDato(objeto d)
8. void asignaLd(nodoDoble x)
9. void asignaLi(nodoDoble x)
10. objeto retornaDato()
11. nodoDoble retornaLd()
12. nodoDoble retornaLi()
13. end(Clase)
68
Algoritmos II
Los algoritmos correspondientes a cada uno de estos métodos son los siguientes:
1. nodoDoble(objeto d) // constructor
2. dato = d
3. Ld = null
4. Li = null
5. end(nodoDoble)
1. void asignaDato(objeto d)
2. dato = d
3. end(Método)
1. void asignaLd(nodoDoble x)
2. Ld = x
3. end(asignaLd)
1. void asignaLi(nodoDoble x)
2. Li = x
3. end(asignaLi)
1. objeto retornaDato()
2. return dato
3. end(retornaDato)
1. nodoDoble retorna(Li)
2. return Li
69
Algoritmos II
3. end(retornaLi)
1. nodoDoble Ld()
2. return Ld
3. end(retornaLd)
2.3.1.2 PROPIEDAD FUNDAMENTAL DE LAS LISTAS DOBLEMENTE LIGADAS
Es importante ver aquí lo que se conoce como la propiedad fundamental de las listas
doblemente ligadas ya que está basada en las características de los campos de liga de los nodos
dobles. Para ello, consideremos los siguientes tres registros consecutivos:
El campo de la liga izquierda del nodo x vale 9, lo cual indica que el nodo anterior es el nodo 9;
por lo tanto, el nodo 9 es el nodo x.retornaLi().
El campo de liga derecha del nodo x vale 5, lo cual indica que el nodo siguiente es el nodo 5; por
consiguiente, el nodo 5 es el nodo x.retornaLd().
El nodo x.retornaLi() tiene un campo de liga derecha, el cual vale 7, es decir, el mismo nodo x.
El nodo x.retornaLd() tiene un campo de liga izquierda, el cual también vale 7, es decir, el nodo
x.
Dado lo anterior, se tiene que:
x.retornaLi().retornaLd() == x == x.retornaLd().retornaLi()
Esta característica se conoce como la “propiedad fundamental de las listas doblemente ligadas”,
y es de suprema importancia entenderla bien con el fin de manipular apropiadamente los objetos
de la clase lista doblemente ligada.
70
Algoritmos II
2.3.2 EJERCICIO DE APRENDIZAJE
Teniendo definida esta clase (clase doble), procedemos a desarrollar un método en el cual
hagamos uso de ella y de sus métodos. Consideremos que se tiene el conjunto de datos b, e, i,
o, u, y que nuestro método los leerá en ese orden:
1. nodoDoble w, x, y, z
2. read(d)
3. w = new nodoDoble(d)
4. read(d)
5. x = new nodoDoble(d)
6. read(d)
7. y = new nodoDoble(d)
8. read(d)
9. z = new nodoDoble(d)
Al ejecutar estas instrucciones el escenario que se obtiene es el siguiente:
Continuemos nuestro algoritmo con estas instrucciones:
10. w.asignaLd(x)
11. x.asignaLi(w)
12. x.asignaLd(y)
13. y.asignaLi(x)
14. y.asignaLd(z)
15. z.asignaLi(y)
Al ejecutar estas instrucciones nuestro escenario es:
Fíjese que el campo Ld del nodo w quedo valiendo 2, en virtud de la instrucción 10, lo cual indica
que el nodo siguiente a w es el 2; el campo Li de x (el nodo 2) quedo valiendo 6, en virtud de la
instrucción 11, lo cual significa que el nodo anterior a x es el 6; el campo Ld del nodo x quedo
71
Algoritmos II
valiendo 7, en virtud de la instrucción 12, lo cual quiere decir que el nodo siguiente a x es el 7. De
una forma similar se han actualizado los campos Li y Ld de los nodos y y z. Asegúrese de entender
bien el escenario actual.
Continuemos ejecutando las siguientes instrucciones:
16. w = null
17. y = null
18. z = null
En este momento nuestra situación es:
Ahora ejecutemos estas otras instrucciones:
19. read(d)
20. y = new nodoDoble(d)
21. y.asignaLd(x.retornaLd())
22. y.asignaLi(x)
23. y.retornaLd().asignaLi(y)
24. x.asignaLd(y)
La situación queda así:
Ahora, al ejecutar esta instrucción:
25. y = null
La nueva situación es:
Por último, ejecutemos estas otras instrucciones:
72
Algoritmos II
26. x.retornaLi().asignaLd(x.retornaLd())
27. x.retornaLd().asignaLi(x.retornaLi())
Y nuestros nodos quedan así:
Fíjese que el resultado de ejecutar las instrucciones 26 y 27 fue eliminar el nodo x. unas de
instrucciones que harían la misma tarea que las instrucciones 26 y 27 son:
1. p = x.retornaLi()
2. q = x.retornaLd()
3. p.asignaLd(q)
4. q.asignaLi(p)
Si lo hubiéramos hecho de ese modo, la lista quedaría así:
Es muy importante entender que las instrucciones 26 y 27 ejecutan la misma tarea que las
instrucciones 1, 2, 3 y 4 mostradas a continuación de ellas.
2.3.3 TALLER DE ENTRENAMIENTO
Pautas para desarrollar los siguientes ejercicios: Para desarrollar cada uno de esos ejercicios,
debes tener muy claro el concepto de nodo y la forma de cómo vas a estructurar el nodo.
Recuerda que, para listas simplemente ligadas el nodo se compone de dos partes, una parte de
datos y una parte de liga; para las listas doblemente ligadas el nodo se conforma de tres partes,
una parte de dato, y dos partes de ligas, una liga que apunta al nodo anterior y una liga que apunta
al nodo siguiente.
1. Elabore un método que lea un entero n y que construya una lista simplemente ligada, de a
digito por nodo.
2. Elabore un método que borre de una lista simplemente ligada un dato dado todas las veces
que lo encuentre.
73
Algoritmos II
3. Se tiene una lista simplemente ligada, con un dato numérico en cada nodo. Elabore un método
que determine e imprima el promedio de datos de la lista.
4. Elabore un método que intercambie los registros de una lista doblemente ligada así: el
primero con el último, el segundo con el penúltimo, el tercero con el antepenúltimo, y así
sucesivamente.
5. Elabore un método que intercambie los registros de una lista doblemente ligada así: el
primero con el tercero, el segundo con el cuarto, el quinto con el séptimo, el sexto con el
octavo, y así sucesivamente.
2.4 TEMA 3 PILAS Y COLAS (ESTÁTICAS Y DINÁMICAS)
➢Video: ” Manipulación de información. Pilas y colas”
➢” Ver Video”: https://www.youtube.com/watch?v=56jBvugTCn0 ”
2.4.1 RELACIÓN DE CONCEPTOS
➢ Pilas: Son estructuras de datos que se manejan de forma estática, donde se realiza las
operaciones de apilar y desapilar, manejando el concepto de último en llegar primero en
salir.
➢ Vector: En programación se denomina matriz, vector o formación (en inglés array) a una
zona de almacenamiento continuo que contiene una serie de elementos del mismo tipo,
los elementos de la matriz. Desde el punto de vista lógico una matriz se puede ver como
un conjunto de elementos ordenados en fila (o filas y columnas si tuviera dos
dimensiones).
Tomado de: https://es.wikipedia.org/wiki/Vector_(inform%C3%A1tica)
➢ Listas ligadas: Las listas ligadas son una mejor alternativa para añadir información a una
base de datos; en lugar de utilizar arreglos que son estáticos pues hay que reservar
TIPS
Las listas dobles permiten realizar recorridos de izquierda a derecha y de
derecha a izquierda.
74
Algoritmos II
memoria a la hora de programarlos, contrario a las listas ligadas que en un principio no
ocupan memoria y se va reservando (creando) conforme lo va requiriendo nuestro
programa. La memoria que ya no se utiliza se puede destruir y así ahorramos memoria en
nuestros programas.
Tomado de: http://sergioaj.blogspot.com.co/2011/01/listas-ligadas.html
➢ Crear: Crea una pila vacía.
➢ Apilar: Incluye el dato d en la pila.
➢ Desapilar: Elimina el último elemento de la pila y deja una nueva pila, la cual queda con
un elemento menos.
➢ Cima: Retorna el dato que esta de último en la pila, sin eliminarlo.
➢ esVacia: Retorna verdadero si la pila está vacía: de lo contrario; retorna falso.
➢ esLlena:Retorna verdadero si la pila está llena; de lo contrario; retorna falso.
➢ Cola: Son estructuras de almacenamiento de datos, donde se maneja de forma estática,
donde las operaciones de inserción se hace al final y las de borrado se hace al principio,
en otras palabras el primero que llega es el primero en salir, y el último en llegar será el
último en salir
➢ Crear: Crea una cola vacía.
➢ esVacia: Retorna verdadero si la cola está vacía; de lo contrario, retorna falso.
➢ esLlena: Retorna verdadero si la cola está llena; de lo contrario, retorna falso.
➢ Encolar: Inserta un dato d al final de la cola.
➢ Desencolar: Remueve el primer elemento de la cola.
➢ Siguiente: Retorna el dato que se halla de primero en la cola.
75
Algoritmos II
2.4.2 DEFINICIÓN
Son estructuras de datos que no tienen representación propia a nivel de programación, para ello
se apoyan en los vectores y en listas ligadas, permitiendo así manejar operaciones sobre ellas.
2.4.3 PILAS CON VECTORES Y LISTAS
Las pilas como vectores son estructuras de datos que se manejan de forma estática, donde se
realiza las operaciones de apilar y desapilar, manejando el concepto de último en llegar primero
en salir. Las pilas como lista son estructuras de datos, pero se maneja de forma dinámica en la
memoria.
2.4.3.1 DEFINICIÓN
Una pila es una lista ordenada en la cual todas las operaciones (inserción y borrado) se efectúan
en un solo extremo llamado tope. Es una estructura LIFO (Last Input First Output), que son las
iniciales de las palabras en inglés “ultimo en entrar primero en salir”, debido a que los datos
almacenados en ella se retiran en orden inverso al que fueron entrados.
Un ejemplo clásico de aplicación de pilas en computadores se representa en el proceso de
llamadas a métodos y sus retornos.
Supongamos que tenemos un programa principal y tres métodos, así:
Cuando se ejecuta el programa principal, se hace una llamada al método P1, es decir, ocurre una
interrupción en la ejecución del programa principal. Antes de iniciar la ejecución de este método
76
Algoritmos II
se guarda la dirección de la instrucción donde debe retornar a continuar la ejecución del
programa principal cuando termine de ejecutar el método; llamamos L1 esta dirección. Cuando
ejecuta el método P1 existe una llamada al método P2, hay una nueva interrupción, pero antes
de ejecutar P2 se guarda la dirección de la instrucción donde debe retornar a continuar la
ejecución del método P1, cuando termine de ejecutar el método P2; llamamos L2 esta dirección.
Hasta el momento hay guardados dos direcciones de retorno:
L1, L2
Cuando ejecuta el método P2 hay llamada a un método P3, lo cual implica una nueva interrupción
y, por ende, guardar una dirección de retorno al método P2, la cual llamamos L3.
Tenemos entonces tres direcciones guardadas, así:
L1, L2, L3
Al terminar la ejecución del método P3 retorna a continuar ejecutando en la última dirección que
guardo, es decir, extrae la dirección L3 y regresa a continuar ejecutando el método P2 en dicha
instrucción. Los datos guardados ya son:
L1, L2
Al terminar el método P2 extrae la última dirección que tiene guardada, en este caso L2, y retorna
a esta dirección a continuar la ejecución del método P1.
En este momento los datos guardados son:
L1
Al terminar la ejecución del método P1 retornara a la dirección que tiene guardada, o sea a L1.
Obsérvese que los datos fueron procesados en orden inverso al que fueron almacenados, es decir,
último en entrar primero en salir. En esta forma de procesamiento la que define una estructura
PILA.
Veamos cuales son las operaciones que definiremos para la clase pila.
Operaciones Características
77
Algoritmos II
Crear Crea una pila vacía.
Apilar Incluye el dato d en la pila.
Desapilar
Elimina el último elemento de la pila y deja una nueva pila, la cual queda con un
elemento menos.
Cima Retorna el dato que esta de último en la pila, sin eliminarlo.
esVacia Retorna verdadero si la pila está vacía: de lo contrario; retorna falso.
esLlena Retorna verdadero si la pila está llena; de lo contrario; retorna falso.
2.4.3.2 REPRESENTACIÓN DE PILAS EN UN VECTOR
La forma más simple es utilizar un arreglo de una dimensión y una variable, que llamaremos
tope, que indique la posición del arreglo en la cual se halla el último elemento de la pila. Por
consiguiente, vamos a definir la clase pila derivada de la clase vector. La variable m de nuestra
clase vector funciona coma la variable tope. Definamos entonces la clase pila.
1. CLASE Pila
2. Privado:
3. Object V[]
4. Entero tope, n
5. Publico:
6. pila(entero m) //constructor
7. boolean esVacia()
8. boolean esLlena()
9. void apilar(objeto d)
10. object desapilar()
78
Algoritmos II
11. void desapilar(entero i)
12. objeto tope()
13. end(Clase)
Como hemos definido la clase pila derivada de la clase vector, veamos como son los algoritmos
correspondientes a estos métodos:
1. pila(entero m) //constructor
2. V = new array[m]
3. n = m
4. Tope = 0
5. end(pila)
1. boolean esVacia()
2. return tope == 0
3. end(esVacia)
1. boolean esLlena()
2. return tope == n
3. end(esLlena)
1. void Apilar(objeto d)
2. if (esLlena()) then
3. write(“pila llena”)
4. return
79
Algoritmos II
5. end(if)
6. tope = tope + 1
7. V[tope] = d
8. end(Método)
Apilar consiste simplemente en sumarle 1 a tope y llevar el dato a esa posición del vector:
1. objeto desapilar()
2. if (esVacia()) then
3. write(“pila vacia”)
4. return null
5. end(if)
6. d = V[tope]
7. tope = tope -1
8. return d
9. end(desapilar)
Estrictamente hablando, desapilar consiste simplemente en eliminar el dato que se halla en el
tope de la pila. Sin embargo, es usual eliminarlo y retornarlo. Eso es lo que hace nuestro anterior
método para desapilar. El proceso de eliminación consiste simplemente en restarle 1 a tope.
Definamos, en forma polimórfica, otro método para desapilar. Este nuevo método tendrá un
parámetro i, el cual indicara cuantos elementos se deben eliminar de la pila:
1. void Desapilar(entero i )
2. if ((tope – 1) >= 0) then
3. tope = tope – i
80
Algoritmos II
4. else
5. write(“no se pueden eliminar tantos elementos”)
6. end(if)
7. end(Método)
1. Objeto cima()
2. if (esVacia()) then
3. write(“pila vacia”)
4. return null
5. end(if)
6. return V[tope]
7. end(cima)
2.4.3.3 REPRESENTACIÓN DE PILAS COMO LISTAS LIGADAS
Para representar una pila como listas ligadas basta definir la clase pila derivada de la clase LSL.
Nuevamente, como estamos definiendo la clase pila derivada de la clase. LSL, podremos hacer
uso de todos los métodos que hemos definido para esta clase LSL. A modo de ejemplo,
representemos como listas ligadas la siguiente pila:
D
C
B
A
81
Algoritmos II
Pila
Dibujémosla de la forma como solemos hacerlo con las listas ligadas:
Como hemos dicho las operaciones sobre una pila son apilar y desapilar:
• Apilar: consiste en insertar un registro al principio de una lista ligada.
• Desapilar: consiste en eliminar el primer nodo de la lista ligada y retornar el dato que se
hallaba en ese nodo.
Al definir la clase pila derivada de la clase LSL el método para controlar pila llena ya no se utiliza.
Los métodos para la clase pila son:
1. void Apilar(objeto d)
2. insertar(d, null)
3. end(Método)
1. Objeto desapilar()
2. If (esVacia()) then
3. Write(“pila vacia, no se puede desapilar”)
4. Return null
5. End(if)
6. nodoSimple p
7. p = primerNodo()
8. d = p.retornaDato()
9. borrar(p, null)
10. return d
82
Algoritmos II
11. end(desapilar)
Fíjese que en los métodos apilar y desapilar hemos usado los métodos insertar y borrar, los
cuales fueron definidos para la clase LSL:
1. Objeto tope()
2. if (esVacia()) then
3. write(“pila vacía, no hay elemento para mostrar”)
4. return null
5. end(if)
6. nodoSimple p
7. p = primerNodo()
8. return p.retornaDato
9. end(tope)
2.4.3.4 MANEJO DE DOS PILAS EN UN VECTOR
Puesto que es muy frecuente tener que manejar más de una pila en muchas situaciones, veremos
cómo manejar dos pilas en un solo vector. Si n es el número de elementos del vector, dividimos
inicialmente el vector en dos partes iguales. Llamamos m la variable que apunta hacia el elemento
de la mitad.
La primera mitad del vector será para manejar la pila 1, y la segunda mitad para manejar la pila
2.
Cada pila requiere una variable tope para conocer en qué posición está el ultimo dado de la pila.
Llamemos estas variables tope 1 y tope 2 para manejar las pilas 1 y 2, respectivamente.
Consideremos el siguiente ejemplo:
83
Algoritmos II
Sea V el vector en el cual manejaremos las dos pilas. El valor de n es 16. Inicialmente, el valor de
m es 8 (la mitad de n):
• La variable tope1 variara de 1 hasta m
• La variable tope2 variara desde m + 1 hasta n
• La pila 1 estará vacía cuando tope1 sea igual a 0
• La pila 1 estará llena cuando tope1 sea igual a m
• La pila 2 estará vacía cuando tope2 sea igual a m
• La pila 2 estará llena cuando tope2 sea igual a n
Si definimos una clase denominada dosPilas cuyos datos privados son el vector V, m, n, tope1 y
tope2, veamos cómo serán los métodos para manipular dicha clase.
Consideremos primero un método para apilar un dato en alguna de las dos pilas. Habrá que
especificar en cual pila es que se desea apilar. Para ello utilizaremos una variable llamada pila, la
cual enviamos como parámetro del método. Si pila es igual a 1 hay que apilar en pila 1, y si pila
es igual a 2, hay que apilar en pila 2. Nuestro método será:
1. void Apilar(entero pila, objeto d)
2. If (pila == 1) then
3. If (tope == m) then
4. pilaLlena(pila)
5. end(if)
6. tope1 = tope1 + 1
7. V[tope] = d
84
Algoritmos II
8. else
9. If (tope2 == n) then
10. pilaLlena(pila)
11. end(if)
12. tope2 = tope2 + 1
13. V[tope2] = d
14. end(if)
15. end(Método)
El método pilaLlena recibe como parámetro el valor pila.
La tarea de pilaLlena es: si el parámetro pila es 1 significa que la pila 1 es la que está llena, y por
lo tanto buscara espacio en la pila 2; en caso de que esta no esté llena, se moverán los datos de
la pila 2 una posición hacia la derecha, se actualizara m y se regresara al método apilar para apilar
en la pila 1. Si es la pila 2 la que está llena buscara si hay espacio en la pila 1, y en caso de haberlo
moverá los datos de la pila 2 una posición hacia la izquierda, actualizara m y regresara a apilar en
la pila 2. Un método que efectué esta tarea es:
1. void PilaLlena(entero pila)
2. entero i
3. if (pila == 1) then
4. if (tope2 < n) then //hay espacio en la pila 2
5. for (i = tope2; i > m; i--) do
6. V[i + 1] =V[i]
7. end(for)
8. tope2 = tope2 + 1
9. m = m + 1
85
Algoritmos II
10. end(if)
11. else
12. if (tope1 < m) then
13. for (i = m; i < tope2; i++) do
14. V[i - 1] = V[i]
15. end(for)
16. tope2 = tope2 – 1
17. m = m – 1
18. end(if)
19. end(if)
20. write(“pilas llenas”)
21. stop
22. end(Método)
Como se podrá observar, la operación de apilar implica mover datos en el vector debido a que
una pila puede crecer más rápido que la otra. En otras palabras, este método tiene orden de
magnitud lineal, el cual se considera ineficiente. Una mejor alternativa de diseño es la siguiente:
La pila 1 se llenara de izquierda a derecha y la pila 2 de derecha a izquierda. Con este diseño no
hay que preocuparse por cual pila crezca más rápido. Las condiciones a controlar son:
• La pila 1 estará vacía cuanto tope1 sea igual a cero
• La pila 2 estará vacía cuando tope2 sea igual a n + 1 (n =16)
• Las pilas estarán llenas cuando tope1 + 1 sea igual a tope2
86
Algoritmos II
El método apilar para este segundo diseño es:
1. void Apilar(entero pila, objeto d)
2. if (tope1 + 1 == tope2) then
3. pilaLlena
4. end(if)
5. if (pila == 1) then
6. tope1 = tope1 + 1
7. V[tope] = d
8. end(if)
9. end(Método)
2.4.4 TEMA 3 COLAS CON VECTORES Y LISTAS
Las cola como vectores son estructuras de almacenamiento de datos, donde se maneja de forma
estática, donde las operaciones de inserción se hace al final y las de borrado se hace al principio,
en otras palabras el primero que llega es el primero en salir, y el último en llegar será el último en
salir, de igual forma se maneja con las listas pero de forma dinámica.
2.4.4.1 DEFINICIÓN
Una cola es una lista ordenada en la cual las operaciones de inserción se efectúan en un extremo
llamado último y las operaciones de borrado se efectúan en el otro extremo llamado primero. Es
una estructura FIFO (First Input First Output).
Como podrá observar, con este diseño el proceso para pila llena no aparece; por lo
tanto, no hay que mover los datos del vector y nuestro método para apilar tiene
orden de magnitud constante.
87
Algoritmos II
En términos prácticos, es lo que supuestamente se debe hacer para tomar un bus, para comprar
las boletas y entrar a cine o para hacer uso de un servicio público. Las operaciones sobre una cola
son:
Operaciones Características
Crear Crea una cola vacía.
esVacia() retorna verdadero si la cola está vacía; de lo contrario, retorna falso
esLlena() Retorna verdadero si la cola está llena; de lo contrario, retorna falso.
Encolar(d) Inserta un dato d al final de la cola.
Desencolar() Remueve el primer elemento de la cola
Siguiente() Retorna el dato que se halla de primero en la cola.
2.4.4.2 REPRESENTACIÓN DE COLAS EN UN VECTOR, EN FORMA NO CIRCULAR
Para representar colas en esta forma se requiere un vector, que llamaremos V, y dos variables:
una que llamaremos primero, la cual indica la posición del vector en la que se halla el primer dato
de la cola, y otra, que llamaremos último, que indica la posición en la cual se halla el último dato
de la cola.
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf
Algoritmos II_2020.pdf

Más contenido relacionado

Similar a Algoritmos II_2020.pdf

Manual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmosManual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmosJaro
 
FUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon Koudsi
FUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon KoudsiFUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon Koudsi
FUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon KoudsiRaimonKoudsi
 
Rc edinson mosquera
Rc edinson mosqueraRc edinson mosquera
Rc edinson mosqueraAlex Lozada
 
Rc edinson mosquera
Rc edinson mosqueraRc edinson mosquera
Rc edinson mosqueraed10mos891
 
EDINSON MOSQUERA
 EDINSON MOSQUERA EDINSON MOSQUERA
EDINSON MOSQUERAed10mos891
 
Rc edinson mosquera
Rc edinson mosqueraRc edinson mosquera
Rc edinson mosqueraed10mos891
 
Manual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmosManual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmosSpacetoshare
 
Jessika parica. Fundamentos y métodos de análisis de los requerimientos.
Jessika parica. Fundamentos y métodos de análisis de los requerimientos.Jessika parica. Fundamentos y métodos de análisis de los requerimientos.
Jessika parica. Fundamentos y métodos de análisis de los requerimientos.Jessika Parica
 
CENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOCENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOyuribel
 
CENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOCENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOyuribel
 
CENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOCENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOyuribel
 
Laboratorio práctico: La sazón del científico de datos
Laboratorio práctico: La sazón del científico de datosLaboratorio práctico: La sazón del científico de datos
Laboratorio práctico: La sazón del científico de datosSoftware Guru
 
Ordenación y búsqueda orientada a C++
Ordenación y búsqueda orientada a C++Ordenación y búsqueda orientada a C++
Ordenación y búsqueda orientada a C++Carlos Ureña
 

Similar a Algoritmos II_2020.pdf (20)

Manual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmosManual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmos
 
FUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon Koudsi
FUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon KoudsiFUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon Koudsi
FUNDAMENTOS Y MÉTODOS DE ANÁLISIS DE REQUERIMIENTOS Raimon Koudsi
 
Rc edinson mosquera
Rc edinson mosqueraRc edinson mosquera
Rc edinson mosquera
 
Rc edinson mosquera
Rc edinson mosqueraRc edinson mosquera
Rc edinson mosquera
 
EDINSON MOSQUERA
 EDINSON MOSQUERA EDINSON MOSQUERA
EDINSON MOSQUERA
 
Rc edinson mosquera
Rc edinson mosqueraRc edinson mosquera
Rc edinson mosquera
 
Manual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmosManual de análisis y diseño de algoritmos
Manual de análisis y diseño de algoritmos
 
Rcorlandorondon301305 17
Rcorlandorondon301305 17Rcorlandorondon301305 17
Rcorlandorondon301305 17
 
Modelado y metodologias para aplicaciones web
Modelado y metodologias para aplicaciones webModelado y metodologias para aplicaciones web
Modelado y metodologias para aplicaciones web
 
Jessika parica. Fundamentos y métodos de análisis de los requerimientos.
Jessika parica. Fundamentos y métodos de análisis de los requerimientos.Jessika parica. Fundamentos y métodos de análisis de los requerimientos.
Jessika parica. Fundamentos y métodos de análisis de los requerimientos.
 
8 resumen ppe 3
8  resumen ppe  38  resumen ppe  3
8 resumen ppe 3
 
Rc orlando rondon 301305-17
Rc orlando rondon 301305-17Rc orlando rondon 301305-17
Rc orlando rondon 301305-17
 
CENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOCENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICO
 
CENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOCENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICO
 
CENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICOCENTRO DE INNOVACIÓN TECNOLÓGICO
CENTRO DE INNOVACIÓN TECNOLÓGICO
 
Laboratorio práctico: La sazón del científico de datos
Laboratorio práctico: La sazón del científico de datosLaboratorio práctico: La sazón del científico de datos
Laboratorio práctico: La sazón del científico de datos
 
Ordenación y búsqueda orientada a C++
Ordenación y búsqueda orientada a C++Ordenación y búsqueda orientada a C++
Ordenación y búsqueda orientada a C++
 
Sistemas operativos 1
Sistemas operativos 1Sistemas operativos 1
Sistemas operativos 1
 
Tecnicas de modelado y metodologias para aplicaciones Web
Tecnicas de modelado y metodologias para aplicaciones WebTecnicas de modelado y metodologias para aplicaciones Web
Tecnicas de modelado y metodologias para aplicaciones Web
 
Infografia
InfografiaInfografia
Infografia
 

Último

guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan JosephBRAYANJOSEPHPEREZGOM
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxaylincamaho
 
ejercicios pseint para aprogramacion sof
ejercicios pseint para aprogramacion sofejercicios pseint para aprogramacion sof
ejercicios pseint para aprogramacion sofJuancarlosHuertasNio1
 
El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...
El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...
El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...JaquelineJuarez15
 
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfPARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfSergioMendoza354770
 
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE  DE TECNOLOGIA E INFORMATICA PRIMARIACLASE  DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIAWilbisVega
 
Plan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docxPlan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docxpabonheidy28
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadMiguelAngelVillanuev48
 
Hernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptxHernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptxJOSEMANUELHERNANDEZH11
 
La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafiosFundación YOD YOD
 
Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024GiovanniJavierHidalg
 
SalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersSalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersIván López Martín
 
KELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento ProtégelesKELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento ProtégelesFundación YOD YOD
 
Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...
Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...
Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...AlanCedillo9
 
trabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdftrabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdfIsabellaMontaomurill
 
ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...
ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...
ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...FacuMeza2
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricKeyla Dolores Méndez
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx241521559
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)GDGSucre
 
Redes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfRedes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfsoporteupcology
 

Último (20)

guía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Josephguía de registro de slideshare por Brayan Joseph
guía de registro de slideshare por Brayan Joseph
 
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptxMedidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
Medidas de formas, coeficiente de asimetría y coeficiente de curtosis.pptx
 
ejercicios pseint para aprogramacion sof
ejercicios pseint para aprogramacion sofejercicios pseint para aprogramacion sof
ejercicios pseint para aprogramacion sof
 
El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...
El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...
El gusano informático Morris (1988) - Julio Ardita (1995) - Citizenfour (2014...
 
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdfPARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
PARTES DE UN OSCILOSCOPIO ANALOGICO .pdf
 
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE  DE TECNOLOGIA E INFORMATICA PRIMARIACLASE  DE TECNOLOGIA E INFORMATICA PRIMARIA
CLASE DE TECNOLOGIA E INFORMATICA PRIMARIA
 
Plan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docxPlan de aula informatica segundo periodo.docx
Plan de aula informatica segundo periodo.docx
 
Presentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidadPresentación inteligencia artificial en la actualidad
Presentación inteligencia artificial en la actualidad
 
Hernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptxHernandez_Hernandez_Practica web de la sesion 12.pptx
Hernandez_Hernandez_Practica web de la sesion 12.pptx
 
La era de la educación digital y sus desafios
La era de la educación digital y sus desafiosLa era de la educación digital y sus desafios
La era de la educación digital y sus desafios
 
Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024Cortes-24-de-abril-Tungurahua-3 año 2024
Cortes-24-de-abril-Tungurahua-3 año 2024
 
SalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 TestcontainersSalmorejoTech 2024 - Spring Boot <3 Testcontainers
SalmorejoTech 2024 - Spring Boot <3 Testcontainers
 
KELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento ProtégelesKELA Presentacion Costa Rica 2024 - evento Protégeles
KELA Presentacion Costa Rica 2024 - evento Protégeles
 
Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...
Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...
Instrumentación Hoy_ INTERPRETAR EL DIAGRAMA UNIFILAR GENERAL DE UNA PLANTA I...
 
trabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdftrabajotecologiaisabella-240424003133-8f126965.pdf
trabajotecologiaisabella-240424003133-8f126965.pdf
 
ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...
ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...
ATAJOS DE WINDOWS. Los diferentes atajos para utilizar en windows y ser más e...
 
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft FabricGlobal Azure Lima 2024 - Integración de Datos con Microsoft Fabric
Global Azure Lima 2024 - Integración de Datos con Microsoft Fabric
 
Proyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptxProyecto integrador. Las TIC en la sociedad S4.pptx
Proyecto integrador. Las TIC en la sociedad S4.pptx
 
International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)International Women's Day Sucre 2024 (IWD)
International Women's Day Sucre 2024 (IWD)
 
Redes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdfRedes direccionamiento y subredes ipv4 2024 .pdf
Redes direccionamiento y subredes ipv4 2024 .pdf
 

Algoritmos II_2020.pdf

  • 2. sfs Algoritmos II 2 © Corporación Universitaria Remington Medellín, Colombia Derechos Reservados ©2011 Primera edición 2020 Algoritmos II José Antonio Polo Facultad de Ingenierías Comité académico Jorge Mauricio Sepúlveda Castaño Decano de la Facultad de Ingenierías jsepulveda@uniremington.edu.co David Ernesto González Parra Director de Educación a Distancia y Virtual dgonzalez@unireminton.edu.co Francisco Javier Álvarez Gómez Coordinador CUR-Virtual falvarez@uniremington.edu.co Edición y Montaje Dirección de Educación a Distancia y Virtual Equipo de diseño gráfico www.uniremington.edu.co virtual@uniremington.edu.co Derechos reservados: El módulo de estudio del curso de ALGORITMOS II es propiedad de la Corporación Universitaria Remington; las imágenes fueron tomadas de diferentes fuentes que se relacionan en los derechos de autor y las citas en la bibliografía. El contenido del módulo está protegido por las leyes de derechos de autor que rigen al país. Este material tiene fines educativos y no puede usarse con propósitos económicos o comerciales. El autor(es) certificó (de manera verbal o escrita) No haber incurrido en fraude científico, plagio o vicios de autoría; en caso contrario eximió de toda responsabilidad a la Corporación Universitaria Remington y se declaró como el único responsable. Esta obra es publicada bajo la licencia Creative Commons. Reconocimiento-No Comercial-Compartir Igual 2.5 Colombia
  • 3. sfs Algoritmos II 3 TABLA DE CONTENIDO Pág. 1 UNIDAD 1 ALGORITMOS DE ORDENAMIENTO Y BÚSQUEDA 7 1.1.1 OBJETIVO GENERAL 7 1.1.2 OBJETIVOS ESPECÍFICOS 7 1.1.3 PRUEBA INICIAL 8 1.2 TEMA 1 BÚSQUEDA SECUENCIAL, BINARIA Y TRANSFORMACIÓN DE CLAVES 8 1.2.1 BÚSQUEDA SECUENCIA 8 1.2.2 BÚSQUEDA BINARIA 10 1.2.3 BÚSQUEDA POR TRANSFORMACIÓN DE CLAVES 14 1.2.4 EJERCICIO DE APRENDIZAJE 14 1.2.5 TALLER DE ENTRENAMIENTO 15 1.3 TEMA 2 ORDENAMIENTO POR BURBUJA, INSERCIÓN Y SELECCIÓN (MARGE SORT, QUICK SORT, COCKTAIL SORT) 16 1.3.1 ORDENAMIENTO ASCENDENTE POR MÉTODO BURBUJA 16 1.3.2 PROCESO DE INSERCIÓN EN UN VECTOR ORDENADO ASCENDENTEMENTE 20 1.3.3 ORDENAMIENTO POR SELECCIÓN 23 1.3.4 MARGE SORT, QUICK SORT, COCKTAIL SORT 28 1.3.5 EJERCICIO DE APRENDIZAJE 31 1.3.6 TALLER DE ENTRENAMIENTO 32 1.4 TEMA 3 ANÁLISIS DE EFICIENCIA DE ORDENAMIENTO Y BÚSQUEDA 33 1.4.1 EJERCICIO DE APRENDIZAJE 35 1.4.2 TALLER DE ENTRENAMIENTO 36 2 UNIDAD 2 MANEJO DE ESTRUCTURAS DINÁMICAS EN MEMORIA (LISTAS LIGADAS) 38 2.1.1 OBJETIVO GENERAL 38 2.1.2 OBJETIVOS ESPECIFICOS 38 2.1.3 PRUEBA INICIAL 39 2.2 TEMA 1 CONCEPTOS BÁSICOS Y LISTAS SIMPLEMENTE LIGADAS 39 2.2.1 TEMA 1 PUNTEROS 39 2.2.2 CLASE NODOSIMPLE 40 2.2.3 LISTAS SIMPLEMENTE LIGADAS 45 2.2.4 DIFERENTES TIPOS DE LISTAS SIMPLEMENTE LIGADAS Y SUS CARACTERÍSTICAS 64 2.2.5 EJERCICIO DE APRENDIZAJE 65 2.2.6 TALLER DE ENTRENAMIENTO 65 2.3 TEMA 2 LISTAS DOBLEMENTE LIGADAS Y OTROS TIPOS DE TOPOLOGÍAS DE LISTAS 66 2.3.1 LISTA DOBLEMENTE LIGADAS 66 2.3.2 EJERCICIO DE APRENDIZAJE 70 2.3.3 TALLER DE ENTRENAMIENTO 72 2.4 TEMA 3 PILAS Y COLAS (Estáticas y Dinámicas) 73
  • 4. sfs Algoritmos II 4 2.4.1 RELACIÓN DE CONCEPTOS 73 2.4.2 DEFINICIÓN 75 2.4.3 PILAS CON VECTORES Y LISTAS 75 2.4.4 TEMA 3 COLAS CON VECTORES Y LISTAS 86 2.4.5 EJERCICIO DE APRENDIZAJE 95 2.4.6 TALLER DE ENTRENAMIENTO 95 3 UNIDAD 3 CONCEPTUALIZACIÓN DE RECURSIVIDAD, ARBOLES Y GRAFOS 97 3.1.1 OBJETIVO GENERAL 97 3.1.2 OBJETIVOS ESPECÍFICOS 98 3.1.3 PRUEBA INICIAL 98 3.2 TEMA 1 DEFINICIÓN Y APLICACIÓN DE LA RECURSIVIDAD 98 3.2.1 EJERCICIO DE APRENDIZAJE 99 3.2.2 TALLER DE ENTRENAMIENTO 100 3.3 TEMA 2 DEFINICIÓN, CONCEPTOS, REPRESENTACIÓN Y RECORRIDOS DE ARBOLES 101 3.3.1 RELACIÓN DE CONCEPTOS 101 3.3.2 ARBOLES 101 3.3.3 ARBOLES BINARIOS Y SU REPRESENTACIÓN 106 3.4 LISTAS GENERALIZADAS 115 3.4.1 DEFINICIÓN DE LISTAS GENERALIZADAS (ESTILO TÍTULO 3) 116 3.4.2 EJERCICIO DE APRENDIZAJE 119 3.4.3 TALLER DE ENTRENAMIENTO 121 3.5 TEMA 3 DEFINICIÓN, CONCEPTOS, REPRESENTACIÓN Y RECORRIDOS DE GRAFOS 122 3.5.1 RELACIÓN DE CONCEPTOS 122 3.6 GRAFOS 122 3.6.1 DEFINICIÓN Y TERMINOLOGÍA BÁSICA SOBRE GRAFOS 122 3.6.2 EJERCICIO DE APRENDIZAJE 136 3.6.3 TALLER DE ENTRENAMIENTO 136 4 PISTAS DE APRENDIZAJE 137 5 GLOSARIO 141 6 BIBLIOGRAFÍA 143
  • 5. sfs Algoritmos II 5 P R O P Ó S I T O G E N E R A L Que el estudiante pueda identificar las diferentes estructuras de almacenamiento y aplicarlas de forma óptima en la solución de problemas. ALGORITMOS II
  • 6. sfs Algoritmos II 6 a O B J E T I V O G E N E R A L Entrenar a los estudiantes en las técnicas de programación para el almacenamiento de datos tanto a nivel de memoria como en disco, para el desarrollo de algoritmos aplicables a diversos retos, que permita la generación de una capacidad analítica y creativa en la solución e implementación. O B J E T I V O S E S P E C Í F I C O S ➢ Reconocer los diferentes algoritmos de ordenamiento y búsqueda y realizar operaciones a nivel de programación. ➢ Identificar las estructuras de almacenamiento de información como piolas y colas, representadas de forma estática y dinámica ➢ Aplicar soluciones a problemas a partir de árboles y grafos U N I D A D 1 U N I D A D 2 Manejo de estructuras dinámicas en Memoria (listas ligadas) Algoritmos de ordenamiento y búsqueda ALGORITMOS II U N I D A 3 Conceptualización de recursividad, árboles y grafos
  • 7. sfs Algoritmos II 7 1 UNIDAD 1 ALGORITMOS DE ORDENAMIENTO Y BÚSQUEDA 1.1.1 OBJETIVO GENERAL ➢Realizar operaciones de ordenamiento y búsqueda sobre grupos de datos, que pueden estar representados en arreglos; permitiendo mejorar la eficiencia de los algoritmos. 1.1.2 OBJETIVOS ESPECÍFICOS ➢ Aplicar algoritmos de búsqueda con sus diferentes esquemas de representación y realizar comparativos de eficiencia entre ellos.
  • 8. sfs Algoritmos II 8 ➢ Aplicar los diferentes algoritmos de búsqueda que permitan encontrar un valor determinado dentro de un grupo de valores dados que pueden estar almacenados en un arreglo. ➢ Aplicar los diferentes algoritmos de ordenamiento que permitan a un grupo de datos ordenarse de forma ascendente o descendente según la necesidad los datos pueden estar almacenados en un arreglo. ➢ Aplicar en análisis de algoritmos para determinar la eficiencia de los procesos de ordenamiento y búsqueda y efectuar la comparación para determinar cuál algoritmo es el de mejor rendimiento. 1.1.3 PRUEBA INICIAL • ¿Cuál es la diferencia entre arreglos unidimensionales y arreglos bidimensionales? • ¿Porque es importante tener los datos ordenados en todo momento? • ¿Qué es la eficiencia en un algoritmo? 1.2 TEMA 1 BÚSQUEDA SECUENCIAL, BINARIA Y TRANSFORMACIÓN DE CLAVES ➢Video: ” Búsqueda Lineal VS Búsqueda Binaria” ➢” Ver Video”: https://www.youtube.com/watch?v=HmUpRHn31FU ” 1.2.1 BÚSQUEDA SECUENCIA Cuando tenemos un grupo de datos almacenados secuencialmente en un arreglo y se necesita determinar si un dato D está dentro de eses grupo, debemos construir un algoritmo que nos permita aplicar la búsqueda secuencial: se debe recorrer el vector con un ciclo hasta su tamaño (cantidad de datos de la estructura), se debe pedir el dato a buscar fuera del ciclo (puede ser un parámetro si es un método o una simple lectura por teclado. Se debe comparar ese dato con el contenido de cada una de las posiciones del vector y el objetivo es encontrar el dato dentro de una de ellas, si lo encuentra debe devolver el índice o la posición donde lo encontró, pero, sino lo encuentra debe devolver un mensaje que diga que el dato no se encuentra en el vector. Algoritmo que realiza este proceso. Búsqueda Secuencial
  • 9. sfs Algoritmos II 9 1. i = 1 1 2. While ((i <= n) and (V[j] <> x) do n + 1 3. i = i - 1 n 4. End (while) n 5. If (i <= n) then return i 1 6. Else write(“el dato” , x , “no existe”) 1 Contador de frecuencia = 3(n + 4) Y el orden de magnitud es O(n) Sea el siguiente vector de tamaño 10, que contiene los preciso de 10 artículos distintos (el vector no se encuentra ordenado). Si el administrador necesita determinar si existe dentro del vector un producto con un valor igual a 80.000 pesos como se podría ilustrar este proceso de búsqueda: D=80000
  • 10. sfs Algoritmos II 10 Al comparar en este paso encuentra que el valor almacenado al dato con el se realiza la búsqueda, el algoritmo inmediatamente debe parar la búsqueda y debe devolver el índice o la posición del vector don se encuentra ese dato. Un caso particular en esta búsqueda se da por ejemplo cunado busca el dato igual a 60000 dentro del vector anterior Como el dato no está en ninguna de las posiciones del vector el algoritmo de búsqueda debe devolver un mensaje que indique que el dato no fue encontrado dentro de la estructura (se debe notar que primero debe haber recorrido todo el vector buscando el dato). El orden de magnitud de este algoritmo que tiene un ciclo para poder trabajar es normalmente O(n); puesto que el peor de los casos el algoritmo recorre todo el vector. 1.2.2 BÚSQUEDA BINARIA El proceso de búsqueda binaria utiliza el hecho de que los datos se encuentran ordenados en forma ascendente o descendente. La primera comparación se hace con el dato de la mitad del vector. Si se tiene suerte, ese es el dato que se está buscando y no hay que hacer más comparaciones; si no lo es, es porque el dato que se está buscando es mayor o menor que el dato de la mitad del vector. Si el dato que se está buscando es mayor que el dato de la mitad del vector, significa que, si el dato se halla en el vector, está a la derecha del dato de la mitad, o sea que no abra necesidad de comparar el dato que se está buscando con todos los datos que están a la izquierda del dato de la mitad del vector. Luego de que hemos descartado la mitad de los datos, la siguiente comparación se hará con el dato de la mitad, de la mitad en la cual posiblemente este el dato a buscar. Así continuamos con este proceso hasta que se encuentre el dato, o se detecte que el dato no está en el vector. Si tuviéramos un millón de datos, con una sola comparación estamos ahorrando 500.000 comparaciones, con la segunda comparación se ahorran 250.000 comparaciones, con la tercera se ahorran 125.000 comparaciones y así sucesivamente. Como se puede ver, la reducción del número de comparaciones es notable. A continuación, se presenta el método con el cual se efectúa este proceso:
  • 11. sfs Algoritmos II 11 1. PUBLICO ESTATICO ENTERO BusquedaBinaria (V, n, d) 2. VARIABLES: li, ls, m (ENTEROS) 3. li = 1 4. ls = n 5. MQ (li <= ls) 6. m = (li + ls) / 2 7. SI (V[m] == d) 8. RETORNE (m) 9. SINO 10. SI (V[m] < d) 11. li = m + 1 12. SINO 13. ls = m – 1 14. FINSI 15. FINSI 16. FINMQ 17. RETORNE (n + 1) 18. FIN(Método) En la instrucción 1 se define el método BúsquedaBinaria, cuyos parámetros son: V, en el cual hay que efectuar la búsqueda; n, el tamaño del vector; y d, el dato a buscar. En la instrucción 2 se definen las variables de trabajo: li, para guardar el límite inferior del rango en el cual hay que efectuar la búsqueda; ls, para guardar el límite superior del rango en el que se efectuará la búsqueda; y m, para guardar la posición de la mitad del rango entre li y ls. En las instrucciones 3 y 4 se asignan los valores iníciales a las variables li y ls. Estos valores iníciales son 1 y n, respectivamente, ya que la primera vez el rango sobre el cual hay que efectuar la búsqueda es desde la primera posición hasta la última del vector. En la instrucción 5 se plantea el ciclo MIENTRAS_QUE (MQ), con la condición de que li sea menor o igual que ls. Es decir, si el límite inferior (li) es mayor o igual que el límite superior (ls), aún existen posibilidades de que el dato que se está buscando se encuentre en el vector. Cuando li sea mayor que ls significa que el dato no está en el vector y retornara n+1. Cuando la condición de la instrucción 5 sea verdadera se ejecutan las instrucciones del ciclo. En la instrucción 6 se calcula la posición de la mitad entre li y ls, llamamos a esta posición m. En la instrucción 7 se compara el dato de la posición m con el dato d. si el dato de la posición m es igual al dato d que se está buscando (V[m] == d), ejecuta la instrucción 8: termina el proceso de búsqueda retornando m, la posición en la cual se halla el dato d en el vector.
  • 12. sfs Algoritmos II 12 Si el dato que se encuentra en la posición m no es el que buscamos, pasamos a la instrucción 10. En caso de que la condición de la instrucción 10 sea verdadera, significa que, si el dato está en el vector, se halla a la derecha de la posición m; por consiguiente, el límite inferior del rango en el cual se debe efectuar la búsqueda es m+1, y por tanto ejecuta la instrucción 11 en el cual a la variable li se le asigna m+1. Si el resultado de la comparación de la instrucción 10 es falso, significa que, si el dato está en el vector, se halla a la izquierda de la posición m; por consiguiente, el límite superior del rango en el cual se debe efectuar en la búsqueda es m–1, y por tanto ejecuta la instrucción 13 en la cual a la variable ls se le asigna m–1. Habiendo actualizando el límite inferior o el límite superior, se llega a la instrucción 16, la cual retorna la ejecución a la instrucción 5, donde se efectúa de nuevo la comparación entre li y ls. Cuando la condición sea falsa se sale del ciclo y ejecuta la instrucción 17, la cual retorna n+1, indicando que el dato no se halla en el vector. Fíjese que la única manera de que se ejecute la instrucción 17 es que no haya encontrado el dato que se está buscando, ya que si lo encuentra ejecuta la instrucción 8, la cual termina el proceso. Consideremos, como ejemplo, el siguiente vector, y que se desea buscar el número 38 en dicho vector: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73 Al ejecutar nuestro algoritmo de búsqueda binaria, cuando se esté en la instrucción 5 por primera vez, li se situará en 1 y ls en n, como vemos en la siguiente figura: Al ejecutar la instrucción 7, la cual compara el dato de la posición m (28) con d (38), se determina que el dato d, si está en el vector, se halla a la derecha de la posición m, por consiguiente, el valor de li deberá ser 9. En constancia, al ejecutar la instrucción 11, el límite inferior del rango sobre el li M Ls 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
  • 13. sfs Algoritmos II 13 cual hay que efectuar la búsqueda es 9, por lo tanto, el rango sobre el cual hay que efectuar dicha búsqueda es entre 9 y 15. Al ejecutar el ciclo por segunda vez el valor de m será 12, como muestra la figura siguiente: Luego, al comparar d (38) con V[m] (52), se determina que el dato que se está buscando, si está en el vector, debe hallarse a la izquierda de m, es decir, entre las posiciones 9 y 11, por consiguiente, el valor de j será 11 (j = m – 1). Al ejecutar el ciclo por tercera vez, las variables quedarán de la siguiente forma: li m ls n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73 En esta pasada se detecta que el dato debe estar a la derecha de m, por consiguiente el valor de li deberá ser 11, y en consecuencia el valor de m también. La situación en el vector queda así: En este punto la comparación de d con V[m] indica que si el dato d está en el vector, debe estar a la izquierda de m, por tanto el valor de ls será 10, y al regresar a la instrucción 5 y evaluar la condición del ciclo (li <= ls), esta será falsa, por consiguiente termina el ciclo y retorna como posición el valor de 16 (n+1), indicando que el 38 no se encuentra en dicho vector. li m ls 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73 li m Ls n 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 V 3 6 7 10 12 18 22 28 31 37 45 52 60 69 73
  • 14. sfs Algoritmos II 14 1.2.3 BÚSQUEDA POR TRANSFORMACIÓN DE CLAVES Cuando se utiliza métodos de búsqueda por transformación de claves permiten aumentar la velocidad de búsqueda, con una condición importante y es que los elementos no tienen que esta ordenados, es decir, que la ventaja es que el tiempo de búsqueda es totalmente independiente al número componentes del arreglo (vector). Supongamos que se tiene una colección de datos donde cada uno de ellos identificado por una clave donde resulta atractivo tener acceso a ellos de forma directa. Se tiene que tener en cuenta que dos claves diferentes pueden apuntar a una misma dirección dentro del arreglo a esto se le llama colisiones. Cuando se quiere trabajar con este método de búsqueda se debe seleccionar previamente: Una función Hash que sea fácil de calcular y que distribuya uniformemente las claves Un método para resolver las colisiones, si estas se presentan, se contará con algún método que genere posiciones alternativas. 1.2.3.1 FUNCIÓN HASH POR MODULO: Consiste en tomar el residuo de la división de la clave entre el número de componentes del arreglo ejemplo: se tiene un arreglo de N elementos y K es la clave del dato a buscar. La función hash correspondiente es: H(K)=(K*ModN)+1 Se observa en la fórmula que al residuo de la división se le suma 1, con el objetivo de tener un valor comprendido entre 1 y N siendo N el tamaño del Arreglo. Para lograr una mayor uniformidad en la distribución es importante que N sea un numero primo o divisible entre muy pocos números, en caso de que N no sea un numero primo, se debe buscar el número primo más cercano a N. 1.2.4 EJERCICIO DE APRENDIZAJE Supongamos que N es igual a 100 es el tamaño del Arreglo y las direcciones que se le deben asignar a los elementos (al guardarlo o recuperarlo) son los números del 1 al 100y además
  • 15. sfs Algoritmos II 15 contamos con las siguientes claves K1=7259 y K2=9359 son las que se les debe asignar posiciones dentro el arreglo, las direcciones correspondientes para K1 y K2 H(K1)=(7259*Mod 100) +1= 60 H(K2)=(9359*Mod 100) +1= 60 Nota: se observa que dos claves distintas apuntan a una misma posición en el arreglo, lo que generó una colisión y este problema se resuelve asignando el primo más cercan para N=100 que es 97. Aplicando las fórmulas con este valor observamos: H(K1)=(7259*Mod 97) +1= 82 H(K2)=(9359*Mod 97) +1= 48 Con N=97 se ha eliminado la colisión. 1.2.5 TALLER DE ENTRENAMIENTO Supongamos que N es igual a 200 es el tamaño del Arreglo y las direcciones que se le deben asignar a los elementos (al guardarlo o recuperarlo) son los números del 1 al 200 y además contamos con las siguientes claves K1=5526 y K2=2850 son las que se les debe asignar posiciones dentro el arreglo, encontrar las direcciones asociadas a las direcciones K1 y K2 para la búsqueda hashing y en caso de que se den colisiones resolverlas (recuerde que se debe tomar el primo más cercano al valor de N). TIPS El hashing usa las claves para asociar y encontrar los datos de un arreglo mayor velocidad.
  • 16. sfs Algoritmos II 16 1.3 TEMA 2 ORDENAMIENTO POR BURBUJA, INSERCIÓN Y SELECCIÓN (MARGE SORT, QUICK SORT, COCKTAIL SORT) ➢Video: ” ALGORITMOS - METODOS DE ORDENAMIENTO” ➢” Ver Video”: https://www.youtube.com/watch?v=VJ_EUuURRg4 ” 1.3.1 ORDENAMIENTO ASCENDENTE POR MÉTODO BURBUJA El método de ordenamiento por burbuja consiste en comparar dos datos consecutivos y ordenarlos ascendentemente, es decir, si el primer dato es mayor que el segundo se intercambia dichos datos, de lo contrario se dejan tal cual están. Cualquiera de las dos situaciones que se hubiera presentado se avanza en el vector para comparar los siguientes dos datos consecutivos. En general, el proceso de comparaciones es: el primer dato con el segundo, el segundo dato con el tercero, el tercer dato con el cuarto, el cuarto con el dato quinto, y así sucesivamente, hasta comparar el penúltimo dato con el último. Como resultado de estas comparaciones, y los intercambios que se hagan, el resultado es que en la última posición quedara el mayor dato en el vector. La segunda vez se compara nuevamente los datos consecutivos, desde el primero con el segundo, hasta que se comparan el antepenúltimo dato con el penúltimo, obteniendo como resultado que el segundo dato mayor queda de penúltimo. Es decir, en cada pasada de comparaciones, de los datos que faltan por ordenar, se ubica el mayor dato en la posición que le corresponde, o sea de ultimo en el conjunto de datos que faltan por ordenar. Veamos el método que efectúa dicha tarea 1. PUBLICO ESTATICO VOID OrdenamientoAscendenteBurbuja (V, n) 2. VARIABLES: i, j (ENTEROS 3. PARA (i= 1, n-1, 1) 4. PARA (j= 1, n-i, 1) 5. SI (V[j] > V[j+1]) 6. INTERCAMBIAR (V, j, j+1) 7. FINSI 8. FINPARA 9. FINPARA 10. FIN(Método) Como ejemplo vamos a considerar el siguiente vector:
  • 17. sfs Algoritmos II 17 1 2 3 4 5 6 V 3 1 6 2 8 4 Nuestro interés es ordenar los datos de dicho vector en forma ascendente, utilizando el método que llamamos burbuja. 1 2 3 4 5 6 Parte 1 3 1 6 2 8 4 Primera pasada: cinco comparaciones Parte 4 1 3 2 6 8 4 En la figura anterior se presentan los cincos comparaciones que se efectúan en la primera pasada. La comparación correspondiente a cada pasada se ve resaltada en cada vector. A cada comparación la llamaremos parte con el fin de evitar redundancias. • En la primera parte se compara el dato de la posición 1 con el dato de la posición 2. Como el dato de la posición 1 es mayor que el dato de la posición 2, se intercambian dichos datos, quedando el vector como se ve en la parte 2. • En la parte 2 se compara el dato de la posición 2 con el dato de la posición 3. Como el dato de la posición 3 es mayor que el dato de la posición 2, los datos se dejan intactos. • En la parte 3 se compara el dato de la posición 3 con el dato de la posición 4. Como el dato de la posición 3 es mayor que el dato de la posición 4, se intercambian dichos datos, quedando el vector como se ve en la parte 4. • En la parte 4 se compara el dato de la posición 4 con el dato de la posición 5. Como el dato de la posición 4 es menor que el dato de la posición 5, los datos permanecen intactos. • En la parte 5 se compara el dato de la posición 5 con el dato de la posición 6. Como el dato de la posición 5 es mayor que el dato de la posición 6, se intercambian dichos datos. Parte 2 1 3 6 2 8 4 Parte 3 1 3 6 2 8 4 Parte 5 1 3 2 6 8 4
  • 18. sfs Algoritmos II 18 Luego de realizar estas comparaciones y estos intercambios, el vector queda de la siguiente forma: En esta figura se ha resaltado el dato de la posición 6, puesto que este ha quedado en el sitio que le corresponde. En la segunda pasada se harán nuevamente comparaciones de datos consecutivos desde la posición 1 hasta la posición 5, ya que la posición 6 ya está en orden. Las comparaciones e intercambios correspondientes a esta segunda pasada se presentan en la figura 31.4 1 2 3 4 5 6 Parte 1 1 3 2 6 4 8 Segunda pasada: cuatro comparaciones Como resultado final de esta segunda pasada el vector quedará de la siguiente forma: 1 2 3 4 5 6 1 2 3 4 6 8 En esta figura se resaltan las dos últimas posiciones, indicando que esta parte del vector ya está ordenada. En la siguiente figura se muestra como es el proceso de comparaciones e intercambios correspondientes a la tercera pasada. Fíjese que las comparaciones solo se efectúan hasta la posición 4, ya que los datos de las posiciones 5 y 6 ya están ordenados y ubicados en sus correspondientes lugares. 1 2 3 4 5 6 1 3 2 6 4 8 Parte 2 1 3 2 6 4 8 Parte 3 1 2 3 6 4 8 Parte 4 1 2 3 6 4 8
  • 19. sfs Algoritmos II 19 1 2 3 4 5 6 Tercera pasada: tres comparaciones Ahora veamos el estado actual de nuestro vector después de la tercera pasada: 1 2 3 4 5 6 1 2 3 4 6 8 En la siguiente figura se muestra las dos comparaciones correspondientes a la cuarta pasada: Cuarta pasada: dos comparaciones Luego de la cuarta pasada el vector quedará de la siguiente forma: 1 2 3 4 5 6 1 2 3 4 6 8 En la siguiente figura se muestra la comparación que se hará en la quinta pasada: Quinta pasada: una comparación Después de la quinta pasada nuestro vector quedará así: 1 2 3 4 5 6 1 2 3 4 6 8 Observe que al concluir la tercera pasada los datos del vector ya estaban ordenados; es decir, las comparaciones correspondientes a las pasadas cuarta y quinta no eran necesarias. Esta situación se puede detectar en el algoritmo si utilizamos una variable auxiliar y le asignamos un valor antes de comenzar el ciclo interno. Si ocurrió algún intercambio, modificamos el valor inicial de dicha 1 2 3 4 6 8 1 2 3 4 6 8 1 2 3 4 6 8 1 2 3 4 5 6 1 2 3 4 6 8 1 2 3 4 6 8 1 2 3 4 5 6 1 2 3 4 6 8
  • 20. sfs Algoritmos II 20 variable auxiliar. Al terminar el ciclo interno averiguamos cual es el contenido de dicha variable auxiliar. Si es el mismo que se le asigno inicialmente, significa que no hubo intercambios en el ciclo interno, por consiguiente, los datos del vector ya están ordenados y no hay necesidad de hacer más comparaciones. Para nuestro ejemplo llamaremos a esa variable auxiliar sw. Nuestro algoritmo queda: 1. PUBLICO ESTATICO VOID OrdenamientoAscendenteBurbujaSW (V, n) 2. VARIABLES: i, j, sw (ENTEROS) 3. PARA (i= 1, n-1, 1) 4. Sw = 0 5. PARA (j= 1, n-i, 1) 6. SI (V[j] > V[j+1]) 7. INTERCAMBIAR (V, j, j+1) 8. sw = 1 9. FINSI 10. FINPARA 11. SI (sw == 0) 12. i = n 13. FINSI 14. FINPARA 15. FIN(Método) El algoritmo anterior es similar al primero que hicimos de ordenamiento ascendente con el método de burbuja, la diferencia está en que agregamos una variable llamada sw con la cual sabremos si el vector está completamente ordenado sin haber hecho todos los recorridos. Cuando la variable sw no cambie de valor significa que el vector ya está ordenado y asignaremos a la variable i el valor de n para salir del ciclo externo. 1.3.2 PROCESO DE INSERCIÓN EN UN VECTOR ORDENADO ASCENDENTEMENTE Si queremos insertar un dato en un vector ordenado ascendentemente, sin dañar su ordenamiento, primero debemos buscar la posición en la que debemos insertar. Para buscar la posición donde vamos a insertar un nuevo dato en el vector ordenado ascendentemente debemos recorrer el vector e ir comparando el dato de cada posición con el dato a insertar. Como los datos están ordenados ascendentemente, cuando se encuentre en el vector un dato mayor que el que se va a insertar esa es la posición en la cual deberá quedar el nuevo dato.
  • 21. sfs Algoritmos II 21 Si el dato a insertar es mayor que todos los datos del vector, entonces el dato a insertar quedara de último. El método siguiente ejecuta esta tarea y retorna en la variable i La posición en la cual debe quedar el dato a insertar: 1. PUBLICO ESTATICO ENTERO BuscarDondeInsertar (V, m, d) 2. VARIABLES: i (ENTERO) 3. i = 1 4. MQ ((i <= m) ^ (V[i] < d)) 5. i = i + 1 6. FINMQ 7. RETORNE (i) 8. FIN(Método) En la instrucción 1 se define el nombre del programa con sus parámetros: V, variable que contiene el nombre del vector en el cual hay que efectuar el proceso de búsqueda; m, variable que contiene el número de posiciones utilizadas en el vector; y d, variable que contiene el dato a insertar. En la instrucción 2 se define la variable i, que es la variable con la que recorre el vector y se va comparando el dato de la posición i del vector (V[i]) con el dato a insertar (d). En la instrucción 3 se inicializa la variable i en 1, ya que esta es la posición a partir de la cual se comienza a almacenar la posición donde se va a insertar el dato. En la instrucción 4, la instrucción del ciclo, se controlan dos situaciones: una, que no se haya terminado de comparar los datos del vector, (i <= m), y dos, que el dato de la posición i sea mayor que d (V[i] < d). Si ambas condiciones son verdaderas se ejecutan las construcciones 5 y 6, es decir, se incrementa la i en 1 y se regresa a la instrucción 4 a evaluar nuevamente las condiciones. Cuando una de las condiciones sea falsa (i>m o V[i]>=d), se sale del ciclo y ejecuta la instrucción 7, es decir, retorna al programa llamante el valor de i: la posición en la cual hay que insertar el dato d. Como ejemplo, consideremos el vector de la siguiente figura, y que se desea insertar el número 10 (d==10).
  • 22. sfs Algoritmos II 22 Al ejecutar el método BuscarDondeInsertar, este retorna i valiendo 4, es decir, en la posición 4 del vector V debe quedar el dato 10. Ahora veamos Conocimos que el dato debe quedar en una posición i, veamos cómo se efectúa este proceso. Si el vector no está lleno (m == n), debemos mover todos los datos desde la posición i del vector hacia la derecha. 1. PUBLICO ESTATICO VOID Insertar (V, m, n, i, d) 2. VARIABLES: j (ENTERO) 3. SI (m == n) 4. IMPRIMA (“vector lleno”) 5. RETORNE 6. SINO 7. PARA (j= m, i, -1) 8. V[j+1] = V[j] 9. FINPARA 10. V[i] = d 11. m = m + 1 12. FINSI 13. FIN(Método) Es la instrucción 1 se define el método con sus parámetros: V, variable que contiene el nombre del vector en el cual hay que efectuar el proceso de inserción; m, variable que contiene el número de posiciones utilizadas en el vector; n, tamaño del vector; i, variable que contiene la posición en la cual se debe insertar el dato contenido en d; y d, variable que contiene el dato a insertar. Es bueno resaltar que los parámetros V y m deben ser parámetros por referencia, mientras que n, i y d son por valor. En la instrucción 2 se define la variable j, la cual se utilizará para mover los datos del vector en caso de que sea necesario. m n 1 2 3 4 5 6 7 8 9 10 V 3 5 7 11 18 23 36
  • 23. sfs Algoritmos II 23 En la instrucción 3 se controla que el vector no esté lleno. En caso de que el vector este lleno (m == n), se ejecuta la instrucción 4, la cual produce el mensaje de que el vector está lleno y finaliza el método sin realizar más acciones, la instrucción 5 indica que el método puede retornar en donde fue invocado. En caso de que el vector no esté lleno se ejecuta la instrucción 7, en la cual se plantea la instrucción PARA, la cual inicializa el valor de j con el contenido de m, compara el valor de j con el valor de i y define la forma como variara el de j. la variación de la variable j será restándole 1 cada vez que llegue a la instrucción fin del PARA. Cuando el valor de j sea menor que i se sale del ciclo. En caso de que el valor inicial de j sea menor que i, no ejecutara la instrucción 8 y continuara con la instrucción 10. En la instrucción 8 se mueve el dato que está en la posición j a la posición siguiente (j + 1). En la instrucción 9, que es el fin de la instrucción PARA, disminuye el valor de j, ejecutara nuevamente las instrucciones 8 y 9, hasta que j sea menor que i. Cuando se sale del ciclo, ejecuta la instrucción 10, en la cual se asigna a la posición i del vector el dato d y continua con la instrucción 11 en la cual se incrementa el valor de m en 1, indicando que el vector ha quedado con un elemento más. Veamos cómo queda nuestro vector después de haber insertado el dato: 1.3.3 ORDENAMIENTO POR SELECCIÓN Como ya hemos visto, el hecho de trabajar los datos ordenados hace que los algoritmos sean más eficientes. Para ejecutar el proceso de ordenamientos se han desarrollado múltiples métodos, buscando que este proceso sea lo más eficiente posible. Ahora veamos un método que ordena los datos de un vector. El método utilizado en este algoritmo se denomina ordenamiento por selección. Este método se enuncia así: de los datos que faltan por ordenar, determinar el menor de ellos y ubicarlo de primero en ese conjunto de datos. i m n 1 2 3 4 5 6 7 8 9 10 V 3 5 7 10 11 18 23 36
  • 24. sfs Algoritmos II 24 Con base en este enunciado se presenta el método: 1. PUBLICO ESTATICO VOID OrdenamientoAscendenteSeleccion (V, m) 2. VARIABLES: i, j, k (ENTEROS) 3. PARA (i= 1, m-1, 1) 4. k = i 5. PARA (j= i+1, m, 1) 6. SI (V[j] < V[k]) 7. k = j 8. FINSI 9. FINPARA 10. OrdenamientoAscendenteSeleccion .Intercambiar (V, k, i) 11. FINPARA 12. FIN(Método) • En la instrucción 1 se define el método con sus parámetros: V, variable en la cual se almacena el vector que desea ordenar, y m, el número de elementos a ordenar. V es un parámetro por referencia, ya que se modificará al cambiar de posición los datos dentro del vector. • En la instrucción 2 se define las variables necesarias para efectuar el proceso de ordenamiento. La variable i se utiliza para identificar a partir de cual posición es que faltan datos por ordenar. Inicialmente el valor de i es 1, ya que inicialmente faltan todos los datos por ordenar y los datos comienzan en la posición 1. Cuando el contenido de la variable i sea 2, significa que faltan por ordenar los datos que hay a partir de la posición 2 del vector; cuando el contenido de la variable i sea 4, significa que faltan por ordenar los datos que hay a partir de la posición 4; cuando el contenido de la variable i sea m, significa que estamos en el último elemento del vector, el cual obviamente estará en su sitio, pues no hay más datos con los cuales se puede comparar. Esta es la razón por la cual en la instrucción 3 se pone a variar la i desde 1 hasta m–1. NOTA: Si deseamos ordenar el vector de forma descendente, simplemente cambiamos el símbolo menor que (<) por el de mayor que (>) en la instrucción 6.descubre el valor propio de las cosas.
  • 25. sfs Algoritmos II 25 • En la instrucción 3 se plantea el ciclo de la variable i, que varían desde 1 hasta m–1, tal como explicamos en el párrafo anterior. • En la instrucción 4 se le asigna a k el contenido de la variable i. la variable k se utiliza para identificar la posición en la que se halla el menor dato. Inicialmente suponemos que el menor dato se encuentra en la posición i del vector, es decir, suponemos que el primero del conjunto de datos que faltan por ordenar. • En la instrucción 5 se plantea el ciclo con el cual se determina la posición en la cual se halla el dato menor del conjunto de datos que faltan por ordenar. En este ciclo se utiliza la variable j, que tiene un valor inicial de i + 1 y varia hasta m. • En la instrucción 6 se compara el dato que se halla en la posición j del vector con el dato que se halla en la posición k. si el contenido de la posición j es menor que el contenido de la posición k, se actualiza el contenido de la variable k con el contenido de j, de esta manera en la variable k siempre estará la posición en la cual encuentra el menor dato. • Al terminar la ejecución 10 se intercambia el dato que se halla en la posición k con el dato que se halla en la posición i, logrando de esta manera ubicar el menor dato al principio del conjunto de datos que faltan por ordenar. Nótese que invocamos al método Intercambiar y lo hicimos con el nombre del método que invoca. El nombre del método invocado • Al llegar a la instrucción 11 continúa con el ciclo externo incrementado a i, que es a partir de esa posición que faltan los por ordenar. Como ejemplo, consideramos el siguiente vector: Al ejecutar por primera vez las instrucciones 3, 4 y 5, los valores de i, k y j son 1, 1 y 2, respectivamente, lo cual indica que faltan por ordenar los datos a partir de la posición 1, en donde se halla el menor dato de los que faltan por ordenar y se va a comenzar a comparar los datos del vector, a partir de la siguiente posición, es decir, 2. Gráficamente se presenta esta situación en la siguiente figura. 1 2 3 4 5 6 V 3 1 6 2 8 4
  • 26. sfs Algoritmos II 26 Al ejecutar la instrucción 6, por primera vez, comparará el dato de la posición 2 (j == 2) con el dato de la posición 1 (k == 1), obteniendo como resultado que la condición es verdadera; por tanto, ejecuta la instrucción 7, la cual asigna a k el valor de j, indicando que el menor dato se halla en la posición 2 del vector. Al ejecutar la instrucción 9, incrementa el contenido de j en 1, quedando j con el valor de 3. Esta nueva situación se presenta a continuación. Se ejecuta de nuevo la instrucción 6 y compara el dato de la posición 3 con el dato de la posición 2, obteniendo como resultado que la condición es falsa; por tanto, no ejecuta la instrucción 7, y continúa en la instrucción 9, es decir, incrementa nuevamente el contenido de j en 1, la cual queda valiendo 4. Se continúan ejecutando las instrucciones del ciclo interno (instrucciones 6 a 9), comparando el contenido de la posición j del vector con el contenido de la posición k, obteniendo siempre falso como resultado, hasta que el contenido de la variable j es 7. Cuando esto sucede, pasa ejecutar la instrucción 10, en la cual se intercambia el dato que se halla en la posición i con el dato que se halla en la posición k. En este momento el vector se encuentra así: i k j 1 2 3 4 5 6 V 3 1 6 2 8 4 i k j 1 2 3 4 5 6 V 3 1 6 2 8 4 i K J
  • 27. sfs Algoritmos II 27 El contenido de la posición 1 lo resaltamos indicando que el dato de esa posición ya está ubicado en la posición que le corresponde. Continúa con la ejecución de la instrucción 11, en la cual incrementa el contenido de i en 1, y regresa a continuación con el ciclo externo. Se asigna nuevamente a k el contenido de i y se comienza de nuevo la ejecución del ciclo interno, con valor inicial de j en 3, así: Al terminar la ejecución del ciclo interno, por segunda vez, el contenido de la variable k será 4, indicando que en esta posición se encuentra el menor de los datos que faltan por ordenar, es decir, de los datos que hay a partir de la posición 2 del vector. Terminando la ejecución del ciclo interno continúa con la instrucción 10 en la cual intercambia el dato que está en la posición i (2) con el dato que está en la posición k (4) del vector. Ahora nuestro vector se ve así: 1 2 3 4 5 6 V 1 3 6 2 8 4 i k j 1 2 3 4 5 6 V 1 3 6 2 8 4 i k j 1 2 3 4 5 6 V 1 3 6 2 8 4
  • 28. sfs Algoritmos II 28 Aquí resaltamos el contenido de las dos primeras posiciones indicando que esos dos datos ya están ordenados y en el sitio que les corresponde. Al ejecutar la instrucción 11 incrementa la i en 1, indicando que ya faltan por ordenar sólo los datos que se encuentran a partir de la posición 3, y regresa a ejecutar nuevamente las instrucciones 4 y56, en las cuales al valor de k le asigna el contenido de i, y a j la inicializamos en 4. Veámoslo gráficamente: El proceso de ordenamiento continuara de esta manera hasta que el valor i sea 6. Cuando el valor de i es 6 el proceso termina y los datos del vector están ordenados en forma ascendente. Finalmente, el vector se verá así: 1.3.4 MARGE SORT, QUICK SORT, COCKTAIL SORT Método de ordenamiento QUICK SORT Es el método de ordenamiento más eficiente estadísticamente, en el caso promedio para ordenar los datos de un vector. El Método consiste básicamente en elegir un dato del vector y ubicarlo en el sitio que le corresponde, es decir, los anteriores serán todos menores que ese dato y los i k j 1 2 3 4 5 6 V 1 2 6 3 8 4 i k j 1 2 3 4 5 6 V 1 3 6 2 8 4 1 2 3 4 5 6 V 1 2 3 4 6 8
  • 29. sfs Algoritmos II 29 siguientes serán todos mayores que ese dato. Luego de efectuar esta operación se procede a ordenar los datos que quedaron antes y los que quedaron después usando la misma técnica. Algoritmo Quicksort Void quickSort (entero m, entero n) Entero i, j If (m<n) then i=m j=j+1 while (i<j) do do i=i+1 while ((i<=n) and (V[i]>=V[m])) do j=j-1 while ((j!=m) and (V[j]>=V[m])) if (i<j) then intercambia(i,j) end(if) end(while) intercambia(j,m) Quicksort(m,j-1) quicksort (j+1, n) end(if) End(quinksort) Método de ordenamiento MERGE SORT Este método de ordenamiento no busca ubicar inicialmente un dato en la posición que le corresponde. Simplemente divide el vector en dos subvectores de igual tamaño, los ordena por separado y luego los intercala. Este método tiene la inconveniencia de que requiere memoria adicional para ejecutarse. El algoritmo para sortMerge se escribe a continuación:
  • 30. sfs Algoritmos II 30 Void sortMerge(entero primero, entero ultimo) entero mitad if (primero < ultimo) then mitad=(primero+ultimo)/2 sortMerge(primero, mitad) sortMerge(mitad + 1, ultimo) intercalar(primero, mitad,ultimo) end(if) End(sortMerge) El algoritmo para el método intercalar es: Void intercalar(entero primero, entero mitad, entero ultimo) Entero i, j, k, b[] B=new entero[V[0]] If (primero > mitad) or (mitad + 1 > ulimo) then return For (k=primero; k <= ultimo; k++) do b.asigneDato(V[k], k) end(for) i=primero j=mitad + 1 k=primero – 1 while ((i<=mitad) and (j<=ultimo)) do k=+1 if (b.datoEnPosicion(i)<=b.datoEnPosicion(j)) then V[k]=b.datoEnPosicion(i) i=i+1 else V[k]=b.datoEnPosicion(j) j=j+1 end(if) end(while) while (i<=mitad) do k=k+1 V[k]=b.datoEnPosicion(i) i=i+1
  • 31. sfs Algoritmos II 31 end(while) while (j<=ultimo) do k=k+1 V[k]=b.datoEnPosicion(j) j=j+1 end(while) Fin(intercalar) Ordenam Método de ordenamiento COCKTAIL SORT Es un algoritmo de ordenamiento que surge como una mejora al algoritmo de ordenamiento de burbuja. Funciona observando que los números grandes se están moviendo rápidamente hasta el final de la lista (estas son las liebres), pero que los números pequeños (las tortugas) se mueven solo muy lentamente al inicio de la lista. La solución plantea ordenar por el método de burbuja y cuando llegamos al final de la primera iteración, no volver a realizar el cálculo desde el principio, sino, que empecemos desde el final hasta el inicio. De esa manera siempre se consigue que tanto los números pequeños como los grandes se desplacen a los extremos de la lista lo más rápido posible 1.3.5 EJERCICIO DE APRENDIZAJE 1. PROCEDIMIENTO cocktail_sort ( VECTOR a[1:n]) 2. dirección ← 'frontal', comienzo ← 1, fin ← n-1, actual ← 1 3. REPETIR 4. permut ← FALSO 5. REPETIR 6. SI a[actual] > a[actual + 1] ENTONCES 7. intercambiar a[actual] Y a[actual + 1] 8. permut ← VERDADERO 9. FIN SI 10. SI (dirección='frontal') ENTONCES 11. actual ← actual + 1 12. SI NO 13. actual ←actual - 1 14. FIN SI
  • 32. sfs Algoritmos II 32 15. MIENTRAS QUE ((dirección='frontal') Y (actual<fin)) OU ((dirección='final) O (actual>comienzo)) 16. SI (dirección='frontal') ENTONCES 17. dirección ← 'final' 18. fin ← fin - 1 19. SI NO 20. dirección ← 'frontal' 21. comienzo ← comienzo + 1 22. FIN SI 23. MIENTRAS permut = VERDADERO 24. 25. FIN PROCEDIMIENTO 1.3.6 TALLER DE ENTRENAMIENTO Void quickSort (entero m, entero n) Entero i, j If (m<n) then i=m j=j+1 while (i<j) do do i=i+1 while ((i<=n) and (V[i]>=V[m])) do j=j-1 while ((j!=m) and (V[j]>=V[m])) if (i<j) then intercambia(i,j) end(if) end(while) intercambia(j,m) Quicksort(m,j-1) quicksort (j+1, n) end(if) End(quinksort)
  • 33. sfs Algoritmos II 33 1.4 TEMA 3 ANÁLISIS DE EFICIENCIA DE ORDENAMIENTO Y BÚSQUEDA ➢Video: ” Análisis de Algoritmos , Complejidad de algoritmos (Actualizado)” ➢” Ver Video”: https://www.youtube.com/watch?v=Sibd8jSTdUQ&t=256s ” A continuación de mostrara y se realzara un análisis de los algoritmos de ordenamiento y búsqueda para encintar su contador de frecuencias y su respectivo orden de magnitud con el objetivo de realizar un comparativo de cual algoritmo en búsqueda y en ordenamiento respectivamente es el más eficiente: Análisis del algoritmo Ordenamiento por selección 1. Void selección() 1 2. Entero i, j, k 1 3. For (i = 1; i < n; i++) do n 4. K = i n - 1 5. For (j= j+1; j<=n; j++) do n(n -1)/2 +(n – 1) 6. If v[j] < V[k] then n(n -1)/2 Nota: Realice una prueba de escritorio para un vector de 10 posiciones, la información en el vector está inicialmente desordenada; después de realizar la prueba, desde su punto de vista escriba que tan eficiente es el método. TIPS La implementación de los métodos de ordenamiento y búsqueda permiten mejorar el rendimiento en colecciones de datos de grandes volúmenes que requieren de esos procesos.
  • 34. sfs Algoritmos II 34 7. K= j n(n -1)/2 8. End (if) n(n -1)/2 9. End (for) n(n -1)/2 10. Intercambia(i,k) n - 1 11. End (for) n – 1 12. End (selección) 1 Contador de frecuencia = 5n(n – 1)/2 + 5n -1 Y el orden de magnitud es O(n2) Análisis del algoritmo Ordenamiento por inserción 1. Void Inserción() 1 2. Entero i, j, d 1 3. For (i = 2; i < n; i++) do n 4. d = V[i] n - 1 5. j = i - 1 n(n -1)/2 +(n – 1) 6. While ((j > 0) and (d <[j])) do n(n -1)/2 7. V[j + 1] = V[j] n(n -1)/2 8. j = j - 1 n(n -1)/2 9. End (while) n(n -1)/2 10. V[j + 1] = d n - 1 11. End (for) n – 1 12. End (Inserción) 1 Contador de frecuencia = 4n(n – 1)/2 + 5n - 2 Y el orden de magnitud es O(n2) Análisis del Algoritmo Búsqueda Binaria 1. primero = 1 1 2. ultimo = n 1 3. while (primero <= ultimo) do log2n + 1 4. Medio = (primero + ultimo) /2 log2n
  • 35. sfs Algoritmos II 35 5. If (V[medio] == x) then return medio log2n 6. If (V[medio] > x) then ultimo = medio - 1 log2n 7. else primero = medio + 1 log2n 8. End (while) log2n 9. write(“el dato” , x , “no existe”) 1 Contador de frecuencia = 6(log2n) + 4 Y el orden de magnitud es O(log2n) Análisis del algoritmo de Búsqueda Secuencial 1. i = 1 1 2. While ((i <= n) and (V[j] <> x) do n + 1 3. i = i - 1 n 4. End (while) n 5. If (i <= n) then return i 1 6. Else write(“el dato” , x , “no existe”) 1 Contador de frecuencia = 3(n + 4) Y el orden de magnitud es O(n) 1.4.1 EJERCICIO DE APRENDIZAJE Análisis del algoritmo Ordenamiento por burbuja 1. Void burbuja() 1 2. Entero i, j 1 3. For (i = 1; i < n; i++) do N 4. For (j= 1; j<=n-i; j++) do n(n -1)/2 +(n – 1) 5. If v[j] > V[j + 1] then n(n -1)/2 6. Intercambia(i, j + 1) n(n -1)/2 7. End (if) n(n -1)/2 8. End (for) n(n -1)/2 9. End (for) n – 1 10. End (burbuja) 1
  • 36. sfs Algoritmos II 36 Contador de frecuencia = 5n(n – 1)/2 + 3n + 1 Y el orden de magnitud es O(n2) 1.4.2 TALLER DE ENTRENAMIENTO Al siguiente algoritmo coloque al frente cada instrucción el número de veces que se ejecuta cada una de ellas, además, hallar el contador de frecuencia y el orden de magnitud. Análisis del algoritmo Ordenamiento por Burbuja mejorado 1. Void burbujaMejorado () 2. Entero i, j, sw 3. For (i = 1; i < n; i++) do 4 Sw = 0 5. For (j= 1; j<=n-i; j++) do 6. If (V[j] > V[j + 1]) then 7. Intercambia(i, j + 1) 8. sw= 1 9. End (if) 10. End (for) 11. If (sw == 0) then return 12. End (for) 13. End (burbuja) Contador de frecuencia = ¿? Y el orden de magnitud es ¿? TIPS Los rendimientos de los algoritmos de ordenamiento y búsqueda alcanzan a llegar a niveles de logarítmicos y semilogarítmicos, mejorando los órdenes de los lineales y cuadráticos.
  • 38. 38 Algoritmos II 2 UNIDAD 2 MANEJO DE ESTRUCTURAS DINÁMICAS EN MEMORIA (LISTAS LIGADAS) 2.1.1 OBJETIVO GENERAL ➢ Reconocer el concepto de nodos, el manejo de listas simples, listas dobles y las operaciones con pilas y colas. 2.1.2 OBJETIVOS ESPECIFICOS ➢ Configurar la estructura nodo tanto simple como doble ➢ Realizar operaciones (buscar, insertar, borrar) con listas simples y dobles ➢ Realizar las operaciones de apilar, desapilar, encolar, desencolar tanto en vectores como en listas simples.
  • 39. 39 Algoritmos II 2.1.3 PRUEBA INICIAL • ¿Qué es un nodo? • ¿Qué es un puntero? • ¿Qué es una lista simplemente ligada? • ¿Qué es una lista doblemente ligada? • ¿Qué es un nodo cabeza? • ¿Qué es una pila? • ¿Qué es una cola? 2.2 TEMA 1 CONCEPTOS BÁSICOS Y LISTAS SIMPLEMENTE LIGADAS ➢Video: ” Conceptos basicos de listas lineales” ➢” Ver Video”: https://www.youtube.com/watch?v=1sObs2NdjrY” 2.2.1 TEMA 1 PUNTEROS Los punteros son direcciones de memoria que indica una posición de memoria dentro de la RAM, son muy utilizados con cuando se trabaja con memoria dinámica. Para representar el concepto de puntero se mostrará una lista. Donde cada cuadro contiene dos campos, uno para el dato y otro para la liga. Técnicamente, cada cuadro se denomina nodo, donde cada nodo posee una dirección de memoria.
  • 40. 40 Algoritmos II Ejemplo: el primer cuadro tiene la dirección 1F, el segundo 2F y el tercero 3F. 2.2.2 CLASE NODOSIMPLE Como nuestro objetivo es trabajar PROGRAMACIÓN ORIENTADA A OBJETOS, y para ello usamos clases con sus respectivos métodos, comencemos definiendo la clase en la cual manipulamos el nodo que acabamos de definir. A dicha clase la denominaremos nodoSimple: 1. CLASE nodoSimple 2. Privado 3. Objeto dato 4. nodoSimple liga 5. publico 6. nodoSimple() // constructor 7. objeto retornaDato() 8. nodoSimple retornaLiga() 9. void asignaDato(Objeto d) 10. void asignaLiga(nodoSimple x) 11. end(Clase nodoSimple) Los algoritmos correspondientes a los métodos definidos son: 1. nodoSimple(objeto d) // constructor 2. dato = d 3. liga = null 4. end(nodoSimple) 1. objeto retornaDato() 2. return dato 3. end(retornaDato)
  • 41. 41 Algoritmos II 1. nodoSimple retornaLiga() 2. return liga 3. end(retornaLiga) 1. void asignaDato(objeto d) 2. dato = d 3. end(asignaDato) 1. void asignaLiga(nodoSimple x) 2. liga = x 3. end(asignaLiga) Para usar esta clase consideremos el siguiente ejemplo: 1. nodoSimple x 2. d = 3.1416 3. x = new nodoSimple(d) Al ejecutar la instrucción 3 el programa se comunica con el sistema operativo y este le asigna una posición de memoria a nuestro programa, el cual identifica esta posición de memoria con la variable x. el resultado obtenido es: En el cual 19 es la dirección del nodo en la que se almacenan los campos de dato y liga. Dicha dirección la suministra el sistema operativo de una forma transparente para el usuario. Si queremos acceder los campos del nodo x, lo haremos así: d = x.retornaDato() // d queda valiendo 3.1416 z = x. retornaLiga() // z queda valiendo nulo
  • 42. 42 Algoritmos II A continuación, presentamos un ejemplo más completo de la utilización de la clase nodo Simple. Supongamos que tenemos el conjunto de datos a, b, c, f y que se procesan con el siguiente algoritmo: 1. nodoSimple x, y, z, p 2. read(d) // lee la letra “a” 3. x = new nodoSimple(d) // digamos que envió el nodo 4 4. read(d) // lee la letra “b” 5. y = new nodoSimple(d) // digamos que envió el nodo 8 6. read(d) // lee la letra “c” 7. z = new nodoSimple(d) // digamos que envió el nodo 3 El resultado grafico al ejecutar estas instrucciones es: Ahora, si ejecutamos las instrucciones: 8. x.asignaLiga(y) 9. y.asignaLiga(z) Los nodos quedaran conectados así: Si ejecutamos las siguientes instrucciones: 10. read(d) // lee la letra “f” 11. y = new nodoSimple(d) // digamos que envió el nodo 7 Nuestros nodos quedan así:
  • 43. 43 Algoritmos II Ahora, ejecutemos estas instrucciones: 12. p= x.retornaLiga() 13. write(p.retornaDato()) La variable p queda valiendo 8 y escribe la letra “b”. Y si ejecutamos esta otra instrucción: 14. x.retornaLiga().asignaLiga(y) Nuestros nodos quedan así: Observe que cuando se ejecuta x.retornaLiga() se está obteniendo el contenido del campo de liga del nodo x, el cual es el nodo 8 en nuestro ejemplo. Entonces. El nodo 8 invoca el método asignaLiga() y le estamos enviando como parámetro el nodo y, que en este momento vale 7. Podemos reorganizar el dibujo de nuestros nodos así: Ahora, si ejecutamos las siguientes instrucciones: 15. y.asignaLiga(z) 16. y = null 17. z = null 18. p = x
  • 44. 44 Algoritmos II Nuestra lista queda así: Y ahora ejecutemos estas instrucciones: 19. while (p != null) do 20. write(p.retornaDato()) 21. p = p.retornaLiga() 22. end(while) En la instrucción 20, la primera vez que entra al ciclo escribe la letra “a”, puesto que p vale 4. En la instrucción 21 modifica el valor de p: a p le asigna lo que hay en el campo de liga del nodo 4, es decir, 8. Nuestra lista está así: La segunda vez que entra al ciclo escribe la letra “b” y la p queda valiendo 7. Nuestra lista está así: La tercera vez que entra al ciclo escribe la letra “f” y la p queda valiendo 3:
  • 45. 45 Algoritmos II La cuarta vez que entra al ciclo escribe la letra “c” y la p queda valiendo null; por consiguiente, termina el ciclo. Este ciclo, instrucciones 19 a 22, tiene orden de magnitud O(n), siendo n el número de nodos de la lista. Ahora, si por último ejecutamos estas instrucciones: 23. x.asignaLiga(x.retornaLiga().retornaLiga()) La lista queda así: Observe que no hemos dibujado el nodo 8 ya que no está conectado con los otros, pues se ha desconectado de la lista con la instrucción 23. Lo que hace la instrucción 23 se puede escribir también con las siguientes instrucciones: 23a. y = x.retornaLiga() 23b. x.asignaLiga(y.retornaLiga()) o 23a. y = x.retornaLiga() 23b. y = y.retorna.Liga() 23c. x.asignaLiga(y) 2.2.3 LISTAS SIMPLEMENTE LIGADAS Las listas simplemente ligadas son estructuras donde se maneja la información de forma dinámica, donde el espacio donde se la guarda la información es un nodo, donde este se subdivide en dos espacios un espacio para guardar la información y otro para guardar la dirección de memoria al siguiente nodo, con estas listas se pueden realizar las operaciones de insertar, ordenar, buscar, borrar y todo esto bajo el concepto de memoria dinámica. Es supremamente importante que entienda bien este ejemplo de aplicación de la clase nodoSimple.
  • 46. 46 Algoritmos II 2.2.3.1 CLASE LISTAS SIMPLEMENTE LIGADA Es un conjunto de nodos conectados cuyo elemento básico son objetos de la clase nodoSimple. Con el fin de poder operar sobre este conjunto de nodos es necesario conocer el primer nodo del conjunto de nodos que están conectados, y en muchas situaciones el último nodo del conjunto. Con base en esto vamos a definir la clase llamada LSL (lista simplemente ligada), la cual tendrá dos datos privados de la clase nodoSimple, que llamaremos primero y último: primero apuntara hacia el primer nodo de la lista y último apuntará hacia el último nodo de la lista. Además, definiremos las operaciones que podremos efectuar sobre objetos de dicha clase. 1. CLASE LSL 2. Privado 3. nodoSimple primero, ultimo 4. Publico 5. LSL() // constructor 6. boolean esVacia() 7. nodoSimple primerNodo() 8. nodoSimple ultimoNodo() 9. nodoSimple anterior(nodoSimple x) 10. boolean finDeRecorrido(nodoSimple x) 11. void recorre() 12. nodoSimple buscaDondeInsertar(Objeto d) 13. void insertar(Objeto d, nodoSimple y) 14. void conectar(nodoSimple x, nodoSimple y) 15. nodoSimple buscarDato(Objeto d, nodoSimple y) 16. void borrar(nodoSimple x, nodoSimple y) 17. void desconectar(nodoSimple x, nodoSimple y) 18. void ordenaAscendentemente() 19. end(Clase)
  • 47. 47 Algoritmos II Expliquemos brevemente cada uno de los métodos definidos. Comencemos con el constructor: cuando se ejecuta el constructor lo único que se hace es crear una nueva instancia de la clase LSL con sus correspondientes datos privados en null. Ejemplo: si tenemos estas instrucciones: 1. LSL a, b 2. a = new LSL() 3. b = new LSL() Lo que se obtiene es: Para explicar que es lo que hace cada uno de los métodos definidos en la clase LSL consideremos el siguiente objeto, perteneciente a la clase LSL y que llamamos a: La función esVacia() retorna verdadero si la lista que invoca el método está vacía; de lo contrario, retorna falso. Una lista está vacía cuando la variable primero es null. La función primerNodo() retorna el nodo que esta de primero en la lista. Si efectuamos la instrucción p = a.primerNodo(), entonces p quedara valiendo 4. La función ultimoNodo(), retorna el nodo que esta de ultimo en la lista. Si ejecutamos la instrucción p = a.ultimoNodo(), entonces p quedara valiendo 5. La función finDeRecorrido(p) retorna verdadero si el nodo p enviado como parámetro es null; de lo contrario, retorna falso.
  • 48. 48 Algoritmos II La función anterior(x) retorna el nodo anterior al nodo enviado como parámetro. Si tenemos que x = 7 y ejecutamos la instrucción p = a.anterior(x), entonces p quedara valiendo 8. El método recorre(), como su nombre lo dice, simplemente recorre y escribe los datos de una lista simplemente ligada. Si ejecutamos la instrucción a.recorre(), el resultado que se obtiene es la escritura de b, e, i, o, u. La función buscaDondeInsertar(d) retorna el nodo a continuación del cual se debe insertar un nuevo nodo con dato d en una lista simplemente ligada en la que los datos están ordenados ascendentemente y deben continuar cumpliendo esta característica después de insertarlo. Presentemos algunos ejemplos: y = a.buscaDondeInsertar(“f”) entonces y queda valiendo 8. y = a.buscaDondeInsertar(“z”) entonces y queda valiendo 5. y = a.buscaDondeInsertar(“a”) entonces y queda valiendo null. El método insertar(d, y) consigue un nuevo nodoSimple, lo carga con el dato d e invoca el método conectar con el fin de conectar el nuevo nodo (llamémoslo x) a continuación del nodo y. Si ejecutamos las siguientes instrucciones: d = “f” y = a.buscaDondeInsertar(d) a.insertar(d, y) El objeto a, quedara así: El método conectar simplemente conecta el nodo x a continuación del nodo y, tal como se ve en la figura anterior. La función buscarDato(d, y), como su nombre lo dice, busca el dato d en la lista invoca el método: si lo encuentra, retorna el nodo en el cual lo encontró; de lo contrario, retorna null. En el
  • 49. 49 Algoritmos II parámetro y, el cual debe ser un parámetro por referencia, retorna el nodo anterior al nodo en el cual encontró el dato d. algunos ejemplos son: x = a.buscarDato(“f”, y) entonces x queda valiendo 9 y y queda valiendo 8. x = a.buscarDato(“u”, y) entonces x queda valiendo 5 y y queda valiendo 3. x = a.buscarDato(“b”, y) entonces x queda valiendo 4 y y queda valiendo null. x = a.buscarDato(“m”, y) entonces x queda valiendo null y y queda valiendo último, es decir 5. El método borrar(x, y) controla que el parámetro x sea diferente de null: si x es null produce el mensaje de que el dato d (el dato buscado con el método buscarDato) no se halla en la lista y retorna; si x es diferente de null, invoca el método desconectar(x, y). El método desconectar(x, y) simplemente desconecta el nodo x de la lista que invoca el método. Para desconectar un nodo de una lista se necesita conocer cuál es el nodo anterior. Por lo tanto, el nodo y, el segundo parámetro, es el nodo anterior a x. si ejecutamos las siguientes instrucciones: d = “i” x = a. buscarDato(d, y) // x queda valiendo 7 y y queda valiendo 9 a.borrar(x, y) // desconecta el nodo x Esta queda así: El método ordenaAscendentemente(), como su nombre lo dice, reorganiza los nodos de una lista simplemente ligada, de tal manera que los datos en ella queden ordenados ascendentemente.
  • 50. 50 Algoritmos II Si tenemos la siguiente lista: Y ejecutamos la instrucción a.ordenaAscendentemente(), la lista quedara así: Observe que los datos no se han movido, son los nodos los que han cambiado de posición y por consiguiente primero y último han variado. Asegúrese de entender bien que es lo que hace cada método. Si usted conoce bien lo que hace cada método, podrá usarlos apropiadamente; de lo contrario, no. 2.2.3.2 IMPLEMENTACIÓN DE LOS MÉTODOS DE LA CLASE LISTA SIMPLEMENTE LIGADA El constructor: LSL() Primero = ultimo = null end(LSL) Simplemente inicializa los datos privados primero y último en null. Como ingeniero de sistemas, debe saber cómo usar los métodos de una clase y además como implementarlos.
  • 51. 51 Algoritmos II Boolean esVacia() Return primero == null end(esVacia) Recuerde que tanto C como en java la instalación return x == y Es equivalente a: if (x == y) return true else return false nodoSimple primerNodo() return primero end(primero) nodoSimple ultimoNodo() return ultimo end(ultimo) boolean finDeRecorrido(nodoSimple x) return x == null end(finDeRecorrido) 1. void recorre() 2. nodoSimple p 3. p = primerNodo() 4. while no finDeRecorrido(p) do
  • 52. 52 Algoritmos II 5. Write(p.retornaDato()) 6. p = p.retornaLiga() 7. end(while) 8. end(Método) Para recorrer y escribir los datos de una lista simplemente ligada se requiere una variable auxiliar, la cual llamamos p. dicha variable se inicializa con el primer nodo de la lista simplemente ligada(instrucción 3 del método anterior) y luego planteamos un ciclo (instrucciones 4 a 7), el cual se ejecuta mientras p sea diferente a null (método finDeRecorrido()). Cuando p sea null se sale del ciclo y termina la tarea. Simplemente no escribe nada. Es decir, la instrucción 4 se controlan dos situaciones: lista vacía y fin de recorrido. 2.2.3.3 PROCESO DE INSERCIÓN DE UN DATO EN UNA LISTA SIMPLEMENTE LIGADA Para insertar un dato d en una lista ligada hemos definido tres métodos en nuestra clase LSL: buscarDondeInsertar(d), insertar(d, y) y conectar(x, y). Analicemos cada uno de ellos. Es importante recordar que en este proceso de inserción se requiere que los datos de la lista se hallen ordenados en forma ascendente. Consideremos la siguiente lista y que se desea insertar el dato “g”. Lo primero que se debe hacer es determinar en qué sitio debe quedar la letra “g” para que se cumpla que los datos continúen ordenados en forma ascendente. Por observación, nos damos cuenta de que la “g” debe quedar entre la “f” y la “o”, es decir, a continuación del nodo 9. Observe que, si por alguna razón el objeto que invoca este método tiene la lista vacía, nuestro método funciona correctamente.
  • 53. 53 Algoritmos II Nuestro primer método, buscaDondeInsertar(d), efectúa la tarea que determina a continuación de cual nodo debe quedar el dato a insertar. El método para esta tarea es: 1. nodoSimple buscaDondeInsertar(Objeto d) 2. nodoSimple p, y 3. p = primerNodo() 4. y = anterior(p) 5. while (no finDeRecorrido(p) and p.retornaDato() < d) do 6. y = p 7. p = p.retornaLiga() 8. end(while) 9. return y 10. end(buscaDondeInsertar) En este método se requieren dos variables auxiliares, las cuales llamamos p y y. con la variable p se recorre y a medida que la vamos recorriendo se va comparando el dato de p (p.retornaDato()) con el dato d que se desea insertar. Mientras que el dato de p sea menor que d se avanza en la lista con p y con y. la variable y siempre estará apuntando hacia a p. como inicialmente p es el primer nodo, inicialmente y es null. Fíjese que si el dato d a insertar es menor que el dato del primer nodo de la lista simplemente ligada nuestro método retorna null. El hecho de que nuestro método retorne null significa que el dato a insertar va a quedar de primero en la lista. Veamos ahora como es el algoritmo para nuestro método Insertar(d, y): 1. void insertar(Objeto d, nodoSimple y) 2. nodoSimple x 3. x = nodoSimple(d) 4. conectar(x, y) 5. end(Método) Nuestro método insertar consigue simplemente un nuevo nodo, lo carga con el dato d e invoca el método conectar. El parámetro y se refiere al nodo a continuación del cual habrá que conectar el nuevo x. Ocupémonos del método conectar(x, y): • Caso 1: Al ejecutar y = buscaDondeInsertar(d) con d = “g” en el objeto de la figura anterior y el método insertar(d, y), estamos en la situación mostrada en la figura siguiente:
  • 54. 54 Algoritmos II Conectar el nodo x a continuación del nodo y implica que cuando lleguemos al nodo y debemos trasladarlo hacia el nodo x, o sea que el campo de liga del nodo y debe quedar valiendo 6, y cuando estemos en el nodo x debemos trasladarnos hacia el nodo 3, es decir, que el campo liga del nodo x debe quedar valiendo 3. O sea que, hay que modificar dos campos de liga: el campo de liga del nodo y y el campo de liga del nodo x. para lograr esto debemos ejecutar las siguientes instrucciones: x.asignaLiga(y.retornaLiga()) // modifica el campo de liga del nodo x y.asignaLiga(x) // modifica el campo de liga del nodo y Y la lista queda así: Y como se podrá observar, se ha insertado el nodo x a continuación del nodo y • Caso 2: Consideremos que el dato a insertar es d = “z”. Al ejecutar y=buscaDondeInsertar(d), y el método insertar(d, y), estamos en la siguiente situación:
  • 55. 55 Algoritmos II Conectar x a continuación de y se logra con las mismas instrucciones del caso 1, teniendo en cuenta que como el dato que se inserta queda de ultimo hay que actualizar la variable último. Lo anterior significa que las instrucciones para conectar x a continuación de y serán: x.asignaLiga(y.retornaLiga()) // modifica el campo de liga del nodo x y.asignaLiga(x) // modifica el campo de liga del nodo y if (y == ultimo) then ultimo = x end(if) Y la lista queda así: • Caso 3: Consideremos que el dato a insertar es d = “a”. al ejecutar y=buscaDondeInsertar(d) y el método insertar(d, y), estamos en la situación mostrada:
  • 56. 56 Algoritmos II En esta situación, cuando la y es null, es decir que el dato a insertar quedara de primero, hay que modificar el campo de la liga x y la variable primero: x.asignaLiga(primero) primero = x Pero hay que tener en cuenta que la lista pudo haber estado vacía. Si esa fuera la situación habría que actualizar también la variable última. Considerando estas situaciones, las instrucciones completas para conectar un nodo x al principio de la lista son: x.asignaLiga(primero) if (primero == null) then ultimo = null end(if) primero = x El algoritmo completo para el método conectar consiste simplemente en agrupar las instrucciones descritas para cada uno de los casos en un solo método. Dicho método se presenta a continuación: en las instrucciones 2 a 7 se consideran los casos 1 y 2, mientras que en las instrucciones 9 a 13 se considera el caso 3: 1. void conectar(nodoSimple x, nodoSimple y) 2. if (y != null) then 3. x.asignaLiga(y.retornaLiga()) 4. y.asignaLiga(x) 5. if (y == ultimo) then 6. ultimo = x 7. end(if) 8. Else 9. x.asignaLiga(primero) 10. if (primero == null) then 11. ultimo = x 12. end(if) 13. primero = x 14. end(if) 15. end(Método)
  • 57. 57 Algoritmos II 2.2.3.4 PROCESO DE BORRADO DE UN DATO EN UNA LISTA SIMPLEMENTE LIGADA Borrar un dato de una lista simplemente ligada consiste en ubicar el nodo en el cual se halla el dato y desconectarlo de lista. Para ello hemos definido tres métodos que hemos llamado buscarDato(d, y), borrar(x, y) y desconectarlo(x, y). Si tenemos la siguiente lista: Y queremos borrar el nodo que contiene la letra “f”, lo primero que debemos hacer es determinar en cual nodo se halla la letra “f” y cuál es su nodo anterior. Esta tarea se efectúa con el método buscarDato(d, y): ejecutamos la instrucción x = a.buscarDato(d, y) Y estamos en esta situación: El algoritmo correspondiente al método buscarDato(d, y) es similar al método buscarDondeInsertar(d) y lo presentamos a continuación. 1. nodoSimple buscarDato(Objeto d, nodoSimple y) 2. nodoSimple x 3. x = primerNodo() 4. y = anterior(x) 5. while (no finDeRecorrido(x) and x.retornaDato()) != d do 6. y = x 7. x = x.retornaLiga() 8. end(while)
  • 58. 58 Algoritmos II 9. return x 10. end(buscarDato) Utilizamos la variable x para recorrer la lista e ir comparando el dato del nodo x con d. de este ciclo, instrucciones 5 a 8, se sale cuando encuentre o cuando haya terminado de recorrer la lista. Observe que cuando el dato que se busca no se halla en la lista el parámetro y queda valiendo último. Además, cuando el dato que se busca es el primer dato de la lista, la variable y queda valiendo null. Nuestro método borrar(x, y) consiste simplemente en controlar que el nodo x sea diferente de null. Si el nodo x es null significa que el dato no se encontró en la lista; por consiguiente no hay ningún nodo para desconectar, entonces produce el mensaje correspondiente y retorna al programa llamante puesto que no hay nada más que hacer. Si x es diferente de null se invoca el método desconectar. El algoritmo correspondiente a dicho método se presenta a continuación: void borrar(nodoSimple x, nodoSimple y) if x == null then write(“dato no existe”) return end(if) desconectar(x, y) end(Método) Analicemos ahora las instrucciones correspondientes al método desconectar (x, y). • Caso 1: Es la situación mostrada en la figura anterior. Lo único que hay que hacer para desconectar el nodo x es modificar el campo de liga del nodo y, asignándole lo que hay en el campo liga del nodo x. esto se logra con la siguiente instrucción: y.asignaLiga(x.retornaLiga())
  • 59. 59 Algoritmos II • Caso 2: Si el dato a borrar es d = “z”, al ejecutar la instrucción x = a.buscarDato(d, y) La situación es: Por consiguiente, cuando se desconecte el nodo x la variable última debe quedar valiendo y y las instrucciones serán: y.asignaLiga(x.retornaLiga()) if (x == ultimo) then ultimo = y end(if) • Caso 3: Si el dato a borrar es d = “b” al ejecutar la instrucción x = a.buscarDato(d, y) La situación es: Con la variable y valiendo null. En esta situación lo que hay que hacer es actualizar la variable primero: a primero se le asigna lo que haya en el campo de liga primero. Hay que tener en cuenta que puede suceder que la lista solo hubiera tenido un nodo; en este caso la variable primero quedará valiendo null, y por lo tanto
  • 60. 60 Algoritmos II la variable ultimo también deberá quedar valiendo null. Las instrucciones para resolver este caso son: primero = primero.retornaLiga() if (primero == null) then ultimo = null end(if) Agrupando las instrucciones correspondientes a los tres casos en un solo algoritmo obtenemos: 1. void desconectar (nodoSimple x, nodoSimple y) 2. if (x != primero) then 3. y.asignaLiga(x.retornaLiga()) 4. if (x == ultimo) then 5. ultimo = y 6. end(if) 7. else 8. primero = primero.retornaLiga() 9. if (primero == null) then 10. ultimo = null 11. end(if) 12. end(if) 13. end(Método) En las instrucciones 2 a 6 se resuelve para los casos 1 y 2, mientras que en las instrucciones 8 a 11 se resuelve para el caso 3. Los métodos para conectar y desconectar son métodos con orden de magnitud 0(1), lo cual mejora sustancialmente estas operaciones con respecto a la representación de datos en un vector.
  • 61. 61 Algoritmos II 2.2.3.5 ORDENAMIENTO DE DATOS EN UNA LISTA SIMPLEMENTE LIGADA Presentemos a continuación un método que utiliza el método selección, el cual, se enuncia así: “de los datos que faltan por ordenar, determine cuál es el menor y colocarlo de primero en ese conjunto de datos”. 1. void OrdenaAscendentemente() 2. nodoSimple p, ap, menor, amenor, q, aq 3. p = primerNodo() 4. ap = anterior(p) 5. while (p != ultimoNodo()) 6. menor = p 7. amenor = ap 8. q = p.retornaLiga 9. aq =p 10. while (no finDeRecorrido(q)) 11. if (q.retornaDato() < menor.retornaDato()) 12. menor = q 13. amenor = aq 14. end(if) 15. aq =q 16. q = q.retornaLiga() 17. end(while) 18. if(menor == p) 19. ap = p 20. p = p.retornaLiga() 21. else 22. desconectar(menor, amenor) 23. conectar(menor, ap) 24. ap = menor 25. end(if) 26. end(while) 27. end(Método) Con base en este enunciado definimos las variables necesarias para elaborar el método. Se requiere una variable que indique a partir de cual nodo faltan datos por ordenar. Dicha variable la llamamos p. inicialmente p apunta hacia el primer nodo ya que al principio faltan todos los datos por ordenar. Se requiere otra variable para recorrer la lista e ir comparando los datos para
  • 62. 62 Algoritmos II determinar en cual nodo se halla el menor dato. Esta variable la llamamos q. y por último requerimos otra variable que apunte hacia el nodo que tiene el menor dato. Esta variable la llamamos menor. Como ya hemos visto, para efectuar las operaciones de conexión y desconexión se requiere conocer los registros anteriores a los nodos con los cuales se desean ejecutar dichas operaciones; por lo tanto, definimos otras tres variables que llamaremos ap, aq y amenor, las cuales apuntan hacia los nodos anteriores a p, q y menor respectivamente. En la instrucción 5 definimos el ciclo principal del ciclo. El método terminara cuando p este apuntando hacia el último nodo de la lista, puesto que cuando p este apuntando hacia ese nodo significa que solo falta un dato por ordenar, y un solo dato esta ordenado. En las instrucciones 6 y 7 asignamos los valores iniciales de menor y amenor. Inicialmente consideramos que el menor dato es el principio del conjunto de datos que faltan por ordenar, es decir, p. En las instrucciones 8 y 9 se asignan los valores iniciales de q y aq. En las instrucciones 10 a 17 se efectúa el ciclo para determinar cuál es el nodo que contiene el menor dato. Se compara el dato de nodo q con el dato del nodo menor. Si el dato de q es menor que el dato de menor, actualizaremos menor y su interior. Cualquiera que hubiera sido el resultado avanzamos con q y su anterior. En la instrucción 18 confrontamos en cual posición está el nodo de tiene el menor dato. Si el menor dato estaba de primero en ese conjunto de datos, es decir, en p, simplemente avanzamos con p y su anterior (instrucciones 19 y 20); de lo contrario, desconectamos el nodo menor, cuyo anterior es amenor, y lo conectamos a continuación de ap (instrucciones 22 y 23). De haber ocurrido esto último, el anterior a p, es decir ap, ya es menor (instrucción 24). Nuestro método consistirá entonces en determinar cuál es el nodo que tiene el menor dato entre los datos que faltan por ordenar; desconectamos el nodo de ese sitio y lo conectamos al principio de ese conjunto de datos.
  • 63. 63 Algoritmos II 2.2.3.6 MÉTODO ANTERIOR(X) Ya hemos definido que nuestro método denominado anterior(x) retornara el nodo anterior al nodo x enviado como parámetro. Para ello bastara con recorrer la lista simplemente ligada utilizando dos variables auxiliares: una (llamémosla p) que se va comparando con x, y otra que siempre apuntara hacia el nodo anterior a x (llamémosla y). cuando p sea igual a x, simplemente se retorna y. inicialmente será el primer nodo y y será null. Nuestro método es el siguiente: nodoSimple anterior(x) nodoSimple p, y p = primerNodo() y = null while (p != x) do y = p p = p.retornaLiga() end(while) return y end(anterior) 2.2.3.7 CONSTRUCCIÓN DE LISTAS SIMPLEMENTE LIGADAS Pasemos ahora a considerar como construir listas simplemente ligadas. Básicamente hay tres formas de hacerlo: una, que los datos queden ordenados ascendentemente a medida que la lista se va construyendo; otra, insertando nodos siempre al final de la lista; y una tercera, insertando los nodos siempre al principio de la lista. Para la primera forma de construcción (que los datos queden ordenados ascendentemente a medida que se va construyendo la lista), un método general es: LSL a a = new LSL()
  • 64. 64 Algoritmos II Mientras haya datos por leer haga Lea(d) y = a.buscaDondeInsertar(d) a.insertar(d, y) end(mientras) Es decir, basta con plantear un ciclo para la lectura de datos e invocar los métodos para buscar donde insertar e insertar desarrollados previamente. Para la segunda forma de construcción (insertando nodos siempre al final de la lista), un método es: LSL a nodoSimple a = new LSL() mientras haya datos por leer haga lead(d) y = a.ultimoNodo() a.insertar(d, y) end(mientras) Nuevamente se plantea un ciclo para la lectura de datos y cada vez que se lea un dato se determina el último y se invoca el método para insertar. 2.2.4 DIFERENTES TIPOS DE LISTAS SIMPLEMENTE LIGADAS Y SUS CARACTERÍSTICAS Comencemos presentando gráficamente los diferentes tipos de lista que se pueden construir: • Listas simplemente ligadas:
  • 65. 65 Algoritmos II • Listas simplemente ligadas circulares: • Listas simplemente ligadas circulares con nodo cabeza: • Listas simplemente ligadas con nodo cabeza: 2.2.5 EJERCICIO DE APRENDIZAJE En cada tema anterior se muestra los ejercicios de aprendizaje. 2.2.6 TALLER DE ENTRENAMIENTO Esta es la tercera forma de construcción de lista (insertando nodos siempre al principio de la lista), nuestro método es:
  • 66. 66 Algoritmos II LSL a a = new LSL Mientras haya datos por leer haga lead(d) a.insertar(d, null) end(mientras) Aquí, basta con plantear el ciclo para lectura de datos e invocar el método insertar enviado como segundo parámetro null. Recuerde que nuestro método insertar(d, y) inserta un nodo con dato d a continuación de y: si y es null significa que el dato d quedara de primero. 2.3 TEMA 2 LISTAS DOBLEMENTE LIGADAS Y OTROS TIPOS DE TOPOLOGÍAS DE LISTAS ➢Video: ” Lista Doblemente Ligada” ➢” Ver Video”: https://www.youtube.com/watch?v=6C8_tKeGp6I&ab_channel=EdwinGonz%C3%A1lezTer%C3 %A1n ” 2.3.1 LISTA DOBLEMENTE LIGADAS Las listas doblemente ligadas son estructuras que permiten manejar la información de forma dinámica, donde el espacio donde se guarda la información es un nodo, que es una dirección de memoria dividida en tres partes, una parte para guardar la información, otra para la dirección al Nota: realice una prueba de escritorio para que visualice el proceso. TIPS El manejo dinámico de la memoria nos permite optimizar este recurso.
  • 67. 67 Algoritmos II siguiente nodo y la otra para apuntar al nodo anterior, con estas listas se pueden realizar las operaciones de insertar, borrar, buscar, ordenar y todo bajo el concepto de memoria dinámica. 2.3.1.1 DEFINICIÓN DE CARACTERÍSTICAS Un nodo doble es un registro que tiene dos campos de liga: uno que llamaremos Li (Liga izquierda) y otro que llamaremos Ld (Liga derecha). Un dibujo para representar dicho nodo es: Liga izquierda Área de datos Liga derecha Donde: Li: apunta hacia el nodo anterior. Ld: apunta hacia el nodo siguiente. Con base en esto vamos a definir una clase que llamaremos nodoDoble: 1. CLASE nodoDoble 2. Privado 3. Objeto dato 4. nodoDoble Li, Ld 5. publico 6. nodoDoble(objeto d) // constructor 7. void asignaDato(objeto d) 8. void asignaLd(nodoDoble x) 9. void asignaLi(nodoDoble x) 10. objeto retornaDato() 11. nodoDoble retornaLd() 12. nodoDoble retornaLi() 13. end(Clase)
  • 68. 68 Algoritmos II Los algoritmos correspondientes a cada uno de estos métodos son los siguientes: 1. nodoDoble(objeto d) // constructor 2. dato = d 3. Ld = null 4. Li = null 5. end(nodoDoble) 1. void asignaDato(objeto d) 2. dato = d 3. end(Método) 1. void asignaLd(nodoDoble x) 2. Ld = x 3. end(asignaLd) 1. void asignaLi(nodoDoble x) 2. Li = x 3. end(asignaLi) 1. objeto retornaDato() 2. return dato 3. end(retornaDato) 1. nodoDoble retorna(Li) 2. return Li
  • 69. 69 Algoritmos II 3. end(retornaLi) 1. nodoDoble Ld() 2. return Ld 3. end(retornaLd) 2.3.1.2 PROPIEDAD FUNDAMENTAL DE LAS LISTAS DOBLEMENTE LIGADAS Es importante ver aquí lo que se conoce como la propiedad fundamental de las listas doblemente ligadas ya que está basada en las características de los campos de liga de los nodos dobles. Para ello, consideremos los siguientes tres registros consecutivos: El campo de la liga izquierda del nodo x vale 9, lo cual indica que el nodo anterior es el nodo 9; por lo tanto, el nodo 9 es el nodo x.retornaLi(). El campo de liga derecha del nodo x vale 5, lo cual indica que el nodo siguiente es el nodo 5; por consiguiente, el nodo 5 es el nodo x.retornaLd(). El nodo x.retornaLi() tiene un campo de liga derecha, el cual vale 7, es decir, el mismo nodo x. El nodo x.retornaLd() tiene un campo de liga izquierda, el cual también vale 7, es decir, el nodo x. Dado lo anterior, se tiene que: x.retornaLi().retornaLd() == x == x.retornaLd().retornaLi() Esta característica se conoce como la “propiedad fundamental de las listas doblemente ligadas”, y es de suprema importancia entenderla bien con el fin de manipular apropiadamente los objetos de la clase lista doblemente ligada.
  • 70. 70 Algoritmos II 2.3.2 EJERCICIO DE APRENDIZAJE Teniendo definida esta clase (clase doble), procedemos a desarrollar un método en el cual hagamos uso de ella y de sus métodos. Consideremos que se tiene el conjunto de datos b, e, i, o, u, y que nuestro método los leerá en ese orden: 1. nodoDoble w, x, y, z 2. read(d) 3. w = new nodoDoble(d) 4. read(d) 5. x = new nodoDoble(d) 6. read(d) 7. y = new nodoDoble(d) 8. read(d) 9. z = new nodoDoble(d) Al ejecutar estas instrucciones el escenario que se obtiene es el siguiente: Continuemos nuestro algoritmo con estas instrucciones: 10. w.asignaLd(x) 11. x.asignaLi(w) 12. x.asignaLd(y) 13. y.asignaLi(x) 14. y.asignaLd(z) 15. z.asignaLi(y) Al ejecutar estas instrucciones nuestro escenario es: Fíjese que el campo Ld del nodo w quedo valiendo 2, en virtud de la instrucción 10, lo cual indica que el nodo siguiente a w es el 2; el campo Li de x (el nodo 2) quedo valiendo 6, en virtud de la instrucción 11, lo cual significa que el nodo anterior a x es el 6; el campo Ld del nodo x quedo
  • 71. 71 Algoritmos II valiendo 7, en virtud de la instrucción 12, lo cual quiere decir que el nodo siguiente a x es el 7. De una forma similar se han actualizado los campos Li y Ld de los nodos y y z. Asegúrese de entender bien el escenario actual. Continuemos ejecutando las siguientes instrucciones: 16. w = null 17. y = null 18. z = null En este momento nuestra situación es: Ahora ejecutemos estas otras instrucciones: 19. read(d) 20. y = new nodoDoble(d) 21. y.asignaLd(x.retornaLd()) 22. y.asignaLi(x) 23. y.retornaLd().asignaLi(y) 24. x.asignaLd(y) La situación queda así: Ahora, al ejecutar esta instrucción: 25. y = null La nueva situación es: Por último, ejecutemos estas otras instrucciones:
  • 72. 72 Algoritmos II 26. x.retornaLi().asignaLd(x.retornaLd()) 27. x.retornaLd().asignaLi(x.retornaLi()) Y nuestros nodos quedan así: Fíjese que el resultado de ejecutar las instrucciones 26 y 27 fue eliminar el nodo x. unas de instrucciones que harían la misma tarea que las instrucciones 26 y 27 son: 1. p = x.retornaLi() 2. q = x.retornaLd() 3. p.asignaLd(q) 4. q.asignaLi(p) Si lo hubiéramos hecho de ese modo, la lista quedaría así: Es muy importante entender que las instrucciones 26 y 27 ejecutan la misma tarea que las instrucciones 1, 2, 3 y 4 mostradas a continuación de ellas. 2.3.3 TALLER DE ENTRENAMIENTO Pautas para desarrollar los siguientes ejercicios: Para desarrollar cada uno de esos ejercicios, debes tener muy claro el concepto de nodo y la forma de cómo vas a estructurar el nodo. Recuerda que, para listas simplemente ligadas el nodo se compone de dos partes, una parte de datos y una parte de liga; para las listas doblemente ligadas el nodo se conforma de tres partes, una parte de dato, y dos partes de ligas, una liga que apunta al nodo anterior y una liga que apunta al nodo siguiente. 1. Elabore un método que lea un entero n y que construya una lista simplemente ligada, de a digito por nodo. 2. Elabore un método que borre de una lista simplemente ligada un dato dado todas las veces que lo encuentre.
  • 73. 73 Algoritmos II 3. Se tiene una lista simplemente ligada, con un dato numérico en cada nodo. Elabore un método que determine e imprima el promedio de datos de la lista. 4. Elabore un método que intercambie los registros de una lista doblemente ligada así: el primero con el último, el segundo con el penúltimo, el tercero con el antepenúltimo, y así sucesivamente. 5. Elabore un método que intercambie los registros de una lista doblemente ligada así: el primero con el tercero, el segundo con el cuarto, el quinto con el séptimo, el sexto con el octavo, y así sucesivamente. 2.4 TEMA 3 PILAS Y COLAS (ESTÁTICAS Y DINÁMICAS) ➢Video: ” Manipulación de información. Pilas y colas” ➢” Ver Video”: https://www.youtube.com/watch?v=56jBvugTCn0 ” 2.4.1 RELACIÓN DE CONCEPTOS ➢ Pilas: Son estructuras de datos que se manejan de forma estática, donde se realiza las operaciones de apilar y desapilar, manejando el concepto de último en llegar primero en salir. ➢ Vector: En programación se denomina matriz, vector o formación (en inglés array) a una zona de almacenamiento continuo que contiene una serie de elementos del mismo tipo, los elementos de la matriz. Desde el punto de vista lógico una matriz se puede ver como un conjunto de elementos ordenados en fila (o filas y columnas si tuviera dos dimensiones). Tomado de: https://es.wikipedia.org/wiki/Vector_(inform%C3%A1tica) ➢ Listas ligadas: Las listas ligadas son una mejor alternativa para añadir información a una base de datos; en lugar de utilizar arreglos que son estáticos pues hay que reservar TIPS Las listas dobles permiten realizar recorridos de izquierda a derecha y de derecha a izquierda.
  • 74. 74 Algoritmos II memoria a la hora de programarlos, contrario a las listas ligadas que en un principio no ocupan memoria y se va reservando (creando) conforme lo va requiriendo nuestro programa. La memoria que ya no se utiliza se puede destruir y así ahorramos memoria en nuestros programas. Tomado de: http://sergioaj.blogspot.com.co/2011/01/listas-ligadas.html ➢ Crear: Crea una pila vacía. ➢ Apilar: Incluye el dato d en la pila. ➢ Desapilar: Elimina el último elemento de la pila y deja una nueva pila, la cual queda con un elemento menos. ➢ Cima: Retorna el dato que esta de último en la pila, sin eliminarlo. ➢ esVacia: Retorna verdadero si la pila está vacía: de lo contrario; retorna falso. ➢ esLlena:Retorna verdadero si la pila está llena; de lo contrario; retorna falso. ➢ Cola: Son estructuras de almacenamiento de datos, donde se maneja de forma estática, donde las operaciones de inserción se hace al final y las de borrado se hace al principio, en otras palabras el primero que llega es el primero en salir, y el último en llegar será el último en salir ➢ Crear: Crea una cola vacía. ➢ esVacia: Retorna verdadero si la cola está vacía; de lo contrario, retorna falso. ➢ esLlena: Retorna verdadero si la cola está llena; de lo contrario, retorna falso. ➢ Encolar: Inserta un dato d al final de la cola. ➢ Desencolar: Remueve el primer elemento de la cola. ➢ Siguiente: Retorna el dato que se halla de primero en la cola.
  • 75. 75 Algoritmos II 2.4.2 DEFINICIÓN Son estructuras de datos que no tienen representación propia a nivel de programación, para ello se apoyan en los vectores y en listas ligadas, permitiendo así manejar operaciones sobre ellas. 2.4.3 PILAS CON VECTORES Y LISTAS Las pilas como vectores son estructuras de datos que se manejan de forma estática, donde se realiza las operaciones de apilar y desapilar, manejando el concepto de último en llegar primero en salir. Las pilas como lista son estructuras de datos, pero se maneja de forma dinámica en la memoria. 2.4.3.1 DEFINICIÓN Una pila es una lista ordenada en la cual todas las operaciones (inserción y borrado) se efectúan en un solo extremo llamado tope. Es una estructura LIFO (Last Input First Output), que son las iniciales de las palabras en inglés “ultimo en entrar primero en salir”, debido a que los datos almacenados en ella se retiran en orden inverso al que fueron entrados. Un ejemplo clásico de aplicación de pilas en computadores se representa en el proceso de llamadas a métodos y sus retornos. Supongamos que tenemos un programa principal y tres métodos, así: Cuando se ejecuta el programa principal, se hace una llamada al método P1, es decir, ocurre una interrupción en la ejecución del programa principal. Antes de iniciar la ejecución de este método
  • 76. 76 Algoritmos II se guarda la dirección de la instrucción donde debe retornar a continuar la ejecución del programa principal cuando termine de ejecutar el método; llamamos L1 esta dirección. Cuando ejecuta el método P1 existe una llamada al método P2, hay una nueva interrupción, pero antes de ejecutar P2 se guarda la dirección de la instrucción donde debe retornar a continuar la ejecución del método P1, cuando termine de ejecutar el método P2; llamamos L2 esta dirección. Hasta el momento hay guardados dos direcciones de retorno: L1, L2 Cuando ejecuta el método P2 hay llamada a un método P3, lo cual implica una nueva interrupción y, por ende, guardar una dirección de retorno al método P2, la cual llamamos L3. Tenemos entonces tres direcciones guardadas, así: L1, L2, L3 Al terminar la ejecución del método P3 retorna a continuar ejecutando en la última dirección que guardo, es decir, extrae la dirección L3 y regresa a continuar ejecutando el método P2 en dicha instrucción. Los datos guardados ya son: L1, L2 Al terminar el método P2 extrae la última dirección que tiene guardada, en este caso L2, y retorna a esta dirección a continuar la ejecución del método P1. En este momento los datos guardados son: L1 Al terminar la ejecución del método P1 retornara a la dirección que tiene guardada, o sea a L1. Obsérvese que los datos fueron procesados en orden inverso al que fueron almacenados, es decir, último en entrar primero en salir. En esta forma de procesamiento la que define una estructura PILA. Veamos cuales son las operaciones que definiremos para la clase pila. Operaciones Características
  • 77. 77 Algoritmos II Crear Crea una pila vacía. Apilar Incluye el dato d en la pila. Desapilar Elimina el último elemento de la pila y deja una nueva pila, la cual queda con un elemento menos. Cima Retorna el dato que esta de último en la pila, sin eliminarlo. esVacia Retorna verdadero si la pila está vacía: de lo contrario; retorna falso. esLlena Retorna verdadero si la pila está llena; de lo contrario; retorna falso. 2.4.3.2 REPRESENTACIÓN DE PILAS EN UN VECTOR La forma más simple es utilizar un arreglo de una dimensión y una variable, que llamaremos tope, que indique la posición del arreglo en la cual se halla el último elemento de la pila. Por consiguiente, vamos a definir la clase pila derivada de la clase vector. La variable m de nuestra clase vector funciona coma la variable tope. Definamos entonces la clase pila. 1. CLASE Pila 2. Privado: 3. Object V[] 4. Entero tope, n 5. Publico: 6. pila(entero m) //constructor 7. boolean esVacia() 8. boolean esLlena() 9. void apilar(objeto d) 10. object desapilar()
  • 78. 78 Algoritmos II 11. void desapilar(entero i) 12. objeto tope() 13. end(Clase) Como hemos definido la clase pila derivada de la clase vector, veamos como son los algoritmos correspondientes a estos métodos: 1. pila(entero m) //constructor 2. V = new array[m] 3. n = m 4. Tope = 0 5. end(pila) 1. boolean esVacia() 2. return tope == 0 3. end(esVacia) 1. boolean esLlena() 2. return tope == n 3. end(esLlena) 1. void Apilar(objeto d) 2. if (esLlena()) then 3. write(“pila llena”) 4. return
  • 79. 79 Algoritmos II 5. end(if) 6. tope = tope + 1 7. V[tope] = d 8. end(Método) Apilar consiste simplemente en sumarle 1 a tope y llevar el dato a esa posición del vector: 1. objeto desapilar() 2. if (esVacia()) then 3. write(“pila vacia”) 4. return null 5. end(if) 6. d = V[tope] 7. tope = tope -1 8. return d 9. end(desapilar) Estrictamente hablando, desapilar consiste simplemente en eliminar el dato que se halla en el tope de la pila. Sin embargo, es usual eliminarlo y retornarlo. Eso es lo que hace nuestro anterior método para desapilar. El proceso de eliminación consiste simplemente en restarle 1 a tope. Definamos, en forma polimórfica, otro método para desapilar. Este nuevo método tendrá un parámetro i, el cual indicara cuantos elementos se deben eliminar de la pila: 1. void Desapilar(entero i ) 2. if ((tope – 1) >= 0) then 3. tope = tope – i
  • 80. 80 Algoritmos II 4. else 5. write(“no se pueden eliminar tantos elementos”) 6. end(if) 7. end(Método) 1. Objeto cima() 2. if (esVacia()) then 3. write(“pila vacia”) 4. return null 5. end(if) 6. return V[tope] 7. end(cima) 2.4.3.3 REPRESENTACIÓN DE PILAS COMO LISTAS LIGADAS Para representar una pila como listas ligadas basta definir la clase pila derivada de la clase LSL. Nuevamente, como estamos definiendo la clase pila derivada de la clase. LSL, podremos hacer uso de todos los métodos que hemos definido para esta clase LSL. A modo de ejemplo, representemos como listas ligadas la siguiente pila: D C B A
  • 81. 81 Algoritmos II Pila Dibujémosla de la forma como solemos hacerlo con las listas ligadas: Como hemos dicho las operaciones sobre una pila son apilar y desapilar: • Apilar: consiste en insertar un registro al principio de una lista ligada. • Desapilar: consiste en eliminar el primer nodo de la lista ligada y retornar el dato que se hallaba en ese nodo. Al definir la clase pila derivada de la clase LSL el método para controlar pila llena ya no se utiliza. Los métodos para la clase pila son: 1. void Apilar(objeto d) 2. insertar(d, null) 3. end(Método) 1. Objeto desapilar() 2. If (esVacia()) then 3. Write(“pila vacia, no se puede desapilar”) 4. Return null 5. End(if) 6. nodoSimple p 7. p = primerNodo() 8. d = p.retornaDato() 9. borrar(p, null) 10. return d
  • 82. 82 Algoritmos II 11. end(desapilar) Fíjese que en los métodos apilar y desapilar hemos usado los métodos insertar y borrar, los cuales fueron definidos para la clase LSL: 1. Objeto tope() 2. if (esVacia()) then 3. write(“pila vacía, no hay elemento para mostrar”) 4. return null 5. end(if) 6. nodoSimple p 7. p = primerNodo() 8. return p.retornaDato 9. end(tope) 2.4.3.4 MANEJO DE DOS PILAS EN UN VECTOR Puesto que es muy frecuente tener que manejar más de una pila en muchas situaciones, veremos cómo manejar dos pilas en un solo vector. Si n es el número de elementos del vector, dividimos inicialmente el vector en dos partes iguales. Llamamos m la variable que apunta hacia el elemento de la mitad. La primera mitad del vector será para manejar la pila 1, y la segunda mitad para manejar la pila 2. Cada pila requiere una variable tope para conocer en qué posición está el ultimo dado de la pila. Llamemos estas variables tope 1 y tope 2 para manejar las pilas 1 y 2, respectivamente. Consideremos el siguiente ejemplo:
  • 83. 83 Algoritmos II Sea V el vector en el cual manejaremos las dos pilas. El valor de n es 16. Inicialmente, el valor de m es 8 (la mitad de n): • La variable tope1 variara de 1 hasta m • La variable tope2 variara desde m + 1 hasta n • La pila 1 estará vacía cuando tope1 sea igual a 0 • La pila 1 estará llena cuando tope1 sea igual a m • La pila 2 estará vacía cuando tope2 sea igual a m • La pila 2 estará llena cuando tope2 sea igual a n Si definimos una clase denominada dosPilas cuyos datos privados son el vector V, m, n, tope1 y tope2, veamos cómo serán los métodos para manipular dicha clase. Consideremos primero un método para apilar un dato en alguna de las dos pilas. Habrá que especificar en cual pila es que se desea apilar. Para ello utilizaremos una variable llamada pila, la cual enviamos como parámetro del método. Si pila es igual a 1 hay que apilar en pila 1, y si pila es igual a 2, hay que apilar en pila 2. Nuestro método será: 1. void Apilar(entero pila, objeto d) 2. If (pila == 1) then 3. If (tope == m) then 4. pilaLlena(pila) 5. end(if) 6. tope1 = tope1 + 1 7. V[tope] = d
  • 84. 84 Algoritmos II 8. else 9. If (tope2 == n) then 10. pilaLlena(pila) 11. end(if) 12. tope2 = tope2 + 1 13. V[tope2] = d 14. end(if) 15. end(Método) El método pilaLlena recibe como parámetro el valor pila. La tarea de pilaLlena es: si el parámetro pila es 1 significa que la pila 1 es la que está llena, y por lo tanto buscara espacio en la pila 2; en caso de que esta no esté llena, se moverán los datos de la pila 2 una posición hacia la derecha, se actualizara m y se regresara al método apilar para apilar en la pila 1. Si es la pila 2 la que está llena buscara si hay espacio en la pila 1, y en caso de haberlo moverá los datos de la pila 2 una posición hacia la izquierda, actualizara m y regresara a apilar en la pila 2. Un método que efectué esta tarea es: 1. void PilaLlena(entero pila) 2. entero i 3. if (pila == 1) then 4. if (tope2 < n) then //hay espacio en la pila 2 5. for (i = tope2; i > m; i--) do 6. V[i + 1] =V[i] 7. end(for) 8. tope2 = tope2 + 1 9. m = m + 1
  • 85. 85 Algoritmos II 10. end(if) 11. else 12. if (tope1 < m) then 13. for (i = m; i < tope2; i++) do 14. V[i - 1] = V[i] 15. end(for) 16. tope2 = tope2 – 1 17. m = m – 1 18. end(if) 19. end(if) 20. write(“pilas llenas”) 21. stop 22. end(Método) Como se podrá observar, la operación de apilar implica mover datos en el vector debido a que una pila puede crecer más rápido que la otra. En otras palabras, este método tiene orden de magnitud lineal, el cual se considera ineficiente. Una mejor alternativa de diseño es la siguiente: La pila 1 se llenara de izquierda a derecha y la pila 2 de derecha a izquierda. Con este diseño no hay que preocuparse por cual pila crezca más rápido. Las condiciones a controlar son: • La pila 1 estará vacía cuanto tope1 sea igual a cero • La pila 2 estará vacía cuando tope2 sea igual a n + 1 (n =16) • Las pilas estarán llenas cuando tope1 + 1 sea igual a tope2
  • 86. 86 Algoritmos II El método apilar para este segundo diseño es: 1. void Apilar(entero pila, objeto d) 2. if (tope1 + 1 == tope2) then 3. pilaLlena 4. end(if) 5. if (pila == 1) then 6. tope1 = tope1 + 1 7. V[tope] = d 8. end(if) 9. end(Método) 2.4.4 TEMA 3 COLAS CON VECTORES Y LISTAS Las cola como vectores son estructuras de almacenamiento de datos, donde se maneja de forma estática, donde las operaciones de inserción se hace al final y las de borrado se hace al principio, en otras palabras el primero que llega es el primero en salir, y el último en llegar será el último en salir, de igual forma se maneja con las listas pero de forma dinámica. 2.4.4.1 DEFINICIÓN Una cola es una lista ordenada en la cual las operaciones de inserción se efectúan en un extremo llamado último y las operaciones de borrado se efectúan en el otro extremo llamado primero. Es una estructura FIFO (First Input First Output). Como podrá observar, con este diseño el proceso para pila llena no aparece; por lo tanto, no hay que mover los datos del vector y nuestro método para apilar tiene orden de magnitud constante.
  • 87. 87 Algoritmos II En términos prácticos, es lo que supuestamente se debe hacer para tomar un bus, para comprar las boletas y entrar a cine o para hacer uso de un servicio público. Las operaciones sobre una cola son: Operaciones Características Crear Crea una cola vacía. esVacia() retorna verdadero si la cola está vacía; de lo contrario, retorna falso esLlena() Retorna verdadero si la cola está llena; de lo contrario, retorna falso. Encolar(d) Inserta un dato d al final de la cola. Desencolar() Remueve el primer elemento de la cola Siguiente() Retorna el dato que se halla de primero en la cola. 2.4.4.2 REPRESENTACIÓN DE COLAS EN UN VECTOR, EN FORMA NO CIRCULAR Para representar colas en esta forma se requiere un vector, que llamaremos V, y dos variables: una que llamaremos primero, la cual indica la posición del vector en la que se halla el primer dato de la cola, y otra, que llamaremos último, que indica la posición en la cual se halla el último dato de la cola.