Está en la página 1de 111

Todos los derechos sobre la presente obra son del autor.

A mi hija.
Tabla de Contenidos

PRÓLOGO

INTRODUCCIÓN

CAPÍTULO 1: RESOLUCIÓN DE PROBLEMAS

¿Qué es un problema?

Algoritmos

Del problema a la solución

El Robot que Dibuja

Decisiones

Repeticiones o iteraciones

Poniendo todo junto

Resumen del capítulo 1

CAPÍTULO 2: REPRESENTACIÓN DE LOS ALGORITMOS

Pseudocódigo

Entrada de datos

Asignación
Ejemplos de instrucciones de asignación:

Salida
Ejemplos de bloques de salida

Decisiones
Ejemplos de decisiones
Otro ejemplo de decisiones: Ordenando cartas

Ciclos o Iteraciones
Requisitos de un ciclo
Ejemplos del uso de ciclos

Ciclos controlados por una variable

Resumen del concepto de ciclo

Variables indizadas
Ejemplo del uso de vectores
¿Eso es todo?
Ordenar una lista de N números
Intersección de conjutos

Resumen del capítulo 2

CAPÍTULO 3: PROGRAMACIÓN

Entrada de datos
Ejemplos

Salida de datos
Ejemplos

Asignación
Ejemplos

Decisiones
Ejemplos

Ciclos
Ejemplos

Variables indizadas
Resumen del capítulo 3

EPÍLOGO
Prólogo
Por el Dr. Javier Trenti

Traten de imaginar que el mundo, por alguna circunstancia insoslayable, debe


apagar todas las computadoras existentes. Dejarían de existir los
procesadores de texto, las transacciones bancarias, los videojuegos, las
compras por internet, los asados convocados a través de una red social, la
televisión por demanda, la búsqueda de palabras o conceptos desconocidos,
los recorridos por lugares no habituales guiados por una voz a la que hemos
caracterizado como “la gallega del GPS”. La humanidad se ha vuelto
dependiente de las computadoras de una manera asombrosa.

Las nuevas generaciones parecen haber adquirido naturalmente una relación


de amistad virtual con todos los dispositivos que llevan incorporado un
microprocesador. Los niños suelen ser consultados por los mayores acerca de
cómo manejar un celular, un televisor o una impresora. Sin embargo, existe
una diferencia importante entre operar una máquina adjetivada con la palabra
“smart” y comprender la lógica que subyace a su funcionamiento.

El autor de este libro, nuestro Profesor Mariano Pagés, ha aprovechado cada


atril al que fue invitado para divulgar, de una manera muy original y
entretenida, la necesidad de enseñar la lógica y la estructura de la
programación desde la primera infancia. En estas páginas ha sabido volcar la
experiencia adquirida en tantos años de docencia de una manera muy amena,
sin perder la rigurosidad del campo matemático en el que se introduce. El
libro recorre desde sus primeras páginas un camino cuyo fin permite arribar a
conceptos de programación estructurada, con una dosis de rigor equilibrada
en la balanza por el grato uso del juego como soporte pedagógico. Su lectura
resultará agradable para cualquier persona, de cualquier edad, que desee
ingresar en los dominios de la programación de computadoras: cómo decirle
a un dispositivo programable qué tarea deseamos que realice y de qué manera
queremos que lo haga.
El libro se divide en tres capítulos que van de menor a mayor. Primeramente
nos enseña a formalizar y resolver problemas mediante herramientas cuya
simpleza se asemeja a la de los bloques de aquellos juegos que permiten
soltar la imaginación para construir objetos más complejos. El planteo de
problemas y la toma de decisiones utilizan como primera herramienta un
robot que dibuja con movimientos sencillos. La resolución de estos primeros
desafíos deja al lector en condiciones ideales para adentrarse en una
representación más compleja que, sin perder versatilidad, nos aproxima al
objetivo final de programar en un lenguaje formal. Así, el segundo capítulo
enfrenta el reto de representar algoritmos utilizando un conjunto reducido de
palabras de uso cotidiano, pero bajo una cierta estructura que marca una
continuidad en los conceptos de sucesión, bifurcación y repetición vistos
anteriormente. La utilización de pseudocódigo permite agregar facilidades a
nuestra forma de comunicar cómo ha de resolverse un problema: entrada de
datos, asignaciones, decisiones, ciclos y datos estructurados simples pueden
incorporarse ahora de un modo gentil y ampliamente comprensible. Ahora
contamos con mecanismos útiles para llevar una idea desde nuestra
imaginación al papel, como paso intermedio para poder plasmarla en un
dispositivo real y observar con entusiasmo el resultado. El cierre triunfal de
este recorrido es la implementación de los algoritmos desarrollados en un
lenguaje de programación real. La accesibilidad a herramientas de fácil
disponibilidad es una preocupación principal para nuestro autor: la parte final
trabaja con un subconjunto de instrucciones del lenguaje Python, sin menguar
por ello la amplitud de posibles soluciones alcanzables desde esa restricción.
El último capítulo cuenta con un gran número de ejemplos, basados en
problemas desarrollados y que muestran un resultado concreto. El recorrido
ha finalizado y casi con seguridad podría apostarles que el objetivo principal
ha sido alcanzado.
Introducción
Después de más de 30 años de docencia, dictando materias introductorias de
carreras de ciencias de la computación, he decidido escribir este libro, que
recopila distintas técnicas y métodos que he ido ensayando, usando,
modificando y adaptando, a lo largo de mi carrera. Cuando mis alumnos me
preguntaban qué libro les recomendaría para aprender a resolver problemas e
introducirse en el mundo de la programación, me veía en aprietos, ya que, si
bien hay muy buenos libros, pocos son los que dedican varias páginas al arte
de la resolución de problemas. Entonces mi respuesta era que todavía no
había escrito el mío. En consecuencia, aquí me encuentro cumpliendo con lo
tácitamente prometido.

Este libro está organizado en tres partes:

Primera parte: Dedicada a exponer el significado de la palabra problema y


proponer métodos de resolución, utilizando distintos personajes, entre los que
se encuentra el lector, para ilustrar de qué se trata la construcción de
soluciones. Esta parte tiene un enfoque general, en donde quizás poco tenga
que ver la informática propiamente dicha, por lo que puede aplicarse a
distintas disciplinas.

Segunda parte: Un poco más enfocados en la ciencia computacional, aquí se


presenta el concepto de pseudocódigo, como representación formal de las
distintas soluciones a los problemas a resolver, cómo someterlos a prueba,
con vistas a ser traducidos a algún lenguaje de programación de
computadoras.

Tercera parte: Programación propiamente dicha, a nivel básico. Aquí se


presenta un esquema de traducción de los algoritmos representados a través
de pseudocódigo de la segunda parte del libro, a un lenguaje de programación
de computadoras. El objetivo de esta parte del libro es que el lector vea sus
soluciones expresadas en algoritmos, traducidas a programas y funcionando,
en el mejor de los casos. Para ello usaremos un sub conjunto muy pequeño
del lenguaje Python. Tan simple y tan pequeño que se podrán probar los
programas en un dispositivo móvil.

Aspiro que además de disfrutar de la lectura, el lector sea capaz de


aprovechar las herramientas que aquí se proporcionan para ayudarlo en la
tarea de resolver problemas y, eventualmente, traducir esas soluciones en
programas.
Capítulo 1: Resolución de problemas
En este capítulo se pretende explicar qué es un problema y plantear un
camino que conduzca a su solución. Sin el intento de establecer una
metodología estricta, analizaremos qué debemos observar y qué actividades
conviene realizar para poder llegar a la especificación semi-formal de una
solución posible.
¿Qué es un problema?
Cuando nos enfrentamos a la palabra "problema", distintas son las reacciones
que experimentamos. Recuerdo en la escuela primaria cuando la maestra
escribía en el pizarrón con letras tamaño catástrofe PROBLEMA, con su
prolija y redondeada letra cursiva. Parecía disfrutarlo. En ese momento entre
mis compañeros podía observar distintos efectos, la mayoría acompañados
del gesto de tomarse la cabeza con ambas manos. Otros parecían gozar con el
desafío, entre los que hoy me incluyo, aunque la memoria pueda fallarme un
poco.
¿Pero qué es lo que había detrás de ese enunciado? Si a la situación le
aplicamos altos niveles de abstracción, seguramente podemos afirmar que lo
que se propone al enunciar un problema es que algo sea transformado, que
determinadas cosas pasen de un estado A a un estado B, diferente y deseable.

Dentro de esta definición, generalmente vamos a encontrar que un problema


contiene datos o insumos que deben ser transformados de alguna manera para
alcanzar resultados o productos deseados, siguiendo algún procedimiento. En
un sentido amplio, en la formulación del problema, una vez comprendido
perfectamente, encontraremos elementos con los que deberemos trabajar para
poder llegar al resultado esperado.

El párrafo precedente es de una densidad conceptual interesante.


Analicémoslo con un poco más de detalle.
Cuando hablamos de datos o insumos, nos referimos a la materia prima que
permite elaborar la solución del problema. Si se trata de un problema
numérico sencillo como por ejemplo sumar dos números A y B, justamente el
insumo está constituido por dos números. Siempre tenemos que evitar las
ambigüedades, por lo tanto, si hablo de dos números sin especificar su tipo,
se trata de simplemente dos números que podrán ser enteros, reales,
naturales, etc. En este tipo de problemas matemáticos claramente los datos
están bien determinados. ¿Pero pasa esto en todo tipo de problemas?
Supongamos ahora que el problema es "preparar un huevo frito". Propongo
antes de continuar la lectura, elaborar una lista de insumos necesarios para
resolverlo.
Pensando de manera básica podemos determinar que necesitamos
sartén
aceite
un huevo
sal a gusto
Podríamos ponernos un poco más detallistas, especificando cantidad de
aceite, tamaño del sartén, o agregando otros elementos tales como fuego, o
fuente de calor y alguna herramienta que resulte apropiada para poder retirar
el huevo una vez terminado.

Siguiendo con el análisis de la definición, al referirnos al resultado o


producto, claramente en los ejemplos citados debemos pensar en el número
que resulta de sumar A y B en el primer problema, y al huevo frito en el
segundo. Lo que obtenemos es un "estado" diferente al que teníamos antes de
resolver los problemas. Ocurrieron transformaciones en los insumos, que más
allá del carácter destructivo o no de las mismas, han producido aquello que
queríamos.
resolver un problema
Para que esa transformación sea posible es necesario seguir un proceso, y
aquí yace la esencia y el arte de la resolución de problemas. Aquí es donde
los procesos tanto tecnológicos como creativos pueden marcar una gran
diferencia. No existe una única manera de resolver un problema. Cuanto más
complejo es, mayor será la cantidad de tareas necesarias para resolverlo, cada
una con sus variantes y en consecuencia más alternativas de solución
aparecen. Pero dentro de todo el conjunto de soluciones posibles, ¿es factible
encontrar la mejor? Me arriesgo a responder que NO. Pero ¿es eso tan malo
como parece? NO. Es difícil establecer un criterio que permita determinar si
una solución es mejor que la otra. En el ejemplo del huevo frito puedo usar
más temperatura en el aceite, o menos, o variar la cantidad del aceite, variar
la forma de extraer el interior del huevo, retirarlo más o menos cocido, la
evaluación del resultado es absolutamente subjetivo y dependerá de las
preferencias del comensal, de la necesidad de ahorrar energía, cantidad de
aceite, etc.
Si pensamos en los procesos, o sea, las acciones que se realizan para resolver
el problema, las opciones aún son mayores. En este punto, debemos
centrarnos en el sujeto que se encargará de resolver el problema. Quizá
resulte un poco extraño pensar que la solución de un problema depende de
quién se encargue de resolverlo. Para evitar confusiones, vamos a hablar de la
descripción del proceso y no del resultado. Veámoslo con un ejemplo:

Problema: Lavarme las manos


Solución A:
Lavarme las manos (simple, ¿no?)

Solución B:
Abrir la canilla
Tomar el jabón
Frotar las manos con el jabón debajo del chorro de agua
Dejar el jabón
Frotar las manos debajo del agua hasta que no quede jabón
Cerrar la canilla
Secarme las manos

Ah, bien diferentes, ¿Pero el resultado es el mismo? Digamos que sí. ¿El
proceso es el mismo? Digamos que ¡sí también! ¿Entonces que cambió? ¡La
descripción del proceso! Porque tiene que ser adecuada para el sujeto que la
ejecuta.
Quizá si ese sujeto fuera un robot, tendría que mostrar el proceso de abrir la
canilla con más detalle, ¡mucho más detalle!
Lo mismo sucede con las recetas de cocina, tan usadas como ejemplos de
solución de problemas. En una receta puedo encontrar términos como
"gratinar", "cortar en juliana", "blanquear", que no son familiares a todas las
personas y constituyen pequeños mini problemas dentro de un gran problema.
Algoritmos
Hasta aquí deliberadamente estuve evitando usar la palabra "algoritmo", que
me gusta definirla de la siguiente manera:

"Un algoritmo es una secuencia de tareas elementales, ejecutadas por un


sujeto para resolver un problema".

En esta definición podemos observar términos conocidos. No existen


palabras rebuscadas, pero, sin embargo, es conveniente analizar la riqueza
semántica de algunas expresiones. Desmenucemos entonces la definición
para ver qué hay realmente dentro de este par de renglones:

- Secuencia: esta palabra representa exactamente eso, una sucesión de


eventos que ocurren unos después de otros en determinado orden. Alterar ese
orden podría significar que nuestro algoritmo deje de funcionar.
- Tareas elementales: es importante destacar este par de palabras que nos
resultan tan familiares, pero que dentro de este contexto son absolutamente
relevantes. Definiremos como "tarea elemental" a aquella operación que
puede ser comprendida y ejecutada por un sujeto, sin necesidad de ser
subdividida en otras tareas. En otras palabras, las tareas elementales
constituyen la "caja de herramientas" con la que cuento para resolver el
problema. Ahondaremos sobre este concepto más adelante, pero aquí
conviene destacar que esta caja de herramientas es totalmente dependiente del
sujeto que resolverá el problema, ejecutando las tareas del algoritmo.
- Sujeto: el término sujeto representa cualquier entidad capaz de ejecutar las
tareas elementales. Puede ser una persona, un grupo de personas, una
computadora, un robot, etc.

Poniendo todo junto, partimos de un problema y llegamos al algoritmo, que


no es otra cosa que el procedimiento que resolverá el problema.

Para que eso suceda el algoritmo tiene que tener ciertas propiedades:
- No debe ser ambiguo
- Debe ser perfectamente comprensible por el sujeto
- Debe terminar en algún momento

La ambigüedad es un defecto de muchos algoritmos que podemos encontrar


en la vida ordinaria. Existen muchos ejemplos de algoritmos que utilizamos
sin saberlo: recetas de cocina y manuales de instrucciones de aparatos que
compramos constituyen claros ejemplos. Como están expresados en lenguaje
natural, y no está claramente determinado el sujeto destinatario del algoritmo,
son escritos en un lenguaje coloquial comprensible para la persona
"promedio". Pero ¿qué es y qué conoce una persona promedio? Quien sabe...
Cuando en una receta dice "batir las claras a punto nieve", está suponiendo
quien escribió ese algoritmo que todos sabemos qué es ese tal punto nieve.
Cuando en un manual dice conectar el dispositivo a la red, se supone que se
sabe si es a la red eléctrica, a la de datos o a la red sanitaria.
Por eso, cuando se trata de resolver problemas y crear un algoritmo, existen
varios momentos cruciales:

- El primer momento es el de comprensión del problema que debo resolver.


permite
- El momento creativo para el que no existen métodos relevantes que consiste
en inventar y diseñar la solución del problema. Aquí debemos siempre
tener en cuenta que no existe una solución única para un problema, pero
sin embargo debo elegir una mediante algún criterio.

- Luego se debe traducir esa solución a un algoritmo.

- Debemos representar ese algoritmo de alguna manera apropiada. Aquí


tengo que sí o sí contar con mi caja de herramientas, que está formada ni
más ni menos que con las tareas elementales que el sujeto es capaz de
comprender. Aquí es donde decido si "abrir la canilla" es una tarea que
puedo exponer en mi algoritmo, o si debo decir "gire la canilla en sentido
horario un cuarto de vuelta", o quizás "coloque la mano sobre la canilla,
tómela, aplique una cupla de tantos kgm...."

Hasta aquí esta breve presentación que se podría considerar informal, sobre
todo en la descripción de algunas tareas elementales. En las próximas
secciones seremos mucho más precisos en la creación de soluciones a
problemas determinados que iremos resolviendo. Paso a paso iremos
develando distintas técnicas hasta llegar a la construcción de nuestros
primeros programas de computadora.
Del problema a la solución

Es un buen momento para ordenar lo visto en la sección anterior en algo que


podemos llamar "metodología para la resolución de problemas", que podría
incluir las siguientes actividades:

1. Identificar y comprender el problema


2. Identificar los datos o insumos del problema
3. Determinar la salida o el producto esperado
4. Construir un modelo de solución que vincule los datos o insumos para
obtener la salida o producto
5. Representar el modelo del punto 4 a través de un algoritmo adecuado para
el sujeto que debe resolver el problema
6. Probar la solución
7. Ejecutar el algoritmo y resolver el problema las veces que sea necesario

Vamos a poner en práctica todo esto a través de un ejemplo.


Problema: Dados dos números, sumarlos e informar el resultado de la suma.
1. Identificar y comprender el problema: simple, tenemos que sumar dos
números.
2. Identificar los datos o insumos del problema: Los datos son dos números
que podemos llamar X e Y.
3. Determinar la salida o el producto esperado: El resultado esperado es la
suma de X e Y, que podemos llamar Z.
4. Construir un modelo de solución que vincule los datos o insumos para
obtener la salida o producto: El modelo podría ser Z=X+Y, eso es lo que hay
que hacer y después informar el valor de Z.
5. Representar el modelo del punto 4 a través de un algoritmo: Hagámoslo

Este problema es sumamente simple. Le propongo en este momento que


"invente" un algoritmo para resolverlo. No siga leyendo, haga su algoritmo
como le parezca y luego siga.
¿Ya lo tiene?
Bueno, si ya lo tiene le cuento que el sujeto que va a resolverlo es un monito
entrenado, al que le hemos enseñado algunas cosas, que podemos enumerar
como las siguientes tareas elementales:
A. Pedir un número y anotarlo en un papel (no se preocupe, lo
puede hacer, pero en un papel solamente puede anotar un
solo número)
B. Memorizar el número anotado en el papel
C. Anotar en el papel el número memorizado
D. Decir en voz alta el número anotado en el papel
E. Sumar el número anotado en el papel con el memorizado y
memorizar la suma
F. Cambiar el papel

Posiblemente el algoritmo que usted creó no le sirva al monito. ¿Por qué pasó
eso? Porque usted desconocía qué sujeto debía resolver el problema, por lo
tanto, también desconocía sus tareas elementales. En pocas palabras: usted no
tenía una caja de herramientas adecuada para construir el algoritmo adecuado
al sujeto.
Sabiendo esto, ahora si puede construir el algoritmo.

¿Ya lo tiene?
¡Hagámoslo juntos!

Primero deberíamos pedir los datos, que son los números X e Y que
determinamos como insumos. El monito no puede pedir dos números, solo
puede pedir uno y anotarlo en un papel, como dice la tarea elemental que
identificamos como A.

Primera tarea: A (Pedir un número y anotarlo en un papel)

Luego debemos pedir otro número, pero sería conveniente que antes
memoricemos el que acabamos de ingresar que está anotado en el papel. Esta
actividad corresponde con la tarea que llamamos B

Segunda tarea: B (Memorizar el número anotado)

Ahora deberíamos pedir otro número, ya que tenemos memorizado el


primero. Pero ya no puedo usar el mismo papelito, porque únicamente se
puede anotar un solo número. Por lo tanto, tengo que cambiar el papel. Tarea
F

Tercera tarea: F (Cambiar el papel)

Estamos listos para anotar el segundo número

Cuarta tarea: A (Pedir el segundo número)

Ya que tenemos un número memorizado y el otro anotado, ¿cómo los


sumamos? ¡Fácil! Tarea E

Quinta tarea: E (Sumarlos)

¡Ya tenemos el resultado de la suma en la memoria! ¿Podemos informarlo?


El monito solamente puede informar el número anotado en el papelito, pero
el resultado de la suma lo tiene en la memoria. ¿Entonces cómo hacemos?
Cambiamos el papelito y anotamos el número que tenemos en memoria

Sexta tarea: F (Cambiar el papel)

Séptima tarea: C (Anotar el número memorizado con el resultado)

Y solamente nos queda informar el resultado, que está en el papelito

Octava tarea: D (Decir en voz alta el resultado)

Poniendo todo junto:


A, B, F, A, E, F, C, D

6. Probar la solución:

Poniéndolo a prueba con los números 3 y 5 como datos quedaría de la


siguiente manera:

Tarea Papel Memoria Salida

A 3

B 3 3

F 3

A 5 3

E 5 8

F 8

C 8 8

D 8 8 8
Si no obtuvo el mismo resultado no hay que desanimarse. Pudieron pasar dos
cosas: o el algoritmo es incorrecto, cosa que puede verificarse al hacer la
prueba, o usted encontró una solución diferente, que es absolutamente
posible.

Ahora veamos si podemos complicar un poco más el problema. Recién


pudimos sumar dos números, pero ¿será cierto que el monito podrá sumar
tres números?

Es razonable pensar que, si acabamos de sumar dos números, y a ese


resultado le sumamos un número más, efectivamente estaremos sumando tres
números.
Matemáticamente sería algo así

T=(X+Y)+Z

Idéntico a la aplicación de la propiedad asociativa de la suma.

Nuestro nuevo algoritmo podría resultar de la siguiente manera:

A - Pedir un número y anotarlo (primer número, nuestro X)


B - Memorizar el número anotado
F - Cambiar de papel
A - Pedir un número y anotarlo (segundo número, nuestro Y)
E - Sumar el número anotado con el memorizado (hasta aquí
tenemos los dos primeros números sumados, con el resultado
memorizado, X+Y)
F - Cambiar el papel
A - Pedir un número y anotarlo (tercer número, nuestro Z)
E - Sumar el número anotado con el memorizado (el resultado
de X+Y que se encuentra en memoria, sumado a Z que se
encuentra en el papel)
F - Cambiar el papel (para anotar el resultado definitivo)
C - Escribir el número memorizado
D - Informar el número anotado en el papel (la suma de los tres
números)

O sea que la secuencia de tareas obtenida es:


A, B, F, A, E, F, A, E, F, C, D

Construyamos ahora la tabla de prueba del algoritmo obtenido con los


números 3, 5, 7. El resultado que deberíamos obtener es 15.

Tarea Papel Memoria Salida

A 3

B 3 3

F 3

A 5 3

E 5 8

F 8

A 7 8

E 7 15

F 15

C 15 15

D 15 15 15

¿Y podremos sumar 5 números?

Siguiendo el mismo criterio, obviamente sí.


La expresión matemática quedaría de la siguiente manera

R=(((X1+X2)+X3)+X4)+X5
Y el algoritmo correspondiente quedaría de la siguiente forma

A, B, F, A, E, F, A, E, F, A, E, F, A, E, F, C, D

¿Qué se puede observar dentro del algoritmo obtenido?

¿Ve lo mismo que yo? Hay una cadena que se repite: AEF
Esa cadena la vemos 4 veces en este algoritmo que suma 5 números, 2 veces
en el algoritmo que suma 3 números, y una vez en el que suma 2 elementos.
Por lo tanto se repite N-1 veces, donde N representa la cantidad de números a
sumar.

Digresión:

Sería fácil inferir un algoritmo que permita sumar N números:


Podría quedar así:

A, B, F, repetir (N-1) veces [A, E, F], C, D

Las tareas encerradas entre corchetes son las que deben repetirse N-1 veces. El único problema es que nuestro
monito no sabe repetir actividades una determinada cantidad de veces, porque no sabe contarlas. Deberíamos
enseñarle y de este modo este algoritmo podría ser posible y correcto.

Repasando rápidamente lo visto hasta ahora, podemos resumirlo en los


siguientes párrafos.

Definimos el concepto de problema y construimos un procedimiento de


algunos pasos que nos ayudan a resolverlo.

Incorporamos el concepto de algoritmo, dando una definición haciendo


hincapié en el sujeto y sus tareas elementales, poniendo en relieve que las
limitaciones del sujeto son las que determinan el algoritmo.

No hay un único algoritmo que resuelve un problema. Disponiendo de una


única caja de herramientas, compuesta por las tareas elementales, puedo
combinar su uso de diferentes maneras obteniendo resultados funcionalmente
equivalentes.
En los capítulos siguientes, se presentarán distintos sujetos y distintos
problemas para ejemplificar con mayor claridad estos conceptos.
El Robot que Dibuja
Supongamos que tenemos un robot con una lapicera. Podemos colocar el
robot sobre una superficie, y éste dibujará a través del movimiento. Si lo
colocamos sobre un papel, al moverse podrá dejar su rastro, pero no es capaz
de detectar si llegó a los límites del papel, y podrá seguir "dibujando" en
cualquier superficie sobre la que se mueva, por lo que deberemos tener
cuidado.
Ahora supongamos también que las tareas elementales que es capaz de
ejecutar este robot son 2:
A. Avanzar (siempre avanza una distancia igual, que podría ser de 5
cm)
B. Girar (siempre gira 90 grados a su derecha)
Si bien este robot parece bastante limitado, puede hacer algunas cosas.

Supongamos que queremos que dibuje una línea recta de 10 cm de longitud.


Los datos o insumos del problema están dados por la longitud de la línea, 10
cm
El resultado esperado es una línea de 10 cm.
Aunque datos y resultados parezcan lo mismo no lo son. El dato es la
longitud de la línea que deseo obtener (un número), y el resultado es la línea
en sí, de la longitud deseada (un dibujo).

El procedimiento, teniendo en cuenta las habilidades del sujeto, sus tareas


elementales, nuestra caja de herramientas, consistiría en dibujar dos líneas de
5cm contiguas, cosa que sabe realizar.
En consecuencia, el algoritmo resultante sería el siguiente:
A, A

Simple, ¿no? Coloco el robot sobre el papel convenientemente, y al ejecutar


la primera instrucción A dibuja una línea de 5 cm, al ejecutar la segunda A a
continuación, dibuja otra línea de 5 cm obteniendo la línea de 10 cm que
deseaba, entonces retiro el robot y problema resuelto.

Ahora propongamos un problema más complejo: dibujar un cuadrado de 5


cm de lado.

El resultado esperado sería algo así


Un algoritmo posible para resolver este problema sería el siguiente:

A, B, A, B, A, B, A, B

De esta manera el robot dibujaría el primer lado hacia arriba, doblaría a la


derecha 90 grados, y repetiría la acción 4 veces, dibujando los 4 lados y
quedando apuntando hacia arriba nuevamente.
Puede probar usted mismo haciendo las veces del robot.

Ahora supongamos que el problema es ligeramente distinto. Queremos


dibujar una figura que consiste en un cuadrado encima del otro, por lo que
resultaría una figura de 10 cm de altura y 5 cm de ancho:

Una solución posible sería:

A, B, A, B, A, B, A, B (primer cuadrado)
A (Avanza sobre el primer lado del cuadrado sobre escribiendo)
A, B, A, B, A (dibuja los 3 lados que le faltan al segundo cuadrado)

Podríamos plantearnos problemas más complejos, que pueden ser resueltos


con este simple sujeto, limitado solo a dos tareas elementales.

Sugiero que el lector pruebe creando nuevas figuras, o incluso agregar nuevas
tareas elementales al robot, para permitirle resolver problemas más
complejos.
Por ejemplo podríamos agregarle las tareas elementales:

C. Subir lápiz
D. Bajar lápiz

De este modo podemos hacer que el robot avance sobre el papel sin dibujar,
permitiendo por ejemplo realizar cierto tipo de escritura con la tipografía
adecuada.

Modificando un poco más sus tareas elementales, podemos evitar las


restricciones de girar siempre 90 grados o dibujar las líneas siempre del
mismo tamaño.
Podemos hacer evolucionar el robot 1.0 al 2.0 modificando sus funciones.
Digamos que ahora además de agregarle un motor que permite subir y bajar
el lápiz, permitimos que gire en un ángulo determinado aunque siempre a
derecha, y que avance una determinada cantidad de milímetros.
Así quedaría el conjunto de tareas elementales:

A. Bajar lápiz
B. Subir lápiz
C. Avanzar X milímetros
D. Girar Y grados

Si quisiéramos dibujar un hexágono de 10 cm de lado, cosa que antes era


imposible, el resultado sería el siguiente:

A
C 100
D 30
C 100
D 30
C 100
D 30
C 100
D 30
C 100
D 30
C 100
D 30
B

Son tan solo dos operaciones nuevas y una mejora de las dos que ya
teníamos, pero la diferencia es enorme. Ahora podemos dibujar hexágonos
como el del ejemplo, o polígonos de cualquier cantidad de lados, avanzar sin
escribir lo que nos permitiría crear letreros por ejemplo. Una enorme
diferencia.
Hemos agregado nuevas herramientas a nuestra caja, y con eso podemos
resolver nuevos problemas, o quizás, problemas que antes podíamos resolver
de una manera, ahora podemos resolverlos de otra más eficiente.
Si quisiéramos construir un rectángulo de 10 cm de altura por 20 de base,
podríamos hacerlo con cualquiera de los dos robots. Veamos los resultados:

Robot 1.0
A, A, B, A, A, A, A, B, A, A, B, A, A, A, A, B

Robot 2.0
A, C 100, D 90, C 200, D 90, C 100, D 90, C 200, D 90, B

Mientras en el primer caso necesitamos 16 instrucciones, en el segundo nos


alcanza con sólo 10.

Mismo problema, distintas soluciones con distintos sujetos.

Digresión:
Con el segundo robot también puedo emular el comportamiento del primero y resolver el mismo
problema sin aprovechar sus ventajas. El algoritmo quedaría expresado de la siguiente manera
A, C50, C50, D90, C50, C50, C50, C50, D90, C50, C50, D90, C50, C50, C50, C50, D90, B

Esto resulta interesante porque, aunque tengamos una máquina poderosa, un


robot cargado de habilidades, podemos construir igualmente algoritmos
ineficientes, que no necesariamente son incorrectos, pero que no aprovechan
al máximo sus capacidades.

Podemos potenciar aún más a nuestro robot agregando nuevas funciones,


como por ejemplo construir un rectángulo dando su base y su altura, entonces
el algoritmo sería mucho más simple: RECTÁNGULO(100,200), por
ejemplo, y con una sola tarea resolvemos el problema, que en el caso anterior
¡se resolvió con 18!

Lo curioso, es que el mismo robot puede hacer lo mismo, en un solo paso o


en 18. Estoy siendo insistente en este punto porque es muy importante, y nos
permite concluir lo siguiente:
"La eficiencia de un algoritmo depende tanto de la persona que lo diseñe,
como de las tareas elementales que conozca el sujeto que lo ejecuta".
Decisiones
Hasta ahora los problemas que planteamos fueron resueltos con la simple
ejecución de instrucciones una a continuación de la otra, sin necesidad de
tomar ninguna decisión. Es más, tanto el monito como el robot dibujante, tal
como fueron enseñados, no son capaces de tomar decisiones. Aunque no
parezca, los algoritmos con los que nos encontramos en la vida real están
llenos de decisiones que a veces resultan inconscientes. Ya hablamos de
recetas, y allí también existen decisiones ocultas, por ejemplo, cuando
lavamos una papa nosotros decidimos cuándo debemos detenernos porque
consideramos que ya está suficientemente limpia. Ahí hay claramente una
decisión. Cuando un artefacto no funciona y consultamos el manual de
instrucciones, al final, donde dice algo así como "resolución de problemas",
generalmente hay una serie de pasos y muchas decisiones que tomar. Por
ejemplo, dirá que verifique que el artefacto esté conectado a la red, que haya
electricidad en su domicilio, que el artefacto esté encendido, y otro conjunto
de verificaciones y acciones que pueden llevarlo a usted a resolver el
problema, o a llamar al servicio técnico.

A modo de ejemplo, vamos a plantear un problema simple, que requiera de


decisiones más evidentes. Supongamos que tenemos dos números diferentes,
y queremos determinar cuál es el mayor. En este problema está claro que
debemos comparar dos números, y como resultado de esa comparación,
determinaremos el valor del mayor. ¿Quiere resolver usted mismo el
problema? Todavía no, esto es muy simple. Entonces convocaremos
nuevamente al monito que suma, para que nos resuelva el problema. ¿Le
parece que podrá resolverlo? Para evitar que vuelva varias páginas atrás el
libro, voy a traer aquí las tareas elementales del monito:

A. Pedir un número y anotarlo en un papel


B. Memorizar el número anotado en el papel
C. Anotar en el papel el número memorizado
D. Decir en voz alta el número anotado en el papel
E. Sumar el número anotado en el papel con el memorizado y
memorizar la suma
F. Cambiar el papel

Este sujeto sabe sumar, algo sorprendente para un monito, pero no sabe
efectuar comparaciones y tomar decisiones. Lo que debemos hacer es
enseñarle algo nuevo; una vez que aprenda, podrá resolver problemas
diferentes.
Imagino que mucho habrá costado enseñarle a sumar y escribir números, ni
me imagino lo que costó enseñarle a hablar, por eso no lo exijamos mucho
más y tratemos de enseñarle una única tarea elemental G, que nos permita
construir un algoritmo para determinar qué número es mayor entre dos
diferentes.
Le doy unos minutos para que haga una pausa en la lectura y escriba la tarea
elemental G.
Una que podría funcionar sería así:

G. Si el número en el papel es mayor que el número memorizado,


memorizar el número anotado en el papel

Está escrita a propósito en dos renglones para que en el segundo quede la


acción que depende de la condición.

¿Se parece a la tarea que usted diseñó? Posiblemente otras funcionen, pero
veamos cómo trabaja esta.

Supongamos que el número en la memoria es 8 y el del papel es 5, la tarea G


quedaría así:

Si 5 es mayor que 8
memorizar 5

Como 5 no es mayor que 8, entonces no ejecuta la tarea “memorizar 5”, en


consecuencia el número memorizado será 8.

Ahora supongamos que el número en la memoria es 5 y el del papel es 8, la


tarea G quedaría así:
Si 8 es mayor que 5
memorizar 8

Como 8 es mayor que 5, entonces se ejecuta la tarea “memorizar 8”, en


consecuencia el número memorizado será 8.

¿Qué podemos concluir? Cualquiera sea la combinación de valores en la


memoria y en el papel, en la memoria quedará registrado el mayor.

Una vez hecho esto, bastará con cambiar el papel, anotar el número
memorizado y decirlo en voz alta. Problema resuelto.

Poniendo todo junto, el algoritmo completo quedará de la siguiente manera:

A, B, F, A, G, F, C, D

Digresión:
Como se puede observar en el algoritmo, no usamos la tarea elemental E. Es que en realidad no hace
falta usar todas las tareas elementales de un sujeto para resolver un problema dado. En este caso no hizo
falta sumar. No siempre es necesario usar todas nuestras habilidades para resolver un problema. Lo que
debemos intentar es usar las habilidades requeridas de la manera más eficiente posible.

Para que quede aún más claro el concepto de "decisiones" y su importancia


en los algoritmos, vamos a resolver un problema juntos. En este caso no nos
valdremos de sujetos imaginarios, simplemente vamos a interactuar usted y
yo. También vamos a necesitar 4 naipes de diferentes valores de cualquier
baraja, dentro del cual usted reconozca una relación de orden. Si no tiene
naipes, bien pueden servir 4 papelitos con números escritos, por ejemplo, del
1 al 4.
Le voy a pedir que los coloque frente a usted, desordenados de la manera que
desee, y lo que vamos a hacer es ordenarlos de menor a mayor.
Si le pido en este momento que los ordene, seguramente usted lo hará
correctamente, porque ordenar 4 números indudablemente está dentro de sus
tareas elementales (repasando: una tarea elemental es aquella que no necesita
subdividirse en otras tareas para poder ser ejecutada). Lo que sucede, es que
si dejamos las cosas aquí, este ejercicio no resulta interesante porque en
realidad usted ordenó las cartas de alguna manera que es incapaz de explicar,
y yo tendré que conformarme y confiar en que usted lo hizo correctamente.
Para evitar estas ambigüedades le voy a dar instrucciones precisas, que deben
ser ejecutadas una a una. Necesitaremos las 4 cartas o sus sustitutos papelitos
numerados, y 4 lugares imaginarios delante suyo, que llamaremos A, B, C y
D. Solamente estas letras identificarán la posición delante suyo.

- Ubique las 4 cartas desordenadas en los cuatro lugares A, B, C y D


- Si la carta en A es mayor que la carta en B, intercambiarlas
- Si la carta en A es mayor que la carta en C, intercambiarlas
- Si la carta en A es mayor que la carta en D, intercambiarlas
- Si la carta en B es mayor que la carta en C, intercambiarlas
- Si la carta en B es mayor que la carta en D, intercambiarlas
- Si la carta en C es mayor que la carta en D, intercambiarlas

Si todo salió bien, ahora usted tiene las cartas ordenadas delante suyo y
aunque parezca magia no lo es. Si a este relato lo hubiera presentado como un
truco de magia alguien podría creer que aquí ocurrió algo sobrenatural, pero
no es así. En realidad se ejecutó de manera correcta un algoritmo que,
cualquiera sea el orden inicial de las cartas, al final quedan inevitablemente
ordenadas.
Este es el poder de las decisiones dentro de los algoritmos, permiten evaluar
las condiciones o estados en un determinado momento, y en base a dicho
estado, ejecutar las acciones correctas que nos lleven a un resultado deseado.
Repeticiones o iteraciones

Otro elemento que encontramos de manera frecuente en los algoritmos es la


repetición(iteración), o más específicamente los ciclos. Cuando hablamos de
iteración, nos referimos a un conjunto de tareas que deben ejecutarse de
manera repetitiva, cero, una o varias veces. Aquí nuevamente podemos poner
como ejemplos algoritmos que incluyen iteraciones dentro de las recetas de
cocina. Cuando en algún punto de la receta dice "batir las claras a punto
nieve", ¿dónde está la iteración o repetición? En la acción de batir. Sin la
condición que nos impone el término "a punto nieve", batir sería una tarea
repetitiva sin fin, infinita, eterna. Podría decir "batir unos minutos", que
resultaría inespecífico y ambiguo, o también "batir durante 5 minutos", que es
más preciso, pero no garantiza el resultado esperado. Se trata de ejecutar una
acción mientras una condición se cumpla, o hasta que una condición se
cumpla. Puedo decir "repetir la acción de batir hasta que las claras se
encuentren en punto nieve", o también con el mismo efecto "repetir la acción
de batir mientras las claras no hayan alcanzado el punto nieve". Al cambiar
“hasta” por “mientras”, modifico la formulación de las condiciones, pero el
resultado de ambas tareas repetitivas, es que al fin de cuentas, las claras
estarán a punto nieve.

Para dar otro ejemplo, consideremos el caso de un albañil que levanta una
pared. El sujeto repite la tarea de colocar un ladrillo a continuación de otro
mientras no haya completado la línea, y una vez completada, inicia otra línea
sobre la anterior. Esta última tarea la realiza hasta que haya llegado a la altura
correcta. De este modo tenemos una tarea repetitiva dentro de otra tarea
repetitiva. Cada fila de ladrillos incluye la tarea de colocar un ladrillo a
continuación de otro, y como se deben hacer varias filas, tenemos lo que
llamamos "ciclos anidados".
Poniendo todo junto
Pudimos observar tres tipos de actividades dentro de los algoritmos que
estuvimos construyendo hasta ahora, y son las siguientes:

- Secuencia: realizar una tarea a continuación de otra


- Decisión: sobre la base de la evaluación de una condición, realizar
una u otra tarea
- Iteración: repetir un conjunto de tareas mientras una condición se
cumpla

El término “condición” expresa la observación del estado de algunos


elementos del problema, estableciendo alguna comparación que arroje un
valor de verdad.

Estos tres conceptos reciben el nombre de "estructuras de control", y fueron


definidas por Edsger Dijkstra, en el año 1968. Lo interesante de estos
conceptos, es que son suficientes para obtener una solución a cualquier
problema computable. Existe un teorema, que no demostraremos, que dice
que todo problema que tenga una solución computable, puede ser resuelto
utilizando secuencia, decisión e iteración. Una solución computable, es
aquella que se alcanza a través de un algoritmo.

Construyamos entonces una máquina que combine estas habilidades para


resolver un problema.

Antes definamos el concepto de variable:

"Una variable es una porción de memoria identificada por un nombre, capaz


de almacenar un dato, cuyo valor va a permanecer inalterado hasta tanto sea
modificado”
Supongamos que esta máquina tiene 5 variables, llamadas A, B, C, D y E.
Cada variable es capaz de almacenar un número a la vez. Además, dicha
máquina es capaz de realizar las siguientes tareas elementales:
- Pedir un número y almacenarlo en una variable (Ej. Pedir un número y
almacenarlo en A).
- Dividir el contenido de una variable por otra y poner el resto en una tercera
(Ej. Dividir A por B y poner resto en C).
- Repetir las veces que indique el valor de una variable [lista de tareas] (Ej,
Repetir C veces [...] Repite la cantidad de veces que indica el valor de la
variable C, las tareas encerradas entre corchetes).
- Si una variable cumple una condición ejecutar [lista de tareas]
- Poner un valor determinado en una variable (Ej. Poner 5 en B).
- Sumar una variable a otra con resultado en alguna variable (Ej. Sumar A a
B con resultado en C).
- Mostrar el valor de una variable (Ej. Mostrar el valor de A).

Bien, ya tenemos la máquina, ahora nos falta el problema, que es el siguiente:

Dada una lista de N números, determinar la suma de aquellos que sean pares.

Siguiendo los pasos del proceso de resolución de problemas propuesto, y


dando por comprendido el enunciado, pasemos a resolverlo:

Para que quede claro que el problema está comprendido, consideremos que la
lista de números es 45, 32, 94, 15.
En esta lista podemos ver que los números pares son 32 y 94. Sumados estos
números, el resultado es 126, por lo tanto, es el resultado esperado.
Continuemos con los siguientes pasos de resolución del problema.

Identificar los datos de entrada: En este caso lo obvio es que los datos son los
números de la lista, pero también hay un dato que no es tan obvio, y es el
hecho que la lista tiene tamaño N, o sea que el valor de N también es un dato.
En el caso del ejemplo N es 4, porque la lista tiene 4 números.

Identificar los resultados esperados: Un número, que resulta de la suma de los


números que resulten pares de la lista. En el ejemplo, ese resultado es 126.

Construir un modelo de solución:


Aquí no existe método. Vale todo. Podemos expresar nuestro modelo de
solución de la forma que nos resulte más comprensible. Aquí es donde
verdaderamente comienza a gestarse la solución del problema y es la etapa
más creativa del proceso.
En este caso debemos ingresar el valor de N, y repetir N veces lo siguiente:
ingresar un número y sumarlo si es par, o ignorarlo si es impar.
¿Cómo sabemos si el número es par? Tenemos que ver qué tareas
elementales es capaz de ejecutar el sujeto. En este caso sabemos que la
máquina sabe obtener el resto de la división. Entonces si dividimos al número
por dos, y el resto es cero, dicho número es par.
Si resulta par debemos sumarlo sobre algún espacio de memoria, o variable.
¿Qué valor debería tener esa memoria al comenzar el algoritmo? Si vamos a
sumar sobre ella, lo indicado es que al inicio valga CERO.
Al final, después de las N repeticiones, debemos mostrar el valor de esa
variable.

Ahora veamos una versión de algún algoritmo apropiado para nuestra


máquina:

- Pedir un número y almacenarlo en E (aquí ingresamos el tamaño de la lista)


- Poner 0 en D
- Poner 2 en B
- Repetir E veces
[Pedir un número y almacenarlo en A
Dividir A por B y poner el resto en C
Si C = 0 [Sumar A y D y poner resultado en D]
- Mostrar el valor de D

Veamos cómo haría esta máquina para ejecutar este algoritmo, paso a paso,
con el mismo ejemplo que usamos anteriormente para comprender el
problema.

Nuestros datos son los siguientes:

N=4, la lista tiene 4 números


Lista: 45, 32, 94, 15
Comencemos:

Pedir un número y almacenarlo en E (Ingresamos 4 y lo asignamos a E)


Poner 0 en D (D ahora vale cero)
Poner 2 en B (B nos servirá para determinar si un número es divisible por 2)
Repetir E veces (repite 4 veces)

- Primera repetición
Pedir un número y almacenarlo en A (ahora A=45, el primer número de la lista)
Dividir A por B y poner el resto en C (el resto de dividir 45 por 2 es 1, entonces C=1)
Si C=0 [Sumar A a D con resultado en D (como C=1 no hace nada y D sigue en 0)

- Segunda repetición
Pedir un número y almacenarlo en A (ahora A=32, el segundo número de la lista)
Dividir A por B y poner el resto en C (el resto de dividir 32 por 2 es 0, entonces C=0)
Si C=0 [Sumar A a D con resultado en D (como C=0 realiza la suma y D=32)

- Tercera repetición
Pedir un número y almacenarlo en A (ahora A=94, el tercer número de la lista)
Dividir A por B y poner el resto en C (el resto de dividir 94 por 2 es 0, entonces C=0)
Si C=0 [Sumar A a D con resultado en D (como C=0 realiza la suma y D=126)

- Cuarta repetición
Pedir un número y almacenarlo en A (ahora A=15, el cuarto número de la lista)
Dividir A por B y poner el resto en C (el resto de dividir 15 por 2 es 1, entonces C=1)
Si C=0 [Sumar A a D con resultado en D (como C=1 no hace nada y D sigue en 126)

Mostrar el valor de D (Muestra 126, que es el resultado esperado)


Resumen del capítulo 1
Construir algoritmos es una mezcla de talento con método y conocimiento,
arte y práctica. Tener un método ayuda a ordenar los pensamientos. Cuanto
más conozcamos acerca del sujeto que va a ejecutar el algoritmo y sus
habilidades, podremos llegar a una solución más eficiente. El talento ayuda y
la práctica aún más.
Podemos darles una tela, pinturas y pinceles a varias personas, encargarles
una misma tarea y seguramente los resultados serán muy diferentes.

¿Pero por qué si todos tienen las mismas herramientas y el mismo problema a
resolver los resultados no son iguales? La respuesta es: talento, método,
conocimiento, arte y práctica.

A lo largo de estas páginas hemos abordado el concepto de problema,


proponiendo un método de resolución. Dentro de este método apareció el
concepto de algoritmo, que resulta central dentro del proceso. Es allí donde el
método deja de ser riguroso y aparecen los elementos más subjetivos, ya que
el algoritmo que creemos para resolver un problema dependerá de las
habilidades del sujeto que lo ejecutará y de nuestra capacidad para construir a
partir de ellas una solución eficiente y efectiva. Esto se mostró a partir de un
conjunto de problemas y sujetos diferentes, proponiendo algoritmos
diferentes.

También exploramos distintos tipos de tareas: secuenciales, decisivas e


iterativas.

Vimos la necesidad de poner a prueba nuestros algoritmos, a fin de realizar


los ajustes necesarios para mejorar su funcionamiento y eficiencia.

En resumen hay un conjunto de ideas que me gustaría resaltar:


- Los algoritmos no deben ser ambiguos.
- La formulación de los algoritmos depende de las capacidades de quienes lo
ejecuten.
- Un algoritmo surge de un proceso creativo.
- La eficiencia de un algoritmo depende de su creador, ya que debemos
intentar construir el mejor algoritmo posible para el sujeto que lo ejecute.
- Si cambian las habilidades del sujeto, puede afectar a nuestro algoritmo.
- Una buena noticia: Un mismo problema puede resolverse de muchas
maneras diferentes y correctas.
- Una mala noticia: Existen muchas más formas de construir algoritmos
incorrectos

Teniendo en cuenta estas ideas podemos formular el propósito: Construir el


algoritmo más eficiente, con los recursos disponibles para que un sujeto
específico pueda resolver un problema dado.
Capítulo 2: Representación de los algoritmos
En este capítulo, veremos una manera adecuada y conveniente de representar
nuestros algoritmos, que luego serán traducidos a algún lenguaje de
programación, con el objetivo de ser ejecutados por una computadora.

Esto significa que abriremos otra caja de herramientas diferente, con las
cuales podremos representar nuestros algoritmos.

Lo que tiene que quedar claro en este punto, es que presentaremos nuevas
herramientas y daremos algunos ejemplos de cómo usarlas, sin pretender
proponer una enciclopedia de problemas resueltos, que para ello existen otros
libros, como por ejemplo “Construyendo algoritmos numéricos”, que
escribiera dos años después que este.

Reforzando más las ideas, si este fuera un libro que enseñe a realizar pinturas
sobre tela, mostraría las distintas herramientas y su forma adecuada de
usarlas, aconsejando sobre distintos tipos de pinturas y texturas, el
aprovechamiento de sus cualidades y como darle una buena terminación a las
piezas creadas. En medio de este camino se propondrán ejemplos, pero eso
no significa que se pretenda enseñar cómo hacer una pintura que proponga un
torso humano, un rostro, un caballo, o cualquier otro objeto imaginable, pero
sí se pretende enseñar el uso correcto de las herramientas para que el lector
pueda comenzar a realizar sus propias piezas, mejorando los resultados
obtenidos a lo largo del tiempo con la práctica.

De esta manera, este capítulo será diferente al anterior, orientándose más a la


creación de soluciones que puedan ser traducidas a un programa que funcione
en algún dispositivo.

Hasta ahora hemos visto distintos algoritmos y de alguna manera su forma de


representarlos. Esa representación no fue siempre igual, debido a que tiene
que ser apropiada para el sujeto que debe resolver el problema. En el caso de
recetas de cocina, podemos decir que la presentación de los algoritmos se
hace mediante un relato textual, en lenguaje natural de las tareas a realizar; en
el caso de los robots o monitos a las tareas elementales les asignamos letras,
que ellos saben comprender.

De aquí en más construiremos algoritmos que serán ejecutados por una


computadora. Para que esto pueda hacerse, dichos algoritmos tendrán que
estar expresados en algún lenguaje que ese sujeto (la computadora)
comprenda. Éstos son lenguajes de programación.

Cuando dos personas se comunican, para que puedan entenderse, ambas


tienen que conocer el lenguaje que habla cada una de ellas. La forma más
sencilla, es que hablen el mismo idioma. Para comunicarnos con la
computadora, y darle las instrucciones que permitan resolver algún problema,
necesitamos un código en común, y ese es un lenguaje de programación.
¿Eso quiere decir que debemos expresar nuestros algoritmos a través de
lenguajes de programación?
La respuesta es "no necesariamente".

Sigamos este camino: los algoritmos que crearemos serán ejecutados por una
computadora, para ello debemos expresarlo de alguna manera que la
computadora lo comprenda, que es a través de un lenguaje de programación,
pero necesitamos un paso intermedio para conseguirlo. Nuestro algoritmo,
que está en nuestra mente, debe ser interpretado por algún sujeto que lo
traduzca a un lenguaje de programación. Para ello nos valdremos de
herramientas que cumplan el rol de traductores de nuestras ideas a futuros
programas.

Nuestra tarea en esta instancia será la de representar nuestros algoritmos


usando una herramienta que permita su traducción posterior a un lenguaje de
programación, ya sea por nosotros mismos o por un programador.

El camino a recorrer sería el siguiente:

Problema > Algoritmo > Representación del algoritmo > Programa de


computadora > Computadora ejecutando el algoritmo.
Hasta aquí hemos recorrido el camino que llega hasta la representación del
algoritmo, pero para sujetos muy especiales. Ahora necesitamos ver una
nueva forma de expresión, para que un programador pueda construir un
programa, en algún lenguaje.

Haciendo analogías, si queremos construir una casa, podemos decir que el


objetivo de este capítulo es el de construir los planos que permitan su
construcción. De un lado están las ideas que determinan cómo será la casa, y
del otro lado está la casa construida. En medio están los planos.

Si deseamos construir una casa bonita y útil, podemos imaginarla, pero para
hacerla realidad, necesitamos primero contar con planos que representen
nuestras ideas para que alguien la construya según nuestros gustos. Lo que
veremos en este capítulo será algo así como la elaboración de los planos de
nuestras ideas.

En rigor de verdad, eso ya lo venimos haciendo, pero ahora nos dirigiremos a


esos especiales sujetos que son capaces de construir programas que funcionen
en computadoras, y ya no trataremos con robots o monitos.

Podemos ser buenos resolviendo problemas y creando algoritmos, pero eso


no nos transforma en buenos programadores, porque deberíamos además
conocer los lenguajes de programación, que son miles.

El contar con esos modelos es importante, porque representan de una forma


comprensible y unívoca, la solución de un problema que puede ser traducida
a diferentes lenguajes de programación. Si por alguna razón se decide que un
sistema terminado se reprograme en otro lenguaje, contar con los modelos
correspondientes será de gran ayuda.

En resumen, y con el ánimo de ser reiterativo, lo que necesitamos es una


herramienta que permita representar nuestros algoritmos de manera
comprensible para un programador que pueda traducirlo a un programa en un
determinado lenguaje.
Podemos llevar a cabo esta tarea tal como hacemos con una receta de cocina:
le podríamos contar al programador en un lenguaje natural y escrito cómo se
resuelve el problema y él a continuación traduciría ese relato en un programa.
Esto no sería del todo correcto ni práctico. El problema de esta solución es
que el lenguaje natural es ambiguo, y las ambigüedades pueden dar lugar a
confusiones, y las confusiones generarían programas incorrectos. Eso
debemos evitar, por lo que el lenguaje natural queda descartado como
herramienta adecuada para la representación del algoritmo.

Reforzando la idea, el lenguaje natural puede ser una buena herramienta para
representar recetas de cocina, pero no lo es para especificar programas de
computadora.

Existen herramientas gráficas compuestas por figuras y texto que en conjunto


forman un diagrama de la solución del problema.

Estas técnicas son conocidas como diagramación de algoritmos. La más


difundida recibe el nombre de diagrama de flujo, que contiene figuras que
indican acciones, conectadas a través de líneas que determinan el flujo de
ejecución del algoritmo. El problema es que con esta clase de diagramas es
posible construir soluciones poco claras y a veces imposibles de programar
con los lenguajes actuales.

Otra forma de representación gráfica de algoritmos es a través de los


diagramas de Nassi-Schneiderman, que fueron expuestos por sus autores en
el año 1973. La ventaja de estos últimos con respecto a los diagramas de
flujo, que son anteriores, es que permiten visualizar rápidamente la estructura
del algoritmo, mostrando de manera clara sus estructuras de control.
Pseudocódigo
Otra herramienta, basada en el lenguaje natural, es el pseudocódigo. Se trata
de instrucciones escritas en un lenguaje natural, pero con un conjunto
reducido de palabras, y con un acotado número de verbos, que permiten
evitar las ambigüedades. Es una herramienta muy útil, y muy difundida.
Existen distintas versiones de pseudocódigo, y nosotros nos basaremos en
una en particular que definiré especialmente para que nosotros nos
comprendamos.

Previo a presentarles el pseudocódigo que nos acompañará en la


representación de nuestros algoritmos, es necesario conocer el concepto de
variable.

"Una variable es una porción de memoria identificada por un nombre, capaz


de almacenar un dato, cuyo valor va a permanecer inalterado hasta tanto sea
modificado".

Una variable, en el contexto de nuestro pseudocódigo, podrá almacenar un


número, cualquiera sea tu tipo, un texto, o cualquier dato simple. Podemos
hacer una analogía entre un dato simple y cualquier dato que podemos usar
para llenar un casillero de cualquier formulario.
A los fines didácticos, trabajaremos mayormente con variables numéricas.

Veamos las distintas tareas elementales y su correspondiente expresión en


pseudocódigo.

Antes de comenzar, nos pondremos de acuerdo en algunas cuestiones de


notación:
- Cada tarea elemental recibirá el nombre de instrucción, y estará
representada por una o más palabras, cada una de las cuales recibe el
nombre de “palabra clave”.
- Las palabras claves, que indican acciones en los algoritmos las escribiremos
con minúsculas.
- Al describir la sintaxis de cualquier instrucción, encerraremos entre <> el
texto que debamos agregar.
- Las variables las escribiremos en mayúsculas, y pueden tener cualquier
cantidad de letras, aunque generalmente usaremos solo una.
Entrada de datos

Ingresar <lista de variables>

La instrucción correspondiente a la entrada de datos, representa la tarea de


pedir un dato y almacenarlo en una variable. Si en lugar de una variable
ponemos más de una, cada dato ingresado se asignará en la variable
correspondiente según su orden. Si fuera un programa ejecutándose en una
computadora, la ejecución se detiene y espera a que el operador ingrese los
datos requeridos.

Por ejemplo:

ingresar A

Pide un dato y su valor es almacenado en la variable A

Veamos otro caso:

ingresar A, B, X

Pide tres datos, y se almacenan correspondientemente en las variables A, B y


X
Asignación

<variable> = <expresión>

Esta instrucción representa la tarea elemental de asignar a una variable, el


resultado de una expresión determinada. Dicha expresión puede ser una
variable, una constante, o cualquier combinación de variables y constantes
vinculadas a través de distintos operadores. La palabra clave aquí parece
ausente, pero en realidad es el signo =. Siempre a la izquierda hay que
colocar la variable que recibe el resultado de la expresión de la derecha.

Los operadores que vamos a utilizar son los siguientes:


Operador Descripción

+ Suma

- Resta

* Multiplicación

/ División

\ División entera

** Potencia

mod Resto de la división entera

El uso de paréntesis está permitido para definir el orden de ejecución de las


operaciones si es necesario.

Quizás la función mod merezca una explicación adicional:

Si dividimos dos números enteros, obteniendo como resultado otro entero, el


resto de esa división es lo que llamaremos mod. Por ejemplo si dividimos 25
entre 7, el resultado entero es 3 y el resto de dicha división es 4. Por lo tanto
25 mod 7 daría como resultado 4.
Ejemplos de instrucciones de asignación:

Instrucción Operación

A=5 Asigna 5 a la variable A

A=B Asigna el valor de la variable B a la variable A

C=C+1 Incrementa en 1 el valor de la variable C

D=X mod 10 Asigna a D el resto de dividir X por 10

C=A*(X+Y) Asigna a C el resultado de X+Y multiplicado por el valor de la variable A


Siempre la variable que recibirá el resultado de la expresión es la que
colocamos del lado izquierdo. De este modo, en el segundo ejemplo sabemos
que es A la variable que está siendo modificada asignándole el valor de la
variable B, y no al revés.
Salida

mostrar <lista de expresiones>

La instrucción de salida es la que permite mostrar los resultados, a través de


la evaluación de expresiones. La salida puede ser una constante, un mensaje
textual, una expresión matemática como las usadas en los bloques de
asignación, o una combinación de todas ellas.

Ejemplos de bloques de salida

Instrucción Operación

mostrar A Muestra el valor de la variable A

mostrar A,B Muestra los valores de las variables A y B

mostrar S/N Muestra el resultado de dividir S por N

mostrar “No tiene solución” Muestra el mensaje “No tiene solución”

Con las instrucciones presentadas hasta ahora, podemos intentar resolver


algunos de los problemas conocidos que ya se han planteado en capítulos
anteriores.

Comencemos por el monito, y lo reemplacemos por una computadora.


Debemos entonces construir un algoritmo en pseudocódigo, que permita a
algún programador, escribir un programa ejecutable por una computadora, en
un determinado lenguaje.

El primer problema que resolvimos con el monito fue el de sumar dos


números. Como ya tenemos resuelto el problema, lo único que tenemos que
hacer es adaptar la representación del algoritmo a través del pseudocódigo
que acabamos de presentar.
Las tareas que debemos realizar son las siguientes:

-Ingresar dos números


-Sumarlos
-Mostrar el resultado

Una versión en pseudocódigo del problema, como representación del


algoritmo, sería la siguiente:

ingresar A
ingresar B
S=A+B
mostrar S

Expliquemos que es todo esto con un ejemplo. Supongamos que queremos


usar este algoritmo para sumar los números 5 y 9. La primera instrucción es
“ingresar A”, que corresponde a nuestro primer dato, por lo tanto lo que
conseguimos es darle a la variable A el valor 5, que sería uno de los datos que
tendría que sumar. La instrucción siguiente es “ingresar B”, entonces ahí
ingresaríamos nuestro segundo dato, que es el número 9, y se lo asignamos a
la variable B. Hasta aquí tenemos a la variable A con el valor 5 y a la variable
B con el valor 9. La siguiente instrucción es “S=A+B”, o sea, una operación
de asignación que coloca en la variable S el valor de la suma de A y B, en
este caso quedaría el número 14 almacenado en S. La última instrucción es
“mostrar S”, con lo que conseguimos mostrar el resultado de S, que es
justamente 14, o sea la suma de nuestros datos 5 y 9.

¿Podemos resolverlo así?

ingresar A,B
S= A+B
mostrar S

¿Y así?

ingresar A,B
mostrar A+B

¿Cuál es correcta? ¡Todas!

¿Cuál es mejor? Depende. Las dos primeras son más expresivas. La tercera
versión es más corta y pareciera más eficiente, pero no es muy clara. Es
mejor en estas instancias iniciales, sacrificar un poco de eficiencia en
beneficio de la claridad de los algoritmos.

Si no se tratara de sumar dos números y éstos fueran 3, la solución sería muy


parecida, y las alternativas también. Por ejemplo:

ingresar A,B,C
D = A+B+C
mostrar D

¿Y si fueran 4?

ingresar A,B,C,D
S = A+B+C+D
mostrar S

¿Y si fueran N números?

Todavía no tenemos los elementos necesarios para sumar una lista larga de
números, o una lista de un número variable de elementos, pero pronto
podremos hacerlo.
Decisiones
Siguiendo el mismo camino recorrido en la primera parte del libro, es el
momento de incorporar de alguna forma el concepto de decisión a nuestro
pseudocódigo. Sabemos a esta altura que las decisiones son importantes
dentro de muchos de nuestros algoritmos, es por eso que debemos contar con
una instrucción que las represente de una manera adecuada. Para ello
usaremos las palabras “si” y “sino”. La palabra “si” siempre irá seguida de
una condición, que tendrá un resultado verdadero o falso. Si resulta la
condición verdadera, entonces se ejecutarán las tareas o instrucciones que
debemos realizar en dicho caso. Al contrario, si la condición resulta falsa, se
ejecutará otro grupo de tareas elementales o instrucciones diferentes.

si <condición> entonces
<instrucciones si la condición es verdadera>
sino
<instrucciones si la condición es falsa>

Donde la condición es expresada a través de operadores relacionales y


lógicos, que se representan de la siguiente manera:

Operador Descripción

= Igual

> Mayor

< Menor

>= Mayor o igual

<= Menor o igual

<> Distinto

^ Conjunción lógica, AND, o simplemente Y

v Disyunción lógica, OR, o simplemente O


~ Negación lógica, NOT, o simplemente NO

Las instrucciones, o tareas elementales, correspondientes a la condición


verdadera pueden contener una o varias instrucciones de cualquier tipo.
Las instrucciones, o tareas elementales, correspondientes a la condición falsa,
pueden contener cero o varias instrucciones de cualquier tipo. Esto significa
que en algunos casos puede no existir la cláusula “sino”.

Para que queden claramente determinados los bloques de instrucciones, se


utiliza el concepto de “indentación o sangría”, que consiste en escribir las
instrucciones con una alineación a la derecha, mediante la utilización de la
inserción de espacios en blanco o del uso del tabulador. La palabra
“indentación” es un anglicismo de la palabra “indentation”, que si bien no
está reconocida como palabra en español, es muy usada en informática, como
suele suceder con muchos términos en esta disciplina. En nuestro caso,
usaremos 4 espacios en blanco como indentación, para determinar las
instrucciones que quedan bajo el efecto del “si” o del “sino”.

Ejemplos de decisiones

Dados dos números distintos, mostrar el valor del mayor.

El problema es simple de comprender: debemos mostrar el valor del mayor


de dos números que sabemos que son distintos, por lo tanto, sabemos que uno
de ellos es mayor. Si fueran iguales, ¿cuál sería el mayor? Posiblemente la
respuesta razonable sea "ninguno", también puede ser "cualquiera", pero el
problema pide mostrar el valor del mayor, por lo que si fueran iguales
bastaría con mostrar el valor de cualquiera de ellos. En estos casos, para
evitar filosofar sobre cuestiones que no son relevantes, conviene que la
consigna aclare bien que es lo que debe hacerse. Para salvar este
inconveniente, el enunciado dice "números distintos", y asunto resuelto. Otra
manera de resolverlo sería modificando el enunciado: "Dados dos números,
mostrar el mayor. Si son iguales mostrar el valor de cualquiera de ellos". Así
deben enunciarse los problemas, para que su forma de expresión no sea un
problema adicional que debemos resolver. Siempre un enunciado debe ser
claro, y no debe admitir ambigüedades.

Volviendo a nuestro problema y siguiendo la metodología propuesta en el


capítulo anterior, los datos o insumos del problema son dos números, que
llamaremos A y B.

El resultado esperado es el valor del mayor entre A y B.

Un modelo de solución, podría ser:

Si A > B entonces hacer M=A, sino M=B, y luego mostrar el valor de M

Es bueno recordar que el momento de modelar una solución, es el momento


creativo del proceso. Aquí podemos analizar alternativas, podemos no estar
de acuerdo, pero lo importante es que lleguemos a una solución correcta. En
el caso del modelo de solución propuesto, aparece una variable M, donde
pondré el valor del mayor entre A y B, para luego mostrar M.
El algoritmo expresado en nuestro pseudocódigo quedaría de la siguiente
manera:

ingresar A y B
si A > B
M=A
sino
M=B
mostrar M

Algoritmo para determinar el mayor de dos números diferentes, primera


versión

Otra solución posible sería modificando el modelo de solución:

Si B>A entonces hacer A=B, y luego mostrar A


Parece más simple, porque es más breve, no aparece la variable M, pero ¿es
correcta esta solución?

Esta solución propone que, si B es mayor que A, entonces en A coloquemos


el valor de B, por lo tanto en A quedará el mayor, pero perdiendo el valor que
tenía antes A, cosa que no nos importa en este contexto. Si la condición no se
cumple, o sea que B no sea mayor que A, no se hace nada, porque justamente
A es mayor que B. Al final de cuentas, siempre en A quedará el valor del
mayor, por lo que solo debo mostrar cuánto vale A.
¿Brillante? No diría tanto. Quizás ingenioso, ahorrativo, un algoritmo avaro,
que mezquina recursos a costa de perder claridad. De todos modos es
correcto y puede usarse.
El algoritmo en pseudocódigo correspondiente quedaría así:

ingresar A y B
si B>A
A=B
mostrar A

Algoritmo para determinar el mayor de dos números diferentes, segunda


versión

Como se ve en el algoritmo, si la condición es falsa no se debe hacer nada, y


de ese lado no existen instrucciones, por lo tanto, no existe la cláusula “sino”
de la condición.

Modifiquemos levemente el enunciado: Dados dos números, mostrar el


mayor. Si fueran iguales, mostrar un mensaje que diga "son iguales".

Los datos son los mismos, pero el resultado esperado es diferente, porque
puede aparecer un mensaje diciendo que los números son iguales.

Un modelo de solución podría ser el siguiente:

Si A=B mostrar "son iguales”, sino Si A>B mostrar A, sino mostrar B


El algoritmo, en consecuencia podría quedar así:
ingresar A, B
si A=B
mostrar "son iguales"
sino
si A>B
mostrar A
sino
mostrar B

Algoritmo para mostrar el mayor de dos números, pudiendo ser iguales,


primera versión

Nótese el uso de la indentación o sangrado para determinar las instrucciones


que deben ejecutarse en cada caso.

Otra solución posible sería:

ingresar A, B
si A=B
mostrar "son iguales"
si A>B
mostrar A
si B>A
mostrar B

Algoritmo para mostrar el mayor de dos números, pudiendo ser iguales,


segunda versión

¿Cuál es mejor? Sin dudas la primera versión, porque es clara y eficiente.


Realiza la menor cantidad de preguntas sin perder claridad. De todos modos,
el gusto es subjetivo.
La segunda versión puede realizar preguntas innecesarias. ¿Por qué? Es un
tema interesante para discutir:

Evaluando la primera condición, ya sabríamos si A=B. Si esto ocurre muestra


el mensaje correspondiente. Sin embargo, la ejecución continúa, preguntando
innecesariamente si A>B y si B>A, sabiendo que esto no ocurrirá.
Por otro lado, si A no fuera igual a B, pero A>B fuera verdadero,
mostraríamos el valor de A, pero después, de manera igualmente innecesaria,
preguntaríamos si B>A.
En el último caso, si B fuera mayor que A, llegaríamos a la condición
verdadera en la tercera pregunta, que también resulta innecesaria, porque si A
no es igual a B ni mayor, seguramente B es mayor que A.
Obviamente esto demuestra que el algoritmo no es eficiente, pero es de todos
modos correcto.

Aquí tratamos con un problema muy simple, pero lo interesante del análisis
de las soluciones propuestas, podría llevarnos a las raíces de la inteligencia
artificial. ¿Es para tanto? Bueno, a la semilla, más que a las raíces. Sin entrar
en muchos detalles, aquí tenemos dos números que son nuestros datos, a
medida que preguntamos cosas sobre ellos vamos "aprendiendo"
características, hechos. En la solución inicial, primero preguntamos si A es
igual a B, si esto no ocurre, solamente preguntamos cómo es A con respecto a
B, ya que sabemos que no son iguales y existe un mayor. En el segundo caso,
no aprovechamos el conocimiento adquirido sobre los datos, y cuando
llegamos a preguntar si A es mayor que B, el algoritmo no usa el resultado de
la pregunta anterior, como si se "olvidara" instantáneamente de algo que
debería saber. Utilizando esa idea, podemos hacer algoritmos más eficientes,
y más “inteligentes".
De todos modos, insistimos que en esta instancia no pretendemos construir
los algoritmos más eficientes, sino simplemente correctos. Sin embargo, daré
mi opinión sobre las distintas soluciones a fin de justificar un criterio de
“solución eficiente”.

Ejercicio propuesto para el lector:

Determinar el mayor de 3 números.

Piense en la versión inteligente y en la "amnésica", que no aprovecha el


conocimiento adquirido.
Otro ejemplo de decisiones: Ordenando cartas

En la primera parte del libro, cuando tratábamos los conceptos de resolución


de problemas y algoritmos, se había planteado un problema que consistía en
ordenar 4 cartas de menor a mayor. ¿Podríamos usar ese algoritmo para
construir un algoritmo que ordene 4 números de menor a mayor?
Seguramente sí.
Para facilitar las cosas, voy a transcribir a continuación el algoritmo de la
primera parte, sólo para evitar ir a buscarlo unas cuantas páginas atrás:

- Ubique las 4 cartas desordenadas en los cuatro lugares A, B, C y D


- Si la carta en A es mayor que la carta en B, intercambiarlas
- Si la carta en A es mayor que la carta en C, intercambiarlas
- Si la carta en A es mayor que la carta en D, intercambiarlas
- Si la carta en B es mayor que la carta en C, intercambiarlas
- Si la carta en B es mayor que la carta en D, intercambiarlas
- Si la carta en C es mayor que la carta en D, intercambiarlas

El único problema es que la tarea “intercambiar” no existe en nuestra caja de


herramientas formada por las instrucciones dadas, en consecuencia,
tendremos que armar un nuevo algoritmo para intercambiar el valor de dos
variables, ya que no es una tarea elemental.
El problema es análogo a intercambiar el contenido de dos vasos. ¿Cómo lo
haría usted? Es probable que necesite un tercer vaso auxiliar para poder hacer
lo siguiente:

- Verter el contenido del vaso A en el vaso auxiliar


- Verter el contenido del vaso B en el vaso A
- Verter el contenido del vaso auxiliar en el vaso B

Problema resuelto. Dependiendo de los líquidos de los vasos quizás haya


hecho falta enjuagarlos antes de ejecutar cada paso, pero por suerte las
variables no necesitan enjuague.
Hecho esto con variables, y llamando a la auxiliar como variable X, la
solución sería así
X=A
A=B
B=X
Algoritmo para intercambiar el contenido de dos variables

Traducido a un algoritmo con 4 variables A, B, C y D, con X como auxiliar,


y teniendo en cuenta el algoritmo de intercambio de variables, quedaría de la
siguiente forma:

Ingresar A,B,C,D
si A>B
X=A
A=B
B=X
si A>C
X=A
A=C
C=X
si A>D
X=A
A=D
D=X
si B>C
X=B
B=C
C=X
si B>D
X=B
B=D
D=X
si C>D
X=C
C=D
D=X
Mostrar A,B,C,D
Algoritmo para ordenar cuatro números

¿Un poco tedioso? Tuvimos que hacer 6 preguntas y 6 intercambios. Eso sólo
con 4 números. Estimo que con 5 números serían 10, con 6 números 15, y
con 10 números 45. Eso provocaría algoritmos extremadamente largos, sólo
para pocos números. La razón es que esta forma de resolver el problema
utiliza más la “fuerza bruta” que la inteligencia.

¿Qué pasaría si tuviéramos que ordenar N números? Existen muchos


algoritmos que resuelven este problema de manera quizás más simple, o al
menos más corta, y seguramente más inteligente, pero todavía no contamos
con los elementos necesarios para construirlos, y los estudiaremos más
adelante.
Ciclos o Iteraciones

Como ya quedó establecido en la primera parte, para la resolución de muchos


problemas es necesario contar con la posibilidad de realizar un conjunto de
tareas en forma repetitiva, a las que llamaremos “ciclos”.

Requisitos de un ciclo
Los requisitos que debemos encontrar al momento de realizar operaciones
repetitivas, cíclicas o iterativas, son los siguientes:

1. Establecimiento de algún estado previo al ingreso al ciclo, mediante el


uso de variables cuyos valores determinen el inicio del mismo.

2. Definir una condición que determine la realización o finalización de


las tareas del ciclo, donde intervendrán las variables del punto 1.

3. Las tareas propias del ciclo, llamadas cuerpo del ciclo.

4. La modificación de algún elemento que permita que en algún


momento se modifique alguna variable que interviene en la
condición.

Es fundamental el punto 4, porque si no se modifica algún valor de las


variables que intervienen en la condición del punto 2, puede ocurrir que el
ciclo nunca termine, entrando en una condición de repetición infinita.

Veamos todo esto dentro de un ejemplo ya estudiado, como puede ser batir
claras de huevo a punto nieve.

Algoritmo:

- Poner claras en un bowl


- Mientras las claras no estén a punto nieve repetir la tarea BATIR
¿Cómo funciona este algoritmo? Revisemos el cumplimiento de los requisitos
definidos antes:
1. Poner las claras de huevo dentro de un bol establece las condiciones
previas, iniciales, indispensables para que el ciclo pueda comenzar. Sin
ellas no tiene sentido batir.

2. Las claras de huevo no alcanzaron el punto nieve (condición bajo la cual


hay que hacer algo). Periódicamente revisaremos esta condición, que
determinará cuando debemos dejar de batir, caso contrario no
terminaríamos nunca.

3. Batir, por ejemplo, podría ser una vuelta del batidor sobre las claras.

4. La acción 3, incorpora aire a las claras, modificando su consistencia, de


este modo en algún momento las claras, pueden hacer que la condición 2
deje de cumplirse y el ciclo termine. Corresponde a una modificación del
estado, o variable, que afecta a la condición.

Quizás con otro ejemplo quede más claro. Supongamos que queremos comer
todos los caramelos de una bolsa. ¿Estará claro cuál es la operación
repetitiva? Tomar un caramelo de la bolsa y comerlo. ¿Cuándo termino?
Cuando ya no queden más caramelos en la bolsa.

Algoritmo:
- Poner caramelos en una bolsa
- Mientras haya caramelos en la bolsa repetir lo siguiente: tomar un caramelo
y comerlo.

La explicación del algoritmo:

1. Debemos tener una bolsa con caramelos, que establece las condiciones
previas

2. Mientras haya caramelos en la bolsa, continuar (condición del ciclo)

3. Tomar un caramelo y comerlo (acción que modifica el estado que puede


afectar a la condición)

4. Claramente la acción 3 modifica las condiciones, que permitirán que en


algún momento la condición 2 determine el fin de la tarea

Los ciclos los representaremos a través de pseudocódigo de la siguiente


manera:

repetir mientras <condición>


<instrucciones del cuerpo del ciclo>

Donde <condición> es una expresión relacional y/o lógica, con resultado


verdadero o falso, bajo la cual se ejecutará el cuerpo del ciclo. Al igual que
en el bloque de decisión, las instrucciones que componen el cuerpo del ciclo
pueden ser una o varias. Incluso dentro de dicho cuerpo puede haber otro
ciclo, condiciones, o cualquier instrucción de cualquier tipo y puede ser tan
simple o tan complejo como sea necesario.

Ejemplos del uso de ciclos


Enunciado del problema: Mostrar los números naturales del 1 al 10

Los datos del problema están representados por los límites del intervalo de
números naturales que debemos mostrar. En este caso 1 y 10

Para ello deberíamos tomar una variable, asignarle el valor 1, mostrar su


valor y luego incrementarla, mientras no se pase de 10. Claramente las tareas
repetitivas son mostrar e incrementar.

Veamos cómo quedaría el algoritmo expresado en nuestro pseudocódigo:

V=1
repetir mientras V<10
mostrar V
V=V+1
Algoritmo que muestra los números naturales del 1 al 10

Ahora podemos hacerlo un poco más interesante, mostrando los N primeros


números naturales.

Tenemos un nuevo dato, que es el número N, que determina la cantidad de


números naturales que se deben mostrar.

Para ello deberíamos tomar una variable, asignarle el valor 1 (primer número
natural, como en el ejemplo anterior), mostrar su valor y luego incrementarla,
mientras no se pase del valor de N. Otra vez, las tareas repetitivas son mostrar
e incrementar.

ingresar N
V=1
repetir mientras V<N
mostrar V
V=V+1

Algoritmo que muestra los N primeros números naturales

Con esta nueva herramienta podemos también realizar actividades que antes
no podíamos. Sumar dos números fue simple, sumar 3 números también,
¿pero, cómo será sumar N números?
La formulación correcta del problema podría ser: Dados N números, obtener
el resultado de su suma.

En este caso, los datos del problema son:

-El valor de N, que representa la cantidad de números de la lista


-Los N números

El resultado esperado es la suma de los N números

El modelo de la solución incluye los siguientes elementos (tengamos en


cuenta como siempre que esta es la parte creativa del proceso y puede haber
muchas formas de resolver el mismo problema).

1. Necesitamos primero conocer el valor de N


2. Debemos contar la cantidad de números que ingresamos, para que sean
exactamente N
3. Sumamos cada número ingresado, uno a la vez
4. Al terminar mostramos el resultado de la suma

Para el punto 2 necesitaremos una variable que cuente cada número que
ingrese y la llamaremos C, que deberá comenzar en cero. Esta variable
actuará como un “contador” de eventos. ¿Porqué comienza en cero? Porque
vamos a contar cuantos elementos hemos sumado hasta un momento dado, y
resulta que antes de comenzar no hemos sumado ninguno, por lo tanto el
contador C vale cero. El nombre de la variable C es arbitrario totalmente,
podríamos haberlo llamado CONTADOR.
Para el punto 3 necesitaremos una variable que sume cada número ingresado
y la llamaremos S, que también deberá comenzar en cero. Esta variable
actuará como “acumulador” de los números de la lista. Obviamente comienza
en cero por la misma razón que hace que C comience en cero.

Al terminar en el punto 4, debemos mostrar el valor de S.

ingresar N
C=0
S=0
repetir mientras C<N
ingresar X
S=S+X
C=C+1
mostrar S

Algoritmo que muestra la suma de N números dados

Para comprender mejor como funciona este algoritmo, vamos a realizar una
“prueba de escritorio”, que consiste en crear una tabla, donde cada columna
representa una variable del algoritmo, a la que agregaremos una columna más
para representar la salida, o sea, los resultados que muestran. En cada fila
colocaremos los valores de las variables que resultan en cada iteración.

Supongamos que nuestra lista es la siguiente: (12,5,3,9)


Tenemos 4 números en la lista, por lo tanto N tomará el valor 4. La variable
X, tomará en cada iteración el valor de cada uno de los números de la lista.
Sabemos que las variables mantienen su valor mientras no se modifiquen, y
cuando ocurre eso, el valor anterior es “olvidado”.
Teniendo en cuenta estos elementos, la prueba de escritorio podría resultar
así:

N C S X Salida Comentarios

4 0 0 Valores iniciales

1 12 12 Primera iteración

2 17 5 Segunda iteración

3 20 3 Tercera iteración

4 29 9 Cuarta iteración y C alcanza al valor de N

29 Se sale del ciclo, y se muestra el resultado S

Prueba de escritorio de la suma de N números

Como siempre señalamos, existen muchas soluciones posibles para un mismo


problema. Sin ánimo de confundir al lector, es posible resolver este problema
usando al contador C de una manera diferente. Por ejemplo podemos hacer
que comience en 1, en cuyo caso la condición de fin sería un poco diferente:
ya no pediremos que C alcance el valor N para terminar el ciclo, sino que lo
supere, quedando el algoritmo de la siguiente forma:

ingresar N
C=1
S=0
repetir mientras C<=N
ingresar X
S=S+X
C=C+1
mostrar S

¿Nos animamos a más?

Aprovechemos lo visto hasta ahora para resolver problemas que planteen


desafíos más complejos.
Supongamos que tenemos un número natural, y queremos contar cuantos
dígitos tiene. ¿Es esto un desafío complejo? En apariencia para nosotros es
muy simple realizar esa tarea, y determinar por ejemplo que el número 7524
tiene 4 dígitos. ¿Pero qué procesos mentales y matemáticos estuvieron
involucrados en este desafío? Me animo a decir que en realidad los
desconocemos, al menos a un nivel consciente. El cerebro humano dispone
de una “caja de herramientas” muy completa y compleja que le permite
resolver algunos problemas como este de una manera aparentemente trivial.
El desafío está en construir un algoritmo con los elementos que vimos hasta
ahora. Para eso vamos a hacer un análisis del problema desde una visión
matemática.
Nunca debemos perder de vista los pasos necesarios para resolver un
problema, que constituyen el modelo de la solución. A medida que
avancemos en el libro quizá podamos ser un poco más laxos en este punto
debido a la acumulación de práctica, pero por ahora somos principiantes,
entonces especifiquemos nuestros modelos de una manera detallada.

Paso 1: Entender el problema. Dado un número natural, determinar la


cantidad de dígitos. No supone dificultad en la comprensión. Sólo debemos
determinar e informar cuantos dígitos tiene un número.

Paso 2: Datos de entrada. Un número natural, que sabemos que es un número


entero mayor o igual que 1.

Paso 3: Resultado esperado. Cantidad de dígitos del número natural.


Paso 4: Construir un modelo de la solución. Aquí insisto con el proceso
creativo que cada uno hace a su manera para poder llegar a los resultados
partiendo de los datos, todo eso usando las herramientas con las que
contamos, que en este caso no es nuestro gran cerebro sorprendente y lleno
de recursos, sino que contamos sólo con las operaciones que definimos hasta
aquí y que podemos usar, que limitan el espacio de la solución.
Dentro de este contexto, sabemos que disponemos de variables que pueden
almacenar números. Sabemos también que un número natural tiene una coma
decimal implícita al final que, si logramos correrla hasta el principio del
número, eliminando su parte decimal y contando cuantas veces lo hacemos,
obtendremos la cantidad de dígitos del número. Esto sucederá sacando el
dígito menos significativo del número hasta que lleguemos a cero.

Pasando en limpio:

ingresamos el número natural,


de alguna manera le sacamos un digito,
contamos en alguna variable lo que acabamos de hacer (dicha
variable debería comenzar en cero),
repetimos esto hasta que ya no queden más dígitos en el número, o
sea, hasta que quede reducido a cero.

Para el ejemplo propuesto, tenemos el número 7524, quedando el proceso


más o menos así:

A 7524 le sacamos el dígito 4 y lo contamos, obteniendo un dígito y


el número ahora es 752
A 752 le sacamos el dígito 2 y lo contamos, obteniendo ya dos
dígitos y el número ahora es 75
A 75 le sacamos el dígito 5 y lo contamos, obteniendo ya tres dígitos
y el número ahora es 7
A 7 le sacamos el dígito 7 y lo contamos, obteniendo ya cuatro
dígitos y el número ahora es 0
Como ya no tenemos dígitos, el algoritmo finaliza y el contador es
cuatro.
Ahora la pregunta sería ¿En qué parte de mi caja de herramientas dice que le
podemos sacar un dígito a un número?
La respuesta es la operación división entera que simbolizamos con el
operador “\”.

7524\10 es 752 o sea que le “sacamos” el último dígito al número

Entonces si hacemos esto mientras el número sea mayor que cero, contando
la cantidad de veces que repetimos la tarea, resolveremos el problema.

Veamos cómo quedaría la solución que ya tenemos, en nuestro


pseudocódigo:

ingresar N
C=0
repetir mientras N>0
N=N\10
C=C+1
mostrar C

Algoritmo para contar los dígitos de un número natural

Veamos la prueba de escritorio correspondiente, para el mismo ejemplo,


N=7524

N C Salida Comentarios

7524 0 Ingresamos el dato, y ponemos C en cero

752 1 Primera iteración, quitamos un dígito y lo contamos

75 2 Segunda iteración, quitamos otro dígito y lo contamos

7 3 Tercera iteración, quitamos otro dígito y lo contamos

0 4 Cuarta iteración, quitamos el último dígito y lo contamos

4 Se sale del ciclo, y se muestra el resultado C


¿Qué pasaría si en lugar de querer contar los dígitos queremos sumarlos?

Modificamos el enunciado diciendo: Dado un número natural, determinar la


suma de sus dígitos.
¿Otra vez es simple, no? Entonces si tenemos el número 7524 el resultado
esperado es 7+5+2+4=18.

Siguiendo la metodología:
Paso 1: Problema comprendido
Paso 2: Igual que el problema anterior, un número natural
Paso 3: La suma de los dígitos del número natural
Paso 4: Se parece mucho al problema anterior, pero en lugar de contar los
dígitos, debemos sumarlos. Para eso no es suficiente con “sacarlo”, porque
perderíamos su valor. Entonces primero deberíamos obtener su valor,
sumarlo y después sí lo descartamos. Algo más o menos así:
Ingresar un número,
Obtener el último dígito,
Sumarlo a alguna variable (esa variable debería comenzar en cero),
Sacarle el último dígito al número,
Repetir hasta que no queden más dígitos

El elemento nuevo aquí es “obtener el último dígito”. Para eso tenemos otra
operación matemática conocida que habíamos llamado “mod”, que determina
el valor del resto de la división entera.
Si dividimos 7524 por 10, resulta 752 como cociente y 4 como resto.
Justamente “mod” es el resto de la división, o sea, el último dígito del
número, si usamos como divisor al número 10.

En el caso del ejemplo sería:

Obtenemos el último dígito haciendo 7524 mod 10, el resultado es 4


y lo sumamos (la suma es 4),
Le sacamos un dígito y queda en 752,
Obtenemos el último dígito haciendo 752 mod 10, el resultado es 2 y
lo sumamos (la suma da 6),
Le sacamos otro dígito y queda en 75
Obtenemos el último dígito haciendo 75 mod 10, el resultado es 5 y
lo sumamos (la suma da 11),
Le sacamos otro y ya queda en 7,
Obtenemos el último dígito haciendo 7 mod 10, el resultado es 7 y lo
sumamos (la suma da 18),
Le sacamos uno más y queda en 0, entonces el ciclo termina y 18 es
la suma de los dígitos, que es el resultado esperado.

Veamos cómo quedaría la solución que ya tenemos, en nuestro


pseudocódigo:

ingresar N
S=0
repetir mientras N>0
D=D mod 10
S=S+D
N=N\10
mostrar S

Algoritmo para sumar los dígitos de un número natural

Resaltamos el texto “la solución que ya tenemos” porque es importante


recordar que el pseudocódigo no resuelve los problemas, sino que representa
su solución. El proceso previo a la escritura del pseudocódigo es el que
realmente lo resuelve.

Veamos la prueba de escritorio correspondiente, para el mismo ejemplo,


N=7524

N S D Salida Comentarios

7524 0 Ingresamos el dato, y ponemos S en cero


752 4 4 Primera iteración, quitamos un dígito y lo sumamos

75 6 2 Segunda iteración, quitamos otro dígito y lo sumamos

7 11 5 Tercera iteración, quitamos otro dígito y lo sumamos

0 18 7 Cuarta iteración, quitamos el último dígito y lo sumamos

18 Se sale del ciclo, y se muestra el resultado S


Ciclos controlados por una variable

Cuando tenemos que realizar tareas repetitivas, a menudo nos encontramos


con un caso particular en que el número de veces que el cuerpo del ciclo se
debe repetir depende solamente del valor de una variable que recibe
incrementos fijos en cada iteración.
Muchos lenguajes tomaron nota de esto, y crearon instrucciones específicas
para que la programación de estos casos sea más simple.
En realidad, no se trata de nada nuevo que no podamos resolver de la forma
que ya sabemos, pero para representar estos casos vamos a usar una nueva
instrucción, o más bien, una modificación de la instrucción “repetir”, y de
esta manera darle soporte con nuestro pseudocódigo a lo que la mayoría de
los lenguajes plantean.
La forma propuesta es la siguiente:

repetir para <variable> = <valor inicial> incremento <incremento>


hasta <valor final>

Tanto <valor inicial> como <incremento> y <valor final> pueden ser valores
constantes, el valor de una variable, o expresiones en general

Es importante resaltar que todas las variables que intervienen en esta


sentencia no deben ser modificadas en el cuerpo del ciclo, sino que serán
modificadas automáticamente según el valor determinado en el argumento
<incremento>.

Su funcionamiento es el siguiente:

1) La variable toma el valor inicial y se verifica que no haya superado el


valor final, sino termina el ciclo.
2) Se ejecuta el cuerpo del ciclo
3) Se incrementa automáticamente la variable con el valor del incremento
4) Se vuelve al paso 1
El funcionamiento descripto corresponde a ciclos con valores ascendentes. Si
el valor final fuera menor que el valor inicial, el incremento debería ser un
valor negativo. Si queremos “contar para atrás”, el paso 1 se modificaría
evaluando que el valor inicial no resulte menor al valor final.

Ejemplos

Anteriormente habíamos visto el siguiente algoritmo para mostrar los 10


primeros números naturales

V=1
repetir mientras V<10
mostrar V
V=V+1

Este es un caso típico de ciclo controlado por una variable. Con nuestra
nueva instrucción quedaría de la siguiente forma:

repetir para V=1 incremento 1 hasta 10


mostrar V

Algoritmo para mostrar los 10 primeros números naturales con ciclos


controlados por una variable

Podemos observar todos los elementos de un ciclo vistos anteriormente,


porque en la misma instrucción se establece el valor inicial, la condición y la
variación de la variable. La variable V comenzaría con el valor 1, que es el
<valor inicial>, controlaría que dicho valor no supere el <valor final>. Si esto
no sucede, ejecuta las sentencias del cuerpo del ciclo y al terminar incrementa
la variable V en 1, que es el valor del parámetro <incremento>.

Si quisiéramos hacer una cuenta regresiva de 10 hasta 1, el algoritmo sería el


siguiente:

repetir para V=10 incremento -1 hasta 1


mostrar V

Algoritmo de cuenta regresiva


Resumen del concepto de ciclo

Pasando en limpio el concepto de ciclo, no es más que un conjunto de


instrucciones que se necesitan ejecutar repetidas veces para resolver un
problema. Claramente hubiera alcanzado con una instrucción “repetir”, pero a
fines de acercarnos más a los que la mayoría de los lenguajes ofrecen, es que
usaremos las instrucciones “repetir mientras” y “repetir para”. La única
diferencia es que la primera está basada simplemente en el valor de verdad de
una proposición, y la segunda se usará cuando el número de veces que debe
ejecutarse el cuerpo del ciclo está perfectamente determinado, ya sea por
valores constantes o por los valores de ciertas variables.
En ejemplos sucesivos veremos algunos usos de las dos formas de la
instrucción “repetir”, e indicaremos claramente en qué casos conviene usar
una u otra.
Variables indizadas

Hasta ahora hemos resuelto algunos ejercicios en los que participan listas de
números, pero en ningún caso fue necesario “memorizar” la lista completa.
Para resolver problemas tales como sumar los números de una lista, o contar
cuantos cumplen con una condición u obtener el valor del promedio, no es
necesario recordar cada elemento de la lista. Basta con almacenar cada
elemento en la misma variable que va cambiando de valor sucesivamente.
Sin embargo, existen problemas donde sí es necesario conservar todos los
elementos de la lista, y esta situación se observa al menos en dos ocasiones:

1) Se necesita acceder a elementos de la lista en un orden diferente al que


fueron ingresados, o en un orden absolutamente aleatorio.

2) Se necesita acceder varias veces a los elementos de la lista.

Pensemos en un problema que pueda de manera fácil y clara ilustrar el


primero de los casos.

Dada una lista de 3 números, mostrarla en orden inverso.

Sin pensar mucho, podemos construir el siguiente algoritmo

ingresar A, B, C
mostrar C, B, A

Eso estuvo fácil, pero sólo sirve para una lista de 3 números. ¿Y si la lista
tuviera 5 números? Tampoco resulta complicado

ingresar A, B, C, D, E
mostrar E, D, C, B, A

Nuevamente tenemos una solución simple, para un problema limitado. Si


nuestra lista no tiene 5 elementos, el algoritmo no sirve.

¿Qué pasaría si la lista tuviera 329 números? ¿O 75? ¿Y si los elementos que
participan en cada caso varían en cantidad?

El enunciado del problema ahora sería:

Dada una lista de N números, mostrarla en orden inverso.

Necesitamos almacenar N números en alguna parte, y parece que usar letras


sucesivas del abecedario no resulta posible, porque desconocemos cuantos
elementos tendremos que almacenar cada vez.

Para ello existen las variables indizadas, que no son más que variables que se
identifican a través de un nombre, y un número que actúa como subíndice.
Si la variable tiene un solo subíndice, recibe el nombre de vector, y sirve para
operar con listas.
Si la variable tiene dos subíndices, recibe el nombre de matriz, y sirve para
operar con tablas.
Las variables pueden tener más índices, pero a efectos de este libro,
trabajaremos con variables de un subíndice, porque resulta suficiente para
ilustrar el concepto, sin entrar en complejidades algorítmicas innecesarias.

Veamos entonces, el caso particular de una variable con un solo subíndice,


que nos resulta suficiente para trabajar con nuestras listas de números.

Un vector, entonces lo representaremos de la siguiente manera:

<variable>[<subíndice>]

Donde el subíndice es una expresión que da como resultado un número que


indica la posición dentro de la lista o vector. Obviamente nos interesa la parte
entera del resultado de dicha expresión, porque justamente como su nombre
lo indica, dicho valor representa la posición del elemento dentro del vector.
Ejemplo del uso de vectores
Supongamos que tenemos el vector V, que va a contener 5 elementos.
Entonces tendríamos 5 variables identificadas de la siguiente manera:

V[1], V[2], V[3], V[4] y V[5]

Haciendo la analogía con las cajitas que representan las variables, podemos
decir que tenemos entonces cinco cajitas, que todas se llaman V, pero cada
una de ellas se identifica con un número.
Ese número puede estar dado por una expresión, por ejemplo:

V[5-2] representaría al elemento V[3]


V[H] dependerá del valor de la variable H
V[J+K+1] dependerá de los valores de J y de K

Como se observa, el subíndice puede ser cualquier expresión aritmética, de la


que tomaremos su parte entera para indicar el elemento de la lista a la que nos
estamos refiriendo. No importa que variables utilice dentro de la expresión
del subíndice, ni lo complejo o simple de la expresión, simplemente importa
su valor.

Volviendo a nuestro problema original, si tenemos una lista de N números y


queremos almacenarla en un vector que llamaremos L, podemos hacerlo con
el siguiente algoritmo:

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[I]

Algoritmo para ingresar un vector o lista de tamaño N

La variable N tomará el tamaño de la lista, cuando comienza el ciclo la


variable I tomará el valor 1, por lo que al ejecutarse la instrucción ingresar
L[I], en realidad estaremos ingresando un valor para L[1], luego I se
incrementa y en la segunda pasada por el ciclo valdrá 2, entonces
ingresaremos un valor para L[2], y así de manera continua, hasta tener la lista
completamente ingresada en el vector L.

Para resolver nuestro problema ahora deberíamos mostrar la lista en orden


inverso al que se ingresó. Debemos agregar al algoritmo anterior, otro ciclo
que comience con N y termine en 1 para que esto suceda:

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[I]
repetir para I=N incremento -1 hasta 1
mostrar L[I]

Algoritmo para mostrar una lista en orden inverso

Funcionaría de la misma manera si usara una variable para que controle el


primer ciclo y otra para el segundo, ya que para identificar los elementos de
un vector solamente importa el valor de la expresión del subíndice.

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[I]
repetir para J=N incremento -1 hasta 1
mostrar L[J]

También podemos complicar las cosas sin necesidad alguna resolviendo el


mismo problema de la siguiente forma:

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[I]
repetir para I=1 incremento 1 hasta N
mostrar L[N-I+1]

Funcionaría de la misma manera, pero con una expresión innecesariamente


más compleja en el índice del vector.
Lo que queda claro, es que no existe una única solución para un problema,
por más sencillo que sea. Con el tiempo sabremos elegir la solución más
eficiente y clara.

Supongamos un problema muy simple para ilustrar el segundo de los casos


de uso de variables indizadas o vectores, o sea, cuando necesitamos recorrer
los datos de la lista más de una vez:

Dada una lista de N números, determinar cuántos elementos son iguales a su


promedio.

Sabemos que para calcular el promedio de una lista de N números, debemos


sumar todos sus elementos y dividirlos por N, obteniendo por ejemplo un
valor que llamaremos P. Luego deberíamos recorrer la lista nuevamente para
contar cuantos elementos son iguales a P. No hay forma de resolver este
problema con “una sola pasada” sobre la lista. Tampoco es prudente decirle
al usuario de nuestro programa que ingrese dos veces la lista: una para
calcular el promedio y otra para contar cuantos elementos son iguales a dicho
promedio. Si la lista tuviera unos 5 elementos sería molesto pero no muy
grave, pero si se tratara de una lista de 1658 números, no resultaría para nada
práctico ni simpático.

En consecuencia, podríamos pensar que para resolver este problema


deberíamos:
- Ingresar la lista y almacenarla de alguna manera en la memoria
- Sumar sus elementos
- Calcular el promedio como la suma obtenida, dividida por la cantidad de
elementos: N
- Recorrer la lista contando cuantas veces aparece el promedio obtenido en
ella, para ello debería usar una variable que actúe como contador, que
comenzará en cero.

Siguiendo este modelo, podemos construir el siguiente algoritmo

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[i]

Hasta aquí tenemos la lista ingresada en el vector L, ahora vamos a sumar sus
elementos, en la variable S

S=0
repetir para I=1 incremento 1 hasta N
S=S+L[i]

Ahora que tenemos la suma en S, podemos calcular el promedio P

P=S/N

Ya conocemos el promedio y podemos ver cuántas veces aparece en la lista.


Usaremos la variable C como contador

C=0
repetir para I=1 incremento 1 hasta N
si L[i] = P entonces
C=C+1

Ya estamos en condiciones de mostrar el resultado

mostrar C

Poniendo todo junto, el algoritmo quedaría así:

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[i]
S=0
repetir para I=1 incremento 1 hasta N
S=S+L[i]
P=S/N
C=0
repetir para I=1 incremento 1 hasta N
si L[i] = P entonces
C=C+1
mostrar C

Algoritmo para mostrar cuantas veces está el promedio dentro de una


lista

Podemos intentar una solución un poquito más eficiente si unimos los dos
primeros ciclos en uno solo, ya que podemos sumar los elementos de la lista a
medida que ingresan.

ingresar N
S=0
repetir para I=1 incremento 1 hasta N
ingresar L[i]
S=S+L[i]
P=S/N
C=0
repetir para I=1 incremento 1 hasta N
si L[i] = P entonces
C=C+1
mostrar C

¿Eso es todo?
Ya están dadas todas las herramientas de interés de este libro en lo que
respecta a representación de algoritmos, sin embargo vamos a ver algunos
problemas típicos más, sólo a modo de ilustración.

Ordenar una lista de N números


Cerca del principio de este capítulo, habíamos construido un algoritmo que
permitía ordenar 4 números, y quedó latente la promesa de ver que sucedía si
en lugar de 4 fueran más los elementos a ordenar. Ahora estamos en
condiciones de afrontar una solución para ese problema, que sin vectores
hubiese sido imposible resolver.
Existen muchos algoritmos de ordenamiento de listas, algunos más eficientes
que otros. Aquí mostraremos uno simple, de baja complejidad, aunque no
muy eficiente pero sí efectivo. De hecho es uno de los menos eficientes pero
también uno de los más simples; y al tratarse de un libro de introducción a la
resolución de problemas, considero más adecuado centrarnos en este tipo de
algoritmos.

Lo que hicimos casi sin querer al ordenar los 4 números, fue hacer un
recorrido completo de la lista al ubicar en el primer lugar el menor de todos, a
continuación hicimos lo mismo con los 3 números restantes, y luego con los
dos últimos, quedando así ordenada la lista.

Generalicemos esta solución: para ordenar N números de menor a mayor,


debemos recorrer la lista completa, comparando sus elementos de modo de
ubicar en el primer lugar siempre al menor de todos. Luego repetimos el
mismo procedimiento para el segundo elemento, comparándolo con el resto
de la lista y haciendo los intercambios de elementos necesarios para que allí
quede el menor. Si repetimos este procedimiento todos los elementos
restantes hasta agotar la lista, ésta quedará ordenada. Cuando analicemos el i-
ésimo elemento siempre tendremos a la izquierda una sublista ordenada, y a
la derecha una sublista desordenada.

Para ello debemos primero, ingresar la lista de N números.


Luego, para cada uno de ellos, desde el primero hasta el penúltimo, recorrer
el resto de la lista siempre eligiendo el menor en el lugar que corresponda.
¿Por qué hasta el penúltimo? Porque el resto de la lista del penúltimo
elemento, es justamente el último elemento y por lo tanto los últimos que
debo comparar para que la lista quede ordenada.

Esto que parece un juego complicado de palabras, podemos expresarlo de


otra manera:

Tomemos un ciclo sobre la variable I, que recorra la lista tomando


los valores desde 1 hasta N-1.
Dentro de ese ciclo incluiremos otro, para el que usaremos la
variable J, que recorra la lista desde I+1 hasta N, que no es más que
el resto de la lista para cada valor que toma I.
Si el elemento que está en la posición J resulta menor que el que está
en la posición I, entonces debemos intercambiarlos.
Mostramos la lista, que quedó ordenada de menor a mayor.

Expresado en un lenguaje más matemático podemos decir:


Dada una lista L de N números, para todo I comprendido entre 1 y N-1 y para
todo J comprendido entre I+1 y N, si L[J]<L[I], entonces intercambiarlos.

Admirable la simpleza del lenguaje matemático. Ahora construyamos el


algoritmo, teniendo en cuenta que al final debemos mostrar la lista como
quedó, o sea, ordenada.

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[I]
repetir para I=1 incremento 1 hasta N-1
repetir para J=I+1 incremento 1 hasta N
si L[J]<L[I] entonces
X=L[J]
L[J]=L[I]
L[I]=X
repetir para I=1 incremento 1 hasta N
mostrarL[I]

Algoritmo para ordenar una lista de N números de menor a mayor

Intersección de conjutos
Supongamos que tenemos dos listas de M y N elementos respectivamente que
representan los conjuntos A y B. Dado que suponemos que son conjuntos, no
tendrán elementos repetidos, pero tampoco estarán ordenados.Debemos
obtener un conjunto C, que sea el resultado de la intersección de A y B, o sea
que cada elemento de C debe estar en A y en B.
¿Cómo resolvemos este problema?
Representaremos cada conjunto con un vector. Esta forma de hacerlo es una
licencia que nos tomamos, porque en rigor matemático son cosas totalmente
diferentes.
Tratándose de la intersección, podemos por ejemplo tomar cada elemento de
A, y si se encuentra en B lo agregamos a C.

Resolvamos el problema paso a paso:

Los datos de nuestro problema entonces son dos conjuntos A y B, de M y N


elementos respectivamente, que representaremos a través de dos vectores,
que sabemos que no tendrán elementos repetidos.

Debemos obtener un conjunto C, con los elementos comunes de A y de B.

Un modelo de la solución podría ser así:


Ingresar el conjunto A
Ingresar el conjunto B
Para cada elemento de A, si está en B agregarlo al conjunto C
Mostrar el conjunto C

Para ejecutar el cuarto paso, debemos recorrer todos los elementos de A, y


para cada uno de ellos recorrer B, pero ¿debemos recorrer todo el vector B?
Sólo mientras no encuentre el elemento de A en B, o mientras en B tenga
elementos. O sea que ahí hay una doble condición.
El ciclo sobre A será uno del tipo “repetir para”, porque debemos ejecutarlo
para todos los elementos de A, en cambio el ciclo que recorrerá el vector B
será un ciclo del tipo “repetir mientras” con la doble condición mencionada
anteriormente. Al salir del ciclo que recorre B deberemos preguntar que pasó.
Salimos porque encontramos el elemento, y en consecuencia agregarlo al
conjunto C, o porque se acabó el vector, en cuyo caso el elemento de A no
está en B y debemos descartarlo. Veamos como expresamos estas ideas en
nuestro pseudocódigo, pero ahora intercalando comentarios separados entre
asterisos *:

*Primero ingresamos al conjunto A de tamaño M


ingresar M
repetir para I=1 incremento 1 hasta M
ingresar A[I]
*Luego ingresamos el conjunto B de tamaño N*
ingresar N
repetir para J=1 incremento 1 hasta N
ingresar B[J]
*Ponemos en cero un contador K, que usaremos para saber cuantos
elementos tendrá el conjunto C*
K=0
*Ahora recorreremos todos los elementos el conjunto A con un ciclo
repetir para I=1 incremento 1 hasta M
*Buscaremos si el I-esimo elemento de A está en B
J=1
repetir mientras (J<=N) ^(A[I]<>B[J])
J=J+1
*Ahora que salimos del ciclo de búsqueda, preguntamos porque
salimos*
*Si encontramos el elemento de A en B, lo agregamos a C
si A[I]=B[J]
K=K+1
C[J]
*Una vez que terminamos, mostramos el conjunto C
repetir para I=1 incremento 1 hasta K
mostrar C[I]

Ahora veamos el mismo algoritmo sin los comentarios:

ingresar M
repetir para I=1 incremento 1 hasta M
ingresar A[I]
ingresar N
repetir para J=1 incremento 1 hasta N
ingresar B[J]
K=0
repetir para I=1 incremento 1 hasta M
J=1
repetir mientras (J<=N) ^(A[I]<>B[J])
J=J+1
si A[I]=B[J]
K=K+1
C[J]
repetir para I=1 incremento 1 hasta K
mostrar C[I]
Resumen del capítulo 2

Este capítulo se basó en los fundamentos del capítulo 1, permitiéndonos


construir algoritmos y expresarlos de una manera particular, que llamamos
pseudocódigo, con el objetivo de ser traducidos posteriormente a algún
lenguaje de programación.
Lo que aquí estudiamos en esencia no fue muy diferente a lo observado a
través de los personajes que resolvían problemas. En un modo simple, un
pseudocódigo no es más que una herramienta usada por un nuevo personaje
imaginario que sabe interpretarlo y ejecutarlo. Si nos ponemos a pensar, no
son más de 5 tareas elementales y algunas operaciones matemáticas,
relacionales y lógicas, lo que nos permitió resolver estos problemas y nos
permitirá resolver otros problemas mucho más complejos. No hay que
intimidarse y creer que programar es tarea de genios superdotados. Todos
podemos construir algoritmos usando los recursos que ya habíamos
mencionado: técnica, práctica y talento. Cada uno sabrá cuanta es la dosis de
cada cualidad que deba o pueda aportar.
Capítulo 3: Programación
En este capítulo del libro, vamos a construir programas a partir de nuestros
algoritmos, capaces de ser ejecutados por algún dispositivo.

Para hacer esto posible, usaremos un sub conjunto muy pequeño de un


lenguaje llamado Python.
Cabe aclarar que no se trata de un curso de un lenguaje de programación
determinado, sino que simplemente nos aprovecharemos de algunas
herramientas de un lenguaje en particular para poder traducir nuestros
algoritmos a programas, y verlos en acción.
¿Por qué Python? Es un lenguaje que cobra cada vez más popularidad, y si
bien es muy completo, podemos tomar de él lo que necesitamos de manera
muy sencilla. Además, existen versiones capaces de funcionar en teléfonos
móviles en forma gratuita, lo que lo hace accesible a casi todas las personas.
Quien quiera seguir profundizando en el uso del lenguaje puede hacerlo en
numerosos tutoriales que existen en la web.

Nos basaremos en la versión 3 del lenguaje y trataremos de usar la sintaxis


más genérica posible a fin de intentar evitar diferencias por incompatibilidad
de versiones. Igualmente, siempre se puede consultar el manual de la versión
que use el lector.

Lo que haremos es muy sencillo: buscaremos una equivalencia en Python a


cada instrucción del pseudocódigo que ya conocemos, para hacer una
traducción lo más directa posible de nuestros algoritmos a programas. Aquí
no resolveremos problemas nuevos, simplemente mostraremos como se
escribirían algunos de los ya vistos para echarlos a andar.
Entrada de datos

Para la entrada de datos habíamos utilizado la instrucción "ingresar". Su


equivalente en Python quedaría de la siguiente manera:

Pseudocódigo Equivalencia en Python


<variable>=int(input("<mensaje>"))
ingresar <variable>
<variable>=float(input("<mensaje>"))

Algunas aclaraciones:
- No usaremos la instrucción“ingresar” con una lista de variables para
facilitar la compatibilidad entre versiones de Python. Ingresaremos una
variable a la vez
- Si ingresamos un número entero usaremos la función“int”
- Si ingresamos un número en punto flotante usaremos la función“float”
- Se puede introducir un texto en la sentencia“input”, de manera que se pueda
mostrar un mensaje que indique que dato estamos pidiendo.

Ejemplos

Pseudocódigo Equivalencia en Python Descripción


Ingresa un número entero en la variable
ingresar A A=int(input())
A

Ingresa un número en punto flotante en


ingresar C C=float(input())
la variable C

Ingresa un número entero en la variable


Ingresar X X=int(input("Ingrese edad:")) X, mostrando el mensaje "Ingrese
edad:" en la pantalla.
Salida de datos

Para la salida de datos habíamos utilizado la instrucción "mostrar". Su


equivalente en Python quedaría de la siguiente manera:

Pseudocódigo Equivalencia en Python


mostar<lista de expresiones> print(<lista de expresiones>)

Por lo visto son bastante parecidas en su forma sintáctica.

Ejemplos

Pseudocódigo Equivalencia en Python Descripción


mostrar A print(A) Muestra el contenido de la variable A

Muestra el contenido de la variable A y a


mostrar A, B print(A, B)
continuación el contenido de la variable B

mostrar 4/8 print(4/8) Muestra 0.5 que es el resultado de la expresión 4/8

Muestra el mensaje "El resultado es:" y a


mostar X print("El resultado es:", X)
continuación el valor de X
Asignación

Para la asignación usaremos el mismo operador "=".


En Python se pueden hacer asignaciones múltiples, pero no las veremos aquí.

Pseudocódigo Equivalencia en Python


<variable> = <expresión> <variable>=<expresión>

Como se ve es idéntica la sintaxis, aunque pueden variar un poco los


operadores. Queda en la curiosidad del lector el estudio de todos los
operadores que Python posee. Aquí usaremos los mismos operadores
aritméticos que hemos visto en nuestro pseudocódigo, con su correspondiente
equivalencia:

Pseudocódigo Python Descripción

+ + Suma

- - Resta

* * Multiplicación

/ / División

** ** Potenciación

\ // División entera

mod % Resto de la división entera

Ejemplos
Pseudocódigo Python

A=5 A=5

C = B +1 C=B+1

P = (N \ S) mod 10 P = (N // S) % 10

Hasta aquí podemos escribir nuestro primer programa Python equivalente a


alguno de los algoritmos en pseudocódigo presentados en el capítulo anterior:

ingresar A
ingresar B
S=A+B
mostrar S
Algoritmo para sumar dos números en pseudocódigo

A=int(input())
B=int(input())
S=A+B
Print S

Programa para sumar dos números enteros en Python

También podríamos aprovechar las ventajas del lenguaje para ser más claros:

A=int(input(“Ingrese el valor de A:”))


B=int(input(“Ingrese el valor de B”))
S=A+B
Print “El resultado de A+B es:”, S

Como puede observarse, la conversión o traducción del algoritmo al


programa no resulta complicado, y estos son programas que el lector ya
puede probar en algún dispositivo para ver su funcionamiento.
Decisiones

En nuestro pseudocódigo usamos las instrucciones “si” y “sino” en las


operaciones de decisión. Veremos su equivalente en Python:

Pseudocódigo Equivalencia en Python


si <condición> entonces if<condición>:
<instrucciones si la condición es verdadera> <instrucciones si la condición es verdadera>
sino else:
<instrucciones si la condición es falsa> <instrucciones si la condición es falsa>

Los operadores relacionales y lógicos en Python, equivalentes a los vistos en


el pseudocódigo son los siguientes:

Pseudocódigo Python Descripción

= == Igualdad lógica

> > Mayor

< < Menor

>= >= Mayor o igual

<= <= Menor o igual

<> != Distinto

^ and Conjunción lógica

v or Disyunción lógica
~ not Negación

Ejemplos

Seguiremos usando los ejemplos vistos en el capítulo anterior y su


correspondiente traducción a Python

ingresar A y B
si A > B
M=A
sino
M=B
mostrar M

Algoritmo para determinar el mayor de dos números diferentes

A=int(input(“Ingrese el valor de A:”)


B=int(input(“Ingrese el valor de B:”)
if A > B:
M=A
else:
M=B
print “El mayor es:”, M

Programa para determinar el mayor de dos números diferentes en Python

Nótese que en Python, al igual que en nuestro pseudocódigo, se usa la


indentación para determinar el ámbito de una instrucción que contiene otras.
Vuelvo a resaltar que estamos usando un subconjunto de las instrucciones del
lenguaje, pudiendo encontrar otras potencialidades y variaciones en la
sentencia “if” de Python.
Veamos cómo quedaría el programa que permite determinar el mayor de dos
números, no necesariamente distintos:

A=int(input(“Ingrese el valor de A:”)


B=int(input(“Ingrese el valor de B:”)
if A > B:
print (“El mayor es:”, A)
else:
if B>A:
print (“El mayor es:”, B)
else:
print (“A y B son iguales”)

Programa para determinar el mayor de dos números

Conoceremos más ejemplos más adelante cuando incorporemos más


elementos del lenguaje
Ciclos

Las mismas formas de iterar que vimos en nuestro pseudocódigo son posibles
de usar con Python. Veremos sus equivalencias en la siguiente tabla

Pseudocódigo Pyhton Descripción


Ciclo cuya iteración depende del
repetir mientras <condición> while <condición>:
valor de verdad de la condición

Ciclo controlado por una variable.


Nótese que en Python debemos
repetir para <variable> = <Vi> incremento> for<variable> in range(<Vi>,<Vf+1>,
sumar uno al valor final, porque
<inc> hasta <Vf> <inc>
considera el intervalo abierto a
derecha.

Ejemplos

Mostrar los primeros N números naturales.


Es un problema que ya hemos resuelto. Repasemos las dos formas que
podríamos resolverlo usando pseudocódigo:

ingresar N
C=1
repetir mientras C<=N
mostrar C
C=C+1

y su equivalente en Python quedaría de la siguiente forma:

N=int(input())
C=1
while C<=N:
print(C)
C=C+1
Nótese el parecido. Prácticamente una traducción directa. Ya puede probarlo
en su dispositivo y ver cómo funciona.

La versión usando ciclos controlados por una variable se resolvería de la


siguiente manera usando pseudocódigo:

ingresar N
repetir para C=1 incremento 1 hasta N
mostrar C

Y la correspondiente traducción a Python sería así:

N=int(input())
for C in range (1, N+1,1):
print (C)

También muy parecido. Nótese que debemos incrementar en 1 el valor final


del ciclo por ser un intervalo abierto. Si no agregamos 1 a N, el ciclo se
ejecutaría mientras C<N, por lo que no lo realizaría para el último valor
requerido N.

Ya tenemos elementos suficientes para escribir en Python otro problema que


ya hemos resuelto, como el de sumar los dígitos de un número natural.

ingresar N
S=0
repetir mientras N>0
D=D mod 10
S=S+D
N=N\10
mostrar S

Su traducción a Python podría resultar así:

N=int(input())
S=0
while N>0:
D = D % 10
S=S+D
N=N//10
print (S)
Variables indizadas

Lo único que nos queda para poder traducir nuestros algoritmos a Python, es
ver la forma de representación y uso de los vectores. Los vectores y las
variables indizadas en general son muy poderosas en Python y se pueden usar
de muchas maneras. Aquí mostraremos la más parecida al pseudocódigo que
ya conocemos, a fin de poder probar de forma simple nuestros programas.

Para usar un vector debemos “crearlo” primero. A diferencia de las variables


simples, a las que les elegimos un nombre y las usamos directamente,
debemos indicarle a Python que queremos crear un vector, indicando su
nombre y su tamaño. Para eso usamos la siguiente instrucción:

<variable>=[None]*<tamaño>

Esto que parece extraño se explica fácilmente. A la variable que actuará


como vector le damos un nombre, y le “asignamos” tantos casilleros como
necesitemos. Eso lo hacemos con [none], que sería un casillero vacío, o lleno
de nada, multiplicado por su tamaño, que nos dirá cuántos [none] queremos.
En consecuencia, si queremos crear un vector V, de tamaño 10 debemos
escribir:

V=[None]*10

Lo que va a ocurrir es que tendremos 10 variables, desde V[0] hasta V[9].


Hasta ahora si queríamos un vector de 10 variables las numerábamos del 1 al
10, Python lo hace del 0 al 9. Podemos arreglar eso “descartando” la variable
de la posición 0, y agregando 1 al tamaño, de ese modo podemos crear
nuestro vector así:

V=[None]*11

Así tendremos las variables desde V[1] hasta V[10] como queremos.
También tendremos la V[0] pero no la usaremos.

Veremos ahora el primer problema que resolvimos usando vectores que fue el
de mostrar una lista invertida:

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar V(I)
repetir para I=N incremento -1 hasta 1
mostrar V(I)
Algoritmo para mostrar una lista de tamaño N invertida

N=int(input())
V=[None]*(N+1)
for I in range (1,N+1, 1):
V[I]=int(input())
for I in range (N, 0, -1)
print (V[I])

Programa en Python para mostrar una lista de tamaño N invertida

Para terminar mostraremos el programa equivalente al algoritmo para ordenar


una lista de tamaño N.

El algoritmo que habíamos creado era el siguiente:

ingresar N
repetir para I=1 incremento 1 hasta N
ingresar L[I]
repetir para I=1 incremento 1 hasta N-1
repetir para J=I+1 incremento 1 hasta N
si L[J]<L[I] entonces
X=L[J]
L[J]=L[I]
L[I]=X
repetir para I=1 incremento 1 hasta N
mostrarL[I]

Algoritmo para ordenar una lista de N números de menor a mayor

y su correspondiente programa el Python quedaría de la siguiente forma:

N=int(input(“Cantidad de elementos en la lista:”)


for I in range (1,N+1,1):
L[I]
for I in range (1,N,1):
for J in range (I+1,N+1,1):
if L[J]<L[I]:
X=L[J]
L[J]=L[I]
L[I]=X
for I in range (1,N+1,1)
print (L[I])

Programa en Python para ordenar una lista de N números de menor a mayor


Resumen del capítulo 3
Finalmente llegamos a construir programas, simples pero programas al fin,
capaces de ser ejecutados en distintos dispositivos. Hemos recorrido un
interesante camino desde la formulación de un problema hasta la creación de
su solución ejecutable y demostrable. En este caso la ruta nos llevó del
problema al programa con muy pocas estaciones. Este capítulo nos demostró
lo simple que puede ser usar un lenguaje, haciendo una traducción muy
directa de nuestra representación del algoritmo en pseudocódigo al lenguaje
de programación. Si el interés del lector está relacionado con la
programación, lo invito a profundizar el estudio de éste y otros lenguajes, sin
perder de vista que sólo se trata de herramientas nuevas que nos facilitarán la
resolución de los problemas, sin olvidar los conceptos que vimos sobre todo
en el primer capítulo, que es a mi criterio el más importante, el que abre el
camino, el que pone en marcha el motor para recorrer el camino de la mejor
manera.
Epílogo
Hasta aquí juntos hemos recorrido el camino que nos lleva desde la
formulación de un problema hasta la creación de un programa ejecutable en
algún dispositivo.
Recorriendo este camino, el tramo quizá más sinuoso pero con la mejor vista
fue el primero, donde el proceso creativo toma protagonismo y es, sin duda,
el más difícil de explicar. Lo hemos recorrido con la ayuda de un método
para la resolución de problemas, con la colaboración de distintos personajes
que nos determinaban claramente qué tareas se podían hacer y cuáles no, a las
que hemos llamado nuestra caja de herramientas, y pasando por un proceso
abstracto de creación de un modelo, que fue representado a través de un
algoritmo comprensible para cada personaje en particular. En este capítulo
nos hemos olvidado de que existen las computadoras intencionalmente,
porque problemas hay en todas las disciplinas, y debemos resolverlos con
algún método y recursos limitados. El mayor activo en este punto resulta ser
nuestra creatividad, habilidad y talento para transformar los recursos en
soluciones. Si bien distintas personas tendrán distintas dosis de estas
características, es la práctica la que al fin de cuentas hace la gran diferencia.
En los capítulos siguientes, ya enfocados más en el propósito de construir
programas que funcionen en computadoras, hemos visto la representación de
los algoritmos a través de un pseudocódigo, y la posterior traducción a un
lenguaje de programación, en este caso Python. Queda claro que este no es un
libro para aprender un lenguaje, ni un compendio de problemas resueltos.
Sólo hemos usado algunos ejemplos típicos para ilustrar los conceptos que se
fueron presentando. Esta es la parte del camino más parecida a una autopista,
sin obstáculos relevantes, pero fue necesaria recorrerla para llegar al destino.
Este libro fue pensado para cualquier persona que quiera comenzar a
sumergirse en el mundo de los problemas y los algoritmos, ya sea por
curiosidad personal o dentro de un programa académico, usando recursos que
creo son novedosos e interesantes que he ido desarrollando a través de mis
años como docente. Es una base, a mi criterio necesaria para romper con los
mitos que envuelven a la programación. Hacer programas no es más
importante ni más complejo que resolver problemas. Ahí está el desafío, lo
que cambia son los personajes y por lo tanto la caja de herramientas. La
capacidad, habilidad, voluntad y talento son todos nuestros.

También podría gustarte