Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
MATERIA
CARRERA
ACTIVIDAD 2.1
RESUMEN –
Modelo de Programación Funcional
18 de SEPTIEMBRE de 2019
EQUIPO
CASA BETA
Contenido
2.1 INTRODUCCIÓN AL MODELO DE PROGRAMACIÓN FUNCIONAL. ................. 6
2.3.4 Strings........................................................................................................... 10
1
2.3.3.2. Por nombre ........................................................................................... 22
2.4 INTERVALOS...................................................................................................... 26
2
2.5.1.9 Orden de precedencia ............................................................................ 33
3
2.5.3.11 Ejemplo de operador relacional Menor que .......................................... 42
4
REFERENCIAS BIBLIOGRÁFICAS .......................................................................... 61
5
2.1 INTRODUCCIÓN AL MODELO DE
PROGRAMACIÓN FUNCIONAL.
2.1.1 ¿Qué es la programación funcional?
Es un paradigma de programación declarativa basado en el uso de funciones
matemáticas. La programación funcional genera un código lindo y declarativo -se lee
y se entiende lo que hace. La diferencia entre una función matemática y «función»
utilizada en programación imperativa es que esta última mencionada puede tener
efectos secundarios (side-effects), como cambiar el valor de variables globales o
pasadas por referencia. Al eliminar dichos efectos secundarios, en la programación
funcional, se puede entender y predecir el funcionamiento de un programa más
fácilmente, porque una función que se invoca con los mismos parámetros siempre va
a retornar el mismo resultado.
Vale la pena destacar que algunos lenguajes utilizan lazy evalúation, como Haskell y
Miranda, donde cada expresión y argumento será evalúado a medida que se necesite,
o sea, que algunos argumentos quizás nunca sean evalúados; en cambio otros utilizan
eager evalúation, como Erlang y la mayoría de los lenguajes imperativos, donde las
expresiones y parámetros se evalúan al momento que se asignan.
6
programas por modificaciones de variables fuera de nuestro control. Aparte de tener
un test unitario mucho más confiable.
Por ejemplo:
Esta función en Erlang comprueba si una lista es vacía mediante pattern matching, si
lo es devuelve true, caso contrario devuelve false.
2.1.4 Recursividad
Se da cuando una función se llama a si misma las veces que sea necesaria para
retornar un resultado, siempre con un criterio de paro.
En los lenguajes imperativos es usada sin problemas, pero en los funcionales es pieza
fundamental, de hecho en vez de usar los famosos loops imperativos, en funcional se
utiliza la recursividad. ¿Por qué? Recordemos que las variables son inmutables, lo que
descalificaría la chance de usar un loop convencional.
2.1.5 Concurrencia
Este concepto es importantísimo en el software, y en la programación funcional es una
clave por sobre la imperativa porque -retomamos- los side-effects son reducidos al
mínimo. Al tener múltiples (decenas, cientos, miles, cientos de miles…)
procesos/threads en ejecución, el hecho de que nuestras variables sean inmutables y
no depender de estados, nos garantiza una concurrencia limpia.
7
2.2 EL TIPO DE DATO
El funcionamiento de los programas Python depende de los datos que maneja. Todos
los valores de datos en Python son objetos, y cada objeto, o valor, tiene "un tipo".
Tener en cuenta que, cada tipo de objeto determina qué operaciones va a soportar el
objeto y, por lo tanto, qué operaciones se van a poder realizar con esos valores de los
datos, qué atributos tiene y si va a poder ser "mutable" o no.
En Python también existe un tipo de dato "objeto" que acepta cualquier objeto como
argumento y devuelve el tipo de objeto al incorporado.
Por último, tener en cuenta que, en Python, también se han incorporado a tipos de
datos: números, cadenas, tuplas, listas y diccionarios. Y, si estos no llegan, también
se pueden crear tipos definidos por el usuario (clases).
En Python los objetos tipo número soporta enteros (normales y largos), números de
punto flotante y números complejos.
Todos los números en Python son "objetos inmutables", esto quiere decir que
siempre que se realice una operación con un número el resultado será otro objeto
número distinto.
8
2.2.1 Números enteros
Un número entero puede ser decimal, octal o hexadecimal.
Así y todo, sí podemos indicar con la letra L que va a ser un entero largo:
0., 0.0, .0
1.0, 1.e0, 1.0e0
Podremos acceder a cada una de esas partes por separado: z.real y z.imag.
Se especifica la parte imaginaria con la letra j o J.
9
Iterables
El concepto de Python que generaliza la idea de "secuencia" es el concepto de
"iterable".
Todas las secuencias son iterables, pero existen más iterables, como las "listas", por
ejemplo.
2.3.4 Strings
Un objeto string (simple o Unicode) es una secuencia de caracteres utilizado
para guardar y representar textos.
Los strings en Python son inmutables. Los objetos string nos van a proporcionar
muchos métodos.
'Este es un string'
"Este también es un string"
Se utilizará backslash para escapar una comilla:
'Este es un \'string\''
"Este también es un 'string'"
Para expandir el string a dos líneas utilizaremos también backslash:
10
Secuencia Significado
\\ Backslash
\n Nueva línea
\r Retorno de carro
\t Tabulador
Una variante del tipo string son las raw string, son utilizadas para que no
realice su función el símbolo backlash. Para definir una raw string hay que
colocar delante de la primera comilla una letra r o R.
Formatear un string automáticamente con el método.
2.3.5 Tuplas
Una tupla es una secuencia de items ordenada e inmutable. Los items de una tupla
pueden ser objetos de cualquier tipo.
Para especificar una tupla, lo hacemos con los elementos separados por comas dentro
de paréntesis.
11
(100, 200, 300) # Tupla con tres elementos
(3.14,) # Tupla con un elemento
() # Tupla vacía (los paréntesis NO son opcionales)
También se puede crear una tupla del siguiente modo: saludo = tuple("hola")
#!/usr/bin/python3
# -*- coding: utf-8 -*-
saludo = tuple("hola")
for letra in saludo:
print ('%s' % letra)
# Vemos que, de este modo se crea una tupla igual a:
# saludo = ('h', 'o', 'l', 'a')
2.3.6 Listas
Una lista es una secuencia ordenada de elementos mutable.
Los items de una lista pueden ser objetos de distintos tipos.
Para especificar una lista se indican los elementos separados por comas en el
interior de corchetes.
Para denotar una lista vacía se emplean dos corchetes vacíos.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
12
# Calculamos la longitud de la lista:
print ("\nLa longitud de la lista es de ", len(lista),
"elementos")
# Las listas comienzan con el elemento "0"
print ("\nEl Primer elemento: %s" % lista[0])
# Con los índices negativos accedemos a los elementos al revés
print ("\nEl Último elemento: %s" % lista[-1])
# Para acceder a porciones de la lista:
# El primer índice de la porción especifica el primer elemento
que se desea obtener,
# y el segundo índice especifica el primer elemento que no se
desea obtener
print ("\nElementos segundo, tercero y cuarto: ", lista[1:4])
13
2.3.6 Diccionarios
Los diccionarios de Python son una lista de consulta de términos de los cuales se
proporcionan valores asociados.
Las claves son únicas dentro de un diccionario, es decir que no puede haber un
diccionario que tenga dos veces la misma clave, si se asigna un valor a una clave ya
existente, se reemplaza el valor anterior.
No hay una forma directa de acceder a una clave a través de su valor, y nada impide
que un mismo valor se encuentre asignado a distintas claves
Veamos un ejemplo:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
14
# Veamos el identificador inicial del diccionario
print ("Identificador del diccionario:
{}\n".format(id(futbolistas)))
# Recorrer el diccionario, imprimiendo clave - valor
print ("Vemos que los elementos no van \"ordenados\":")
for k, v in futbolistas.items():
print ("{} --> {}".format(k,v))
# Nº de elementos que tiene un diccionario
numElemen = len(futbolistas)
print ("\nEl número de futbolistas es de {}".format(numElemen))
# Imprimir las claves que tiene un diccionario
keys = futbolistas.keys();
print ("\nLas claves de nuestro diccionario son :
{}".format(keys))
# Imprimir los valores que tiene un diccionario
values = futbolistas.values();
print ("\nLos valores de nuestro diccionario son :
{}".format(values))
# Obtener el valor de un elemento dada su clave
elem = futbolistas.get(6)
print ("\nEl futbolista con clave 6 es {}".format(elem))
15
print ("El identificador de la copia del diccionario :
{}".format(id(futbolistas_copia)))
# Borramos los elementos de un diccionario
futbolistas_copia.clear()
print ("\nVaciamos el diccionario nuevo creado, ahora los valores
en el: {}".format(futbolistas_copia))
# Creamos un diccionario a partir de una lista de claves
keys = ['nombre', 'apellidos', 'edad']
datos_usuario = dict.fromkeys(keys, 'null')
print ("\nCreamos un diccionario a partir de la lista de
claves:")
print (keys)
print ("y con valor 'null'")
print ("Así el diccionario queda: {}".format(datos_usuario))
# Comprobamos si existe o no una clave en un diccionario
if 2 in futbolistas:
print ("\nEl futbolista con la clave 2 existe en el
diccionario.")
else:
print ("\nEl futbolista con la clave 2 NO existe en el
diccionario.")
if 8 in futbolistas:
print ("\nEl futbolista con la clave 8 existe en el
diccionario.")
else:
print ("\nEl futbolista con la clave 8 NO existe en el
diccionario.")
# Devolvemos los elementos del diccionario en una tupla
tupla = futbolistas.items()
print ("\nEl diccionario convertido en tupla queda así:")
print (tupla)
# Unimos dos diccionarios existentes
suplentes = {
4:'Marchena', 12:'Valdes', 13:'Mata',
17:'Arbeloa', 19:'Llorente', 20:'Javi Martinez',
21:'Silva', 23:'Reina'}
print ("\nUnimos el diccionario: ")
print (futbolistas)
futbolistas.update(suplentes) # Aquí hacemos la unión de los
diccionarios
print ("con el diccionario:")
print (suplentes)
print ("siendo el resultado:")
print (futbolistas)
16
2.3 FUNCIONES
Una función es un bloque de código con un nombre asociado, que recibe cero o más
argumentos como entrada, sigue una secuencia de sentencias, la cuales ejecuta una
operación deseada y devuelve un valor y/o realiza una tarea, este bloque puede ser
llamados cuando se necesite.
def NOMBRE(LISTA_DE_PARAMETROS):
"""DOCSTRING_DE_FUNCION"""
SENTENCIAS
RETURN [EXPRESION]
17
A continuación, se detallan el significado de pseudo código fuente anterior:
Los bloques de function deben estar identados como otros bloques estructuras de
control.
La palabra reservada def se usa para definir funciones. Debe seguirle el nombre de la
función en el ejemplo anterior hola() y la lista de parámetros formales entre paréntesis.
Las sentencias que forman el cuerpo de la función empiezan en la línea siguiente, y
deben estar identado.
La primer sentencia del cuerpo de la función puede ser opcionalmente una cadenas
de caracteres literal; esta es la cadenas de caracteres de documentación de la función,
o docstrings. (Puedes encontrar más acerca de docstrings en la sección Cadenas
de texto de documentación).
18
La ejecución de la función hola() muestra la impresión de un mensaje Hola Plone !
que se imprime por consola. Devolver el objeto por los valores de retorno opcionales.
La ejecución de una función introduce una nueva tabla de símbolos usada para las
variables locales de la función. Más precisamente, todas las asignaciones de variables
en la función almacenan el valor en la tabla de símbolos local; así mismo la referencia
a variables primero mira la tabla de símbolos local, luego en la tabla de símbolos local
de las funciones externas, luego la tabla de símbolos global, y finalmente la tabla de
nombres predefinidos. Así, no se les puede asignar directamente un valor a las
variables globales dentro de una función (a menos se las nombre en la sentencia
global), aunque si pueden ser referenciadas.
19
2.3.2 Argumentos y parámetros
Al definir una función los valores los cuales se reciben se denominan parámetros, pero
durante la llamada los valores que se envían se denominan argumentos.
Cuando envía argumentos a una función, estos se reciben por orden en los parámetros
definidos. Se dice por tanto que son argumentos por posición:
Sin embargo es posible evadir el orden de los parámetros si indica durante la llamada
que valor tiene cada parámetro a partir de su nombre:
Al momento de llamar una función la cual tiene definidos unos parámetros, si no pasa
los argumentos correctamente provocará una excepción TypeError:
>>> resta()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: resta() takes exactly 2 arguments (0 given)
20
2.3.2.4. Parámetros por defecto
Se debe crear una lista dinámica de argumentos, es decir, un tipo tupla, definiendo el
parámetro con un asterisco, para recibir los parámetros indeterminados por posición:
21
2.3.3.2. Por nombre
Los nombres args y kwargs no son obligatorios, pero se suelen utilizar por convención.
Muchos frameworks y librerías los utilizan por lo que es una buena practica llamarlos
así.
22
2.3.4. Sentencia pass
Es una operación nula — cuando es ejecutada, nada sucede. Eso es útil como un
contenedor cuando una sentencia es requerida sintácticamente, pero no necesita
código que ser ejecutado, por ejemplo:
def suma(numero1,numero2):
'''función la cual suma dos números'''
print numero1 + numero2
print "\n"
>>> suma(23,74)
97
23
2.3.5.1. Retorno múltiple
24
2.3.6. Ejemplos de funciones
A continuación, se presentan algunos ejemplos de su uso:
def iva():
'''función básica para el calculo del IVA'''
iva = 12
costo = input('¿Cual es el monto a calcular?: ')
calculo = costo * iva / 100
print "El calculo de IVA es: " + str(calculo) + "\n"
>>> iva()
¿Cual es el monto a calcular?: 300
36
def suma(numero1,numero2):
'''función la cual suma dos números'''
print numero1 + numero2
print "\n"
>>> suma(23,74)
97
25
2.4 INTERVALOS
El intervalo de una variable está definido como la diferencia entre el valor más alto y el
valor más bajo que esa variable puede guardar.
En el caso de una variable entera, el intervalo cubrirá todos los números dentro de su
intervalo (incluyendo el máximo y el mínimo). En el caso de una variable entera, la
definición está restringida a números enteros, y el intervalo cubrirá todos los números
dentro de su intervalo (incluyendo el máximo y el mínimo).
26
2.4.1 El tipo range
El tipo range es una lista inmutable de números enteros en sucesión aritmética.
Un range se crea llamando al tipo de datos con uno, dos o tres argumentos numéricos,
como si fuera una función.
El tipo range() con un único argumento se escribe range(n) y crea una lista inmutable
de n números enteros consecutivos que empieza en 0 y acaba en n - 1.
Para ver los valores del range(), es necesario convertirlo a lista mediante la función
list().
>>> x = range(10)
>>> x
range(0, 10)
>>> list(x)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(7)
range(0, 7)
>>> list(range(7))
[0, 1, 2, 3, 4, 5, 6]
Si n no es positivo, se crea un range vacío.
>>> list(range(-2))
[]
>>> list(range(0))
[]
El tipo range con dos argumentos se escribe range(m, n) y crea una lista inmutable de
enteros consecutivos que empieza en m y acaba en n - 1.
27
Si n es menor o igual que m, se crea un range vacío.
El tipo range con tres argumentos se escribe range(m, n, p) y crea una lista inmutable
de enteros que empieza en m y acaba justo antes de superar o igualar a n, aumentando
los valores de p en p. Si p es negativo, los valores van disminuyendo de p en p.
>>> range(4,18,0)
Traceback (most recent call last):/span>
File "<pyshell#0>", line 1, in <module>
range(4,18,0)
ValueError: range() arg 3 must not be zero
Si p es positivo y n menor o igual que m, o si p es negativo y n mayor o igual que m,
se crea un range vacío.
En los range( m, n, p), se pueden escribir p range distintos que generan el mismo
resultado. Por ejemplo:
m: el valor inicial
n: el valor final (que no se alcanza nunca)
p: el paso (la cantidad que se avanza cada vez).
28
Si se escriben sólo dos argumentos, Python le asigna a p el valor 1. Es decir range(m,
n) es lo mismo que range(m, n, 1)
29
2.4.3 La función len()
La función len() devuelve la longitud de una cadena de caracteres o el número de
elementos de una lista. El argumento de la función len() es la lista o cadena que
queremos "medir".
El valor devuelto por la función len() se puede usar como parámetro de range().
30
2.5 OPERADORES
Los operadores son símbolos matemáticos que llevan a cabo una operación específica
entre los operandos y tienen una función en específico. Los operadores reciben
pueden recibir operandos variables. Los operandos serian aquellos argumentos que
reciben los operadores para realizar su función..
Hay diferentes operadores y mas te vale conocerlos a todos!! Porque son de gran
utilidad en el uso de condiciones y funciones entre otras cosas como dije son un
elemento crucial en la programación! Veamos los tipos y cuales son:
>>> 3 + 2
31
>>> 4 - 7
-3
>>> -7
-7
>>> 2 * 6
12
>>> 2 ** 6
64
>>> 3.5 / 2
1.75
>>> 3.5 // 22
1.0
32
No obstante hay que tener en cuenta que si utilizamos dos operandos enteros, Python
determinará que quiere que la variable resultado también sea un entero, por lo que el
resultado de, por ejemplo, 3 / 2 y 3 // 2 sería el mismo: 1. Si quisiéramos obtener los
decimales necesitaríamos que al menos uno de los operandos fuera un número real,
bien indicando los decimales:
r = 3.0 / 2
O bien utilizando la función float() para convertir a entero coma flotante o real:
r = float(3) / 2
Esto es así porque cuando se mezclan tipos de números, Python convierte todos los
operandos al tipo más complejo de entre los tipos de los operandos.
El operador módulo no hace otra cosa que devolver el resto de la división entre los dos
operandos. En el ejemplo, 7 / 2 sería 3, con 1 de resto, luego el módulo es 1.
>>> 7 % 2
1. Exponente: **
2. Negación: -
3. Multiplicación, División, División entera, Módulo: *, /, //, %
4. Suma, Resta: +, -
>>> 2**1/12
0.16666666666666666
>>>
33
Más igualmente se puede omitir este orden de precedencia de ejecución de los
operadores aritméticos usando paréntesis () anidados entre cada nivel calculo, por
ejemplo:
>>> 2**(1/12)
1.0594630943592953
>>>
2.5.1.10 Ejemplos
print a + b
print c - a
print d * c
print c ** 2
print float(c) / a
34
Ejemplo de operador aritmético División entera.
print 7 / 3
print a // c
print 7 % 3
2.5.2.1 Operador =
2.5.2.2 Operador +=
>>> r = 5; r += 10; r
15
15
2.5.2.3 Operador -=
>>> r = 5; r -= 10; r
-5
>>> r = 5; r = r - 10; r
-5
2.5.2.4 Operador *=
>>> r = 5; r *= 10; r
50
>>> r = 5; r = r * 10; r
50
2.5.2.5 Operador /=
>>> r = 5; r /= 10; r
36
0
>>> r = 5; r = r / 10; r
9765625
>>> r = 5; r = r ** 10; r
9765625
>>> r = 5; r = r // 10; r
37
2.5.2.8 Operador %=
>>> r = 5; r %= 10; r
>>> r = 5; r = r % 10; r
Es frecuente que una variable tenga que ser definida de nuevo en función
de sí misma. Normalmente se escribir la siguiente sintaxis:
>>> contador += 1
2.5.2.10 Ejemplos
a, b, c = 21, 10, 0
38
print "Valor de variable 'b':", b
c=a+b
c += a
c *= a
c /= a
c=2
c %= a
c **= a
c //= a
39
2.5.3 Operadores relacionales
Los valores booleanos son además el resultado de expresiones que utilizan
operadores relacionales (comparaciones entre valores):
2.5.3.1 Operador ==
El operador == evalúa que los valores sean iguales para varios tipos de datos.
>>> 5 == 3
False
>>> 5 == 5
True
>>> "Plone" == 5
False
True
True
2.5.3.2 Operador !=
>>> 5 != 3
True
>>> "Plone" != 5
True
True
40
2.5.3.3 Operador <
El operador < evalúa si el valor del lado izquierdo es menor que el valor del lado
derecho.
>>> 5 < 3
False
El operador > evalúa si el valor del lado izquierdo es mayor que el valor del lado
derecho.
>>> 5 > 3
True
El operador <= evalúa si el valor del lado izquierdo es menor o igual que el
valor del lado derecho.
>>> 5 <= 3
False
El operador >= evalúa si el valor del lado izquierdo es mayor o igual que el
valor del lado derecho.
>>> 5 >= 3
True
2.5.3.7 Ejemplos
41
2.5.3.8 Ejemplo de definir variables numéricas
a, b, a1, b1, c1 = 5, 5, 7, 3, 3
lista1, lista2 = [1, 'Lista Python', 23], [11, 'Lista Python', 23]
c = a == b
print c
print cadenas
print listas
d = a1 != b
print d
print cadena0
f = b1 < a1
print f
42
2.5.3.12 Ejemplo de operador relacional Mayor que
e = a1 > b1
print e
h = b1 <= c1
print h
g = b1 >= c1 print g
Estos son los distintos tipos de operadores con los que puede trabajar con
valores booleanos, los llamados operadores lógicos o condicionales:
False
2.5.4.2 Operador or
True
43
2.5.4.3 Operador not
False
True
2.5.4.4 Ejemplos
a, b = 10, 20
if (a and b):
else:
if (a or b):
44
"o ambas variables son VERDADERAS."
else:
else:
45
2.6 APLICACIONES DE LAS LISTAS
Las listas en Python tienen muchos métodos que podemos utilizar, entre todos ellos
vamos a nombrar los más importantes. Para esto utilizaremos esta lista de ejemplo.
Sobre esta vamos a realizar diferentes métodos que son propios de las listas.
Append()
Este método nos permite agregar nuevos elementos a una lista.
my_list.append(10) # [2, 5, 'DevCode', 1.2, 5, 10]
my_list.append([2,5]) # [2, 5, 'DevCode', 1.2, 5, [2, 5]]
Podemos agregar cualquier tipo de elemento a una lista, pero tengan en cuenta lo que
pasa cuando agregamos una lista dentro de otra, esta lista se agrega como uno y solo
un elemento.
Extend()
Extend también nos permite agregar elementos dentro de una lista, pero a diferencia
de append al momento de agregar una lista, cada elemento de esta lista se agrega
como un elemento más dentro de la otra lista.
my_list.extend([2,5]) # [2, 5, 'DevCode', 1.2, 5, 2, 5]
Remove()
El método remove va a remover un elemento que se le pase como parámentro de la
lista a donde se le esté aplicando.
my_list.remove(2) # [5, 'DevCode', 1.2, 5]
En este ejemplo estamos removiendo el elemento 2, de la lista que tiene por nombre
"my_list".
Index()
Index devuelve el número de indice del elemento que le pasemos por parámetro.
my_list.index('DevCode') # 2
Aquí estamos preguntando por el indice de la cadena 'DevCode' dentro de la lista
"my_list", esto devuelve 2.
Count()
Para saber cuántas veces un elemento de una lista se repite podemos utilizar el
metodo count().
my_list.count(5) # 2
46
Contamos cuantas veces se repite el número 5 dentro de la lista, y esto devuelve 2.
Reverse()
También podemos invertir los elementos de una lista.
my_list.reverse() # [5, 1.2, 'DevCode', 5, 2]
Estas son algunos de los métodos más útiles y más utilizados en las listas.Python es
un gran lenguaje de programación que hace las cosas de una manera realmente
sencilla
1jugadores.append('Mayada')
jugadores.insert(2, 'Casco')
1jugadores.insert(2, 'Casco')
47
1 jugadores.pop(5)
2 jugadores.pop()
Cuando una lista contiene muchos elementos puede resultar difícil precisar a simple
vista si un valor específico está incluido en la misma. Lo mismo sucede si tenemos que
procesar la lista utilizando un script o un programa. Para verificar la existencia de un
ítem dentro de una lista utilizaremos la palabra clave in (o not in) de la siguiente
manera. El resultado será un valor booleano que indicará la respuesta:
48
2.7 ÁRBOLES
Los Árboles son las estructuras de datos más utilizadas, pero también una de las más
complejas, Los Árboles se caracterizan por almacenar sus nodos en forma jerárquica
y no en forma lineal como las Listas Ligadas, Colas, Pilas, etc., de las cuales ya hemos
hablado en días pasados.
49
2.7.1 Datos importantes de los Árboles
Para comprender mejor que es un árbol comenzaremos explicando cómo está
estructurado.
50
2.7.2 Recorrido sobre Árboles
Los recorridos son algoritmos que nos permiten recorrer un árbol en un orden
específico, los recorridos nos pueden ayudar encontrar un nodo en el árbol, o buscar
una posición determinada para insertar o eliminar un nodo.
Las búsquedas no informadas son aquellas en que se realiza el viaje por todo el árbol
sin tener una pista de donde pueda estar el dato deseado. Este tipo de búsquedas
también se conocen como búsquedas a ciegas.
A este tipo de escenarios en los cuales las búsquedas de hacen a ciegas los
conocemos como búsquedas no informadas.
51
2.7.2.2 Búsqueda en profundidad
Esta definición puede ser un poco compleja de entender por lo que mejor les dejo la
siguiente imagen.
52
Para comprender mejor esta definición observemos la siguiente imagen:
En la imagen podemos observar cómo se realiza el recorrido en Post-Orden, Sin embargo, es importante
notar que el primer nodo que se imprime no es la Raíz pues en este recorrido la Raíz de cada Sub-Árbol es
procesado al final, ya que toda su descendencia ha sido procesada.
53
En la imagen se muestra como es el recorrido In-Orden, Podemos apreciar que la Raíz no
es el primero elemento en ser impreso pues este recorrido recorre su rama izquierda, luego
la raíz del sub-árbol y luego la rama derecha.
54
2.7.2.3 Búsqueda en amplitud.
Se recorre primero la raíz, luego se recorren los demas nodos ordenados por el nivel
al que pertenecen en orden de Izquierda a derecha.
Este tipo de búsqueda se caracteriza por que la búsqueda se hace nivel por nivel y de
izquierda a derecha.
55
Si observamos el código de forma minuciosa podemos observar dos puntos muy
interesantes, el primero es que esta función no es recursiva, y la segunda es que se
utiliza una Cola para controlar el flujo del recorrido.
Un árbol binario es un árbol que tiene máximo dos nodos descendientes (izquierdo y
derecho). Se define una clase llamada ‘Arbol’
class Arbol(object):
def __init__(self):
self.der = None # Rama derecha del árbol
self.izq = None # Rama izquierda del árbol
self.dato = None # Dato del nodo del árbol
raiz = Arbol()
raiz.dato = 'Raiz'
raiz.izq = Arbol()
raiz.izq.dato = 'Izquierda'
raiz.der = Arbol()
raiz.der.dato = 'Derecha'
print(raiz.izq.dato)
56
De esta misma forma se puede ir aumentando el tamaño del árbol y agregándole mas
información:
class Arbol(object):
def __init__(self):
self.der = None
self.izq = None
self.dato = None
raiz = Arbol()
raiz.dato = 'Raiz'
raiz.izq = Arbol()
raiz.izq.dato = 'Izquierda'
raiz.der = Arbol()
raiz.der.dato = 'Derecha'
raiz.izq.izq = Arbol()
raiz.izq.izq.dato = 'Izquierda 2'
raiz.izq.der = Arbol()
raiz.izq.der.dato = 'Izquierda - Derecha'
Lógicamente, si se quiere definir un árbol que no sea binario, entonces se aumentan
las posibles ramas en ‘__init__’:
class Arbol(object):
def __init__(self):
self.der = None
self.der2 = None
self.cent = None
self.izq = None
self.izq2 = None
self.dato = None
57
2.8 EVALÚACIÓN PEREZOSA
En programación la evaluación perezosa, o llamada por necesidad, o por su nombre
en inglés: lazy evaluation. Es una técnica de evaluación, que consiste en retrasar el
cálculo (o ejecución) de una instrucción hasta que en realidad es necesaria.
Por ejemplo, para calcular el segundo primo entre 10000 y 100000 podemos hacer:
ls = srange(10000,100000)
primos = [t for t in ls if is_prime(t) ]
print primos[1]
pero esto nos obliga a guardar en memoria todos los números naturales entre 10000
y 100000, y después a calcular si cada uno es primo, sólo para quedarnos con el
segundo.
sage: %time
sage: ls = srange(10000,100000)
sage: primos = [t for t in ls if is_prime(t) ]
sage: print primos[2]
10037
CPU time: 0.39 s, Wall time: 0.39 s
Sin embargo, es posible mantener esta sintaxis sin hacer cálculos innecesarios. Para
ello, se usan generadores , objetos que generan los elementos de la lista uno por uno,
según se vayan solicitando desde otras partes del programa. A esta técnica se le
denomina evaluación perezosa, porque no se hacen cálculos hasta que no son
necesarios.
sage: srange(100)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
97, 98, 99]
sage: xsrange(100)
<generator object generic_xsrange at 0x5dacf50>
58
Una vez creado el generador, podemos pedir los números uno por uno, usando el
método next() , o recorrerlos todos, usando un bucle for igual que si fuera una lista:
Ahora podemos modificar el programa original para calcular el segundo primo entre 10000 y
100000, usando una cantidad de memoria y cpu equivalente a un programa tradicional:
sage: %time
sage: ls = xrange(10000,100000)
sage: primos = (t for t in ls if is_prime(t) )
sage: primos.next()
sage: print primos.next()
10009
CPU time: 0.01 s, Wall time: 0.01 s
sage: %time
sage: contador = 2
sage: for j in xsrange(10000,100000):
... if is_prime(j):
... contador -= 1
... if contador == 0:
... break
sage: print j
10009
CPU time: 0.00 s, Wall time: 0.00 s
59
Siguiendo la ejecución del programa paso a paso:
ls = xrange(10000,100000)
primos = (t for t in ls if is_prime(t) )
con estas dos líneas, se definen dos generadores, pero no se realiza ningún cálculo.
primos.next()
al llamar al método next , ponemos a trabajar al generador primos , que debe rodar
hasta devolver un número primo. Para ello, prueba los números de la lista ls uno por
uno. Cuando encuentra uno que pasa el filtro is_prime(t) , lo devuelve. En la primera
llamada a next , primos devuelve el número 10007, el primer primo mayor que 10000.
print primos.next()
pedimos otro número más a primos , que pide a su vez números al generador ls
continuando donde lo dejó. Recorre primero el número 10008 e inmediatamente
después encuentra 10009, que es primo. El programa concluye.
60
REFERENCIAS BIBLIOGRÁFICAS
FUENTE SUBTEMA
61
COVANTEC. (16 de Julio de 2015). Operadores Relacionales. Recuperado el 14
de Septiembre de 2019, de COVANTEC: https://entrenamiento-python-
2.5.3
basico.readthedocs.io/es/latest/leccion3/operadores_relacionales.html
62