Como se ve del capítulo anterior, un algoritmo imperativo que va en un orden secuencial puede bifurcar sus caminos dentro de su lógica algorítmica a través del uso de condicionales, y todas estas bifurcaciones finalmente deberían volver a encontrar un camino central, a menos que termine una función abruptamente con un resultado de función, como es el caso de un return. Esto nos presenta un algoritmo como un grafo o red, cuya complejidad puede crecer de forma indefinida, a medida que se dan redes cooperativas de funciones.
Pero tal vez uno de los mayores poderes computacionales es la posibilidad de que una de estas bifurcaciones se dé recurrentemente de forma cíclica dentro de ese grafo, de tal forma que las tareas dentro de un pequeño sector de nuestro código sean repetitivas.
Este posible modo de fluidez de nuestros algoritmos es tal vez una de las características más poderosas de la algoritmia lleva a la computación: tener ciclos dentro del grafo que controlados por condiciones. Dichos ciclos buscarán su ruptura en el tiempo, pues, de no hacerlo, serían ciclos infinitos, y si bien es cierto un ciclo infinito también puede ser útil, se pretenderá tener ciclos finitos para tareas finitas repetitivas.
La aplicación que usted usa en su celular o su pc, contiene al menos un ciclo infinito para mantener las ventanas abiertas mientras usted no de la orden de cerrarlas. Los dispositivos electrónicos con sensores ambientales o cualquier otro sensor tienen ciclos perpetuos y un temporizador para hacer lecturas espaciadas en el tiempo de las variables.
Pero nuestros problemas no son tan perpetuos: una serie o suma para buscar un valor deberá ser lo más finito posible. Un análisis sobre millones de datos será una tarea donde la repetición se da mientras halla datos para analizar, o mientras no hallamos cumplido nuestro propósito, como en los algoritmos de búsqueda o clasificación. Un algoritmo que ‘escanea’ un código QR pasará primero por un ciclo de ajuste del foco de la cámara de su celular antes de poder capturarlo.
En este capítulo potenciaremos nuestros algoritmos en papercode con estos ciclos.
Pero tal vez uno de los mayores poderes computacionales es la posibilidad de que una de estas bifurcaciones se dé recurrentemente de forma cíclica dentro de ese grafo, de tal forma que las tareas dentro de un pequeño sector de nuestro código sean repetitivas.
Este posible modo de fluidez de nuestros algoritmos es tal vez una de las características más poderosas de la algoritmia lleva a la computación: tener ciclos dentro del grafo que controlados por condiciones. Dichos ciclos buscarán su ruptura en el tiempo, pues, de no hacerlo, serían ciclos infinitos, y si bien es cierto un ciclo infinito también puede ser útil, se pretenderá tener ciclos finitos para tareas finitas repetitivas.
La aplicación que usted usa en su celular o su pc, contiene al menos un ciclo infinito para mantener las ventanas abiertas mientras usted no de la orden de cerrarlas. Los dispositivos electrónicos con sensores ambientales o cualquier otro sensor tienen ciclos perpetuos y un temporizador para hacer lecturas espaciadas en el tiempo de las variables.
Pero nuestros problemas no son tan perpetuos: una serie o suma para buscar un valor deberá ser lo más finito posible. Un análisis sobre millones de datos será una tarea donde la repetición se da mientras halla datos para analizar, o mientras no hallamos cumplido nuestro propósito, como en los algoritmos de búsqueda o clasificación. Un algoritmo que ‘escanea’ un código QR pasará primero por un ciclo de ajuste del foco de la cámara de su celular antes de poder capturarlo.
En este capítulo potenciaremos nuestros algoritmos en papercode con estos ciclos.
Construyendo un bucle
Hay dos tipos de bifurcaciones que debemos usar para construir un bucle: Una bifurcación condicional que controlará el bucle de tal modo que se entra al ciclo si la condición es cierta(.t.), y una bifurcación incondicional, que se encarga de cerrarlo. Las bifurcaciones incondicionales son aquellas que no necesitan de una condición, e inmediatamente se dirigen a un punto concreto del código.
Un blucle se cierra con una transferencia incondicional directamente al condicional del ciclo para volver a evaluarlo. Esto es, detrás del escenario, estaremos usando el tan protestado y potencialmente ‘abusable pero útil’ goto [1].
Para simplificar lo dicho, diremos que un bucle tiene una condición que indica si se corre o no el ciclo, y un cierre que indica que la condición debe evaluarse: el cierre de un bucle simplemente salta de nuevo a la condición.
En nuestros algoritmos en pseudocódigo papercode, un goto está permitido (solo intente no hacer código espagueti[2]). Las construcciones cíclicas las construiremos con conceptos de programación estructurada, y serán suficientes para todos los ejemplos y problemas. Dicho esto, es claro que no se requiere usar goto. Sin embargo, se deja abierta la posibilidad responsable de su uso en pseudocódigo.
[1] Brian W. Kernighan; Dennis Ritchie (1988). C Programming Language (2nd ed.). Prentice Hall. pp. 60–61. ISBN 978-0-13-308621-8.
[2] https://en.wikipedia.org/wiki/Spaghetti_code
Un blucle se cierra con una transferencia incondicional directamente al condicional del ciclo para volver a evaluarlo. Esto es, detrás del escenario, estaremos usando el tan protestado y potencialmente ‘abusable pero útil’ goto [1].
Para simplificar lo dicho, diremos que un bucle tiene una condición que indica si se corre o no el ciclo, y un cierre que indica que la condición debe evaluarse: el cierre de un bucle simplemente salta de nuevo a la condición.
En nuestros algoritmos en pseudocódigo papercode, un goto está permitido (solo intente no hacer código espagueti[2]). Las construcciones cíclicas las construiremos con conceptos de programación estructurada, y serán suficientes para todos los ejemplos y problemas. Dicho esto, es claro que no se requiere usar goto. Sin embargo, se deja abierta la posibilidad responsable de su uso en pseudocódigo.
[1] Brian W. Kernighan; Dennis Ritchie (1988). C Programming Language (2nd ed.). Prentice Hall. pp. 60–61. ISBN 978-0-13-308621-8.
[2] https://en.wikipedia.org/wiki/Spaghetti_code
Uso del goto para crear bucles
Hoy en día en muchas calculadoras de bolsillo, es posible programar. Sin embargo, muchas de ellas ya lo hacían hace unos 40 años, en los años 80. Muchos aún guardamos nuestras antiguas calculadoras Casio, sin darnos cuenta que son programables. Esas calculadoras aún contienen estos lenguajes clásicos para calculadora, que manejaban el concepto de goto. En esos lenguajes, es normal implementar un blucle con un if y una transferencia incondicional.
Pero no necesitamos ir a las calculadoras para encontrar un goto. Lenguajes muy aún en uso, cuentan con dicha instrucción para poder hacer brincos entre distintos lugares del código. Y no hay que ir a la historia: hoy hay lenguajes modernos en los que puedes hacer un goto en aquellos casos en que los patrones de estructuras de control no fueron suficientes a tus propósitos.
A continuación, se presenta un pseudocódigo que implementa un bucle usando una etiqueta y un goto:
Pero no necesitamos ir a las calculadoras para encontrar un goto. Lenguajes muy aún en uso, cuentan con dicha instrucción para poder hacer brincos entre distintos lugares del código. Y no hay que ir a la historia: hoy hay lenguajes modernos en los que puedes hacer un goto en aquellos casos en que los patrones de estructuras de control no fueron suficientes a tus propósitos.
A continuación, se presenta un pseudocódigo que implementa un bucle usando una etiqueta y un goto:
label 'A' if a > b then tarea 1 tarea 2 tarea 3 … tarea n goto 'A' endif |
Lo primero que se evalúa antes de comenzar un bucle, es si el condicional es verdadero. Si lo es, el bucle entra a un bloque de instrucciones. Pero si el condicional es falso, salta fuera del bloque y sigue adelante con el código posterior.
Cuando el clico es verdadero y se corre el bloque, habrá un fin de bloque, y automáticamente se salta de nuevo al condicional para volverlo a valorar (bifurcación o transferencia incondicional). Esa transferencia incondicional es un goto etiquetado. La condición vuelve a evaluarse y el bloque se ejecuta cada que el condicional es verdadero. Cuando el condicional es falso, se salta fuera del bucle.
Cuando el clico es verdadero y se corre el bloque, habrá un fin de bloque, y automáticamente se salta de nuevo al condicional para volverlo a valorar (bifurcación o transferencia incondicional). Esa transferencia incondicional es un goto etiquetado. La condición vuelve a evaluarse y el bloque se ejecuta cada que el condicional es verdadero. Cuando el condicional es falso, se salta fuera del bucle.
BUCLES CONDICIONADOS ESTRUCTURADOS
Hoy en día existen algunos patrones de programación para escribir bucles de forma automática, de tal modo que no tengamos que usar un goto. El más común es el bucle while, donde la condición de evalúa antes de comenzar el bucle.
Algunas personas que ya conocen algo de programación se estarán preguntando por el bucle for. En realidad, en los lenguajes tradicionales el bucle for[1] tiende por norma general a ser muy distinto al bucle while, pues el patrón for es hoy día más tradicional para iterar sobre estructuras denominadas colecciones, donde el bucle itera sobre cada uno de los elementos, de modo que la condición es llegar al fin de la colección.
Casi todos los lenguajes cuentan con la estructura while, así algunos lenguajes no la llamen while (como por ejemplo Go que lo llama for[2]).
Una condición acompaña a la palabra while, y mientras la condición sea verdadera, el interior del bucle se ejecuta hasta la transferencia incondicional que cierra el bucle y que transfiere el control de nuevo a la condición.
En pseudocódigo papercode, las palabras claves para bucles serán, while, loop, o cycle según su preferencia, y lo cerraremos con endwhile, endloop, o endcycle respectivamente, o simplemente con la palabra end. Cualquier palabra que se use tiene el mismo efecto. Pero, en general, en un lenguaje de programación real solo habrá una única palabra válida, la cual tradicionalmente es while. La adición de otras palabras en un lenguaje significa normalmente que el lenguaje tiene otros tipos de patrones para bucles. En pseudocódigo, tenemos la flexibilidad de usar muchas palabras para el mismo patrón.
También, así como en nuestros pseudocódigos con el if tengo la posibilidad de escribir opcionalmente la palabra then, para abrir el bucle podré opcionalmente hacerlo con las palabras then y do.
Como ya lo hemos mencionado, el bloque de instrucciones dentro de un while o loop, se da mientras la condición sea verdadera ( .t. ), y el bloque caducará tan pronto la condición sea falsa (.f.).
En el caso de que la condición siempre sea .t., el ciclo será infinito. Y si lo que se requiere es un loop infinito, en pseudocódigo podemos obviar la condición, o simplemente usar como condición el valor de verdad .t.
[1] No hay ninguna obligación para que los lenguajes usen varias palabras para los distintos tipos de ciclos. El lenguaje Go de Google (Go es el nombre oficial, pero también se le conoce popularmente con el pseudónimo de Golang), usa la palabra reservada for como reemplazo de la tradicional palabra while, y a su vez también usa la palabra for para recorrer los elementos de colecciones de forma automática.
[2] https://golang.org/ref/spec#For_statements
Algunas personas que ya conocen algo de programación se estarán preguntando por el bucle for. En realidad, en los lenguajes tradicionales el bucle for[1] tiende por norma general a ser muy distinto al bucle while, pues el patrón for es hoy día más tradicional para iterar sobre estructuras denominadas colecciones, donde el bucle itera sobre cada uno de los elementos, de modo que la condición es llegar al fin de la colección.
Casi todos los lenguajes cuentan con la estructura while, así algunos lenguajes no la llamen while (como por ejemplo Go que lo llama for[2]).
Una condición acompaña a la palabra while, y mientras la condición sea verdadera, el interior del bucle se ejecuta hasta la transferencia incondicional que cierra el bucle y que transfiere el control de nuevo a la condición.
En pseudocódigo papercode, las palabras claves para bucles serán, while, loop, o cycle según su preferencia, y lo cerraremos con endwhile, endloop, o endcycle respectivamente, o simplemente con la palabra end. Cualquier palabra que se use tiene el mismo efecto. Pero, en general, en un lenguaje de programación real solo habrá una única palabra válida, la cual tradicionalmente es while. La adición de otras palabras en un lenguaje significa normalmente que el lenguaje tiene otros tipos de patrones para bucles. En pseudocódigo, tenemos la flexibilidad de usar muchas palabras para el mismo patrón.
También, así como en nuestros pseudocódigos con el if tengo la posibilidad de escribir opcionalmente la palabra then, para abrir el bucle podré opcionalmente hacerlo con las palabras then y do.
Como ya lo hemos mencionado, el bloque de instrucciones dentro de un while o loop, se da mientras la condición sea verdadera ( .t. ), y el bloque caducará tan pronto la condición sea falsa (.f.).
En el caso de que la condición siempre sea .t., el ciclo será infinito. Y si lo que se requiere es un loop infinito, en pseudocódigo podemos obviar la condición, o simplemente usar como condición el valor de verdad .t.
[1] No hay ninguna obligación para que los lenguajes usen varias palabras para los distintos tipos de ciclos. El lenguaje Go de Google (Go es el nombre oficial, pero también se le conoce popularmente con el pseudónimo de Golang), usa la palabra reservada for como reemplazo de la tradicional palabra while, y a su vez también usa la palabra for para recorrer los elementos de colecciones de forma automática.
[2] https://golang.org/ref/spec#For_statements
Estructura y uso de un bucle condicionado
Un bucle condicionado lleva a cabo una tarea, una o muchas veces, determinado por la condición: mientras la condición se de verdadera, el bucle permanece activo: tan pronto la condición sea falsa, se rompe el bucle de forma controlada. Más adelante veremos cómo forzar la salida de un bucle sin importar el estado de la condición.
Esto hace muy potente y útil los bucles para problemas que ameriten dicho patrón cíclico. Muchos problemas generatrices usan bucles condicionados: series que generan valores, búsquedas, o bucles que son controlados por estados. En general, el análisis de datos secuencial es un objetivo muy común de un bucle, y cuando esos datos están en colecciones en memoria, se usan iteradores, que es un caso especial de los bucles, y que serán analizados en el capítulo siguiente.
Por el momento, nos centraremos en el uso de bucles while.
Para algoritmos en pseudocódigo, la estructura del bucle while es la que se presenta a continuación:
Esto hace muy potente y útil los bucles para problemas que ameriten dicho patrón cíclico. Muchos problemas generatrices usan bucles condicionados: series que generan valores, búsquedas, o bucles que son controlados por estados. En general, el análisis de datos secuencial es un objetivo muy común de un bucle, y cuando esos datos están en colecciones en memoria, se usan iteradores, que es un caso especial de los bucles, y que serán analizados en el capítulo siguiente.
Por el momento, nos centraremos en el uso de bucles while.
Para algoritmos en pseudocódigo, la estructura del bucle while es la que se presenta a continuación:
while | loop expresión-condicional [then][do] #código condicionado end |
Note que la estructura es la misma que se analizó al comienzo del capítulo, cuando se construyó un bucle con un if y un goto.
Aquí, el ‘while’ hace las veces del ‘if’, y el ‘end’ hace las veces del ‘goto’ para hacer la transferencia incondicional necesaria para que se de el rechequeo de la condición.
La mejor forma de entender el uso de los bucles, es comenzar con los ejercicios de los talleres. En un blucle, la actualización de variables es fundamental, ya que la condición dependerá del estado de las variables involucradas en el bucle.
Aquí, el ‘while’ hace las veces del ‘if’, y el ‘end’ hace las veces del ‘goto’ para hacer la transferencia incondicional necesaria para que se de el rechequeo de la condición.
La mejor forma de entender el uso de los bucles, es comenzar con los ejercicios de los talleres. En un blucle, la actualización de variables es fundamental, ya que la condición dependerá del estado de las variables involucradas en el bucle.
Modelos generatrices
Algunas soluciones a problemas se basan en que la naturaleza de un bucle se aprovecha para generar datos manipulando el contenido de variables. Esta estrategia es bastante común en problemas donde no se procesan datos estáticos, sino que los datos se generan a medida que manipulamos los datos con nuestro algoritmo, a partir de un conjunto mínimo de datos de entrada que son paramétricos.
Bucles infinitos
Las repeticiones de grupos de tareas de forma infinita pueden llegar a ser útiles. El siguiente bucle muestra una condición que lo hace infinito: luego de entrar al bucle, no podremos salir de él.
loop (.t.) do
live() #vivir infinitamente
end
En general, en pseudocódigo podremos evitar la condición, pero para evitar ambigüedades debemos usar en ese caso la palabra do:
loop do
lifeforever()
end
El siguiente bucle muestra una condición que hace que no podamos morir eternamente:
loop (.f.) do //el ciclo no se ejecuta!
dead()
endloop
Veamos algo más concreto. Suponga que usted tiene un sensor que lee alguna variable ambiental para mantener un monitoreo constante. En ese caso, usted desea que el bucle nunca acabe. Dentro del bucle, se podría, por ejemplo, estar atento a valores concretos, y sobre esa base llevar a cabo algunas tareas.
loop (.t.) do
live() #vivir infinitamente
end
En general, en pseudocódigo podremos evitar la condición, pero para evitar ambigüedades debemos usar en ese caso la palabra do:
loop do
lifeforever()
end
El siguiente bucle muestra una condición que hace que no podamos morir eternamente:
loop (.f.) do //el ciclo no se ejecuta!
dead()
endloop
Veamos algo más concreto. Suponga que usted tiene un sensor que lee alguna variable ambiental para mantener un monitoreo constante. En ese caso, usted desea que el bucle nunca acabe. Dentro del bucle, se podría, por ejemplo, estar atento a valores concretos, y sobre esa base llevar a cabo algunas tareas.
EJEMPLO: Sensor de temperatura.
Este ejemplo presenta una función que contiene un bucle infinito. R/ procedure leerTemperatura in puertoSensor::Z+ begin temperatura::R while .t. esperar(1000) #esperar 1000 milisegundos leerPuerto(puertoSensor, temperatura) if temperatura > 40.0 then activarAireAcondicionado(‘bloque-7’,’aula-102’) endif end endproc |
Entonces, ¿cuándo termina el bucle? De hecho, ¡no termina nunca!. En ese caso debemos apagar el circuito que está corriendo este programa. Esta no es una forma elegante de terminar un programa que corre en el procesador central de un circuito con sensores, y es por eso que muchas veces, a pesar de que tengamos un bucle infinito, debemos buscar alternativas para salir de él.
En el ejemplo que se plantea de lectura de temperatura desde un sensor, da sentido tener un bucle infinito. Claro que también se puede buscar una forma elegante de hacerlo sin contar con un bucle infinito.
En el ejemplo que se plantea de lectura de temperatura desde un sensor, da sentido tener un bucle infinito. Claro que también se puede buscar una forma elegante de hacerlo sin contar con un bucle infinito.
Rompiendo bucles
En prácticamente todos los lenguajes de programación debe ser posible fugarse de un bucle.
La forma oficial de hacerlo es por medio de una condición. Sin embargo, a veces aparecen situaciones en las que se debe salir del bucle inmediatamente, no porque se de una condición especial, sino porque se da una situación que lo amerita. La forma alternativa de hacer ese rompimiento en muchos lenguajes es usar la palabra break.
La instrucción break es un goto o transferencia incondicional a la línea siguiente al end del bucle. Un break es como abrir un hueco y salir por un lado distinto al oficial.
Por ejemplo, Una búsqueda secuencial en un arreglo desordenado siempre se debe abordar de la misma forma: recorrer todos los elementos uno a uno; tan pronto se encuentre el elemento, se puede abortar el bucle rompiéndolo con un break.
Por supuesto, se podría manejar un condicional que incluya las condiciones necesarias para controlarlo, pero, a veces, puede ser muy legible muy y más fácil de mantener, si se usa una instrucción break.
En nuestros pseudocódigos, usaremos la palabra break, pero podrá escribirse exit, exitwhile, o exitloop.
La forma oficial de hacerlo es por medio de una condición. Sin embargo, a veces aparecen situaciones en las que se debe salir del bucle inmediatamente, no porque se de una condición especial, sino porque se da una situación que lo amerita. La forma alternativa de hacer ese rompimiento en muchos lenguajes es usar la palabra break.
La instrucción break es un goto o transferencia incondicional a la línea siguiente al end del bucle. Un break es como abrir un hueco y salir por un lado distinto al oficial.
Por ejemplo, Una búsqueda secuencial en un arreglo desordenado siempre se debe abordar de la misma forma: recorrer todos los elementos uno a uno; tan pronto se encuentre el elemento, se puede abortar el bucle rompiéndolo con un break.
Por supuesto, se podría manejar un condicional que incluya las condiciones necesarias para controlarlo, pero, a veces, puede ser muy legible muy y más fácil de mantener, si se usa una instrucción break.
En nuestros pseudocódigos, usaremos la palabra break, pero podrá escribirse exit, exitwhile, o exitloop.
EJEMPLO: Búsqueda secuencial en arreglo desordenado.
Construya un algoritmo que reciba un arreglo de cadenas en desorden, y una cadena que se desea buscar, y devuelva la posición en el arreglo en que se encuentra la cadena buscada. Si la cadena no está, se devuelve 0. fx buscar in data []::string, buscado ::string out ::Natural0 valid: |data| > 0 begin idx <- 1 size <- | data | found <- 0 loop idx ≤ size then do if data[idx] .EQ. buscado then do found <- idx break endif idx <- idx + 1 endloop return found endfx Una versión con return en vez de break es posible en este tipo de problema: fx buscar in data []::string, buscado ::string out ::Natural0 valid: |data| > 0 begin idx <- 1 size <- | data | loop idx ≤ size then do if data[idx] .EQ. buscado then do return idx endif idx <- idx + 1 endloop return 0 endfx El algoritmo puede ser simplificado aún más, si tenemos en cuenta el cortocircuito para el condicional and (&&). fx buscar in data ::[]string, buscado ::string out ::Z+ valid: |data| > 0 begin idx ::Z+ <- 1 size <- | data | loop idx ≤ size then do data[idx] .EQ. buscado && return idx idx <- idx + 1 endloop return 0 endfx |
La estrategia de romper bucles debería usarse con precaución, ya que por orden y legibilidad en el código es mejor estructurar los bucles de tal forma que la condición del bucle sea suficiente. Sin embargo, las rupturas break a veces surten el efecto positivo de simplificar el código.
EJEMPLO: Búsqueda de extremos.
Construya un algoritmo que reciba un arreglo de cadenas en desorden, y busque una cadena. La función devuelve la posición de la primera ocurrencia, y la posición de la última ocurrencia. Si no existe, devuelve la tupla(0,0). Si solo existe una vez, devuelve una tupla con la posición (pos,pos). Si existen las dos cadenas, devuelve una tupla con las dos posiciones. R/ Estrategia. Examinar desde adelante y desde atrás a la vez. fx buscar_elemento_matriz in matiz [,]::R out :: begin izq ::Z+ <- 1 loop izq ≤ |data| then do if data[izq] .EQ. buscado then do fizq <- .t. break end izq <- izq + 1 end if ¬fizq then return (0,0) endif der ::Z+ <- |data| loop der > izq then do if data[der] .EQ. buscado then do fder <- .t. break end der <- der - 1 endloop if ¬fder then return (izq,izq) else return (izq,der) endif end |
Rechequeo de condición de un bucle
Es probable que algunas veces necesitemos volver a la condición, sin haber llegado al final del bloque del bucle. En este caso usamos la palabra especial continue o next, muy usada en muchísimos lenguajes.
Esta posibilidad es útil cuando conocemos con antelación que ya podemos hacer la transferencia incondicional hace el comienzo del bucle, lo que sucede cuando ya logramos el objetivo de la iteración, y es más cómodo escribir continue o next, que estructurar el código para una caída hasta el end y lograr el mismo objetivo.
Aunque es posible estructurar la última opción mencionada, y aunque existen programadores puristas que dicen que eso debe ser así, La sentencia continue es a veces necesaria. Sin embargo, muchas veces la experiencia puede dictar que este tipo de transferencia obscurece el código, y, en ese caso, se puede evitar siempre.
Esta posibilidad es útil cuando conocemos con antelación que ya podemos hacer la transferencia incondicional hace el comienzo del bucle, lo que sucede cuando ya logramos el objetivo de la iteración, y es más cómodo escribir continue o next, que estructurar el código para una caída hasta el end y lograr el mismo objetivo.
Aunque es posible estructurar la última opción mencionada, y aunque existen programadores puristas que dicen que eso debe ser así, La sentencia continue es a veces necesaria. Sin embargo, muchas veces la experiencia puede dictar que este tipo de transferencia obscurece el código, y, en ese caso, se puede evitar siempre.
bucles anidados
Cuando hablamos de condicionales (if), se planteó que estos podían estar anidados dentro de otros condicionales. Dado que los bucles son condicionales, se podrán dar situaciones donde dentro de un bucle encontremos otro, y así sucesivamente. Esto es bastante útil en la solución de algunos problemas como irá viendo en la medida que se encuentre situaciones concretas que ameriten tales anidamientos.
Una situación que exige usar bucles anidados es común cuando necesito recorrer una matriz de forma exhaustiva. Por ejemplo, si necesito buscar un elemento en una matriz, o si necesito operar elementos, la mejor alternativa es usar bucles anidados, uno para enumerar las filas o columnas, y otro para moverme internamente entre sus elementos.
Una situación que exige usar bucles anidados es común cuando necesito recorrer una matriz de forma exhaustiva. Por ejemplo, si necesito buscar un elemento en una matriz, o si necesito operar elementos, la mejor alternativa es usar bucles anidados, uno para enumerar las filas o columnas, y otro para moverme internamente entre sus elementos.
EJEMPLO: suma de elementos de arreglo bidimensional.
Construya un algoritmo que reciba un arreglo bidimensional de números reales, y determine la suma de todos sus elementos. Estrategia. Un bucle externo se encargará de enumerar las filas, y un bucle interno enumerará los elementos de esa fila, o sea las columnas. fx sumar_matriz in data [,]::R out suma::R begin row ::Z+ <- 1 loop row ≤ |data,1| then do col::Z+ <- 1 loop col ≤ |data,2| then do suma <- suma + matriz[row,col] col <- col + 1 end row <- row + 1 end return suma end EJEMPLO: plano más pesado de un arreglo tridimencional.
Construya un algoritmo que reciba un arreglo tridimensional de números reales, y determine sobre la dimensión 3, qué plano suma más, y cuánto suma. R/ Entrada. Un arreglo de tres dimensiones que contiene los datos en sus celdas. Salida. La función devuelve un numero entero que indica el número del plano que más suma. Estrategia. Un bucle externo se encargará de enumerar los planos, mientras que bucles más internos recorren filas y columnas de cada uno de los planos. Cada que se termina una suma, se compara con un mayor. Inicialmente el mayor se pondrá en -Infinito. fx sumar_matriz in data [,,]::R out ::tuple(Z+,R) begin mayor <- 0.0 plano <- 1 pmayor::Z+ loop plano ≤ |data,3| then do suma::Z+ <- 0 fil <- 1 loop fil ≤ |data,1| then do col <- 1 loop col ≤ |data,2| then do suma <- suma + matriz[fil ,col, plano] col <- col + 1 endloop fil <- fil + 1 endloop if suma > mayor then do mayor <- suma pmayor <- plano endif plano <- plano + 1 endloop return (pmayor, suma) end EJEMPLO: Conteo de peones en tablero de ajedrez.
Construya una función algorítmica en pseudocódigo papercode, que reciba un tablero de ajedrez, y determine cuántos peones hay en el tablero. El tablero está representado por un arreglo bidimensional, y en aquellas casillas donde hay una pieza, se representa por una string, donde el primer caracter es el color, 'P', 'N' para negras, 'B' para blancas, y el segundo caracter es para el tipo de pieza entre 'T' para torres, 'C' para caballos, 'A' para alfiles, 'R' para rey, 'Q' para reinas, y 'P' para peones. Por ejemplo, la pieza "BT" es una torre blanca, mientras que la pieza "NQ" es una reina negra. R/ Entrada. Matriz de strings que representa el tablero. Salida. Número de peones en el tablero. Estrategia. Se requieren dos bucles, uno anidado al otro. Si se encuentra un peón, se cuenta. Si ya se contaron 16 peones, se devuelve el valor, para no seguir buscando, pues ya no hay más. fx total_peones in tablero [8,8]::String out peones::R begin fil ::Z+ <- 1 loop ≤ |data,1| then do col::Z+ <- 1 loop col ≤ |data,2| then do if tablero[fil,col][2] .EQ. 'P’ then do peones <- peones + 1 peones .EQ. 16 && return peones endif col <- col + 1 endeloop fil <- fil + 1 endloop return suma end |
BICLES ITERADORES DE COLECCIONES
En muchos lenguajes de programación existe la posibilidad de iterar de forma intuitiva sobre los objetos de una colección de datos. Las colecciones de datos son estructuras lineales que son iterables, esto es, se puede barrer uno a uno sus elementos sin necesidad de recurrir a los índices para indicar una posición.
Según esto, un iterador exige que haya un referenciador, que es una variable receptora de una referencia a un objeto de la colección, lo que significa que cada que se itera sobre una colección obtiene la referencia al dato que sigue, y abre un bloque de trabajo no condicionado.
A diferencia del bucle while que es condicionado, la condición que maneja un iterador es automática y siempre la misma, y es que, tan pronto se alcance el fin de la colección, el bucle iterador termina. Eso es una gran ventaja, ya que no tendremos que preocuparnos por manejar índices que apunten a posiciones dentro de los arreglos, y no tendremos que estar atentos a los límites del arreglo, o a la posición inicial del arreglo.
Entonces, si los iteradores reemplazan el uso de índices al momento de recorrer la colección, y tampoco es necesario establecer una condición ya que automáticamente se establece una condición única basada en el tamaño de la colección, los iteradores mejoran el trabajo de los desarrolladores, y su existencia es apenas lógica: si lo único que se desea es recorrer en orden los elementos, es altamente preferible un bucle iterador a un bucle condicionado.
Dejaremos entonces el ciclo while solo para los casos en los que no se recorren colecciones, o para cuando el uso de índices es crucial.
En pseudocódigo, para crear un bucle iterador, usaremos la estructura
Según esto, un iterador exige que haya un referenciador, que es una variable receptora de una referencia a un objeto de la colección, lo que significa que cada que se itera sobre una colección obtiene la referencia al dato que sigue, y abre un bloque de trabajo no condicionado.
A diferencia del bucle while que es condicionado, la condición que maneja un iterador es automática y siempre la misma, y es que, tan pronto se alcance el fin de la colección, el bucle iterador termina. Eso es una gran ventaja, ya que no tendremos que preocuparnos por manejar índices que apunten a posiciones dentro de los arreglos, y no tendremos que estar atentos a los límites del arreglo, o a la posición inicial del arreglo.
Entonces, si los iteradores reemplazan el uso de índices al momento de recorrer la colección, y tampoco es necesario establecer una condición ya que automáticamente se establece una condición única basada en el tamaño de la colección, los iteradores mejoran el trabajo de los desarrolladores, y su existencia es apenas lógica: si lo único que se desea es recorrer en orden los elementos, es altamente preferible un bucle iterador a un bucle condicionado.
Dejaremos entonces el ciclo while solo para los casos en los que no se recorren colecciones, o para cuando el uso de índices es crucial.
En pseudocódigo, para crear un bucle iterador, usaremos la estructura
[iterate] {for [each|loop] | ref ∈ | in colección [then|do] #bloque end |
En pseudocódigo podremos usar la palabra for, for loop, for each junto con el operador ∈ o in que indica que el elemento pertenece a la colección que será iterada.
Opcionalmente podemos usar la palabra iterate antes de for o for each, para documentar el caracter iterador.
El anterior pseudocódigo para un bucle iterador, equivale al siguiente pseudocódigo para un bucle condicionado:
idx <- 1
while idx ≤ |colección| [then][do]
ref <- colección[idx]
#bloque
i <- i + 1
end
Al igual que con el if y el while en pseudocódigo, en los bloques iteradores for se podrá de forma opcional usar las palabras then y do para abrir el bloque. El bucle iterador podrá ser cerrado usando cualquiera de end, enditerator, endfor, endforeach.
Opcionalmente podemos usar la palabra iterate antes de for o for each, para documentar el caracter iterador.
El anterior pseudocódigo para un bucle iterador, equivale al siguiente pseudocódigo para un bucle condicionado:
idx <- 1
while idx ≤ |colección| [then][do]
ref <- colección[idx]
#bloque
i <- i + 1
end
Al igual que con el if y el while en pseudocódigo, en los bloques iteradores for se podrá de forma opcional usar las palabras then y do para abrir el bloque. El bucle iterador podrá ser cerrado usando cualquiera de end, enditerator, endfor, endforeach.
¿for o while?
Algunas personas que han hecho programación para sus proyectos universitarios o en investigaciones, comentan que es mejor el for que un while, y que nunca usan un while.
Debo aclarar, sin embargo, que un for y un while no son sinónimos, pues son estructuras pensadas para distinto uso. Esto es así desde 1954 que apareció el lenguaje de programación FORTRAN, aunque 18 años después que nace el lenguaje de programación C en 1972, Dennis Ritchie, su creador, convierte el for a un equivalente while con algunas variantes, y hoy día el lenguaje Go rediseña para si el for dándole un uso más general eliminando la palabra while del lenguaje.
Actualmente y por lo general (con pocas excepciones), estos dos patrones son bien diferentes, y se usan para estrategias distintas de bucles.
Un while permite construir bucles controlado por una condición que puede ser tan compleja como se quiera, de modo que su naturaleza es booleana (se da el bucle, o no se da el bucle).
De otro lado, un for permite construir bucles que iteran uno a uno los elementos de una colección de datos tradicionalmente finita (aunque puede ser infinita), y cuyo único control de finalización es alcanzar el fin de la colección si no se dan rupturas break antes de alcanzar el fin de colección mencionado.
Se considera una colección cualquier estructura de elementos consecutivos, tradicionalmente arreglos lineales de una dimensión, tuplas, y cadenas de caracteres, aunque los rangos numéricos también son particularmente útiles y se usan bastante.
En este capítulo revisaremos adicionalmente el uso de iteradores para pseudocódigo, en los que incluso podremos usar cuantificadores universales, y adicionaremos ejemplos en Python al final del capítulo.
Debo aclarar, sin embargo, que un for y un while no son sinónimos, pues son estructuras pensadas para distinto uso. Esto es así desde 1954 que apareció el lenguaje de programación FORTRAN, aunque 18 años después que nace el lenguaje de programación C en 1972, Dennis Ritchie, su creador, convierte el for a un equivalente while con algunas variantes, y hoy día el lenguaje Go rediseña para si el for dándole un uso más general eliminando la palabra while del lenguaje.
Actualmente y por lo general (con pocas excepciones), estos dos patrones son bien diferentes, y se usan para estrategias distintas de bucles.
Un while permite construir bucles controlado por una condición que puede ser tan compleja como se quiera, de modo que su naturaleza es booleana (se da el bucle, o no se da el bucle).
De otro lado, un for permite construir bucles que iteran uno a uno los elementos de una colección de datos tradicionalmente finita (aunque puede ser infinita), y cuyo único control de finalización es alcanzar el fin de la colección si no se dan rupturas break antes de alcanzar el fin de colección mencionado.
Se considera una colección cualquier estructura de elementos consecutivos, tradicionalmente arreglos lineales de una dimensión, tuplas, y cadenas de caracteres, aunque los rangos numéricos también son particularmente útiles y se usan bastante.
En este capítulo revisaremos adicionalmente el uso de iteradores para pseudocódigo, en los que incluso podremos usar cuantificadores universales, y adicionaremos ejemplos en Python al final del capítulo.
Cuantificadores y cardinalidad
En el capítulo sobre tipos, revisamos el tema de representación de conjuntos de datos, para facilitar la tipificación. Dijimos, por ejemplo, que en pseudocódigos papercode, podemos definir tipos de datos muy concretos, que son subconjuntos de tipos de datos más genéricos.
Un ejemplo de tipo de dato concreto es:
::{1,2,3,4,5,6,7,8,9}
El anterior conjunto representa los números naturales del 1 al 9, los cuales podrían expresarse con un cuantificador como
::{ Z+ < 10} o ::{ x | x ∈ Z+ , x < 10}
Este es un conjunto contable finito pues sus miembros pueden ser contados, y su cardinalidad es 9, siendo su cardinalidad 9, que corresponde al número de elementos del conjunto para el tipo de dato.
Un conjunto es contable infinito si sus miembros pueden ponerse en una correspondencia uno a uno con los números naturales.
w::{x | x ∈ Z , 4x-3} U {x | x ∈ Z, 5x2+1}
es contable infinito, pues se expande como
{…, -19, -15, -11,-7, 0, 1, 5, 6, 9, 13, 21, 46, …}
También se mencionó que la cardinalidad de un conjunto contable infinito se expresa como Aleph0, y se lee Alef-cero, Alef-nul, o Alef-nada.
En contraste, los números reales ::R son incontables. También lo son sus subconjuntos que derivan de él, pues entre dos números reales cualquiera hay otro conjunto infinito, y no puede haber una correspondencia 1 a 1 con el conjunto de los números naturales.
Esta teoría numérica afectará la forma en que veamos los iteradores.
Un ejemplo de tipo de dato concreto es:
::{1,2,3,4,5,6,7,8,9}
El anterior conjunto representa los números naturales del 1 al 9, los cuales podrían expresarse con un cuantificador como
::{ Z+ < 10} o ::{ x | x ∈ Z+ , x < 10}
Este es un conjunto contable finito pues sus miembros pueden ser contados, y su cardinalidad es 9, siendo su cardinalidad 9, que corresponde al número de elementos del conjunto para el tipo de dato.
Un conjunto es contable infinito si sus miembros pueden ponerse en una correspondencia uno a uno con los números naturales.
w::{x | x ∈ Z , 4x-3} U {x | x ∈ Z, 5x2+1}
es contable infinito, pues se expande como
{…, -19, -15, -11,-7, 0, 1, 5, 6, 9, 13, 21, 46, …}
También se mencionó que la cardinalidad de un conjunto contable infinito se expresa como Aleph0, y se lee Alef-cero, Alef-nul, o Alef-nada.
En contraste, los números reales ::R son incontables. También lo son sus subconjuntos que derivan de él, pues entre dos números reales cualquiera hay otro conjunto infinito, y no puede haber una correspondencia 1 a 1 con el conjunto de los números naturales.
Esta teoría numérica afectará la forma en que veamos los iteradores.
Tipos numéricos con cardinalidad Aleph0
Tipos numéricos con cardinalidad À0
En pseudocódigo, podemos iterar sobre un tipo de datos cuya cardinalidad sea un número natural, o cuya cardinalidad sea Aleph0 . Para conjuntos con cardinalidad 𝔠 , no es posible iterar.
En el caso de conjuntos con cardinalidad Aleph0, su valor “más a la izquierda” deberá estar bien definido para poder ser iterable.
No es iterable el conjunto de datos ::R, pues su cardinalidad es 𝔠.
Tampoco es iterable el conjunto de datos ::Z, pues aunque su cardinalidad es Aleph0 y es supuestamente iterable, el elemento de su izquierda es - ¥, lo que lo hace no iterable.
Pero sí es iterable el conjunto de los números naturales ::N0, dado su cardinalidad Aleph0 , y su elemento a la izquierda numérica bien definido (0).
Por ejemplo, el tipo de dato {x | x ∈ Z, 5x2+1}, representa los valores {0, 1, 5, 6, 9, 13, 21, 46, …+infinito}. Por lo tanto su cardinalidad es Aleph0 , y el menor elemento numérico es cero.
Para iterar sobre el conjunto anterior, usaremos el iterador for
{for,loop} elemento ∈ {x | x ∈ Z, 5x^2 + 1} [do]
#bloque
end
Cada iteración en el bucle asociará al elemento (que en realidad es una variable automática con referencia a un solo elemento del conjunto), un número del conjunto 5x^2 + 1. Por supuesto, esto es un bucle infinito, según se ve de su definición. El primer elemento que será asociado es el menor elemento posible según la definición hecha del conjunto, en este caso, el número 0, pues siempre tomaremos desde el menor valor posible, ya que el mayor valor posible, infinito (+infinito en este caso), no es posible usarlo.
En pseudocódigo, podemos iterar sobre un tipo de datos cuya cardinalidad sea un número natural, o cuya cardinalidad sea Aleph0 . Para conjuntos con cardinalidad 𝔠 , no es posible iterar.
En el caso de conjuntos con cardinalidad Aleph0, su valor “más a la izquierda” deberá estar bien definido para poder ser iterable.
No es iterable el conjunto de datos ::R, pues su cardinalidad es 𝔠.
Tampoco es iterable el conjunto de datos ::Z, pues aunque su cardinalidad es Aleph0 y es supuestamente iterable, el elemento de su izquierda es - ¥, lo que lo hace no iterable.
Pero sí es iterable el conjunto de los números naturales ::N0, dado su cardinalidad Aleph0 , y su elemento a la izquierda numérica bien definido (0).
Por ejemplo, el tipo de dato {x | x ∈ Z, 5x2+1}, representa los valores {0, 1, 5, 6, 9, 13, 21, 46, …+infinito}. Por lo tanto su cardinalidad es Aleph0 , y el menor elemento numérico es cero.
Para iterar sobre el conjunto anterior, usaremos el iterador for
{for,loop} elemento ∈ {x | x ∈ Z, 5x^2 + 1} [do]
#bloque
end
Cada iteración en el bucle asociará al elemento (que en realidad es una variable automática con referencia a un solo elemento del conjunto), un número del conjunto 5x^2 + 1. Por supuesto, esto es un bucle infinito, según se ve de su definición. El primer elemento que será asociado es el menor elemento posible según la definición hecha del conjunto, en este caso, el número 0, pues siempre tomaremos desde el menor valor posible, ya que el mayor valor posible, infinito (+infinito en este caso), no es posible usarlo.
Rangos
La notación de conjuntos puede ser interesante para la generación de números muy concretos, y secuencias de datos no necesariamente consecutivos.
Los rangos son un tipo de colección de datos muy popular en muchos lenguajes de programación, incluyendo lenguajes modernos como Julia o Rust. En lenguajes viejos, Python es un buen ejemplo.
En un rango, se indica un comienzo, un fin, y opcionalmente una etapa o paso (incremento o salto dentro de los elementos del conjunto a iterar).
Un rango es una colección que no genera espacio en memoria y solo se trata de una definición, y es útil para aquellos casos en lo que necesitemos secuencias en las que podemos volver explícito un comienzo y un fin.
En el caso de pseudicódigo, podremos usar la notación start : stop. Esta notación indica que vamos desde el número start hasta el número stop con incrementos de 1.
Entonces, en aquellos casos que queramos generar un conjunto de datos con un incremento o etapa específico, podremos anotarlo como start : step : stop.
Por ejemplo, para representar el conjunto
{ 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0}
podemos usar la forma descriptiva corta
{1.0 : 0.5 : 7.0}
donde el primer elemento indica el punto de arranque, el segundo el tamaño del paso, y el tercero indica el punto de llegada.
Los rangos son un tipo de colección de datos muy popular en muchos lenguajes de programación, incluyendo lenguajes modernos como Julia o Rust. En lenguajes viejos, Python es un buen ejemplo.
En un rango, se indica un comienzo, un fin, y opcionalmente una etapa o paso (incremento o salto dentro de los elementos del conjunto a iterar).
Un rango es una colección que no genera espacio en memoria y solo se trata de una definición, y es útil para aquellos casos en lo que necesitemos secuencias en las que podemos volver explícito un comienzo y un fin.
En el caso de pseudicódigo, podremos usar la notación start : stop. Esta notación indica que vamos desde el número start hasta el número stop con incrementos de 1.
Entonces, en aquellos casos que queramos generar un conjunto de datos con un incremento o etapa específico, podremos anotarlo como start : step : stop.
Por ejemplo, para representar el conjunto
{ 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0}
podemos usar la forma descriptiva corta
{1.0 : 0.5 : 7.0}
donde el primer elemento indica el punto de arranque, el segundo el tamaño del paso, y el tercero indica el punto de llegada.
Colecciones de datos en pseudocódigo
Casi la totalidad de las iteraciones sobre conjuntos de datos tradicionalmente se requieren en la práctica para hablar de objetos en colecciones.
Si bien es cierto se pueden usar conjuntos en pseudocódigo para generar datos útiles, como por ejemplo posiciones en arreglos o colecciones, en la práctica se usa un while condicionado cuando los números que se desean generar van más allá de simples colecciones ordenadas de números. En general, es muy tradicional generar colecciones de números enteros, aunque las colecciones de números en etapas reales también son comunes.
En pseudocódigo podremos usar cualquier colección o cualquier tipo de dato a manera de conjunto de números como lo mencionamos previamente con los cuantificadores y los tipos.
Eso significa que no tendremos qué preocuparnos de las posiciones, y el iterador for se encargará de recorrer uno a uno los elementos, si lo que queremos es recorrerlos desde el primero en adelante, en ese orden.
Colecciones como rangos, strings, arreglos, tuplas y mapas, podrán ser recorridos en pseudocódigo usando un iterador.
La transferencia incondicional end encontrada en el bucle while, también se da de igual manera en un bucle for iterador de colección: tan pronto se alcance el end, se pasa al siguiente ciclo del bucle while o for según sea el caso.
Si bien es cierto se pueden usar conjuntos en pseudocódigo para generar datos útiles, como por ejemplo posiciones en arreglos o colecciones, en la práctica se usa un while condicionado cuando los números que se desean generar van más allá de simples colecciones ordenadas de números. En general, es muy tradicional generar colecciones de números enteros, aunque las colecciones de números en etapas reales también son comunes.
En pseudocódigo podremos usar cualquier colección o cualquier tipo de dato a manera de conjunto de números como lo mencionamos previamente con los cuantificadores y los tipos.
Eso significa que no tendremos qué preocuparnos de las posiciones, y el iterador for se encargará de recorrer uno a uno los elementos, si lo que queremos es recorrerlos desde el primero en adelante, en ese orden.
Colecciones como rangos, strings, arreglos, tuplas y mapas, podrán ser recorridos en pseudocódigo usando un iterador.
La transferencia incondicional end encontrada en el bucle while, también se da de igual manera en un bucle for iterador de colección: tan pronto se alcance el end, se pasa al siguiente ciclo del bucle while o for según sea el caso.
Iterando colecciones con for
Un arreglo de una dimensión podrá ser recorrido con un iterador (sin preocuparnos de la longitud de este), si lo que se desea es simplemente recorrer uno a uno sus elementos. Para recorridos en otro orden distinto a uno secuencial, o para cuando se quiere consultar varios elementos a la vez durante el recorrido, es recomendable volver al poderoso bucle condicionado while.
A continuación, se presenta un ejemplo en el que el uso de un bucle while es la mejor alternativa.
A continuación, se presenta un ejemplo en el que el uso de un bucle while es la mejor alternativa.
Comprehensions
Las comprehensiones es una forma de generar un arreglo de datos de forma simplificada con un bucle for.
Dado que un iterador puede recorrer una colección, a veces es útil usar cada iteración para generar un resultado parcial que puede llevarse a un arreglo.
En pseudocódigo, para una comprehension podrémos escribir
[expresión for elemento {∈ , in} colección]
En pseudcódigo, esta forma de trabajo permite generar un arreglo de valores, donde cada posición del arreglo se carga con la expresión evaluada en cada una de las iteraciones.
El uso de ‘comprehensions’ se verá mejor en talleres con el uso de lenguajes de programación.
Dado que un iterador puede recorrer una colección, a veces es útil usar cada iteración para generar un resultado parcial que puede llevarse a un arreglo.
En pseudocódigo, para una comprehension podrémos escribir
[expresión for elemento {∈ , in} colección]
En pseudcódigo, esta forma de trabajo permite generar un arreglo de valores, donde cada posición del arreglo se carga con la expresión evaluada en cada una de las iteraciones.
El uso de ‘comprehensions’ se verá mejor en talleres con el uso de lenguajes de programación.
TALLER BUCLES
- Sistema de fuerzas.
Un sistema de fuerzas se encuentra en equilibro, si la sumatoria de sus fuerzas es cero (0). Elabore una función equilibrio(), que reciba un arreglo de números reales que representan fuerzas, y determine si están en equilibrio. - Suma de inversos.
Elabore una función que sume los números inversos de los enteros positivos en el rango [m,n]. Por ejemplo,
si m = 9 y n = 12, la función calcula 1/9 + 1/10 + 1/11 + 1/12 - Multiplicación del Peatón Ruso.
Este es un algoritmo sobre multiplicación, planteado en el libro Mathematical Curiosities de Posamenter & Lehmann, 2014.
Construya un algoritmo que permita multiplicar dos números a y b, según el ejemplo:
a = 73, b = 82
a * 2 = 146, b / 2 = 41
146 * 2 = 292, 41 / 2 = 20 (excluye fracción)
292 * 2 = 584, 20 / 2 = 10
584 * 2 = 1168, 10 / 2 = 5
1168 * 2 = 2336, 5 / 2 = 2 (excluye fracción)
2336 * 2 = 4672, 2 / 2 = 1
Cuando la división sea 1, se suman todos aquellos valores obtenidos de multiplicar por 2, siempre y cuando la división por 2 del compañero tenga como resultado un número impar.
Si el número inicial b era impar, también se suma el primer a.
En este ejemplo, 73 * 82 = 146 + 1168 + 4672 = 5986
Otro ejemplo:
a = 15, b = 15
a * 2 = 30, b / 2 = 7
a * 2 = 60, b / 2 = 3
a * 2 = 120, b / 2 = 1
Note que en este caso todas las divisiones son impares. Incluso b inicial es impar, por lo que a inicial también se suma.
En este ejemplo, 15 * 15 = 15 + 30 + 60 + 120 = 225 - Suma de volumen de cilindros.
Elabore una función que halle la suma total de volumen de cilindros cuyo radio equivale a los números enteros entre 1 y n, y su altura al inverso de esos números. Por ejemplo
si n=1, volumen total es p.(12).1
si n=2, volumen total es p.(12).1 + p.(22).(1/2)
si n=4, volumen total es p.(12).1 + p.(22).(1/2) + p.(32).(1/3) - Volúmenes extraños.
Elabore una función que halle la suma total de volúmenes de esferas cuyo radio equivale a los números enteros entre 1 y n. Para números pares el volumen suma, y para impares el volumen resta. Por ejemplo
para n=1, el volumen total es 4/3.p.(-13)
para n=2, el volumen total es 4/3.p.(- 13 + 23)
para n=4, el volumen total es 4/3.p.(- 13 + 23 - 33 + 43) - Primer dígito de un número entero.
Construya una función algorítmica que determine el primer dígito de un número entero dado. Por ejemplo, el primer dígito de 7366844 es 7. Restricción: No use el tipo string. - Número palíndrome.
Un número entero positivo es palíndrome, si el número se lee igual de izquierda a derecha y de derecha a izquierda. Por ejemplo, el número 13431 es palíndrome, al igual que el número 33.
Construya una función algorítmica que determine si un número entero positivo dado es palíndrome. Restricción: No use el tipo string. - Conjetura de Collatz.
Dado un número entero
-Si el número es par, dividirlo por 2.
-Si es impar, multiplicarlo por 3 y adicionar 1, y a ese resultado dividirlo por 2.
La conjetura de Collatz establece que, sin importar el número seleccionado x > 1, la función f(x) siempre llegará a 1, y el tiempo recursivo que tome en hacerlo, será el tiempo de parada de x.
Construya una función algorítmica que, dado un x, determine el tiempo de parada.
ejemplo:
para n = 12, la secuencia es 12, 6, 3, 10, 5, 16, 8, 4, 2, 1. Por lo tanto, el número de pasos es 9.
para n = 19, la secuencia es 19,58,29,88,44,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1, por lo tanto el número de pasos es 20.
(Cai & Ding, 2017) - Mayor tiempo de parada en rango de enteros para conjetura de Collatz.
Dado un número entero
-Si el número es par, dividirlo por 2.
-Si es impar, multiplicarlo por 3 y adicionar 1, y a ese resultado dividirlo por 2.
La conjetura de Collatz establece que, sin importar el número seleccionado x > 1, la función f(x) siempre llegará a 1, y el tiempo recursivo que tome en hacerlo, será el tiempo de parada de x.
Construya una función algorítmica que, dados dos enteros p y q, determine el tiempo de parada más grande, y el número entero asociado.
ejemplo:
para n = 12, la secuencia es 12, 6, 3, 10, 5, 16, 8, 4, 2, 1. Por lo tanto, el número de pasos es 9.
para n = 19, la secuencia es 19,58,29,88,44,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1, por lo tanto el número de pasos es 20.
(Cai & Ding, 2017) - N-esimo término de Fibonacci.
Elabore una función llamada fibonacci(x), que use un bucle para determinar el término enésimo de la secuencia de fibonacci. La semilla de la secuencia es 0,1, que son los dos primeros términos. Los números que siguen se generan sumando los dos números anteriores.
Los primeros términos son
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... Por ejemplo,
para x = 1, la función devuelve 1
para x = 4, la función devuelve 5
para x = 9, la función devuelve 55 - Sumatoria de términos Fibonacci.
Elabore una función llamada fibonacci(x,y), que use un bucle para determinar la suma de los términos x-esimo a y-esimo de la secuencia de fibonacci. La semilla de la secuencia es 0,1, que son los dos primeros términos. Los números que siguen se generan sumando los dos números anteriores. Los primeros términos son
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ... Por ejemplo,
para x = 1, y=3, la función devuelve 1+2+3 = 6
para x = 4, y=7, la función devuelve 5+8+13+21 = 47 - Productoria.
Elabore una función que halle la productoria entre los enteros n y m. Por ejemplo: la productoria 5,7 es 5 * 6 * 7
la productoria 50,72 es 51 * 52 * ... * 71 * 72 - Sumatoria.
Elabore una función que halle la sumatoria entre los enteros n y m. Por ejemplo:
la sumatoria 5,7 es 5 + 6 + 7
la sumatoria 50,72 es 51 + 52 + ... + 71 + 72 - Multiplicar solo sumando.
Elabore una función que multiplique dos números enteros ø, ß usando solo sumas.
Por ejemplo,
la multiplicación 4 x 5 es igual a 5 + 5 + 5 + 5, que es 20
Considere la inversión al comienzo de los términos, de tal modo que se optimice el proceso. - Área de rectángulo.
Elabore un algoritmo que determine el área de un rectángulo conocidos sus dos lados, sin usar la operación de multiplicación. - Potencias solo multiplicando.
Elabore una función que eleve un número a una potencia natural usando solo multiplicaciones. Esto es, si se pide elevar un número b a una potencia natural x, multiplique x veces b. Al número b se le conoce normalmente como base, y a x como el exponente. Por ejemplo,
si b=8.1, x = 3, entonces 8.1 * 8.1 * 8.1 = 531.441
si b=4.5, x = 4, entonces 4.5 * 4.5 * 4.5 * 4.5 = 410 - Factorial solo sumas.
Elabore una función que determine el factorial de un número usando solo sumas.
El factorial (que se escribe n!) de un número se define como n * (n-1) * (n-2) *... Esto es, el factorial es una productoria de los n primeros números naturales.
Por ejemplo, para n = 4, 4! = 4 * 3 * 2 * 1 = 24.
La idea en este caso, sin embargo, es elaborar el factorial usando solo sumas.
Para el ejemplo
para 4! = 4 * 3 * 2 * 1 = ((4+4+4) + (4+4+4)) = 24
para 5! = 5 * 4 * 3 * 2 * 1 =
( ((5+5+5+5) + (5+5+5+5) + (5+5+5+5)) +
((5+5+5+5) + (5+5+5+5) + (5+5+5+5))
) = 120 - Suma de dígitos.
Elabore una función que determine la suma de los dígitos de un número. Por ejemplo,
para el número 65535 la función devuelve 24. - Suma de dígitos impares.
Elabore una función que determine la suma de los dígitos impares de un número. Por ejemplo, para el número 65535 la función devuelve 18. - Suma de dígitos pares.
Elabore una función que determine la suma de los dígitos pares de un número. Por ejemplo, para el número 65535 la función devuelve 6. - Persistencia multiplicativa.
Escriba una función en pseudocódigo que determine la persistencia multiplicativa de un número, que es el número de veces que usted tiene que multiplicar los dígitos de un número para que el resultado tenga un solo dígito. Por ejemplo:
para 39, 3*9=27, 2*7=14, 1*4=4; devuelve 3.
para 999, 9*9*9=729, 7*2*9=126, 1*2*6=12, 1*2=2; devuelve 4.
para 4; devuelve 0.
para 25, 2*5=10, 1*0=0; devuelve 2.
(Codewars https://www.codewars.com/kata/55bf01e5a717a0d57e0000ec/) - Diferencia suma de dígitos.
Elabore una función que determine la distancia numérica entre la suma de los dígitos impares y la suma de los dígitos pares. Por ejemplo, para el número 65535 la función devuelve 12. Tenga en cuenta que la distancia numérica siempre es positiva. - Ceros.
Elabore un algoritmo que determine el número de ceros que tiene un número. Por ejemplo, el número 1250890 tiene dos ceros. El número 23013002504 tiene 4 ceros. El número 10 tiene un cero. En este problema no puede usar el tipo de dato string. - Conteo de Dígitos divisibles.
Elabore una función que cuente los dígitos que son divisibles por un dígito dado. Por ejemplo,
Para el número 65535 y dígito 5, la función devuelve 3.
Para el número 65535 y el dígito 2 la función devuelve 1.
Para el número 65535 y el dígito 9 la función devuelve 0.
Para el número 65535 y el dígito 3 la función devuelve 2. - Suma de Dígitos divisibles.
Elabore una función que sume los dígitos que son divisibles por un dígito dado. Para el número 65535 y el dígito 5 la función devuelve 15.
Para el número 65535 y el dígito 3 la función devuelve 9. - Promedio de Dígitos.
Elabore una función que halle el promedio de los dígitos de un número dado. - Suma de dígitos divisibles excede entero.
Elabore una función que indique si la suma de los dígitos que son divisibles por un dígito dado excede un número dado.
Para el número 65535, dígito 2, y número 4, la función devuelve .t.
Para el número 65535, dígito 3, y número 4, la función devuelve .f.
Para el número 65535, dígito 5, y número 10, la función devuelve .f. - Divisible por 3.
Sin usar el operador %, elabore una función que determinen si un número x es divisible por 3. Un número es divisible por 3, si la suma de todos sus dígitos es divisible por 3. - Divisible por 6.
Sin usar el operador %, elabore una función que determinen si un número x es divisible por 6. Un número es divisible por 6, si es a la vez divisible por 2 y por 3. - Divisible por 11.
Sin usar el operador %, elabore una función que determine si un número x es divisible por 11. Un número es divisible por 11, si al restar de la suma de sus dígitos impares de la suma de los dígitos pares. - Número de dígitos primos 2,3,5,7.
- Función que determine el número de dígitos primos en un número entero dado. Los dígitos primos son 2, 3, 5 y 7. El 1 no se considera primo. Por ejemplo,
si el número es 5366446, la función devuelve 2.
si el número es 99268755, la función devuelve 4.
si el número es 100, la función devuelve 0.
si el número es 57392357, la función devuelve 6 - Conteo de dígitos es impar.
Función que determine si el número de dígitos en un número entero dado es impar.
Por ejemplo,
si el número es 395823, devuelve .f.
si el número es 39582, devuelve .t.
si el número es 0, devuelve .t. - Generación de números palíndromos.
A partir de un número entero positivo cualquiera, se puede generar un número palíndromo si se invierten sus dígitos para obtener otro número, el que, finalmente, se le suma al número inicial. Si el resultado de la suma no es palíndromo, se repite el proceso desde dicho resultado.
Ejemplos:
23+32=55 (pasos hasta palindromía = 1)
75+57=132, 132+231=363 (pasos hasta palindromía = 2)
86+68=154, 154+451=605, 605+506=1111 (pasos hasta palindromía = 3)
Nota: Algunos números, cuando se procesan con este algoritmo, nunca llegan a un palíndromo, como es el caso de los números 196, 295, 394, entre otras excepciones.
Construya una función algorítmica, o un conjunto de funciones, que determine para un número cualquiera x, el número palíndromo asociado. (tip: haga una función aparte para determinar el número invertido de otro número, otra para determinar si un número es palíndromo, y otra para la suma recurrente).
(Posamentier, 2014, p.45) - Factores primos.
Todo número entero, se puede descomponer en factores primos.
Por ejemplo,
13 = 13 (es primo, y su único factor es él mismo)
2678 = 2 x 13 x 103
249 = 3 x 83
714 = 2 x 3 x 7 x 17
9792 = 2 x 2 x 2 x 2 x 2 x 2 x 3 x 3 x 17
71 = 71
Construya un algoritmo que le permita determinar los factores primos de un número dado. - Suma de factores primos.
Dado que un número se puede descomponer en sus factores primos (ver problema titulado “Factores primos”), construya un algoritmo que determine la suma de los factores primos de un número. - Números Ruth-Aaron.
Dados dos números enteros positivos consecutivos, donde la suma de sus factores primos da el mismo valor, se les denomina números Ruth-Aaron.
Por ejemplo, los números consecutivos
714 = 2 x 3 x 7 x 17 con 2 + 3 + 7 + 17 = 29
715 = 5 x 11 x 13 con 5 + 11 + 13 = 29
(Posamentier, Lehmann, 2014, pag 46)
Construya un algoritmo que determine para un rango de enteros dados, los pares de números Ruth-Aaron. - Números de Kaprekar.
Los cuadrados de algunos números enteros pueden ser fragmentados en alguna parte de sus dígitos, y los números resultantes sumados para obtener de nuevo el número que fue elevado al cuadrado. Por ejemplo,
1 -> 12 -> 1
9 -> 9^2 = 81 -> 8 + 1 = 9
45 -> 45^2 = 2025 -> 20 + 25 = 45
999 -> 9992 = 998001 -> 998 + 001 = 999
4879 -> 4879^2 -> 23804641 -> 238 + 04641 = 4879
Construya un algoritmo para determinar los primeros n números de Kaprekar. - Es número perfecto.
Elabore una función que determine si un número es perfecto. Esto es, la suma de todos sus divisores propios da el mismo número. Por ejemplo, el número 6 es perfecto, porque 1 + 2 + 3 = 6. - Cuántos son perfectos.
Elabore una función que determine cuántos números de un arreglo de enteros dado son perfectos. Un número perfecto es aquel cuya suma de todos sus divisores propios da el mismo número. Por ejemplo, el número 6 es perfecto, porque 1 + 2 + 3 = 6. El número 28 es perfecto, porque 1 + 2 + 4 + 7 + 14 = 28. - Suma de divisores.
Elabore una función que halle la suma de los divisores exactos de un arreglo de números dado. Por ejemplo:
para [45,17,36], la suma es
para 45 es: 1 + 3 + 5 + 9 = 15
para 17, la suma es 1
para 36, la suma es 1 + 2 + 3 + 4 + 6 + 9 = 25
Según lo anterior, se suman 15 + 1 + 25, para un total de 41. - Suma de divisibles exactos I.
Elabore una función que, dado un arreglo de números enteros, y un divisor d, determine la suma de los números divisibles exactamente por el divisor. Por ejemplo:
para [2,9,4,60,22,21], con d = 2, la función devuelve 88.
para [2,9,4,60,22,21], con d = 3, la función devuelve 90. - Suma de divisibles exactos II.
Elabore una función que, dado un arreglo de números enteros, y un arreglo de divisores, determine la suma de los números divisibles exactamente por alguno de los divisores. Por ejemplo,
para [2,9,4,60,22,21], con [2,3], la función devuelve 118
para [2,9,4,60,22,21], con [7], la función devuelve 21
para [2,9,4,60,22,21], con [13,14], la función devuelve 0 - División por restas.
Elabore una función que permita dividir dos números a y b, usando solo restas. La función devuelve el cociente y el residuo como una tupla. Por ejemplo:
si a=40 y b=8: a/b = 40-8=32. 32-8=24, 24-8=16. 16-8=8. 8-8=0. Devolver (5 , 0)
si a=8 y b=3: 8-3=5. 5-3=2. Devolver (2 , 2).
si a=100 y b=31: 100-31=69. 69-31=38. 38-31=7. Devolver(3 , 7) - Determinar si un número es primo.
Elabore un algoritmo que determine si un número es primo. Un número es primo si es solo divisible por él mismo y por uno. Por ejemplo, Los números primos menores que 50 son los siguientes: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47. - Es primo de Sophie Germain.
Dado un número p primo, este es un número primo de Sophie Germain si 2p + 1 también es primo. Elabore un algoritmo que determine si un número p dado es de Sophie Germain. - Primo nth.
Dado un valor n, determine el primo enésimo. Se sabe que el 2 es el primer primo. - Intercambio de extremos.
Elabore una función que reciba una string, y cree una nueva cadena donde el primer y último caracter están intercambiados. Por ejemplo, si la cadena es “PESO”, la función devuelve “OESP. - Invetir string.
Construya una función en pseudocódigo que reciba una string, y genere otra que es la string invertida. Por ejemplo
si entra “venom”, sale“monev”
si entra “123”, sale“321” - Complementaria ADN.
Construya una función que devuelva la cadena complementaria de una secuencia de ADN. Una cadena simple de ADN se complementa con otra cadena, sobre la base que A y T se complementan mutuamente, al igual que lo hacen C y G. Por ejemplo,
la cadena “ACGT”se complementa con “TGCA”
la cadena “ACGTTATAGCCATT”se complementa con “TGCAATATCGGTAA” - Contar un tipo de aminoácido.[BIO]
Construya una función que cuente cuántos aminoácidos del mismo tipo que el primero de la cadena, hay en toda la cadena. Por ejemplo
para la cadena “ACGTTATAGCCATT”el primer aminoácido es A. La función devuelve 4.
para la cadena “TCCGTTATTGCACGTTATAGCCATT”el primer aminoácido es T. La función devuelve 10. - Carga de aminoácidos.[BIO]
Construya una función Python que determine la fracción que un aminoácido dado tiene en una cadena. Por ejemplo
para “ACGTTATAGCCATT, ‘A’está 4 en longitud 14. = 0.2857 - Carga de aminoácidos combinada.[BIO]
Construya una función Python que determine la fracción que un conjunto de aminoácidos dado tiene en una cadena. Por ejemplo
para “ACGTTATAGCCATT, ‘AC’= 8. 8 en longitud 14 = 0.5714
para “ACGTTATAGCCATT, ‘ACGT’= 1.0
para “ACGTTATAGCCATT, 'GC’= 5. 5 en longitud 14 = 0.3571 - Contar un caracter concreto.
Dada una string y un caracter, construya una función en pseudocódigo que calcule cuántas veces está el caracter. - Estadística letras.
Construya una función que dada una string, genere un arreglo con la estadística de las letras de los caracteres en la cadena. El arreglo de salida contendrá solo aquellos caracteres que se encuentran disponibles en la cadena. Cada elemento del arreglo de salida contendrá una tupla con el caracter y el conteo. Por ejemplo,
Si la cadena es “tall”, devuelve [(‘t’,1) , (‘a’,1) , (‘l’,2)] - Substring existe.
Construya una función que reciba dos strings, y diga si en la primera string, existe la segunda. Por ejemplo
si las cadenas son "una" ,“construya una función” devuelve .t.
si las cadenas son "dos" , “construya una función” devuelve .f. - Contar diferencias.
Construya una función que recibe dos strings que determine cuántos caracteres son diferentes en ambas. Por ejemplo,
si las dos cadenas son “pseudocode”y “pseudo”, la diferencia es 4.
si las dos cadenas son “canon”y “nikon”, la diferencia es 3.
si las dos cadenas son “haskel”y “python”, la diferencia es 6. - Enzimas de restricción.[BIO]
Construya una función que reciba una string que contiene una secuencia de ADN, y un arreglo de strings que contiene secuencias de enzimas de restricción. La función deberá indicar cuáles secuencias de enzimas de restricción se encuentran en la secuencia de ADN. La función devuelve un arreglo nuevo que agrupa dichas secuencias. Por ejemplo, si la secuencia ADN es “...CCTCTTTAGGCAGGCAGAGAATTCTTATCGAATACGGCGTAAGTCAGGT...”, y el arreglo de enzimas contiene [“GAATTC”, “GGATCC” , “AGTC”], la función devuelve el arreglo [“GAATTC”,“AGTC”]. - Eliminar blancos repetidos.
Dada una string que representa un texto, genere una nueva string donde los espacios en blanco repetidos sean eliminados. Por ejemplo,
si el texto es “next generation digital information.”
la salida es “next generation digital information.” - Contar palabra.
Construya una función que reciba dos strings, una que representa un texto, y otra que representa una palabra, y busque cuántas veces está la palabra en el texto. - Contar palabras.
Construya una función que reciba una string que representa un texto, y cuente cuántas palabras hay. Una palabra se define como cualquier secuencia entre espacios en blanco. Si la última palabra no tiene un blanco a la derecha, también cuenta. De igual modo, si la primera palabra no tiene un espacio en blanco a la izquierda, también debe ser contada. Un punto, coma o punto y coma, cuenta como separador de palabra y no como palabra. Un conjunto de signos de puntuación no cuenta como palabra. Los únicos signos de puntuación con la coma, el punto y coma y el punto. No hay caracteres especiales en la cadena.
Por ejemplo:
"el zorro quería; pero no pudo. ;”, devuelve 6
"el zorro quería comer uvas y pudo comer uvas”, devuelve 9 - Separar palabras.
Construya una función que reciba una string que representa un texto, y separe todas las palabras en un nuevo arreglo sin palabras repetidas. Por ejemplo
"el zorro quería comer uvas y pudo comer uvas”, devuelve
["el", "zorro", "quería", "comer", "uvas", "y", "pudo"]. - Separar palabras repetidas.
Construya una función en pseudocódigo que reciba una string que representa un texto, y separe todas las palabras que estén repetidas en el texto. Se crear un nuevo arreglo que contiene solo las palabras que ya están repetidas. El nuevo arreglo no repetirá las palabras repetidas. Por ejemplo:
"el zorro quería comer uvas y pudo comer uvas”, devuelve ["uvas”,"comer"]
"el zorro quería comer uvas pero no pudo”, devuelve []. - El dígito que más se repite.
Construya una función en pseudocódigo que, dado un número entero, determine el dígito que más se presenta. Si no se repite ninguno más que otro, el resultado es -1. Por ejemplo,
para el número 120358275102, el resultado es -1
para el número 122358275102, el resultado es 2 - Número de puntos en cuadrante.
Dado un arreglo unidimensional donde cada posición contiene una tupla que representa un punto en el plano cartesiano, construya una función en pseudocódigo que devuelva un arreglo de 4 posiciones, cada posición con el total de puntos en el cuadrante 1,2,3 o 4. - Los n bisiestos.
Dado un año inicial x y un valor n, construya una función en pseudocódigo que devuelva un arreglo de los n siguientes años bisiestos a x. Un año bisiesto es aquel que es divisible por 4. Pero si el año es divisible por 100 pero no por 400, no es bisiesto. - Lista de los bisiestos. Dado un arreglo que contiene años, devuelva en otro arreglo aquellos que son bisiestos. Un año bisiesto es aquel que es divisible por 4. Pero si el año es divisible por 100 pero no por 400, no es bisiesto.
- Mayor producto contiguo. ("CodeSignal", 2020) Dado un arreglo de enteros, encuentre la pareja contigua de elementos que genera el mayor producto, y devuelva el producto. Por ejemplo,
para [3, 6, -2, -5, 7, 3], la salida es 21, dado que la pareja contigua que mayor producto genere es 7,3. - Tamaño de estatuas. ("CodeSignal", 2020)
Ratiorg obtuvo estatuas de diferentes tamaños como un presente por su cumpleaños, donde cada tamaño tiene un número entero. Debido a su perfeccionismo, quiere ordenarlas de la más pequeña a la más grande, de tal modo que cada estatua sea mayor a la anterior exactamente en 1, por lo que necesitará algunas estatuas adicionales para lograrlo. Elabore una función Python que determine el mínimo número de estatuas adicionales que necesita para lograrlo. Por ejemplo,
Para [6,2,3,8], necesita 3
Para [5,4,6 ], necesita 0
Para [6,3], necesita 2 - Las strings más largas.
Construya una función en pseudocódigo que, dado un arreglo de strings, devuelva otro arreglo con las strings más largas. Por ejemplo,
para ["aba", "aa", "ad", "vcd", "aba"], devolver["aba", "vcd", "aba"] - Caracteres repetidos.
Construya una función en pseudocódigo que reciba una string, y devuelva un arreglo de strings con las palabras que contienen caracteres repetidos.
Por ejemplo,
para "I am a book keeper", devuelve ["book" , "keeper"]
para "build algorithms", devuelve [] - Palabras que presentan un caracter dado contiguo n veces.
Construya una función en pseudocódigo que reciba una string y un caracter, y devuelva un arreglo con las palabras que contienen más veces el caracter dado. Por ejemplo,
para "good book keeper", caracter 'k', devuelve
["book", "keeper"]
para "good book keeper", caracter 'o', devuelve
["good", "book"]
para "you are a fool", caracter 'o', devuelve ['fool'] - Palabras con mayor número de caracteres repetidos contiguos.
Construya una función en pseudocódigo que reciba una string, y devuelva un arreglo con las palabras con el caracter que más se repite. Si hay dos caracteres que son los que más se repiten, se devuelven aquellas con el caracter lexicográficamente menor.
Por ejemplo,
para "good book keeper", devuelve ['keeper']
para "you are a fool", devuelve ['fool'] - Pareja de números con la menor suma.
Construya una función en pseudocódigo que determine qué par de números de un arreglo de elementos al ser sumados, da el resultado más número menor. El resultado del algoritmo es una tupla con las dos posiciones de los elementos encontrados. En caso de haber un empate entre parejas, la tupla que se emite es aquella que contenga el elemento en la posición menor. - Subsección de arreglo que más suma.
Construya una función en pseudocódigo que determine qué sector de elementos contiguos de un arreglo, al ser sumados, da el resultado más grande. El resultado del algoritmo es una tupla con la posición inicial y la posición final del sector.
Por ejemplo, para el arreglo [-1,3,7,-4]
Los posibles sectores de números consecutivos y sus sumas son
[-1]=-1, [3]=3, [7]=7, [-4]=-4, [-1,3] = 2,
[3,7]=10, [7,-4]=3, [-1,3,7] = 9, [3,7,-4]=6, [-1,3,7,-4] = 5,
por lo que el sector que más suma comienza en la posición 2 y termina en la posición 3.
El resultado entonces es la tupla (2,3). - Arreglo circular derecha.
Construya una función en pseudocódigo que, dado un arreglo, mueva todos elementos a la derecha una posición, de tal modo que el último quede de primero.
Por ejemplo,
Para [1,2,3,4,5,6,7,8,9] se devuelve [9,1,2,3,4,5,6,7,8] - Arreglo circular izquierda.
Construya una función en pseudocódigo que, dado un arreglo, mueva todos elementos a la izquierda una posición, de tal modo que el primero quede de último.
Por ejemplo,
Para [1,2,3,4,5,6,7,8,9] se devuelve [2,3,4,5,6,7,8,9,1] - Invertir arreglo por pares.
Construya una función en pseudocódigo que reciba un arreglo de números enteros, que se sabe tiene un número par de posiciones, y devuelva el arreglo invertido por pares de elementos. Por ejemplo,
Para [12,34,39,45,78,89], devuelve [78,59,39,45,12,34]
Para [1,2,3,4,5,6], devuelve [5,6,3,4,1,2] - Invertir arreglo, con elemento invisible.
Construya una función en pseudocódigo que reciba un arreglo de números enteros, y devuelva el arreglo con el orden de los elementos de tal modo que queden invertidos, excepto una posición, que no puede ser alterada y es como si fuera invisible. Por ejemplo,
Para [12,34,39,45,78,89], pos = 1, devuelve [12,78,45,39,34,12]
Para [12,34,39,45,78,89], pos = 6, devuelve [78,45,39,34,12,89]
Para [12,34,39,45,78,89], pos = 3, devuelve [89,78,39,45,34,12] - Mover a izquierda con relleno.
Construya una función que, dado un arreglo con números enteros, y dado un valor n, mueva los elementos a la izquierda tantas veces como diga n. Los n elementos más a la izquierda se pierden, y a la derecha se rellena con ceros.
Para [12,34,39,45,78,89], n = 1, devuelve [0, 12,34,39,45,78]
Para [12,34,39,45,78,89], n = 6, devuelve [0,0,0,0,0,0]
Para [12,34,39,45,78,89], n = 3, devuelve [0,0,0,12,34,39] - Mover a derecha con relleno específico.
Construya una función que, dado un arreglo con números enteros, y dado un valor n, mueva los elementos a la derecha tantas veces como diga n. Los n elementos más a la derecha se pierden, y a la izquierda se rellena con un número específico dado de relleno.
Para [12,34,39,45,78,89], n = 1, r = 10, devuelve [34,39,45,78,89,10]
Para [12,34,39,45,78,89], n = 6, r = 77, devuelve [77,77,77,77,77,77]
Para [12,34,39,45,78,89], n = 3, r = 42, devuelve [45,78,89,42,42,42] - Polinomio.
Se cuenta con un arreglo que contiene coeficientes de un polinomio de grado n. Construya una función en pseudocódigo que evalúe el polinomio
El valor para x y el arreglo son parámetros de la función.
Por ejemplo,
para [1,2,3,4], y x= 0.5 tenemos = 6.125 - Suma de dígitos 1 y 0 en representación binaria.
Dado un número entero, determine el número de 1s y 0s que contiene. Por ejemplo,
para 13524124452, el número binario es 1100100110000110011100001100100100,
por lo tanto, la función devuelve la tupla (14,20). - Conteo de dígitos hexadecimales.
Dado un número entero, cuente los dígitos hexadecimales diferentes que contiene. Por ejemplo,
Para 13524124452, el número hexadecimal es 32619c324
Por lo tanto, la función devuelve 7 (los únicos dígitos presentes son 1,2,3,4,6,9,c). - Faltantes en el orden. Dado un arreglo ordenado ascendentemente que contiene números enteros positivos, determine cuántos faltan, para que el arreglo sea una secuencia ordenada de números enteros sin saltos intermedios. Por ejemplo,
para [2, 3, 6, 8], la salida es 3. (faltan el 4, 5 y 7)
para [18, 25, 27], la salida es 7. (faltan el 19,20,21,22,23,24,26) - Matriz identidad.
Elabore una función que reciba una matriz cuadrada, y evalúe si se trata de una matriz identidad. Una matriz identidad es aquella que contiene unos en su diagonal principal. El resto de los elementos es cero. - Matriz triangular inferior.
Elabore una función que reciba una matriz cuadrada, y evalúe si se trata de una matriz triangular inferior, que es aquella que tiene todos los elementos por encima de la diagonal superior igual a cero. - Matriz triangular superior.
Elabore una función que reciba una matriz cuadrada, y evalúe si se trata de una matriz triangular superior, que es aquella que tiene todos los elementos por debajo de la diagonal superior igual a cero. - Matriz simétrica.
Elabore una función que reciba una matiz cuadrada, y evalúe si se trata de una matriz simétrica, que es aquella en la que todo ai,j = aj,i. - Arreglo de índices de datos.
Se cuenta con un arreglo que contiene las posiciones de otro arreglo de datos que debe ser procesado. Elabore una función algorítmica que determine el promedio de los elementos del arreglo de datos indicado en el arreglo de posiciones. - Multiplicar fila por una constante.
Las matrices normalmente no aparecen en alguna forma especial, como por ejemplo las matrices diagonales. Una de las operaciones sobre filas que persiguen dar un primer paso en ese tipo de propósitos, es multiplicar una fila por una constante. Construya una función algorítmica en pseudocódigo, que multiplique una fila de matriz por una constante dada. Los parámetros de la función son la matriz, el número de la fila, y la constante que deberá ser distinta de cero. El valor de retorno es la nueva matriz. - Intercambio de filas de una matriz.
Las matrices normalmente no aparecen en alguna forma especial, como por ejemplo las matrices diagonales. Una de las operaciones sobre filas que persiguen dar un primer paso en ese tipo de propósitos, es intercambiar dos filas. Construya una función algorítmica en pseudocódigo, que intercambie dos filas de una matriz. Los parámetros de la función son la matriz y los números de fila que se van a intercambiar. El valor de retorno es la nueva matriz. - Multiplicar fila por una constante con adición a otra fila.
Las matrices normalmente no aparecen en alguna forma especial, como por ejemplo las matrices diagonales. Una de las operaciones sobre filas que persiguen dar un primer paso en ese tipo de propósitos, es multiplicar una fila por una constante. Construya una función algorítmica en pseudocódigo, que multiplique una fila i de matriz por una constante dada, y adicione el resultado a otra fila k dada. Los parámetros de la función son la matriz, la constante, y los números de fila i,k. la constante que deberá ser distinta de cero. El valor de retorno es la nueva matriz. - Multiplicar columna por una constante.
Construya una función algorítmica en pseudocódigo, que multiplique una columba de matriz por una constante dada. Los parámetros de la función son la matriz, el número de la columba, y la constante que deberá ser distinta de cero. El valor de retorno es la nueva matriz. - Intercambio de columnas de una matriz.
Construya una función algorítmica en pseudocódigo, que intercambie dos columnas de una matriz. Los parámetros de la función son la matriz y los números de columna que se van a intercambiar. El valor de retorno es la nueva matriz. - Multiplicar columna por una constante con adición a otra fila.
Construya una función algorítmica en pseudocódigo, que multiplique una columna i de matriz por una constante dada, y adicione el resultado a otra columna k dada. Los parámetros de la función son la matriz, la constante, y los números de columna i,k. la constante que deberá ser distinta de cero. El valor de retorno es la nueva matriz. - Multiplicar diagonal por una constante.
Construya una función algorítmica en pseudocódigo, que multiplique una columna i de matriz por una constante dada, y adicione el resultado a otra columna k dada. Los parámetros de la función son la matriz, la constante, y los números de columna i,k. la constante que deberá ser distinta de cero. El valor de retorno es la nueva matriz. - Intercambio de diagonales.
Elabore un algoritmo que intercambie las diagonales de una matriz cuadrada. Esto es, todos los elementos de la diagonal principal, deben quedar en la diagonal secundaria, y todos los elementos de la diagonal secundaria deberán pasar a ser los elementos de la diagonal principal.
Por ejemplo,
si la entrada es la matriz
| 10 20 30 40 |
| 50 60 70 80 |
| 90 100 110 120 |
|130 140 150 160 |
La salida de la función es
| 40 20 30 10 |
| 50 70 60 80 |
| 90 110 100 120 |
|160 140 150 130 | - Arreglo circular izquierda n movimientos.
Construya una función en pseudocódigo que, dado un arreglo, y un número de movimientos, mueva todos elementos a la izquierda n posiciones. Por ejemplo,
Para [1,2,3,4,5,6,7,8,9], m=4 se devuelve [5,6,7,8,9,1,2,3,4] - Movimiento adelante de elementos de fila de matriz.
Elabore un algoritmo que, da una matriz cuadrada C, un número de fila f, un número de movimientos m, y un número de relleno x, mueva tantos elementos hacia la derecha como indique m, rellenando con el número x el contenido de las posiciones que se movieron. Las posiciones finales que se muevan, se pierden.
Por ejemplo,
si la entrada es la matriz
| 10 20 30 40 |
| 50 60 70 80 |
| 90 100 110 120 |
|130 140 150 160 |
f = 2, m = 3, x = 0 :
La salida de la función es
| 10 20 30 40 |
| 0 0 0 90 |
| 90 100 110 120 |
|130 140 150 160 | - Movimiento adelante de elementos de columna de matriz.
Elabore un algoritmo que, da una matriz cuadrada C, un número de columna c, un número de movimientos m, y un número de relleno x, mueva tantos elementos hacia abajo como indique m, rellenando con el número x el contenido de las posiciones que se movieron. Las posiciones finales que se muevan, se pierden.
Por ejemplo,
si la entrada es la matriz
| 10 20 30 40 |
| 50 60 70 80 |
| 90 100 110 120 |
|130 140 150 160 |
c = 2, m = 3, x = -5 :
La salida de la función es
| 10 -5 30 40 |
| 50 -5 70 80 |
| 90 -5 110 120 |
|130 20 150 160 | - Movimiento adelante de elementos de diagonal de matriz.
Elabore un algoritmo que, da una matriz cuadrada C, un número de movimientos m, y un número de relleno x, mueva tantos elementos de la diagonalhacia abajo hacia abajo como indique m, rellenando con el número x el contenido de las posiciones que se movieron. Las posiciones finales que se muevan, se pierden.
Por ejemplo,
si la entrada es la matriz
| 10 20 30 40 |
| 50 60 70 80 |
| 90 100 110 120 |
|130 140 150 160 |
m = 2, x = 0 :
La salida de la función es
| 0 -5 30 40 |
| 50 0 70 80 |
| 90 -5 10 120 |
|130 20 150 60 |