Algoritmos de Programación Con Python
Algoritmos de Programación Con Python
com/libros/algoritmos-python
1.1.Computadoras y programas
En la actualidad, la mayoría de nosotros utilizamos computadoras permanentemente: para mandar correos electrónicos, navegar por Internet,
chatear, jugar, escribir textos.
Las computadoras se usan para actividades tan diferentes como predecir las condiciones meteorológicas de la próxima semana, guardar
historias clínicas, diseñar aviones, llevar la contabilidad de las empresas o controlar una fábrica. Y lo interesante aquí (y lo que hace
apasionante a esta carrera) es que el mismo aparato sirve para realizar todas estas actividades: uno no cambia de computadora cuando se cansa
de chatear y quiere jugar al solitario.
Muchos definen una computadora moderna como "una máquina que almacena y manipula información bajo el control de un programa que
puede cambiar". Aparecen acá dos conceptos que son claves: por un lado se habla de una máquina que almacena información, y por el otro
lado, esta máquina está controlada por un programa que puede cambiar.
Una calculadora sencilla, de esas que sólo tienen 10 teclas para los dígitos, una tecla para cada una de las 4 operaciones, un signo igual,
encendido y CLEAR, también es una máquina que almacena información y que está controlada por un programa. Pero lo que diferencia a esta
calculadora de una computadora es que en la calculadora el programa no puede cambiar.
Un programa de computadora es un conjunto de instrucciones paso a paso que le indican a una computadora cómo realizar una tarea dada, y
en cada momento uno puede elegir ejecutar un programa de acuerdo a la tarea que quiere realizar. Las instrucciones se deben escribir en un
lenguaje que nuestra computadora entienda. Los lenguajes de programación son lenguajes diseñados especialmente para dar órdenes a una
computadora, de manera exacta y no ambigua. Sería muy agradable poder darle las órdenes a la computadora en castellano, pero el problema
del castellano, y de las lenguas habladas en general, es su ambigüedad:
Si alguien nos dice "Compra el collar sin monedas", no sabremos si nos pide que compremos el collar que no tiene monedas, o que
compremos un collar y que no usemos monedas para la compra. Habrá que preguntarle a quien nos da la orden cuál es la interpretación
correcta. Pero tales dudas no pueden aparecer cuando se le dan órdenes a una computadora.
Este curso va a tratar precisamente de cómo se escriben programas para hacer que una computadora realice una determinada tarea. Vamos a
usar un lenguaje específico (Python) porque es sencillo y elegante, pero éste no será un curso de Python sino un curso de programación.
NotaExisten una gran cantidad de programas desarrollados en Python, desde herramientas para servidores, como mailman, hasta programas
amigables para usuarios finales, como emesene, pasando por aplicaciones empresariales, openerp, tryton; herramientas de
desarrollo, meld, mercurial, bazaar, trac; plataformas web, django, turbogears, zope; clientes de bittorrent, bittorrent, bittornado, deluge; montones de
juegos de todo tipo, y muchísimas aplicaciones más.
Todas estas aplicaciones son software libre, por lo que se puede obtener y estudiar el código con el que están hechas
Sin embargo eso no es así: existen algunos problemas, llamados no computables que nunca podrán ser resueltos por una computadora digital,
por más poderosa que ésta sea. La computabilidad es la rama de la computación que se ocupa de estudiar qué tareas son computables y qué
tareas no lo son. De la mano del mito anterior, viene el mito del lenguaje todopoderoso: hay problemas que son no computables porque en
realidad se utiliza algún lenguaje que no es el apropiado.
En realidad todas las computadoras pueden resolver los mismos problemas, y eso es independiente del lenguaje de programación que se use.
Las soluciones a los problemas computables se pueden escribir en cualquier lenguaje de programación. Eso no significa que no haya
lenguajes más adecuados que otros para la resolución de determinados problemas, pero la adecuación está relacionada con temas tales como
la elegancia, la velocidad, la facilidad para describir un problema de manera simple, etc., nunca con la capacidad de resolución.
Los problemas no computables no son los únicos escollos que se le presentan a la computación. Hay otros problemas que si bien son
computables demandan para su resolución un esfuerzo enorme en tiempo y en memoria. Estos problemas se llaman intratables. El análisis de
algoritmos se ocupa de separar los problemas tratables de los intratables, encontrar la solución más barata para resolver un problema dado, y
en el caso de los intratables, resolverlos de manera aproximada: no encontramos la verdadera solución porque no nos alcanzan los recursos
para eso, pero encontramos una solución bastante buena y que nos insume muchos menos recursos (el orden de las respuestas de Google a una
búsqueda es un buen ejemplo de una solución aproximada pero no necesariamente óptima).
En este curso trabajaremos con problemas no sólo computables sino también tratables. Y aprenderemos a medir los recursos que nos demanda
una solución, y empezaremos a buscar la solución menos demandante en cada caso particular.
Una solución posible, por supuesto, es hacer el producto N × N × . . . × N, que involucra 32 multiplicaciones. Otra solución, mucho más
eficiente es:
• Calcular N × N.
• Al resultado anterior multiplicarlo por N con lo cual conseguimos el resultado deseado con sólo 6 multiplicaciones.
Cada una de estas soluciones representa un algoritmo, es decir un método de cálculo, diferente. Para un mismo problema puede haber
algoritmos diferentes que lo resuelven, cada uno con un costo distinto en términos de recursos computacionales involucrados.
El origen de la palabra algoritmo La palabra algoritmo no es una variación de logaritmo, sino que proviene
de algorismo. En la antigüedad, los algoristas eran los que calculaban usando la numeración arábiga y mientras que los
abacistas eran los que calculaban usando ábacos. Con el tiempo el algorismo se deformó en algoritmo, influenciado por el
término aritmética.
A su vez el uso de la palabra algorismo proviene del nombre de un matemático persa famoso, en su época y para los estudiosos
de esa época, Abu Abdallah Muhammad ibn Mûsâ al-Jwârizmî, que literalmente significa: "Padre de Ja'far Mohammed, hijo de
Moises, nativo de Jiva". Al-Juarismi, como se lo llama usualmente, escribió en el año 825 el libro Al-Kitâb al-mukhtasar fî
hîsâb al-gabr wa'l-muqâbala ("Compendio del cálculo por el método de completado y balanceado"), del cual surgió también la
palabra "álgebra".
Hasta hace no mucho tiempo se utilizaba el término algoritmo para referirse únicamente a formas de realizar ciertos cálculos, pero
con el surgimiento de la computación, el término algoritmo pasó a abarcar cualquier método para obtener un resultado.
Problema 1.2. Tenemos que permitir la actualización y consulta de una guía telefónica.
Para este problema no hay una solución única: hay muchas y cada una está relacionada con un contexto de uso. ¿De qué guía estamos
hablando: la guía de una pequeña oficina, un pequeño pueblo, una gran ciudad, la guía de la Argentina? Y en cada caso ¿de qué tipo de
consulta estamos hablando: hay que imprimir un listado una vez por mes con la guía completa, se trata de una consulta en línea, etc.? Para
cada contexto hay una solución diferente, con los datos guardados en una estructura de datos apropiada, y con diferentes algoritmos para la
actualización y la consulta.
La versión 2.0, lanzada en 2000, fue un paso muy importante para el lenguaje ya que era mucho más madura, incluyendo un recolector de
basura. La versión 2.2, lanzada en diciembre de 2001, fue también un hito importante ya que mejoró la orientación a objetos. La última
versión de esta línea es la 2.7 que fue lanzada en noviembre de 2010 y aún está vigente.
En diciembre de 2008, se lanzó la versión 3.0, cuya versión actual es la 3.4.1, de mayo de 2014. Sin embargo, debido a que estas versiones
introducen importantes cambios y no son totalmente compatibles con las versiones anteriores, todavía no se utiliza extensamente.
El lenguaje Python nos provee de un intérprete, es decir un programa que interpreta las órdenes que le damos a medida que las escribimos.
Para orientarnos, el intérprete presenta una línea de comandos (los comandos son las órdenes) que identifica al comienzo con los símbolos
>>>, y que llamaremos prompt. En esta línea, a continuación del prompt podemos escribir diferentes órdenes.
Algunas órdenes sencillas, por ejemplo, permiten utilizar la línea de comandos como una calculadora simple con números enteros. Para esto
escribimos la expresión que queremos resolver en el prompt y presionamos la tecla <ENTER>. El intérprete de Python "responde" el resultado
de la operación en la línea siguiente, sin prompt, y luego nos presenta nuevamente el cursor para escribir la siguiente orden.
>>> 2+3
>>>
Python permite utilizar las operaciones +, -, *, / (división entera), y ** (potenciación). La sintaxis es la convencional (valores intercalados con
operaciones), y se pueden usar paréntesis para modificar el orden de asociación natural de las operaciones (potenciación, producto/división,
suma/resta).
>>> 5*7
35
>>> 2+3*7
23
>>> (2+3)*7
35
>>> 10/5
>>> 5**2
25
Otra orden sencilla de Python permite indicarle al intérprete que escriba o "imprima" por pantalla una palabra o frase, que llamaremos cadena
de texto.
>>> print 'Hola'
Hola
Como estan?
print es una instrucción de Python: aquélla que le indica a la máquina que debe imprimir un texto en pantalla, que deberá ser ingresado entre
comillas simples (') o dobles (") indistintamente. Ya veremos con qué otras instrucciones viene equipado Python.
Pero ya dijimos que como programadores debíamos ser capaces de escribir nuevas instrucciones para la computadora. Los programas de
correo electrónico, navegación por Internet, chat, juegos, escritura de textos o predicción de las condiciones meteorológicas de los próximos
días no son más que grandes instrucciones que se le dan a la máquina, escritas por uno o muchos programadores.
Si queremos escribir una función (que llamaremos holaMar) que escribe en una línea el texto "Hola Marta!"" y en la línea siguiente el texto
"Estoy programando en Python.", lo que debemos hacer es ingresar el siguiente conjunto de líneas en Python:
>>>
def holaMar():le indica a Python que estamos escribiendo una instrucción cuyo nombre es holaMar. ¿Por qué se ponen esos dos paréntesis? Lo
veremos dentro de unos párrafos. La sangría con la que se escriben las dos instrucciones print le indican a Python que estamos escribiendo el
cuerpo (es decir las instrucciones que la componen) de la función en cuestión. Las dos teclas <ENTER> que tecleamos después de ingresar el
texto "Estoy programando en Python." le indican a Python que se acabó el cuerpo de la función (y por eso aparece nuevamente el cursor).
Si ahora queremos que la máquina ejecute la instrucción holaMar, debemos escribir holaMar() a continuación del cursor de Python:
>>> holaMar()
Hola Marta!
>>>
Se dice que estamos invocando a la función holaMar. Al invocar una función, se ejecutan las instrucciones que habíamos escrito en su
cuerpo, una a continuación de la otra.
Nuestro amigo Pablo seguramente se pondrá celoso porque escribimos una función que la saluda a Marta, y nos pedirá que escribamos una
función que lo salude a él. Y así procederemos entonces:
Pero, si para cada amigo que quiere que lo saludemos debemos que escribir una función distinta, parecería que la computadora no es una gran
solución. A continuación veremos, sin embargo, que podemos llegar a escribir una única función que se personalice en cada invocación, para
saludar a quien querramos. Para eso están precisamente los paréntesis.
Las funciones tienen partes variables, llamadas parámetros, que se ponen dentro de los paréntesis. Escribimos por ejemplo una función
hola general que nos sirva para saludar a cualquiera, de la siguiente manera:
En este caso, alguien es un parámetro cuyo valor será reemplazado por un texto (nombre en este caso) en cada invocación. Por ejemplo,
podemos invocarla dos veces, para saludar a Ana y a Juan:
>>> hola("Ana")
Hola Ana !
>>> hola("Juan")
Hola Juan !
>>>
Solución. Para resolver este problema, se combinan los recursos utilizados hasta ahora:
def cuad1(num):
print num*num
>>> cuad1(5)
25
>>>
Solución. Para esto utilizaremos una nueva función input que permite leer valores ingresados por el usuario:
def cuad2():
cuad1(n)
>>> cuad2()
Ingrese un numero: 5
25
>>>
... cua = x * x
...
>>> y
25
>>>