Está en la página 1de 20

Carátula para entrega de prácticas

Facultad de Ingeniería Laboratorio de docencia

Laboratorios de computación
salas A y B
Profesor: M.I. Edgar Tista García

Asignatura: Estructura de Datos y Algoritmos 1

Grupo: 01

No de Práctica(s): 11

Integrante(s): Cote Valencia Alexis Daniel

No. de Equipo de Personal


cómputo empleado:

No. de Lista o Brigada: 11

Semestre: 2021-2

Fecha de entrega: 31 de Julio de 2021

Observaciones:

CALIFICACIÓN:
__________
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
OBJETIVOS DE LABORATORIO
El objetivo de esta guía es implementar, al menos, dos enfoques de diseño
(estrategias) de algoritmos y analizar las implicaciones de cada uno de ellos.
ACTIVIDAD 1
Buscar contraseña

Figura 1.1 Fragmento del Código Buscar Contraseña

Figura 1.2 Fragmento de la Ejecución Exitosa Buscar Contraseña


Este código su finalidad es buscar una contraseña en un archivo de texto plano el
cuál almacenará contraseñas creadas de manera aleatoria con números y letras
iniciando con contraseñas de 3 caracteres utilizando todas las combinaciones
posibles(las primeras combinaciones inician con a pasando todas las
combinaciones que se pueden crear utilizando el abecedario y números del 0-9, y
hacemos lo mismo con las demás letras) hasta hacer combinaciones de
contraseñas con 4 caracteres.
Primero que nada importamos un total de 4 bibliotecas mediante la función from
nombre_biblioteca import* para poder usar todas las funciones que contengan:
 string Esta nos ayudará a utilizar la función ascii_letters la cuál contiene
todas las letras del abecedario en minúsculas y mayúsculas, y usamos la
función digits el cuál contiene los dígitos del 0-9.
 itertools Mediante esta biblioteca podemos hacer uso de la función producto
la cuál nos devuelve una serie de caracteres cuando le pasamos una cadena
de caracteres.
 os En este caso no importamos todas las funciones debido a que entraría en
conflicto más adelante con otra, por lo tanto solo importamos la función
system para poder hacer uso de las funciones del sistema (cls y pause).
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
 time Con esta podemos usar la función time para poder hacer uso del tiempo
marcado por el reloj de nuestra computadora.
Después de eso lo que se hace es definir la función para buscar la contraseña
(buscar) que tiene como parámetro de entrada la contraseña que deseamos
encontrar (con); ya dentro de la función se iguala una variable a un archivo de texto
plano el cuál vamos a modificar, para ello hacemos lo siguiente
archivo=open(“nombre_archivo.txt”, “w”) en dónde la “w” significa que vamos a
escribir en el archivo. Seguido de eso hacemos una validación para saber si la
longitud de la contraseña ingresada a la función está dentro de 3 y/o 4, porque de
no ser cierto eso arroja en pantalla una leyenda de que por favor ingrese una
contraseña de 3 a 4 caracteres.
Si la condición se cumple se pasa a un for el cual itera mientras que i se encuentre
dentro de range(3,5) lo cuál se interpreta que esté en el rango de 3 a 4, luego
entramos a otro ciclo for el cual itera mientras que la variable comb se encuentre
dentro de los caracteres que devuelva la función product (para ser sincero no se
entendió muy bien cómo funciona dicha función), después mediante la función join
une/concatena los caracteres almacenados devueltos por product en comb y los
guarda en una nueva variable llamada prueba; en seguida mediante el comando
archivo.write(prueba+”\n”) se escribirá en el documento la cadena de caracteres
almacenada en la variable prueba junto con un salto de línea (enter), en seguida se
hace la igualación para comprobar si prueba es igual a con porque de ser así se
imprime una leyenda indicando cuál es la contraseña que se buscaba para después
cerrar el archivo y terminar con la función mediante break.
Fuera de la función se escribieron instrucciones para almacenar la hora en la que
se va a iniciar la ejecución del programa (t0=time()), después igualamos la variable
con=”H104” y en seguida mandamos a llamar la función buscar pasándole la
variable previamente mencionada, cuando termina de ejecutarse la función se
imprime una leyenda en la que indica el tiempo de ejecución de dicha función, para
ello utilizamos nuevamente time() y le restamos t0 (lo que significa que la hora en
la que se terminó de ejecutar el programa se le resta la hora en la que inició, la hora
se da en segundos).
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario (se podrían hacer las modificaciones pertinentes
para que el usuario le diera a buscar una contraseña diferente a la estipulada) y se
emplearon las funciones cls junto con pause para darle mejor presentación al
programa.
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
ACTIVIDAD 2
Cambio

Figura 2.1 Fragmento del Código Cambio

Figura 2.2 Fragmento de la Ejecución Exitosa Cambio


Lo primero que se hace es importar la biblioteca os para hacer uso de las funciones
del sistema (cls y pause) mediante system; en seguida se declara una función con
nombre cambio la cual recibe dos parámetros de entrada cantidad y una lista de
los “billetes” con las que se puede hacer un cambio (en términos simples es cómo
si fuéramos al banco y pidiéramos que nos cambien un billete de mil por otros más
chicos). Dentro de la función lo que se hace es crear otra lista vacía llamada
resultado, en seguida nos dirigimos a un ciclo while con la validación de que se
repetirá mientras que cantidad sea mayor a 0, dentro del while nos encontraremos
con un if para saber si cantidad es mayor o igual al valor de la primera posición de
la lista de cambio si esto se cumple pasaremos a la igualación de una variable (num)
con el valor de la división entera de la cantidad entre la denominación de la primera
posición de la lista num=cantidad//denominaciones[0], en seguida a la cantidad
le restamos el valor obtenido al dividir las denominaciones cantidad=cantidad-
(num*denominaciones[0]) y el resultado de cuántos billetes utilizamos junto qué
denominación se empleó se agregan a la lista resultado
resultado.append([denominaciones[0], num]). Luego lo que se hace es
“disminuir” a lista de las denominaciones (se puede entender que se van eliminando
las posiciones ya usadas) mediante la instrucción denominaciones=
denominaciones[1:] para terminar con retornar la variable resultado.
Fuera de la función se escriben 6 print mandando a llamar la función previamente
descrita para obtener los resultados que aparecen en la Figura 2.2, cabe destacar
que para tener un “cambio” eficiente debemos colocar las denominaciones de mayor
o menor, de lo contrario tendremos algo parecido al 6to print con su resultado en
pantalla.
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario (se podrían hacer las modificaciones pertinentes
para que el usuario indicara cuál es la cantidad y las respectivas denominaciones
para trabajar) y se emplearon las funciones cls junto con pause para darle mejor
presentación al programa.
ACTIVIDAD 3
Programación Dinámica

Figura 3.1 Fragmento del Código Programación Dinámica

Figura 3.2 Fragmento de la Ejecución Exitosa Programación Dinámica


En esta parte nos encontramos con un total de 4 funciones las cuáles legan al mismo
resultado de Fibonacci pero con diferentes procedimientos, enlistaremos las
funciones junto con sus respectivas instrucciones:
 fibonacci_iterativo_v1 Espera como parámetro de entrada la posición de la
serie de Fibonacci que deseamos calcular (numero), dentro se declaran tres
variables (f1=0, f2=1, tmp=0) en seguida nos adentramos a un ciclo for el
cual se repetirá en el rango de 1 a (numero-1) (se inicia en 1 y se terminar
una posición antes esto porque el 0 también forma parte de la serie, y se le
resta una unidad porque ya tenemos el 1, que es la segunda posición de la
serie, por lo que nos falta calcular sólo 4 posiciones más.
 fibonacci_iterativo_v2 Recibe el mismo parámetro de entrada que la
función anterior (numero), lo que cambia es que sólo hace uso de dos
variables f1 y f2, después nos dirigimos a un ciclo for con las mismas
características que la función anterior. Dentro del for lo que se hace es
asignación paralela f1,f2=f2,f1+f2 lo que significa que la primera variable a
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
la izquierda del igual tomará el valor de la primera variable a la derecha del
signo igual (f1=f2) y así sucesivamente, al final de la función se retorna el
valor de f2, tuve una duda en la asignación paralela de por qué si el valor de
f1 toma el valor de f2 esto no afecta al momento de cambiarle el valor de f2.
 fibonacci_bottom_up Recibe el mismo parámetro de entrada que las
funciones anteriores lo que cambia aquí es que ahora hace uso de una lista,
con 3 valores ya designados (0,1,1), para hacer el proceso de Fibonacci,
después de que se declaró la lista (f_parciales) pasamos a un while que
tiene como condición fa_parciales<numero, mientras esto se cumpla lo que
hará la función es ir agregando a la lista valores que son el resultado de
sumar las últimas posiciones de esta f_parciales.append=(f_parciales[-1]+
f_parciales[-2]); a diferencia de C, en Python tenemos índices negativos los
cuáles inician en -1 refiriéndose a la última posición de una
lista/diccionario/tupla, entonces con el -2 y el -1 siempre nos estaremos
refiriendo a las últimas dos posiciones de la lista que estamos utilizando.
Conforme se vayan agregando valores a la lista también se irán imprimiendo,
al final la función retorna la posición de la lista que sea numero-1.
 fibonacci_top_down Hace uso de un diccionario el cuál se declara antes de
la función teniendo los primeros tres valores de la sucesión de Fibonacci
memora={1:0,2:1,3:1}, después entramos a la función que recibe como
parámetro de entrada numero, dentro hacemos una validación si el número
ingresado se encuentra ya dentro de la memoria porque de ser así solamente
se retorna dicho valor mediante memoria[numero]. Si no se cumple el if
igualamos una variable f a la suma del resultado de llamar dos veces a la
segunda función del archivo de la siguiente manera:
f=fibonacci_iterativo_v2[numero-1]+ fibonacci_iterativo_v2[numero-2]
y obtenemos el valor de la posición (numero) que estamos buscando,
agregamos una nueva posición al diccionario de la siguiente manera
memoria[numero]=f y para terminar la función retorna el valor del
diccionario en la posición del numero.
Al termino de cada función se mandan a llamar con ciertos valores de entrada, las
primeras dos funciones (fibonacci_iterativo_v1 y v2) se mandan a llamar con el
valor de 6 y obtenemos en pantalla el resultado de 5, la tercera función
(fibonacci_bottom_up) se manda a llamar con el valor de 5 obteniendo en pantalla
las modificaciones que se hacen a su lista junto con el valor final que es 3; mientras
que la última función fibonacci_top_down se manda a llamar dos veces, la primera
vez con el valor 12 (después de que se manda a llamar con este valor se imprime
la memoria) obteniendo en pantalla el valor de 89 y el diccionario modificado
teniendo el nuevo valor 12:89, después se vuelve a llamar con el valor 8 (después
de que se manda a llamar con este valor se imprime la memoria) obteniendo en
pantalla el valor 13 y el diccionario modificado teniendo el nuevo valor 8:13.
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
Después lo que hacemos, para que cada que ejecutemos este programa no tenga
que iniciar de 0, es abrir un archivo con extensión .p (también se puede poner con
extensión txt) y escritura en binario wb esto para que el archivo sólo lo entienda la
computadora al ejecutar el programa. La apertura del archivo lo hacemos mediante
archivo=open(“memoria.txt”, “wb”), luego mediante la función dump hacemos
que se escriba el diccionario memoria en el archivo almacenado en la variable
archivo y luego cerrarlo mediante archivo.close().
Luego lo volvemos a abrir el archivo memoria.txt pero ahora en lectura binaria “rb”
y lo almacenamos en la variable archivo, en seguida igualamos una variable a
archivo mediante memoria_de_archivo=load(archivo), cerramos el archivo
abierto mediante archivo.close() y para acabar mandamos a imprimir el diccionario
memoria seguido de la variable memoria_de_archivo obteniendo en pantalla el
mismo resultado.
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario (se podrían hacer las modificaciones pertinentes
para que el usuario indicara cuál es la posición de Fibonacci que desea encontrar)
y se emplearon las funciones cls junto con pause para darle mejor presentación al
programa.
ACTIVIDAD 4
Insertion Sort

Figura 4.1 Fragmento del Código Insertion Sort

Figura 4.2 Fragmento de la Ejecución Exitosa Insertion Sort


Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
Lo que hace el programa es ordenar los valores de una lista desordenada de menor
a mayor, para ello se declara la función insertionSort que tiene como parámetro de
entrada la lista a ordenar (n_lista), dentro de la función nos encontramos un ciclo
for que utiliza un índice (index) el cuál estará avanzando en el rango de 1 hasta
alcanzar el tamaño de la lista ingresada; después igualamos una variable al valor
de la lista en la posición del índice actual=n_lista[index], una variable almacenará
el valor del índice (posicion) e imprimimos el valor que se va a ordenar, enseguida
nos dirigimos a un ciclo while dónde se tienen que cumplir dos condiciones que
posicion>0 y que el valor de la lista que está antes del actual sea mayor a este
(n_lista[posicion-1]>actual) si no se cumple solamente nos movemos al siguiente
valor mediante el for, si se cumple lo que pasa adentro del while es que ahora la
lista en la posición de la variable que almacena el índice tendrá el valor que se
encuentre una posición antes de este (n_lista[posicion]=n_lista[posicion-1]),
después la variable posición se le resta una unidad (posicion=posicion-1),
enseguida con el valor de la variable modificado le asignamos el valor almacenado
en actual (n_lista[posicion]=actual) y se imprime la lista completa; cada vez que
se mueva de posición un valor se imprimirá la lista y al final de la función se retorna
la lista.
Fuera de la función declaramos una lista con estos valores 21,10,0,11,9,24,20,14,1,
se imprime una leyenda para mostrar la lista desordenada, mandamos a llamar la
función previamente mencionada y al final imprimimos la lista ordenada. Para el
correcto funcionamiento de este programa no se espera ningún parámetro de
entrada por parte del usuario (se podrían hacer las modificaciones pertinentes para
que el usuario indicara cuál es la lista que desea ordenar) y se emplearon las
funciones cls junto con pause para darle mejor presentación al programa.

ACTIVIDAD 5
Quick Sort

Figura 5.1 Fragmento del Código Quick Sort


Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos

Figura 5.2 Fragmento de la Ejecución Exitosa


La finalidad del programa es el mismo que la ACTIVIDAD 4 (Insertion Sort) sólo
que ataca el problema desde dos lados. Dentro del archivo se declaran tres
variables as cuáles son:
 quicksort Recibe como parámetro de entrada una lista, dentro de la función
lo que se hace es mandar a llamar quicksort_aux pasándole los parámetros
de entrada lista, 0 y la longitud de la lista restado una unidad (len(lista)-1),
en el orden dicho.
 quicksort_aux Tiene como parámetros de entrada una lista, un “índice” que
funge como inicio de la lista (inicio) y otro que funge como final de la lista
(fin), dentro de la función nos encontramos un if para saber que el índice del
inicio es menor al final (inicio<fin) si se cumple pasaremos a la igualación
de una variable a la siguiente función a utilizar de la siguiente forma
pivote=particion(lista, inicio, fin), después se realiza recursividad dos
veces modificando la primera vez el valor del índice final quick_sort(lista,
inicio, pivote-1) y la segunda modificando el índice inicio
quick_sort(lista,pivote+1, final).
 particion Tiene como parámetro de entrada una lista, un índice que indica la
posición del inicio de la lista y un índice que indica la posición final de la lista.
Dentro de la función lo que se hace es igualar una variable local al valor del
inicio de la lista pivote=lista[inicio] para después imprimirlo indicando que
es el pivote para trabajar, enseguida se igualan dos variables uno al final de
la lista y otro a la siguiente posición del inicio (izquierda=inicio+1 y
derecha=final) para imprimirlos indicando cuál es cuál. Luego declaramos
una bandera que será falsa, entramos a un ciclo while que usa lógica negada
not bandera (lo que quiere decir que mientras sea verdadero), ya dentro del
ciclo while nos encontramos con otros dos ciclos while:
o El primero tiene dos condiciones: que el índice izquierda sea menor
igual a derecha y que el valor de la lista en la posición izquierda sea
menor igual al pivote (izquierda<=derecha y lista[izquierda]
<=pivote), mientras se cumplan ambas condiciones el índice
izquierda aumentará una unidad (izquierda=izquierda+1).
o El segundo también tiene dos condiciones: que el valor de la lista en
la posición derecha sea mayor igual al pivote y que el índice derecha
sea mayor igual al izquierda (lista[deracha]>=pivote y derecha>=
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
izquierda), mientras esto se cumpla el índice derecha se reduce en
una unidad (derecha=derecha-1)
Cuando se terminan los ciclos se pasa a un if el cuál valida
derecha<izquierda si es así la variable booleana se convierte en
verdadero (bandera=True), de lo contrario en una variable temporal
almacenamos el valor de la lista en izquierda (temp=lista[izquierda]) y
luego a esta posición le asignamos el de derecha de la siguiente forma
lista[izquierda]=lista[derecha] para después el valor de la posición
derecha tome el del temporal (lista[derecha]=temp); al terminar el primer
ciclo while (el de lógica negada) se imprime la lista, la variable temp toma
el valor de lista[inicio], la posición de inicio toma el valor de
lista[derecha], la posición derecha toma el valor de temp y para acabar
la función retorna derecha.
Fuera de las funciones declaramos una lista con los mismos valores que la
ACTIVIDAD 4, imprimimos una leyenda con la lista desordenada, mandamos a
llamar la primera función (quicksort) pasándole la lista creada, y al final se imprime
una leyenda con la lista ordenada. Para el correcto funcionamiento de este
programa no se espera ningún parámetro de entrada por parte del usuario (se
podrían hacer las modificaciones pertinentes para que el usuario indicara cuál es la
lista que desea ordenar) y se emplearon las funciones cls junto con pause para
darle mejor presentación al programa.
ACTIVIDAD 6
Medición y gráficas de los tiempos de ejecución

Figura 6.1 Fragmento del Código Medición y Gráficas de los Tiempos de


Ejecución
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos

Figura 6.2 Fragmento de la Ejecución Exitosa Medición y Gráficas de los


Tiempos de Ejecución
El programa hace uso de un total de 6 bibliotecas (matplotlib.pylot (con el
sobrenombre de plt), mpl_toolkits.mplot3d (para hacer uso de la función Axes3D),
numpy (para usar todas sus funciones), os (para hacer uso de funciones del
sistema), random (para hacer uso de funciones para crear valores aleatorios), time
(para hacer uso de la función time y registrar la hora en segundos del ordenador))
además de que importa dos archivos creados por el programador (InsertionSort
(para hacer uso de la función insertionSort) y QuickSort (para hacer uso de la
función quickSort), cabe señalar que dichos archivos son en su totalidad idénticos
a los de las actividades 5 y 6, sólo que se omitieron las impresiones de pantalla y
las funciones del sistema).
Creamos una lista llamada datos los cuáles serán datos comprendidos entre 1y 20
multiplicados por 100 (ii*100 for ii in range(1,21)), después creamos dos listas de
tiempo (una para el método insert sort y otra para el método quick sort); enseguida
entramos a un ciclo for que se repetirá mientras ii se encuentre dentro de la lista
datos, dentro del ciclo lo que haremos es declarar una lista de números aleatorios
para el método insert sort (lista_is) mediante la función
sample(range(1,10000000), ii) (significa que generará un valor aleatorio entre 1-
10000000 por cada ii), luego dicha lista la copiamos en otra para el método quick
sort (lista_qs) de la siguiente forma lista_qs=lista_is.copy(). Después se registra
el tiempo del ordenador t0=time(), mandamos a llamar la función del método insert
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
sort con la lista de éste método (insertionSort(lista_is)) cuando termine la función
agregamos el tiempo que tardó a la lista correspondiente de la siguiente manera
tiempo_is.append(round(time()-t0), los pasos anteriores (guardar el tiempo,
mandara llamar la función, agregar el tiempo tardado a la lista) se repiten sólo que
hacemos las modificaciones necesarias para el método quick sort; todo lo anterior
sucede dentro del ciclo for.
En seguida mandamos a imprimir el tiempo que tardó cada método por lista
(recuerde que dentro del for se hicieron varias listas para cada método) mediante
las siguientes instrucciones:
 print("Tiempos parciales de ejecución en INSERT SORT {}
[s]\n".format(tiempo_is))
 print("Tiempos parciales de ejecución en QUICK SORT {}
[s]\n".format(tiempo_qs))
Después imprimimos el tiempo total de ejecución de la siguiente forma:
 print("Tiempo total de ejecución en insert sort {}
[s]\n".format(sum(tiempo_is)))
 print("Tiempo total de ejecución en quick sort {}
[s]".format(sum(tiempo_qs)))
La función suma nos permite sumar todos los valores de las listas de manera
automática; después agregamos los comandos necesarios para realizar la gráfica,
con fig,ax=plt.subplots() generamos la “aplicación” (por así decirlo) para crear en
gráfica, después con ax.plot(datos, tiempo_is, label=”Insert Sort”, marker=”*”,
color=”r”) graficamos los valores referidos a la lista de tiempo_is que tiene la
leyenda de Insert Sort con marcadores como asterisco y de color rojo (para graficar
los datos de tiempo_qs hacemos lo mismo sólo que hacemos las modificaciones
necesarias para que se grafiquen los valores deseados y se pueda distinguir de
Insert Sort), con ax.set_xlabel/ax.set_ylabel le ponemos nombre a los ejes de la
gráfica, con ax.grid(True) se dibuja la cuadrícula dentro de la gráfica, con
ax.legend(loc=2) muestra un recuadro con las indicaciones de qué se refiere cada
trazo de la gráfica, con pl.title le asignamos un título a la gráfica y con plt.show()
hacemos que la gráfica se muestre en pantalla. La gráfica en cuestión muestra qué
tanto se tarda cada método en resolver el problema, llegando a la conclusión de que
insert Sort es el peor de ambos.
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario (se podrían hacer las modificaciones pertinentes
para que el usuario indicara cuál es la lista que desea ordenar) y se emplearon las
funciones cls junto con pause para darle mejor presentación al programa.
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
ACTIVIDAD 7
Modelo RAM

Figura 7.1 Fragmento del Código Modelo RAM

Figura 7.2 Ejecución Exitosa Modelo RAM


Hace uso de 4 bibliotecas (matplotlib.pylot (con el sobrenombre de plt),
mpl_toolkits.mplot3d (para hacer uso de la función Axes3D), numpy (para usar
todas sus funciones), os (para hacer uso de funciones del sistema), random (para
hacer uso de funciones para crear valores aleatorios)), declaramos una variable
global times=0, después se crea una función insertionSort_graph la cuál tiene
como parámetro de entrada una lista (n_lista) ya dentro de la función se agrega la
instrucción global times que indica que la variable global se modificará dentro de
la función; después entramos a un for el cual tiene un índice (index) que se moverá
dentro del rango de 1 y el tamaño de la lista (len(n_lista)), ya dentro del for la
variable global aumenta en una unidad (times+=1), después una variable almacena
el valor de la lista en la posición del índice (actual=n_lista[index]) y otra almacena
el valor del índice (posicion=index). En seguida entramos a un while con dos
condiciones: que la posición sea mayor a 0 y que el valor de la lista en la posición
menos 1 sea mayor al actual (posicion>0 and n_lista[posicion-1]>actual), si
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
estas dos condiciones se cumplen la variable times vuelve aumentar en una unidad
para después hacer el intercambio de posiciones (n_lista[posicion] =
n_lista[posicion-1]) y terminar el while con el decremento de la variable opción en
una unidad; si no se cumple el while se hace lo siguiente n_lista[posicion]=actual,
para terminar la función se retorna la lista modificada.
Se declara una variable que contendrá un valor de 101 (TAM), después se crea una
lista de la siguiente forma eje_x=list(range(1,TAM,1)) (la lista inicia en 1 hasta
llegar al 100 con “escalones” de una unidad, o sea que va sumando uno en uno
hasta el 100), se crean otras listas vacías llamadas eje_y y lista_variable. Nos
dirigimos a un for el que tiene como índice num moviéndose sobre la lista eje_x,
dentro del ciclo se llena la lista lista_variable con números aleatorios comprendidos
entre 0 y 999 por cada num, después igualamos la variable times a 0 para modificar
el valor de lista_variable=insertionSort_graph(lista_varaible) y agregar al final
del for el valor de times a la lista restante vacía (eje_y).
Después se agregan los comandos necesarios para realizar la gráfica, con
fig,ax=plt.subplots(facecolor=”w”, edgecolor=”k”) generamos la “aplicación”
(por así decirlo) para crear en gráfica con fondo blanco (por eso la “w”), después
con ax.plot(eje_x,eje_y,marker=”o”,linestyle=”None”) graficamos los valores
referidos a las listas eje_x y eje_y con puntos de color azul, con
ax.set_xlabel/ax.set_ylabel le ponemos nombre a los ejes de la gráfica, con
ax.grid(True) se dibuja la cuadrícula dentro de la gráfica, con
ax.legend([“Insertion sort”]) muestra un recuadro con las indicaciones de qué se
refiere los puntos de la gráfica, con pl.title le asignamos un título a la gráfica y con
plt.show() hacemos que la gráfica se muestre en pantalla. La gráfica en cuestión
muestra las veces que se repiten las instrucciones de la función
insertionSort_graph.
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario y se emplearon las funciones cls junto con pause
para darle mejor presentación al programa.
ACTIVIDAD 8
Calendarización de Actividades

Figura 8.1 Fragmento del Código en C Calendarización de Actividades


Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos

Figura 8.2 Ejecución Exitosa del Código en C Calendarización de Actividades

Figura 8.3 Código en Python Calendarización de Actividades

Figura 8.3 Ejecución Exitosa del Código en Python Calendarización de


Actividades
Lo que hace el código en C es seleccionar cuáles actividades puede realizar una
persona en determinado tiempo, para ello utilizamos dos funciones:
 main contiene dos listas (s y f) las cuáles indican la hora en que se inicia una
actividad y la otra es la hora en que se termina dicha actividad. Por ejemplo,
en la primera posición de la lista s tenemos el valor 1 que podemos interpretar
diciendo que la primera actividad se comienza a realizar a la 1:00 am o pm,
en la primera posición de la lista f tenemos un valor 4 y lo podemos interpretar
que la primera actividad termina de realizarse a las 4:00 am o pm; entonces
la primera actividad inicia a la 1:00 am (o pm) y termina a las 4:00 am (o pm),
lo mismo aplica para todos los demás espacios de las listas. La variable n
(de tipo entero hace referencia a la cantidad/al número de actividades que se
planean realizar. Después se manda a llamar la función activities.
 activities Tiene como parámetro de entrada las dos listas de la función main
junto con la variable n, se crean dos contadores enteros (i y j) para después
imprimir una leyenda que indique que se mostrarán las actividades a realizar
(esto porque el problema dice que la persona sólo puede realizar una
actividad a la vez y debe terminar la que está haciendo para pasar a la
siguiente) y se le asigna el valor 0 a la variable i.
Mediante un printf se muestra la primera actividad que se realiza A1, esto
porque es la primera actividad que siempre se realiza, luego pasamos a un
for que itera desde j=1 (porque ya se “registró” la primera actividad) hasta
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
que sea menor al número total de actividades; ya dentro se encuentra un if
el cuál compara si el valor de tiempo de la lista s (que hace referencia a los
tiempos iniciales de cada actividad) en la posición j es mayor igual al de la
lista f (tiempo final de las actividades) en la posición i, si esto se cumple se
imprime la actividad siguiente a realizar mediante printf(“A%i”, j+1) y el valor
de i pasa a tomar el valor de j, pero si la condición no resulta verdadera no
se realiza nada y se vuelve a iterar.
Ahora bien, el for sirve para ver que actividades se pueden realizar y una
explicación sencilla es la siguiente: la actividad A1 inicia a la 1:00 y termina
4:00, la actividad A2 inicia a las 2:00 y termina a las 5:00 pero como la
persona sólo puede realizar una actividad a la vez no puede realizar A2 hasta
terminar A1 por lo que esta actividad no la realiza, luego la actividad A3 inicia
a las 3:00 y termina a las 6:00 pero nuevamente como no ha terminado A1
la A3 tampoco se realiza, y esto se va efectuando hasta que el tiempo inicial
de cualquier actividad coincida con el tiempo final de la actividad que se está
realizando (por lo que hasta la actividad A5 la persona termina la A1 y
empieza a realizar esta última).
El código en Python funciona de la misma manera, sólo se hicieron las
modificaciones necesarias para que el código pudiera implementarse en este
lenguaje. Desde mi punto de vista este algoritmo tiene el diseño Top-Down debido
a que la función principal manda a llamar a otra función la cuál se encarga de hacer
las iteraciones necesarias (el ciclo for) para dar con el resultado deseado además
de que imprime la solución sin necesidad de regresar a la función principal para
realizar alguna otra actividad que dependa del resultado obtenido.
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario y se emplearon las funciones cls junto con pause
para darle mejor presentación al programa.
ACTIVIDAD 9
Mínimo y Máximo de una Lista

Figura 9.1 Fragmento del Código Mínimo y Máximo de una Lista

Figura 9.2 Ejecución Exitosa del Código Mínimo y Máximo de una Lista
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
Este código ocupa recursividad para llegar al resultado; imagine que llamamos a
una función dentro de sí misma, esto lo podemos visualizar como si estuviéramos
subiendo las escaleras un edificio así que, la primera vez que se usa una función
estamos en la planta baja y cuando se llama dentro de sí misma por primera vez
hemos subido al primer piso del edificio, pero nuevamente se llama a sí misma
entonces hemos subido al segundo piso; cuando llegamos al último piso del edificio
(o sea ya no se necesita la recursividad) tenemos que ir bajando los pisos para
llegar a la planta baja por lo tanto iremos saliendo de las “capas” de recursividad
hasta encontrarnos con la primera vez que utilizamos la función en cuestión., consta
de dos funciones:
 MinMax Que recibe como parámetro de entrada una lista; dentro de la función
nos encontramos con un if para validar si la lista es de tamaño 1 porque de
ser así retorna dos veces el único valor de la lista, si no se cumple pasamos
a un elif que valida si la lista es de tamaño 2 para después hacer una
validación mediante otro if para saber si el valor de la posición inicial de la
lista es menor al de la siguiente posición (L[0]<=L[1]) y si esto se cumple
retornará la función L[0] seguido de L[1], pero si no se cumple retorna
primero L[1] y luego L[0]. Si tanto el if y el elif no se cumple pasaremos a un
else el cuál declara una variable que será el tamaño de la lista a la mitad.
Después lo que hace es igualar dos variables a la función con la que se está
trabajando (recursividad) pero esta vez con la primera mitad de la lista
((minL,maxL)=MinMax(L[:int(middle)])), tal parece que con la instrucción
L[:int(middle)] hace que sólo trabaje con la primera mitad de la lista, si la
lista es de número impar se estará trabajando con las primeras posiciones
que indique la variable int(middle) (esto quiere decir que supongamos que
la lista tiene 5 posiciones e int(middle) es 2, entonces trabajaremos con la
posición 0 y 1 de la lista) mediante este llamado se volverá a ejecutar lo
explicado anteriormente hasta que sólo tengamos una lista de un elemento.
Cuando esto suceda iremos retrocediendo en la recursividad hasta llegar a
la “función original” (dónde la utilizamos por primera vez) para ir al siguiente
paso el cuál consiste en prácticamente lo mismo que el anterior sólo que
ahora trabajamos con la segunda mitad de la lista
(minR,maxR)=MinMax(L[int(middle):]).
Al finalizar todos los pasos de recursividad compararemos los valores
obtenidos mediante if’s, el primer if compara si minL<=minR y así almacenar
min=minL de lo contrario se almacena minR, el segundo if compara
maxL>=maxR para almacenar max=maxL de lo contrario almacena maxR;
para finalizar la función retornará min y max.
 principal En esta función lo que se hace es crear una lista para después
imprimir el máximo y mínimo valor de la lista mediante un print que manda a
llamar la función previamente descrita:
print(“Los valores son: “, MinMax(lista)).
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
Al final del código se manda a llamar la función principal para llevar acabo la
ejecución del programa; pertenece a la categoría divide y vencerás porque, como
se explico anteriormente, trabaja con la lista original creando listas más pequeñas
de la mitad del tamaño de la original y estas listas a su vez se vuelven a dividir por
la mitad hasta el punto en que ya no se pueden dividir y se empieza a resolver el
problema de manera más sencilla, este algoritmo trabaja de manera Top-down para
después ir con Bottom-up y también podemos decir que este algoritmo pertenece a
BackTrack por el hecho de que hace una búsqueda sistemática a través de las
diferentes soluciones posibles (si las primeras dos posiciones una es mayor que
otra), además de que tiene soluciones parciales (los mínimos y máximos van
cambiando) y en el momento que encuentre que un valor es más eficiente al que ya
tiene lo puede cambiar.
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario y se emplearon las funciones cls junto con pause
para darle mejor presentación al programa.
ACTIVIDAD 10
Merge Sort

Figura 10.1 Fragmento del Código Merge Sort

Figura 10.2 Ejecución Exitosa del Código Merge Sort


Este código, al igual que el anterior, hace uso de la recursividad (así que podemos
entenderlo nuevamente con el ejemplo de las escaleras del edificio) para acomodar
de menor a mayor los valores de una lista y consta de dos funciones:
 merge que recibe como parámetros de entrada dos listas (left y right), dentro
de la función declara una lista vacía (result para más adelante irle agregando
valores) y dos índices igualados a 0 (left_idx y right_idx), después lo que
hace es con un ciclo while con condiciones left_idx<len(left) and
right_idx<len(right) comparar los valores de las listas proporcionadas
mediante un if left[left_idx]<=right[right_idx] si se cumple se agregará el
valor de la lista left en la posición left_idx a la lista result y el índice left_idx
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
aumentará en una posición pero si esto es mentira entonces se hará los
pasos anteriores pero con la lista right y el índice right_idx.
Después con un if left nos dirigimos a la instrucción
result.extend(left[left_idx:]), por lo que se entiende es que con extend y lo
que se encuentre dentro del paréntesis se “checará” si el valor en de la lista
en el índice indicado se encuentra dentro de la lista result si se encuentra no
hace nada de lo contrario agrega dicho valor; después se hará lo mismo pero
ahora con if right utilizando la lista right para que al final la función retorne
la lista result.
 merge_sort recibe como parámetro de entrada una lista m, dentro de la
función lo que se hace es comparar si el tamaño de la lista es 1 para así
solamente retornar la misma lista de entrada, de lo contrario pasará a
determinar la mitad del tamaño de la lista mediante una división entera
middle=len(m)//2 después se crean dos listas para almacenar la primera y
segunda mitad de la lista original justo como el código de la ACTIVIDAD 9
(left=m[:middle] la primera mitad de la lista original y right=m[middle:] la
segunda mitad de la lista original) para después hacer recursividad (llamarse
a sí misma) con la primera mitad de la lista left=merge_sort(left) las veces
que se requieran y hacer lo mismo con la segunda mitad de la lista
right=merge_sort(right); una vez completadas todas las instrucciones de
recursividad necesarias se retornará la lista acomodada de menor a mayor
llamando a la primera función descrita (merge) mediante return
list(merge(left,right)).
Al final del código se crea una lista1 la cuál se imprime para ver sus valores
desacomodados y después se imprime dicha lista acomodada mediante
print(merge_sort(lista1)). Pertenece a Top-down y Bottom-up por el hecho de que
para ir acomodando la lista va realizando recursividad para trabajar con sublistas de
la original y tener mejor manejo de los datos (Top-down), cuando llega a un punto
en que ya no es necesario utilizar la recursividad entonces empieza a resolver las
operaciones pendientes (Bottom-up), al igual que lo podemos considerar como
Divide y Vencerás porque como se comentó se divide la lista original en sublistas
de la mitad del tamaño para tener un mejor manejo de datos.
Para el correcto funcionamiento de este programa no se espera ningún parámetro
de entrada por parte del usuario y se emplearon las funciones cls junto con pause
para darle mejor presentación al programa.
Cote Valencia Alexis Daniel Gpo1 Práctica 11 Estrategias para la
construcción de algoritmos
CONCLUSIONES
Los objetivos de la práctica se pudieron cumplir en su totalidad, a pesar de que el
profesor nos comentó que varios de los códigos provenientes de la guía de
laboratorio no eran o no hacían referencia a las estrategias de algoritmos
mencionados, pudimos observar la manera en que se pueden implementar algunas
de las estrategias vistas en clase además de que pudimos analizar con mayor
profundidad el cómo funcionan dichas estrategias tal es el caso de Top-
Down/Bottom-up, vimos como mediante recursividad nos vamos adentrando a
“diferentes” capas utilizadas para poder ir resolviendo algunos de los ejercicios
propuestos y luego ir terminando las instrucciones pendientes en cada llamado de
la función recursiva.
Otra cosa que pudimos observar es en cómo se puede optimizar la memoria o el
tiempo en algunos casos (InsertionSort se optimiza la memoria y QuickSort se
optimiza el tiempo) con sólo observar que uno tarda más tiempo en ejecutarse que
otro, pero también pudimos observarlo mediante una gráfica para cada acción
realizada contra el tiempo llegando al resultado de que InsertionSort su gráfica es o
se asemeja a una complejidad cuadrática mientras que el caso del QuickSort se
asemeja más a una complejidad lineal. Por otro lado se hizo una gráfica con el
método InsertionSort en la que se lograba ver las veces que se realizaban acciones
dándonos como resultado que conforme tiene listas más grandes ésta realiza
muchas operaciones dentro de la memoria RAM para llegar al resultado del
programa.
Los últimos tres problemas de la práctica (los propuestos por el profesor) dejaron
que el alumno pudiera identificar más estrategias/categorías del diseño de
algoritmos contribuyendo a un aprendizaje mayor aprendizaje del tema
proporcionando más formas en las que se pueden resolver los problemas y así no
solamente optar por la clásica y preferida por los alumnos (fuerza bruta) sin embargo
estas nuevas estrategias pude ocasionar que nos llevemos más tiempo en la
resolución del problema ya que debemos tener cuidado en que no entremos en
ciclos infinitos, pero gracias a esto no debeos estar probando todas las soluciones
que se nos ocurra y ver cuál funcionará teniendo una mayor eficiencia en nuestro
código.
Para finalizar puedo decir que la práctica en su mayoría estuvo bien diseñada para
que el alumno reforzara conocimientos y pudiera identificar varios conceptos, la
excepción es en el caso de que los códigos eran “erróneos” o no hacían referencia
de forma correcta y exacta a algunos conceptos, pero esto se pudo corregir con los
códigos empleados por el profesor.

También podría gustarte