Beruflich Dokumente
Kultur Dokumente
Licenciatura en Matemticas
9 cuatrimestre
Computacin II
Clave:
050930936
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
ndice
Unidad 1. Estructuras de datos y anlisis de algoritmos .................................................... 4
Presentacin de la Unidad ................................................................................................. 4
Propsitos de la unidad...................................................................................................... 4
Competencia especfica ..................................................................................................... 5
1.1. Introduccin ................................................................................................................ 5
1.1.1.
1.1.2.
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
1.4.2. Pilas ..................................................................................................................... 54
1.4.3. Heaps ................................................................................................................... 55
1.4.4. rboles ................................................................................................................. 56
1.4.5. Funciones y tablas de hash .................................................................................. 58
Actividad 4. Estructuras de datos ..................................................................................... 60
Autoevaluacin ................................................................................................................ 60
Evidencia de aprendizaje. Diseo de algoritmo........................................................... 60
Autorreflexiones ............................................................................................................... 61
Cierre de la Unidad .......................................................................................................... 61
Para saber ms ............................................................................................................... 61
Referencias Bibliogrficas ................................................................................................ 62
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Unidad 1. Estructuras de datos y anlisis de algoritmos
Presentacin de la Unidad
Las computadoras son popularmente vistas como aparatos electrnicos capaces de efectuar
clculos inmediatos, pero este concepto est incompleto, ya que esas son nicamente las
computadoras digitales. Entonces, es importante aclarar el concepto de computadora con el que
vamos a trabajar. Una computadora es un dispositivo capaz de mapear valores entre un par de
conjuntos a travs de una serie de pasos finitos que se denominan algoritmos. El modelo de
Turing (Turing, 1936) es el modelo matemtico que fundamenta la descripcin de las
computadoras digitales con las que trabajas, y que fue posteriormente implementado en una
computadora electrnica construida por von Neumann, a partir de quien se populariz el
concepto de programa almacenado. Estas computadoras, como todos saben, corren
programas para calcular valores. Sin embargo, un par de caractersticas del modelo de Turing
es hacer uso de una banda infinita donde leer o escribir la informacin procesada, as como un
conjunto de instrucciones que le dicen a la cabeza lectora si debe moverse a la derecha o
izquierda. En la prctica este particular aspecto guarda una diferencia abismal con la
computadora construida por von Neumann, ya que la posibilidad de recursos infinitos est fuera
de nuestro alcance, en tanto que respecto al conjunto de instrucciones, es fcil observar que
pueden agregarse instrucciones innecesarias para realizar algn cmputo deseado, o bien, el
caso complementario: es fcil suponer que existen algoritmos que hacen un uso innecesario de
instrucciones o espacio para poder realizar su cmputo.
En esta unidad aprenders a clasificar este conjunto de instrucciones, a la postre denominados
algoritmos, de acuerdo con su eficiencia. Aprenders a medir ciertos elementos que los hacen
ms eficientes, adems de conocer distintas estructuras de datos que son fundamentales para
hacer un uso ptimo de los recursos de la mquina, dependiendo del problema especfico que
tengas a la mano. Todo esto lo hars mediante un lenguaje de programacin actualmente muy
popular y sencillo de usar, llamado Python
Propsitos de la unidad
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Competencia especfica
Disear algoritmos para que hagan uso de los recursos computacionales de forma ptima
mediante las herramientas descritas en la teora de la complejidad computacional y el anlisis
de algoritmos.
1.1. Introduccin
En la presentacin de la unidad se mencionan un par de modelos tericos (uno de ellos
implementado) sobre las computadoras que actualmente usas; entre ellos est el modelo de
Turing que puedes ver en la figura 1. Otro ejemplo de computadora es el cerebro humano, ya
que tiene la capacidad de hacer clculos usualmente relacionados con valores alimentados a
travs de los sentidos, y cuyos clculos se pueden observar a travs de las decisiones o
acciones que tomas. Al igual que las computadoras digitales, es fcil ver que el cerebro humano
tiene una cantidad finita de recursos, como el espacio fsico donde se alberga, o bien, la
cantidad de conexiones sinpticas que son usadas y mantenidas comnmente a lo largo de la
vida de un individuo. En estos ejemplos se puede vislumbrar un compromiso entre rapidez y
exactitud, es decir, el uso eficiente de los recursos dependiendo del problema en cuestin.
El uso de una computadora para resolver problemas suele ser transparente a las necesidades
del usuario final, pero no debe ser as para el programador; es aqu donde los aspectos de
eficiencia se hacen patentes y ste es el punto que tendrs en mente todo el tiempo a lo largo
de esta unidad: el hacer uso de los recursos de la computadora de forma eficiente, o por lo
menos, no los perders de vista, y es que el que una mquina sea muy rpida para resolver
algoritmos con una entrada pequea (por pequea puede suponerse algo menor a una decena
de datos), no implica que esta relacin se conserva para una entrada con muchos ms datos
para el mismo algoritmo. Por ejemplo, no es lo mismo encontrar una ruta ptima en una grfica
con 5 nodos que con 200, de hecho, ese particular problema es un problema NP-Completo, lo
cual significa que para este tipo de problemas no se ha encontrado un algoritmo que pueda
resolverlo en tiempo polinomial, pero esto se definir con ms precisin ms adelante.
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Figura 2. Grafica con pesos en las cuales una es intrnsecamente ms sencilla de examinar que la otra por lo
tanto cualquier algoritmo para recorrerlas tardar ms en la segunda grfica.
En la figura 2 puedes ver un ejemplo del problema particular antes mencionado, problema
denominado usualmente como el Problema del Agente Viajero (TSP por sus siglas en ingls).
Este problema consiste en tener que visitar todos los nodos una sola vez, minimizando el
esfuerzo (o distancia) recorrida, representado en las grficas por los pesos en las aristas. Una
forma ingenua de resolverlo podra ser la siguiente:
1. Crear una lista vaca L
2. Escoger un nodo al azar y ponerlo al inicio de L
3. Viajar a cualquiera de sus vecinos y agregarlo a la lista L
4. Repetir el paso 3 hasta que todos los nodos estn visitados. Una vez hecho esto, la
lista L indicar el orden en el que hay que visitar esos particulares nodos para
completar un recorrido en la grfica que pase por todos los nodos.
5. Repetir desde el paso 1 hasta que todas las posibles rutas estn construidas
Pero es claro ver que este algoritmo, si bien es factible para la grfica a, es impensable para la
grfica b, y esta ltima no es ni siquiera comparable a la configuracin de una ciudad promedio.
En este punto es importante aclarar que este tipo de problemas (NP-Completos) no tienen
soluciones que ocupen un tiempo acotado de resolucin, y lo que se ha desarrollado hasta
ahora no son ms que aproximaciones heursticas, y no se ha tenido que conformar con alguna
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
aproximacin. As que, dicho esto, podra incluso hacerse otra propuesta de algoritmo para
resolver el TSP.
Crear un conjunto V vaco
Tomar
y
En este ltimo algoritmo se sabe que vas encontrar la mejor solucin posible que permita
buscar sobre la raz de N recorridos en la grfica; tal vez no sea la ptima, pero, por lo menos,
es una solucin factible de implementar en nuestras computadoras y completar en un tiempo
razonable.
Este tipo de compromiso es algo que se puede ponderar y optimizar, siempre y cuando tengas
claro alguna medida sobre algn algoritmo en particular.
(1)
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
El ttulo de esta subseccin hace una distincin implcita entre lo que son los datos y lo que es
la informacin. Esta distincin no es difcil de entender, y es que no es lo mismo tener una serie
de valores desligados, que agrupados bajo alguna estructura que infiera alguna secuencia
lgica de los mismos. No es lo mismo tener todos los nombres de los habitantes de la ciudad de
Mxico, as como sus respectivos telfonos de manera desordenada, que estructurados en una
gua telefnica ordenada alfabticamente.
Entonces, algo importante que puede decirse sobre lo que es la informacin, es que est
estructurada con algn patrn discernible. Ms an, ese patrn puede ser computable mediante
un algoritmo.
Para poder practicar las diferentes estructuras y algoritmos que vers en esta unidad, tienes
que usar una computadora y, particularmente, un lenguaje de programacin.
En este sitio puedes ver las opciones para bajar Python en distintas distribuciones. Si sigues la
primer liga (http://www.python.org/download/releases/), entrars a la siguiente pgina
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Una vez instalado, podrs ver las siguientes opciones en el men de inicio:
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Figura 5. Python instalado. Usaremos principalmente el Canopy command prompt, pero, si deseas, puedes
familiarizarte con la interfaz IDLE mostrada en la figura b.
Si eres usuario de Linux es muy probable que ya lo tengas instalado, y si no, es muy sencillo
instalarlo; depende de tu distribucin para lograr esto.
Python es un lenguaje de programacin interactivo, orientado a objetos, y de tipado dinmico,
as como con algunas caractersticas de un lenguaje funcional. Su principal motivacin es la de
crear cdigo entendible y restringir ms el laconismo que caracteriza a C o Java. Para hacer
esto, en Python la identificacin de los programas no es despreciable; esto significa que el
margen izquierdo que caracteriza en el editor de scripts tiene un significado: el alcance de las
variables definidas en ese nivel, o bien, la definicin de un mbito concreto. Esto significa que
todas las variables que defina en cierto nivel pueden ser ledas en ese nivel o en aquellos
donde la identacin es mayor. Identar un texto se refiere a alinearlo con un margen izquierdo
mayor que el nivel anterior. El nivel de identacin original es el margen 0. Si identaras el texto
un nivel, por ejemplo, al margen izquierdo 4, entonces todo el texto que estuviera alineado al
margen 4 estara a un nivel de identacin. En el caso concreto de Python, los distintos niveles
de identacin determinan el estilo de codificacin que seguirs, ya que es la manera en que
este lenguaje decide qu lneas pertenecen o no a un mismo bloque de cdigo.
A continuacin puedes ver un par de ejemplos, uno de ellos correcto y el otro incorrecto.
Ejemplo
>>> i = 4
>>> for j in range(5):
...
print i,j
...
4 0
>>> i = 4
>>> for j in range(5):
... print i,j
File <stdin>, line 2
print i,j
10
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
4 1
4 2
4 3
4 4
>>>
En este par de ejemplos puedes ver, en el panel A, un uso correcto de la identacin en Python.
La lnea que contiene el print es correctamente ejecutada dentro del ciclo del for en la lnea
anterior, que es como est definida la sintaxis en Python. Por otro lado, en el panel B puedes
ver el uso incorrecto de esto, ya que el uso del for es idntico al del panel B, con el nico
cambio en que la lnea con print est pegada al lado izquierdo, y no correctamente indentada.
Por cierto, lo que el for est diseado a ejecutar en ambos ejemplos es imprimir el valor de la
variable i, que est fijo en la primera lnea, y el de j, que va variando conforme se llevan a cabo
iteraciones del for. Es decir, est diseado para imprimir la pareja ordenada (i,j) como puedes
ver en el panel A.
En esta seccin vers un tutorial extremadamente condensado sobre el uso y sintaxis de
Python, lo cual es necesario para poder comprender el resto de la unidad, pero se dejarn una
serie de ligas y libros para que puedas profundizar en el uso de este lenguaje.
Uso Bsico
Los scripts de Python son archivos de texto, es decir, tienes que editarlo con el notepad,
notepad++, o cualquier editor que deje los archivos en texto claro, y al final le vas a anexar, por
convencin, la extensin de archivo py, sin espacios o caracteres especiales en los nombres.
Los siguientes son ejemplos vlidos de nombres de script en Python:
- tree.py
- Hola_mundo.py
- basico1.py
Y los siguientes son ejemplos de nombres invlidos
- lo malo.py
- Nio.py
- Trmino.py
- Script
Para poder correr el siguiente ejemplo vas crear un directorio llamado computacin2 en el
directorio C:\
C:\computacion2
y dentro de l vas a copiar el siguiente contenido, tal cual:
-*- coding:utf8 -*for i in range(2,5):
print i, Hola Mundo
11
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
- en un archivo que se llamar hola_mundo.py, para despus ejecutarlo con Python como se
muestra a continuacin:
C:\computacion2> python hola_mundo.py
Para ejecutarlo tienes que abrir el intrprete de comandos de Windows y cambiarte al directorio
especificado arriba. La ejecucin debe verse como a continuacin se presenta:
(Canopy 32bit) C:\computacion2>python hola_mundo.py
2 Hola Mundo
3 Hola Mundo
4 Hola Mundo
Sugerencia: cambia el contenido del script que acabas de crear para que te salude a ti.
Sintaxis Bsica
Como todo lenguaje de programacin, Python tiene definido una sintaxis de operacin bsica
en la que est definido cmo hacer la asignacin de variables, cmo usar los operadores
aritmticos bsicos, las operaciones lgicas bsicas, la ejecucin de ciclos, la definicin de
clases, etctera. En esta seccin repasars algunos de estos puntos.
Asignacin y Cadenas
Python es un lenguaje de tipado dinmico, lo que quiere decir que no tiene palabras reservadas
para determinar si algn nmero es entero, flotante, o cualquier variante de sas que son
ampliamente usadas en otros lenguajes fuertemente tipados como Java. Los detalles sobre
cmo Python puede identificar la precisin del nmero con el que ests trabajando son ajenos a
este curso; sin embargo, de aqu en adelante usars la siguiente regla de asignacin de
variables sin mayor diferencia:
>>>
>>> var =
>>> print
45
>>> var =
>>> print
nombre
>>>
>>> var =
>>> print
0.445
>>>
45
var
nombre
var
0.445
var
Como puedes ver, sin mayor problema asignas no slo un valor, sino un tipo completamente
diferente de datos a la misma variable, y as es como funciona la asignacin de variables en
Python.
12
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Como puedes ver en la salida anterior, el uso de cadenas se hace a travs de envolver las
mismas con un par de comillas (), o bien, tambin puede hacerse con una comilla simple ()
siempre y cuando sea consistente, por ejemplo:
>>> var = cadena 1
cadena 1
>>> var = cadena 1
cadena 1
>>>
Un conjunto de funciones existentes en Python que vale la pena recordar son: len, str,
print, input. A continuacin puedes ver un ejemplo de cada una aplicada a la variable var
del ejemplo anterior
>>> len(var) #logitud de var
7
>>> str(12)
#convierte a cadena el argumento
12
>>> var=input(Otro nombre )
Otro nombre otromas
>>> print var
otromas
>>>
En los ejemplos anteriores es importante notar que len calcula la longitud del argumento que
hayas pasado, str convierte a cadena el argumento; es por esto que aparece envuelto en
comillas simples, y var recibe una cadena, ya que de otra forma fallara.
Listas
Otra caracterstica en la operacin de Python es su orientacin al manejo de listas, las cuales
se conforman de la siguiente manera.
Si deseas hacer una lista vaca, debes:
>>> L = []
O bien,
>>> L = list()
Si deseas hacer una lista con una cantidad ya conocida de elementos, lo que tienes que hacer
es lo siguiente:
>>> L = [1,2,3,6,8,a,algo,8, 3.2]
>>> Desayuno = [fruta, huevos, frijoles, tocino, cafe]
Para que puedas obtener (indexar) algn elemento de una lista previamente hecha, lo que
tienes que hacer es usar los parntesis cuadrados y el ndice del elemento requerido:
>>> L[4]
8
13
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
>>> Desayuno[0]
fruta
>>>
Observa que, al igual que en muchos lenguajes de programacin, el indexado de elementos
empieza en 0 y no en 1 como usualmente se hace en matemticas (o incluso en Matlab u
Octave).
Pero con Python se han esforzado mucho en hacer un uso eficiente y cmodo de las listas y
otro tipo de secuencias, por lo que la siguiente notacin, aunque no es estndar, te ayudar
mucho a poder manipularlas con comodidad.
Si deseas obtener todos los elementos de una lista cuyos ndices sean, por ejemplo, el 3, 4 y 5,
lo que tienes que hacer es pasar entre corchetes los ndices 3 y 6, separados por dos puntos de
la siguiente forma:
>>> L[3:6]
[6, 8, a]
>>>
Es decir, entre corchetes pasas el ndice donde quieras empezar a tomar la subsecuencia
(slice) y el ndice siguiente de donde quieras que termine; o sea, si tu subsecuencia va del
ndice i al ndice j, entonces, entre corchetes, pasas desde i hasta j+1.
Si quieres todos los elementos de una lista a partir del elemento 2 (o bien, lo puedes generalizar
del n-simo elemento en adelante), lo que tienes que haces es:
>>> Desayuno[2:]
[frijoles, tocino, cafe]
>>>
Puedes pasar ndices negativos. Por ejemplo, si pasas Desayuno[-1], lo que obtienes es:
>>> Desayuno[-1]
caf
>>>
O bien, puedes pedir toda la subsecuencia de los ltimos dos elementos de la lista Desayuno
de la siguiente manera:
>>> Desayuno[-2:]
caf
>>>
Esta instruccin puede ser interpretada en lenguaje natural como: dame los elementos de la
lista Desayuno, empezando dos antes de terminar.
14
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Pero quieres los elementos de la lista Desayuno, dejando fuera los ltimos dos elementos,
entonces
>>> Desayuno[:-2]
[fruta, huevos, frijoles]
>>>
Si lo que quieres es obtener una copia de los valores de una lista, lo que tienes que hacer es
ocupar el operador dos puntos (:) dentro de los corchetes sin acompaarlo de ningn nmero,
o sea:
>>> P = L[:]
>>> P
[1, 2, 3, 6, 8, a, algo, 8, 3.2]
>>> L
[1, 2, 3, 6, 8, a, algo, 8, 3.2]
>>>
Es muy importante que recuerdes que as se copian los valores de una lista, ya que al hacer
una simple asignacin, como Q=L, lo que estaras haciendo sera referenciar la lista L con el
nombre Q.
>>>
>>>
>>>
[1,
>>>
Lo que significa que si haces un cambio en la lista Q, se ver reflejado tambin en L sin que sea
necesariamente lo que necesitas, y esto puede inducir a errores, ya que Python no lanza una
excepcin en este caso, pues as est diseado.
>>>
8
>>>
>>>
[1,
>>>
Q[4]
Q[4] = cambio
L
2, 3, 6, cambio, a, algo, 8, 3.2]
15
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
>>>
O bien, puedes concatenar varias veces el valor de alguna lista, por ejemplo:
>>> O = L*4
>>> O
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>>
En Python las cadenas de caracteres tambin son consideradas como listas, lo que significa
que el primer carcter de alguna cadena lleva el ndice 0, 1 el segundo, y as hasta el ltimo
carcter, el cual se puede saber haciendo uso de la funcin len, que dir la longitud total de la
cadena y, por lo tanto, el ltimo carcter tiene como ndice un nmero menor que lo que indique
esta funcin. Al ser tratadas como listas, podrs indexarlas de la misma manera que estas
ltimas.
>>> c = Hola Mundo
>>> len
10
>>> c[0]
H
>>> c[2:6]
la M
>>> c[-4:]
undo
>>> c[:-2]
Hola Mun
>>>
Existen otras estructuras extremadamente tiles que se mencionarn en su momento en caso
de que las ocupes, pero sera bueno que investigaras su funcin y las conocieras; se trata de
las tuplas y los diccionarios.
Operadores Aritmticos
Los operadores matemticos son un tema que prcticamente ya conoces porque son muy
similares al de otros lenguajes, excepto por algunas particularidades referentes a la conversin
de tipos en los nmeros.
Los operadores de suma, multiplicacin, divisin, potenciacin, negacin, etctera, los puedes
encontrar en la siguiente tabla:
16
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Operacin
Suma ## Resta
Multiplicacin ## Divisin
Potenciacin (a a la potencia b)
Mdulo (a mdulo b)
Negacin
Valor absoluto
Operador
a + b ## a- b
a * b ## a / b
a**b
a % b
-a
abs(a)
Una observacin importante es que si divides un entero entre otro entero, el resultado por
default es entero:
>>> a = 5/4
>>> a
1
>>>
Pero si lo que quieres es la expansin decimal, entonces tienes que hacer un truco como se
muestra a continuacin:
>>> a = float(5)/4
>>> a
1.25
>>> a = 5.0 / 4
>>> a
1.25
>>>
Observa el uso de la funcin float. Lo que hace est funcin es convertir en flotante el
argumento que le pases.
La jerarqua para aplicar estos operadores est determinada por la siguiente tabla. Primero se
ejecuta lo que haya entre parntesis, luego se evalan los exponentes, luego la multiplicacin y
divisin, y hasta el final, la suma y la resta.
1
Parntesis
2
3
4
Exponentes
Multiplicacin y Divisin
Suma y Resta
Los ejemplos para esta seccin son de tu conocimiento, ya que son prcticamente triviales.
17
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Operadores lgicos
Los valores lgicos en Python son el True y el False. Los operadores lgicos son el and, or
y not. La forma de checar la igualdad entre dos valores es igual que en muchos lenguajes, con
el doble igual (==)
Ejemplos
>>> a= 1
>>> b= 2
>>> c= 1
>>> a==b
False
>>> a==c
True
>>> not a
False
>>> not True
False
>>> d = 0
>>> not d
True
>>>
Para comprobar la relacin entre dos valores puedes usar los siguientes operadores, ==
(igualdad), > (mayor que), < (menor que), >= (mayor o igual), <= (menor o igual), y que
funcionan como en otros lenguajes que ya conoces
Relacin
Igualdad
Mayor / Menor que
Mayor igual / Menor igual que
Operador
a == b
a > b / a < b
a >= b / a <= b
Ciclos
Una de las partes ms importantes de un lenguaje de programacin es su control de flujo,
aspecto que se controla a travs de las instrucciones para establecer ciclos; en Python stas
son el for y el while.
La sintaxis del for es como sigue:
for variable in lista_de_valores:
Cuerpo del for
Se han marcado con rojo los elementos que no debes dejar pasar. Esta forma del for indica
que todas las lneas especificadas en el cuerpo se ejecutan tantas veces como valores tome
variable en la lista_de_valores. Presta particular atencin en los dos puntos al final de
18
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
la lnea que contiene al for, y en el tabulador que debe aplicarse a Todas las lneas dentro del
cuerpo del for; estos no son Opcionales.
A continuacin puedes ver un par de ejemplos de cmo invocar el for:
>>> for i in [1, 2, 3]:
...
print Linea , i
...
Linea 1
Linea 2
Linea 3
Aqu puedes ver cmo el cuerpo del for que consta de una sola lnea se ejecuta tantas veces
como valores toma la variable i dentro de la lista especificada. El siguiente ejemplo es un poco
ms complicado, no slo porque el for usa dos lneas, sino porque tambin se introducen dos
funciones nuevas que son str y range, as como la concatenacin de cadenas.
>>> for i in range(5):
...
print Esta es la linea , i
...
str(i) + El doble de + str(i) + es: +str(i*2)
...
Esta es la linea 0
0 El doble de 0 es: 0
Esta es la linea 1
1 El doble de 1 es: 2
Esta es la linea 2
2 El doble de 2 es: 4
Esta es la linea 3
3 El doble de 3 es: 6
Esta es la linea 4
4 El doble de 4 es: 8
>>>
La funcin range entrega una lista que va desde el valor inicial indicado en el parmetro hasta
el final, tambin indicado en el parmetro; cuando slo se indica un nmero, toma por defecto
que la lista comienza en 0 y acaba en ese nmero. Opcionalmente, tambin puedes indicarle
cuntos pasos debe dejar intermedios.
>>>
[0,
>>>
[2,
>>>
[2,
range(5)
1, 2, 3, 4]
range(2,5)
3, 4]
range(2,5,2)
4]
19
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
>>>
La funcin str convierte su argumento en una cadena con todas las propiedades de la misma,
particularmente con la propiedad de poderse concatenar a otras cadenas. En el ejemplo se
concatena el nmero i con la cadena El doble de, luego con el nmero i otra vez, luego
con la cadena es: para concatenarlo, finalmente, con el nmero que corresponde al doble
de i
str(i) + El doble de + str(i) + es: +str(i*2)
Observa cmo en este ltimo ejemplo ambas lneas tenan la misma indentacin y fueron stas
las que se ejecutaron mientras la variable i tomaba los valores especificados con range, a
saber 0, 1, 2, 3 y 4.
La funcin while es muy similar, y la diferencia radica en que el cuerpo del while se ejecuta
mientras la condicin lgica especificada se siga cumpliendo. La sintaxis es como sigue:
while condicin:
cuerpo del while
De igual forma, no debes perder de vista las partes resaltadas en rojo, as como el tabulador en
el cuerpo del while, ya que es forzoso ponerlas.
En el siguiente ejemplo puedes ver su funcionamiento:
>>> while x < valor:
...
print str(x) + es menor + str(valor)
...
x += 1
...
0 es menor 5
1 es menor 5
2 es menor 5
3 es menor 5
4 es menor 5
>>>
Observa cmo se ejecutaron las dos lneas en el cuerpo del while hasta que la condicin dej
de cumplirse. En la segunda lnea del cuerpo puedes notar que hay una instruccin atpica que
es
...
x += 1
Lo que en Python significa que la variable va a aumentar en 1 su valor. Esta instruccin tiene
la misma funcin que en Java o en C tiene la instruccin
x++
Con la diferencia de que en Python, en vez de poner 1, puedes poner el valor que desees.
20
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Imports
En Python, como en cualquier otro lenguaje, existen funciones preprogramadas o mdulos que
se qiueran incorporar al cdigo, lo cual se logra con la palabra reservada import. Por ejemplo
>>> import math
- incorpora todo un conjunto de funciones que puede intuirse que son de naturaleza
matemtica, y a las cuales vas a acceder a travs del operador . (punto), por ejemplo, la
funcin sqrt, que calcula la raz cuadrada, pertenece a este mdulo; entonces, para invocar a
la raz cuadrada, lo que tienes que hacer es lo siguiente:
>>> math.sqrt(25)
5.0
>>>
Otras formas equivalentes de importar las funciones de un mdulo son:
>>> import math as m
Lo que hace que tengas un alias para el mdulo math llamado m
>>> from math import sin
Lo que hace que importes la pura funcin sin, que dependa del mdulo math. Aunque esta
particular forma de importar funciones no es la mejor prctica de programacin, ya que puede
suceder que tengas redundancia de funciones en el mismo mbito de programacin.
Con esto tienes una introduccin muy bsica pero bastante robusta para entender cualquier
programa en Python.
Para saber ms
http://en.wikibooks.org/wiki/Python_Programming/Sequences
http://docs.python.org/2/tutorial/datastructures.html
http://docs.python.org/2/library/stdtypes.html
21
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
5. Enva el documento a tu Facilitador(a) y espera su retroalimentacin.
* Recuerda consultar la Escala de evaluacin de la actividad para saber qu aspectos se
tomarn en cuenta para su revisin.
22
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Short
Int o Integer
Long
Float
Double
Este tipo de datos son usados para los clculos ms bsicos y son comnmente asociados al
modelo de tipado esttico, es decir, se usan en aquellos lenguajes donde se debe declarar a
qu tipo pertenece cada variable.
Bajo el modelo de tipado dinmico de Python esta asignacin es transparente, excepto por las
ocasiones en las que explcitamente necesites mapear una variable a un tipo entero o flotante.
Para saber ms
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
struct entrada{
int edad;
char [100] nombre;
char [10] telefono;
};
23
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Figura 6. Struct que ilustra la implementacin de la entrada en una agenda telefnica.
Qu aporte tiene un tipo de dato struct sobre definir las variables por separado? La ventaja de
definir tipos compuestos de esta forma es la de proveer consistencia en el manejo de
variables dentro del programa y dejar que el lenguaje de programacin se encargue de asignar
los valores necesarios en memoria.
Esto no puede parecer una gran ventaja basada en ciencia y anlisis, y parece recaer
nicamente en una implementacin basada en la heurstica y diseada para fomentar la
comodidad del programador. Esto no es enteramente falso, pero no es la nica razn. Al
incorporar a tu modelo tipos compuestos, tambin facilitas la tarea de incorporar
consistentemente operaciones propias del dominio al que corresponda el tipo struct en
cuestin. El ejemplo ms sencillo del que se puede valer es el de los nmeros complejos,
aquellos que se componen de una parte real y una imaginaria, mas ambos valores son nmeros
reales, al menos en el modelo matemtico. La forma en la que puedes incorporar esto en un
struct es la siguiente:
struct complejo {
float parte_real;
float parte_compleja;
};
Al tener un tipo de datos como el mostrado en la figura 6 puedes implementar los axiomas que
operan sobre los nmeros complejos con ms facilidad. Por ejemplo, la suma de dos complejos,
como sabes, se realiza sumando las partes reales y las partes imaginarias correspondientes. El
resto de los axiomas sobre la operacin sobre nmeros complejos como el conjugado de un
nmero, la multiplicacin, etctera, preservan esta simplificacin incorporada en el momento en
que encapsulas todo un concepto en un espacio en memoria.
Otro tipo de dato compuesto es el enum, y la finalidad en su diseo es la de especificar
variables en las que hay una secuencia implcita en un conjunto de valores. El ejemplo ms
sencillo son de tipo temporal, por ejemplo, los das de la semana o los meses del ao.
enum semana { dom, lun, mar, mie, jue, vie, sab } semanaX;
24
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Entonces, lo que hay que resaltar en esta transicin desde los tipos primitivos hasta los
compuestos, es el concepto de encapsulacin de los axiomas y propiedades concernientes al
dominio modelado con estos tipos de datos ms complejos.
Para saber ms
Data Structures: Abstract Data Types. En lnea http://www.youtube.com/watch?v=HcxqzYsiJ3k
25
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
lograr, ya que cada persona percibe su entorno de manera distinta. Si te hace sentir mejor, no
debes olvidar el refrn
Todos los modelos son malos, pero algunos sirven mejor que otros.
Todo esto viene a cuento porque las computadoras son las herramientas de modelacin por
excelencia, y las computadoras digitales son las ms usadas actualmente. Esto los logrars
haciendo uso de lenguajes de programacin, que es donde vas a plasmar los modelos que
hagas en papel para poder obtener algn resultado medible.
Los tipos de datos abstractos (TDA) o tipos abstractos (Abstract Data Type o ADT en ingls)
son la abstraccin ms general que se puede hacer en un tipo de dato, y es que, a diferencia de
los structs, quienes incorporan nicamente los distintos componentes de un nuevo tipo de
dato o los tipos primitivos que se derivan bsicamente de la estructura del procesado, en los
TDA se hace una descripcin axiomtica de los elementos de un dominio incorporando las
propiedades, caractersticas y operaciones que actan sobre cada elemento del dominio. Es
decir, en la definicin del TDA se incorpora qu es lo que este nuevo tipo de dato tiene
permitido hacer, as como los elementos que lo componen.
Ejemplo: Puedes retomar el ejemplo de los nmeros complejos como un TDA. Como ya se dijo
y sabes, los nmeros complejos constan de dos nmeros reales que modelars con un par de
entradas flotantes, pero tambin constan de un conjunto de operaciones especficas de los
nmeros complejos como:
1.
2.
3.
4.
5.
El conjugado de un nmero
La suma de complejos
El producto de complejos
Una norma especfica
La igualdad entre dos nmeros complejos
Pero tambin puedes distinguir un par de constantes concretos de los Complejos,
1. Neutro aditivo
2. El nmero complejo
,
tal que
( )
( )
Cada una de estas funciones se opera de una forma muy especfica y no es la misma que la
multiplicacin de reales o de matrices; son funciones especficas de los complejos, entonces, si
defines un objeto que modele a los nmeros complejos, vas a querer que incorpore estas
funciones especficas concernientes a los complejos. Ests listo, pues, para la definicin de
objeto complejo.
TDA Complejo
Constantes:
26
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
0: Complejo
i: Complejo
Atributos:
real: Parte real <float>
imaginaria: Parte imaginaria <float>
Operaciones:
Igualdad:
Suma:
Producto:
Escalar:
Norma:
Operacin Igualdad
Recibe: c1 y c2 nmeros complejos
Regresa: z complejo
Regresa z
Operacin Norma
Recibe: c complejo
Regresa: z real
Regresa z
Operacin Escalar
Recibe: c complejo y r real
Regresa: z complejo
Operacin suma
Recibe: c1 y c2 complejos
Regresa: z complejo
Operacin multiplicacin
Recibe: c1 y c2 complejos
Regresa: z complejo
27
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Figura 9. Definicin del TDA para nmeros complejos y un par de prototipos de funciones para la suma y la
norma.
Lo importante de los TDA como el que se acaba de especificar es que en un tipo de dato de
computadora se han capturado todos los elementos, axiomas y propiedades, que describen al
campo de los nmeros Complejos correctamente bien encapsulado dentro de un objeto.
Los TDA pueden extenderse a objetos con una definicin formal ms laxa, pero la definicin
depende de tu habilidad como programador para identificar los elementos que componen
alguna problemtica especfica. Por ejemplo, podemos definir TDA sobre objetos que
pertenezcan al dominio de la biologa, los cuales tienen una serie de caractersticas, as como
un conjunto de funciones ms o menos conocidas.
Clase
Hasta ahora el concepto de TDA es una descripcin terica que describe a los elementos de un
dominio junto con sus operaciones. Una clase es la implementacin de un TDA en un lenguaje
de programacin, considerando los atributos (elementos caractersticos) y las funciones u
operaciones que actan sobre ellos. En el siguiente ejemplo puedes ver cmo se podra
implementar el TDA de nmero complejo presentado anteriormente en Python.
Ejemplo. Clase de nmero complejo implementada en Python
from math import sqrt
class Complejo(object):
Ejemplo de clase que implementa
numeros complejos en Python
def __init__(self, v=(0,0)):
Constructor
if v==(0,0):
self.real = 0.0
self.imag = 0.0
else:
self.real = v[0]
self.imag = v[1]
def __str__(self):
Regresa la representacion en cadena de este nmero con formato
a+bi
if self.imag == 0.0:
return str(self.real)
elif self.real == 0.0:
28
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
return str(self.imag) + i
else:
return str(self.real) + + + str(self.imag) + i
def suma(self, num2):
Suma el numero complejo actual con num2
self.real += num2.real
self.imag += num2.imag
def multiplicacion(self, num2):
Multiplica el numero complejo actual con num2
self.real = self.real * num2.real - self.imag * num2.imag
self.imag = self.real * num2.imag + self.imag * num2.real
def por_escalar(self, r):
Multiplica el nmero actual por el escalar r
self.real *= r
self.imag *= r
def absoluto(self):
Calcula el valor abosluto de un nmero
return sqrt(self.real**2 + self.imag**2)
El ejemplo anterior resulta un poco redundante, ya que los nmeros complejos ya estn
definidos nativamente en Python junto con todas sus definiciones, pero en l puedes ver la
finalidad de definir un TDA y, posteriormente, convertirlo en una clase en algn lenguaje de
programacin. Como puedes ver en el cdigo anterior, estn definidas algunas operaciones con
complejos, as como la estructura que todo complejo posee, una parte real y una imaginaria;
aparte de esto, puedes ver que hay dos funciones requeridas por Python, definidas __init__ y
__str__. La primera es el constructor del objeto y la segunda es una funcin para convertir un
objeto en cadena para as poder imprimirlo en pantalla
Sugerencia
Define, tomando como modelo las funciones definidas, la funcin conjugado que determine el
conjugado del nmero complejo actual.
29
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
un algoritmo, independientemente de la computadora o lenguaje de programacin que se est
usando.
Ya se ha hablado y referenciado el modelo de Turing como modelo de cmputo. El siguiente
ejemplo no es exactamente el modelo de Turing, pero en algo se asemeja. Antes de que
existieran las hojas de clculo, los contadores solan usar unas hojas tabuladas para escribir
sus datos. Este modelo de cmputo va a ser una hoja de clculo donde las instrucciones las
irs definiendo conforme cada problema vaya apareciendo. La mencin sobre las hojas
tabuladas es porque un modelo de cmputo usando una computadora puede no ser el ms
adecuado, pero si esto te llega a molestar, puedes pensar que ests trabajando con las
limitaciones que una hoja tabular impone.
La motivacin para ocupar una hoja de clculo como modelo de cmputo es que la memoria de
una computadora es bsicamente un arreglo de celdas direccionadas donde tus datos existen y
son manipulados.
Ejemplo: Considera los siguientes datos en una hoja de clculo
1
2
3
4
5
12
6
9
21
6
Donde la primer columna indica el ndice del elemento, y la segunda ndica el valor que ese
ndice representa. En todos los aspectos de computacin, encontrar algn valor particular de un
arreglo es particularmente requerido. A continuacin puedes ver un par de algoritmos diseados
para obtener el mximo de ese arreglo. Estn escritos en pseudocdigo, el cual seguramente
ya conoces, pero lo se volver a describir, ya que no es propiamente un lenguaje de
programacin, pero s es lo suficientemente genrico para poder ser implementado en uno,
salvo algunos aspectos tcnicos dependientes de cada lenguaje.
Algoritmo maximo1
Recibe: Arreglo K
Entrega: m, K[m] tal que 1<=m<=longitud(K), K[m] mximo en el arreglo
1. Inicializamos v = 0, m = -1
2. Id = 1
3. vact = K[id]
4. si vact > v entonces v = vact
30
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Para saber ms
Crescenzi, Pierluigi. A compendium of NP optimization problems. En lnea
http://www.csc.kth.se/~viggo/problemlist/
Bell R. A begginers guide to Big O Notation. En lnea http://rob-bell.net/2009/06/a-beginnersguide-to-big-o-notation/
31
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Todas estas consideraciones para considerar una instruccin bsica se deben bsicamente al
hecho de que, en un solo paso o ciclo del reloj, estas instrucciones pueden ser realizadas.
Particularmente, Python tiene un conjunto de instrucciones que no suceden precisamente en un
solo paso como, por ejemplo, la instruccin
x += 1
Son dos instrucciones bsicas, una es la operacin y la otra es la asignacin. Pero vers que
este particular detalle tpicamente no va a ser muy importante, como se detallar en un par de
prrafos.
Ve el siguiente segmento de cdigo
>>>
>>>
>>>
>>>
a =
n =
L =
for
M[0]
len(M)
range(n)
i in L:
if (M[i] > 5):
M[i] += a
>>>
Figura 10. Segmento de cdigo
El segmento de cdigo anterior lleva a cabo una operacin al inicio, cuando hace la asignacin
a = M[0] El conteo de operaciones va en 2, ya que se hizo una asignacin y una lectura de un
arreglo. Despus se hace una asignacin a n = len(M), lo que aumenta el contador a tres
instrucciones ejecutadas.
Despus se tiene una instruccin que asigna a L un arreglo con n enteros, lo que significa
aumentar el contador en 1, con lo que se llega a 4, pero despus la instruccin range(n) crea un
arreglo con n elementos enteros, lo que va a tomar n pasos. Entonces, el contador va en
.
Despus se ejecuta una operacin un tanto invisible, pero que se sabe que sucede, y es la
asignacin a i del primer elemento del rango de valores en L; el contador va ahora en
.
En este punto es donde la tarea de contar instrucciones empieza a complicarse un poco y esto
es por el uso del for, que son muy comunes en cualquier programa, y como puedes advertir,
van a aumentar el nmero de instrucciones ejecutadas tantas veces como entres en el for. En
32
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
este particular caso no vas a considerar la ltima instruccin contada, y la vas a cambiar por n
asignaciones a la variable i, con lo que tendrs al contador en
.
Si no entras ninguna vez al cuerpo del for, obtenedrs el siguiente conteo de instrucciones:
( )
Tiempo de ejecucin mximo
Ahora, el contar las instrucciones que estn contenidas en el cuerpo del for, como puedes ver,
no es trivial, ya que las condiciones pueden darse para que entre una sola vez al if, o bien,
tantas veces como elementos tenga el arreglo. Qu debes considerar entonces?
Lo que usualmente se hace es tomar el peor de los casos, es decir, vas a considerar que entras
tantas veces como elementos tiene el arreglo. Entonces, si entras a la evaluacin del if tantas
veces como elementos, tienes que contar dos instrucciones ms, una por la recuperacin del
elemento del arreglo M y otra por la comparacin, por cada vez que entras al ciclo; en otras
palabras, tienes que agregar
pasos al contador
( )
Pero, como ests considerando el tiempo mximo, tambin debes considerar que la evaluacin
del if es verdadera, con lo que debes considerar que entre al cuerpo del if, lo que arroja otras
tres instrucciones ms por cada vez que entres al for: una por la operacin aritmtica de sumar
4, otra por recuperar el valor de M[i], y la ltima por la asignacin; entonces, el conteo de
instrucciones final queda como
( )
A esto se le conoce como tiempo mximo de ejecucin, y se define de la siguiente manera
Definicin
El tiempo mximo de ejecucin
es el mximo nmero de pasos necesarios
para ejecutar un algoritmo ( ) con una entrada de tamao en una mquina de
Turing
( )
( )
(2)
| |
Este es el tipo de anlisis que vas a hacer con el cdigo; lo irs haciendo ms eficiente
conforme vayas avanzando en la unidad. En este caso, obtuviste el tiempo de cmputo para el
peor de los casos, aunque tambin se puede obtener el promedio de tiempo de cmputo, pero
este suele ser muy engorroso y, por lo pronto, no lo vas a considerar.
Comportamiento asinttico
Una pregunta que vale la pena hacerse es, qu tan importante es la expresin recin
encontrada para el segmento de cdigo presentado si para todo fin prctico sucede
instantneamente a nuestros ojos? La pregunta es vlida, y la respuesta es que es irrelevante
para arreglos pequeos, pero no as para arreglos cada vez ms grandes. Suponiendo este
33
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
ltimo caso, en el que cada vez el arreglo es ms grande, puedes notar que el trmino 4 de la
expresin anterior es cada vez menos significativo que el trmino 7n.
Precisamente porque piensas usar los algoritmos con entradas grandes, es decir,
los
trminos independientes no hacen diferencia alguna; de hecho, nicamente vas a considerar el
trmino dominante del tiempo de cmputo, lo que vas a representar mediante la notacin
( ( )), denotada como la asntota de ( ). La asntota del ejemplo revisado es
( )
Esto recibe una definicin especfica y se le denomina Cota Superior Asinttica ( ( )), o bien,
un trmino ms informal y popular, O grande.
Definicin
Se dice que una funcin ( ) est acotada superiormente, o dominada, por la funcin
( ) si para algn
y para una constante se cumple que
( )
( )
(3)
como:
Se usa el menor o igual porque, aunque basta con que lo cumpla, tambin interesan las
constantes que hacen que hagan a la asntota mayor que la funcin que quieres acotar.
Ejemplo:
La funcin ( )
es de orden ( ). Para poder ver esto tienes escoger
Entonces podrs verificar fcilmente que
34
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Figura 11. Dominio en el crecimiento de la funcin en verde que es sobre la roja que representa a
Ejemplo: La funcin ( )
tal que
Esto significa que
NO es de orden (
que no es posible.
Otra definicin que conviene introducir es la ( ( )), que funciona como complemento al de
( ( )), es decir, la funcin que acota inferiormente a ( )
Definicin
Se dice que una funcin ( ) est acotada inferiormente por la funcin ( ) si para
algn
y para una constante se cumple que
( )
( )
(4)
35
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
( ) no crece ms rpido que ( )
o bien
( ) crece a lo ms tan rpido que ( )
Entonces, se puede empezar a trabajar con esta definicin para construir algoritmos ms
complejos y determinar el orden por el que estn dominados. Es decir, surge la pregunta, cul
es el orden de un algoritmo que consta de ejecutar un algoritmo seguido de otro?
Teorema
Si tienes dos algoritmos
y , cada uno con un tiempo mximo de cmputo ( ) y
( ) y de orden ( ( )) y ( ( )) respectivamente, entonces el orden del algoritmo
, que consta de ejecutar secuencialmente cada uno de los dos algoritmos, es de
. ( ( ))
(1)
( ( ))/.
Demostracin
La demostracin es muy sencilla. El tiempo mximo de cmputo de
Sabes que
( ( ))
( ( ))
Esto quiere decir que existen
es
( )
( )
( ).
tales que
( )
( )
*
+ para garantizar que tienes un punto en el que no se
Escoge entonces a
viole dicha definicin. Sumando estas expresiones obtienes
( )
( )
*
Al construir as a
y has demostrado que al concatenar dos algoritmos, su complejidad
queda acotada por la cota ms grande de los algoritmos que la componen, i.e.
* ( ) ( )+)
( )
(
Otra propiedad fundamental es la de ejecutar un algoritmo
dentro del algoritmo , un
ejemplo de lo cual sera ejecutar un for dentro de otro for. Qu complejidad tiene asociada
esta composicin de algoritmos?
36
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Teorema
Si tienes dos algoritmos
y , cada uno con un tiempo mximo de cmputo ( ) y
( ) y de orden ( ( )) y ( ( )) respectivamente, entonces el orden del algoritmo
, que consta de ejecutar
como una instruccin de , tiene una complejidad de
( ( ) ( )).
Demostracin
El tiempo mximo de cmputo del algoritmo
dentro de la ejecucin de
vas a ejecutar
(2)
( )
es de
( ); esto se sigue de que
como una de las instrucciones que lo componen.
Se sabe que
( ( ))
( ( ))
Esto quiere decir que existen
tales que
( )
( )
*
+, entonces puedes garantizar que tienes un punto en el que no
Si escoges
se viola esa definicin, y por lo tanto, puedes multiplicar estas dos expresiones.
( )
( ) (
) ( ( ) ( ))
As, pues, has construido
Las funciones que usualmente se ocupan para establecer un marco de referencia son las
siguientes:
37
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
( ))
( ))
(
Nombre
Constante
Logartmica
Cuasi lineal
Cuadrtica
Cbica
Exponencial
Donde claramente la que crece ms rpido es . Pero es interesante resaltar el hecho que se
aprecia en la grfica. De hecho, ese crecimiento es exponencial segn la entrada,
y eso es fcil de ver, ya que si la complejidad de un algoritmo crece tan rpido, apenas
doblando el tamao de su entrada, es fcil suponer que los recursos para ejecutarlo se
terminarn igual de pronto.
38
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Todos estos tipos de resultados son el fundamento para determinar qu tanto puede tardar un
algoritmo en ejecutarse en toda su entrada, y a partir de este esquema de comparacin se
podr determinar si los algoritmos son ms o menos eficientes.
En este segmento de cdigo puedes ver que en la lnea In[17] hay un for dentro de otro.
Primero analizas el ms anidado. En el peor de los casos se va a ejecutar la comparacin y la
lnea del print, esas son dos lneas por cada elemento de M.
( )
Y este for, el que regula el ndice j, se va a ejecutar tantas veces como el que regula el ndice i,
por lo que la cuenta final queda
( )
39
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Es fcil encontrar
tal que
( )
De hecho, usando los teoremas antes vistos, y de aqu en adelante usars como resultado, que
cuando tengas una serie de fors anidados ( de ellos, por ejemplo), donde todos recorran un
arreglo, este segmento de algoritmo tendr una complejidad polinomial de ( ). Usualmente
, por lo tanto, en fors anidados, espera tener una complejidad de ( ).
Recursividad
Un algoritmo recursivo consta de dos caractersticas muy importantes. La primera es que hace
una llamada a s mismo con un argumento reducido, y la segunda es que contiene una clusula
de escape a la cual se llega cuando el argumento rebasa algn umbral predefinido.
( )
El ejemplo de funcin recursiva arriba escrito es la forma ms bsica de una funcin recursiva
en el que la clusula de escape se alcanza si el argumento rebasa un umbral que usualmente
puede pensarse como un entero, al que, en otro caso, le vas restando para poder alcanzar la
clusula de escape. Esto no tiene que ser forzosamente, ya que la funcin que altere el
argumento no necesariamente tiene que ser una resta, sino puede ser una funcin de tal forma
que converja a .
El primer algoritmo recursivo que puedes encontrar es el clculo de factorial, que es
bsicamente el primer ejemplo de recursividad que siempre se revisa. Su definicin matemtica
es la siguiente
{(
Aunque tambin se puede definir usando el operador de producto, por lo pronto esta definicin
te ayudar a hacer tu punto. A continuacin puedes ver el cdigo en Python:
In [1]: def factorial(n):
...:
return n*factorial(n-1) if n>1 else 1
Figura 14. Definicin de factorial en Python con una forma alternativa del if-else
40
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
( )
( )
.
{
/
.
Para analizar este algoritmo vas a determinar el tiempo mximo de cmputo. Para lograr esto
es fcil ver que el peor de los casos es cuando n es impar, ya que se llevan a cabo tres
multiplicaciones aparte de la reduccin del argumento. Lo que significa que
( )
. /
41
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
( )
. /
( )
. /
( )
. /
( )
( )
. /
. /
.
(
/
.
Es decir, en cada momento lo peor que tienes que calcular es la mitad del argumento ms una
constante por algunas operaciones elementales involucradas en ese paso de cmputo. En la
( )
funcin original se sabe que si
, entonces
. Esto, en trminos de tiempo de
cmputo, significa
( )
Como se desconoce la constante , puedes usar este hecho para conocerla. Para poder
obtener
. /
requieres que
, entonces
( )
( )
Es decir, la complejidad del algoritmo es logartmica y se puede afirmar que su orden es como
sigue
( )
( ( ))
No es difcil comprender este hecho, ya que en cada paso del que elegiste como de mayor
consumo de tiempo computacional, el tamao del argumento se reduce a la mitad. En la
siguiente seccin revisars otro ejemplo en el que se repite este hecho.
En general, el anlisis de algoritmos recursivos no es sencillo, y de los ejemplos que has visto
hasta el momento es fcil advertir la importancia que tiene el anlisis combinatorio en estos
temas, particularmente el uso de funciones generadoras. Para analizar algoritmos recursivos
usualmente se hace uso del llamado teorema maestro. Del que puedes ver una versin
simplificada a continuacin:
Teorema Maestro
Sean
y
tal que
relacin recurrente de la forma
( )
(5)
. Tambin sean
2
* +. Si tenemos la
( )
42
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Entonces, para potencia de se cumple alguna de estas proposiciones
( )
a) Si
( )
(
)
(
)
b) Si
c) Si
, ( )
(
)
Este teorema resulta muy prctico cuando se analizan algoritmos recursivos. Cabe aclarar que
la definicin de ( ( )) significa que la complejidad del algoritmo comparado es exactamente
( ). La demostracin de este teorema no la revisars en este contenido, ya que se requieren
ms herramientas y experiencia analizando algoritmos; su demostracin es usualmente parte
de un curso de anlisis de algoritmos.
Un problema muy particular de los algoritmos recursivos es que, aunque pueden ser muy
eficientes y elegantes, tienen que usar una estructura de los sistemas operativos denominada
pila de llamadas. En esta estructura el sistema va almacenando la ltima funcin a la que debe
contestarle; entonces, para argumentos no muy grandes de una funcin recursiva, esta
estructura se agota, as que al programar algoritmos recursivos hay que ser muy cuidadosos
con la cantidad de llamadas que en promedio vas a hacer con ella.
43
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Eliminacin de la recursin de cola
Una forma para convertir un algoritmo recursivo y convertirlo en iterativo es lo que se hace en la
eliminacin de la recursin de cola. Cuando se tiene un procedimiento ( ) con una llamada a
s mismo, se puede eliminar ese llamado pasando otra variable que sirva de contador y el
argumento modificado.
Considera el siguiente cdigo de Fibonacci en Python
In [1]: def fib(n):
...:
if n==0:
...:
return 1
...:
elif n==1:
...:
return 1
...:
else:
...:
return fib(n-1)+fib(n-2)
...:
Figura 16. Cdigo de Fibonacci(n) recursivo estndar.
Se puede eliminar la llamada a fib dentro del mismo cdigo, como puedes ver en el siguiente
ejemplo de Fibonacci iterativo.
In [6]: def fib2(n,v1=1,v2=1):
...:
L = [v1,v2]
...:
if n>=0 and n<2:
...:
return L[n]
...:
elif n>=2:
...:
for i in range(n-2): L.append(L[-1]+L[-2])
...:
return L
...:
Figura 17. Cdigo de Fibonacci(n) iterativo.
Se pueden evitar las llamadas recursivas incorporando una variable que guarde los resultados
de llamadas internas que seran regresadas por las llamadas de fib(n). En este caso se llama L,
y como puedes ver, vas guardando ah los subsecuentes resultados que de otra forma se
calcularan recursivamente. Esto permite calcular valores mucho ms grandes de Fibonacci que
de otra forma se acabaran la pila de llamadas a funciones de Python (por ejemplo, intenta
calcular fib(40) y fib2(40)).
Divide y vencers
Otra tcnica muy comn para resolver problemas es la de divide y vencers, en la que
dividimos el problema a la mano en subproblemas ms bsicos. Por ejemplo, multiplicar dos
enteros muy grandes, realmente grandes en realidad.
44
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Si P y Q son enteros grandes de longitud
Programacin dinmica
Este mtodo es bastante popular. Dividir un problema en subproblemas ms sencillos no
siempre es posible, pero, en cambio, lo que sucede es que se tienen casos distintos, para los
cuales tendrs que resolver alguno de estos casos repetidamente. Entonces, lo que conviene
es crear una tabla con las soluciones para dicho problema para simplemente buscar su solucin
en el momento requerido y despus usarla. Esto funciona bien cuando dichos casos son parte
interna de algn otro caso; entonces, recuperar su informacin es ms sencillo en vez de crear
un crecimiento exponencial de llamadas a diferentes algoritmos. Para hacer una
implementacin usando programacin dinmica, usualmente se tienen que ir guardando los
resultados previos en una tabla.
Backtracking
Es una estrategia de programacin para hacer bsquedas exhaustivas de todas las soluciones
posibles a un problema, el cual est compuesto por varios pasos intermedios. Consiste en
probar una solucin, y si no se viola la funcin a optimizar, entonces se agrega otro elemento a
probar.
Un ejemplo clsico de esto es el problema de las nueve reinas. Este problema consiste en
colocar nueve reinas en un tablero de ajedrez, considerando su capacidad de moverse dentro
de l, de tal forma que no se ataquen. La estrategia es la siguiente:
1. Colocar una en el primer escaque
2. Si no se viola la funcin a optimizar
3. Colocar la siguiente en un escaque no visto por la reina anterior
4. Si no hay forma de poner la reina siguiente en otro escaque
5. Quitar la reina anterior y ponerla en el escaque siguiente al que fue ubicada
6. Regresar al paso 2.
45
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
1.3.4. Complejidad en ordenamientos y bsquedas
Dos de las principales tareas que llevan a cabo cualquier algoritmo en cualquier programa en
cualquier computadora son
Ordenar
Buscar
Puedes apreciar la importancia de contrastar estos dos mtodos tomando en cuenta que la
recuperacin de un elemento de un arreglo tiene complejidad ( ). De hecho, parece que
intuitivamente son los algoritmos que van a permitir llevar a cabo buena parte del cmputo que
hagas.
Bsqueda binaria
Una de las bsquedas ms populares es la bsqueda binaria. Esta se hace en alguna
estructura Q en la que, si tomas un elemento c, sabes que Q[a]<Q[c] sii a<c y Q[c]<Q[b] sii c<b.
Es decir, tienes una estructura perfectamente ordenada bajo algn orden predeterminado
creciente montonamente.
El mejor ejemplo de esto es el directorio telefnico. Es inmenso, pero est ordenado, y si
buscas algn nombre, por ejemplo, Salazar, si abres el directorio aleatoriamente y encuentras
que la primera palabra es Rodrguez, sabes bien de qu lado del directorio se encuentra el
apellido Salazar.
Una implementacin de bsqueda binaria para una lista en Python la puedes ver a continuacin
def binaria(L, k, imn=0, imx=None):
Hace la busqueda binaria de k en L, es decir, existe idx tal
que L[idx]=k
L debe ser un arreglo ordenado
k la llave a buscar
imn es el indice inferior de L sobre el cual se busca
imx es el indice superior de L sobre el cual se busca
regesa idx tal que L[idx]=k o -1 si no se encuentra
if imx is None:
print Arreglo completo
imx =len(L)-1
while imn < imx:
print Llamada
imd = (imn+imx)/2
mval = L[imd]
if k < mval:
46
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
print Izquierda
return binaria(L, k, imn, imd)
elif mval < k:
print Derecha
return binaria(L, k, imd+1, imx)
elif k == mval:
print Resultado
return imd
else:
print Fallo
>>> L = [1,1]
>>> for i in range(24): L.append(L[-1]+L[-2])
>>> k = L[23]
>>> x = b.binaria(L, k)
Arreglo completo
Llamada
Derecha
Llamada
Derecha
Llamada
Derecha
Llamada
Izquierda
Llamada
Resultado
>>> x
23
Figura 18. Algoritmo de bsqueda binaria en Python usado en la lista de nmero de Fibonacci con 24
elementos.
). El anlisis no es realmente
La complejidad de este algoritmo, como puedes intuir, es (
complicado, ya que se parece mucho al del ejemplo de elevar un nmero a alguna potencia. El
tiempo total de cmputo de este algoritmo es el que le lleve examinar la mitad restante de su
entrada ms una constante , donde pones todas las asignaciones y operaciones que sean de
complejidad ( ), excepto por la clusula de escape, que es la operacin en la que recuperas
el elemento buscado del arreglo L.
( )
( )
( )
Entonces, para las diferentes iteraciones obtienes la siguiente progresin, considerando el peor
de los casos
( )
( )
47
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
( )
, ( )
( )
( )
( )
( )
( )
, implica que
Ordenamientos
Otra de las tareas ms socorridas en computacin son los ordenamientos. La tarea de ordenar
consiste en tomar un arreglo A donde a cada ndice se le denomina llave, y el contenido del
arreglo es el valor sobre el cual se impondr el orden.
Uno de los ejemplos ms sencillos de ordenamiento es Bubble Sort. La idea es muy sencilla.
nicamente se tiene que recorrer el arreglo en reversa, desde atrs hacia adelante, para ir
intercambiando los elementos que sean mayores y que, por lo tanto, correspondan al final del
arreglo; y esto lo debes hacer de manera progresiva por todos los elementos dejando fijos los
ya ordenados.
def bubblesort(A):
n =len(A)
for i in range(n-1):
for j in range(n-1, i, -1):
if A[j-1] > A[j]:
temp=A[j-1]
A[j-1]=A[j]
A[j] = temp
El peor de los casos es que este algoritmo entre todas las veces a la seccin de intercambio, lo
que est determinado por el for interno al que se entra tantas veces como lo indique el for
externo.
(
). Pero no es el nico
48
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Para saber ms
Maas, Jos. Anlisis de algoritmos: Complejidad. En lnea
http://www.lab.dit.upm.es/~lprg/material/apuntes/o/index.html#s4
Zindros, Dyonisis. A gente introduction to Algorithm Complexity Analysis. En lnea
http://discrete.gr/complexity/.
1.4.
Estructuras de datos
49
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
aspecto que puede obviarse con los arreglos donde la secuencia viene dada por los ndices del
arreglo.
En Python, el uso de listas es muy comn y tiene todos los mtodos que podras implementar
no tan naturalmente en otros lenguajes, pero lo hars con el fin de mostrar cmo funciona una
lista ligada. Este puede ser un tema un tanto engorroso pero sencillo al final.
Figura 20. Diagrama de una lista ligada. a) Lista de registros ligada apuntando a un registro especfico b)
borrado de un registro c) insercin de un registro
Lo que hars en este caso ser disear un TDA de tipo lista para que controle todas las
operaciones referentes a ella; esto lo convertirs en un par de clases funcionales y operables en
Python.
En una lista ligada, cada elemento tiene registrado qu elemento le sigue. Entonces, para
problemas donde necesitas obviar la secuencia de los elementos, viene muy bien, por ejemplo,
los das de la semana. En el siguiente cdigo puedes ver la implementacin de la misma junto
con la clase registro que es donde guardars los datos.
class registro(object):
def __init__(self,t):
50
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
self.c = t
self.s = None
def siguiente(self,t):
self.s = t
def contenido(self):
return self.c
def sigue(self):
return self.s
class lista(object):
def __init__(self):
self.h = None
#cabeza
self.a = self.h #celda actual
self.pos = 0
self.conteo = 0
def cuantos(self):
return self.conteo
def posicion(self):
return self.pos
def ubica(self,p):
if p > 0 and p <= self.pos:
self.a = self.h
self.pos = 1
while self.pos < p:
self.a = self.a.s
self.pos += 1
def contenido(self):
return self.a.contenido()
def siguiente(self):
if self.pos < self.conteo:
self.a = self.a.sigue()
self.pos += 1
def inserta(self,r):
if self.h is None:
self.h = r
self.a = self.h
else:
self.a.siguiente
self.a = self.a.sigue()
self.pos += 1
self.conteo += 1
def borra(self,p):
if p==1:
51
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
self.h = self.h.sigue()
self.conteo -= 1
elif p > 1 and p < self.conteo:
self.a = self.h
self.pos = 1
while self.pos < p-1:
self.siguiente()
self.a.siguiente(self.a.siguiente().siguiente())
self.conteo -= 1
def imprime(self):
self.a = self.h
i = 1
while i < self.conteo:
print self.contenido()
self.siguiente()
i += 1
Figura 21. Cdigo para implementar una lista simplementa ligada en Python junto con una clase de registro
ocupada para las diferentes celdas de la lista.
Hay dos tipos de mtodos en esta implementacin. Aquellos de complejidad constante como
son inserta (o los que reportan un valor) y los de complejidad ( ), entre stos estn: ubica,
imprime, borra. Y es que todos estos tienen que recorrer toda la lista para poder llevar a cabo
su operacin.
Aqu puedes ver el uso de los registros.
In [49]: t = b.registro(5)
In [50]: s = b.registro(3)
In [51]: r = b.registro(1)
In [52]: u = b.registro(7)
52
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
In [55]: L.inserta
In [56]: L.inserta(s)
In [57]: L.inserta(t)
In [58]: L.inserta(u)
In [59]: L.h.contenido()
Out[59]: 1
In [60]: L.h.sigue().contenido()
Out[60]: 3
In [61]: L.h.sigue().sigue().contenido()
Out[61]: 5
In [62]: L.h.sigue().sigue().sigue().contenido()
Out[62]: 7
Colas
Las listas ligadas tienen un uso aplicado para muchos procesos, por ejemplo, un tipo de listas
ligadas es una cola. Las colas son un tipo de lista ligada denominada FIFO, que significa First In
First Out, que es bsicamente el funcionamiento que todos identifican con las filas. El primero
que se forma es el primero en salir.
Esto cmo se refleja en la implementacin? Cmo asignas un orden a tu lista? Hasta el
momento casi todo est implementado, ya que cuando se agrega un elemento a la lista es en el
orden en el que van llegando a ella; lo nico que falta es un mtodo que los extraiga de acuerdo
a este principio.
Una propuesta es tener un mtodo pop que elimine el primer elemento de la lista.
def pop(self):
if self.conteo > 1:
self.borra(1)
53
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
1.4.2. Pilas
Las pilas o stacks son otro tipo de estructura que puede ser implementado con una lista o con
un arreglo. A diferencia de las colas, estas estructuras son del tipo FILO, First In Last Out. No
es una fila particularmente intuitiva, al menos no en el andar cotidiano, pero s lo es en otros
aspectos.
Considera el siguiente conjunto de parntesis
((([(([])[[ ]])])[[]]))
El conjunto de parntesis anterior est bien apareado. La estructura de datos que puede ayudar
a llevar bien la cuenta de este fenmeno es precisamente una pila; esto se debe a que cada
vez que cierras un parntesis, su contraparte que lo abre debe ser el inmediato anterior, es
decir, el ltimo elemento que entr en la pila es el primero en salir (complementariamente el
primero en entrar debe ser el ltimo en salir).
A continuacin puedes ver la implementacin de un stack, usando una lista como estructura
interna para guardar los elementos del stack.
class stack:
def __init__(self):
self.elementos = []
def es_vacio(self):
return self.elementos == []
def push(self, elem):
self.elementos.append(elem)
def pop(self):
return self.elementos.pop()
def peek(self):
return self.items[len(self.items)-1]
def tamano(self):
return len(self.items)
54
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Los nombres de las funciones son notacin estndar en el uso de pilas y colas. Un programa
que podras implementar con una pila es una calculadora con notacin sufija. Por ejemplo, la
instruccin
46+
Usando notacin sufija, la expresin anterior significa que debes sumar el 4 y 6 obteniendo 10.
La suma se puede llevar a cabo en el momento en el que detectes el smbolo +; en ese
momento sacas los dos elementos superiores del stack y los sumas.
Figura 26. Calculadora con notacin sufija que implementa una calculadora, la operacin usualmente
depende del programador, puede suceder apenas recibamos un smbolo de operacin o hasta el final que se
llene la pila. a) Esquema de una pila b) Insercin c) Ejemplo de pop.
1.4.3. Heaps
El trmino heap significa montculo en ingls y refleja en buena medida lo que deseas modelar
con esta estructura, un montculo donde lo ms importante que requieras est hasta el tope del
montculo. Incluso existe una expresin en ingls con este significado que va: top of the heap.
Los heaps son otro tipo de listas, usualmente conocidos como listas con prioridad. Por ejemplo,
una lista de urgencias en un hospital, aunque todos los pacientes llegan en un orden
cronolgico bien determinado, no todos tienen la misma prisa por ser atendidos; hay unos casos
que son mucho ms urgentes.
55
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Esto lo puedes denotar en un arreglo. Considera el siguiente ejemplo:
5 1 4 6 3 8 2 1
Si el tamao del nmero en cada entrada del arreglo anterior determinara el grado de
importancia de esa entrada, entonces el 8 sera el elemento ms importante, mismo que puedes
encontrar con tiempo ( ) al escanear el arreglo de nmeros. O bien, puedes crear una
estructura de datos que siempre los mantenga ordenados segn su prioridad.
1.4.4. rboles
Los rboles son de las estructuras ms cmodas y eficientes para representar datos, ya que
implcitamente representan una jerarqua en ellos, y ya no son lineales como todas las
estructuras que has visto hasta ahora.
De hecho, ya examinaste previamente una de las ventajas de tener la informacin estructurada
en un rbol cuando revisaste el algoritmo de la bsqueda binaria. En este algoritmo descartabas
la mitad del espacio de bsqueda que no te interesaba, y de esta manera la complejidad del
).
algoritmo es de (
Como bien sabes, un rbol es una grfica sin ciclos que consta de un conjunto de nodos y de
aristas.
(
)
Por ejemplo, considera el siguiente rbol:
56
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
En este rbol el nodo raz A tiene iluminado de verde toda su rama izquierda, y de naranja toda
la derecha. Un problema que aparece inmediatamente es el de cmo vas a representar una
estructura de dimensin 2 en Python. Una opcin es hacer uso de las ventajas del manejo de
listas y hacer una lista de listas. Por ejemplo, el rbol de la figura puede ser representado as:
In [4]: Arbol = ['A',
...:
['B', ['F', [], [] ], []],
...:
['C', ['G', [], [] ], ['H',[],[]]]
...: ]
En esta seccin revisars la implementacin de un rbol binario, aunque hay varios tipos de
rboles.
def ArbolBinario(r):
return [r, [], []]
def ramaIzquierda(raiz,rama):
t = root.pop(1)
if len(t) > 1:
raiz.insert(1,[ramaI,t,[]])
else:
raiz.insert(1,[ramaI, [], []])
return raiz
def ramaDerecha(raiz,rama):
t = raiz.pop(2)
if len(t) > 1:
raiz.insert(2,[rama,[],t])
else:
raiz.insert(2,[rama,[],[]])
return raiz
def pon_raiz(arbol):
return arbol[0]
Como puedes ver, la bsqueda en este rbol reduce el tiempo de cmputo en potencias de dos,
despreciando todo la rama que no es de tu inters.
57
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
1.4.5. Funciones y tablas de hash
Hasta ahora las estructuras que has visto han podido reducir, en el mejor de los casos, el
), en buena medida por el orden que guarda el dominio
tiempo de cmputo y bsqueda a (
que toman las llaves de tus elementos.
Si las llaves fueran las entradas del arreglo de dnde quieres recuperar la informacin,
entonces todo estara resuelto, ya que con simplemente incorporar esa llave al hipottico
arreglo que est guardando la informacin, obtendras lo que buscas en orden ( ), que es la
gran gracia de los arreglos: su rapidez para recuperar informacin.
Es por esto que servira tener un arreglo de este tipo, donde pusieras la informacin para ser
recuperada. El problema con este planteamiento es que, si haces un arreglo, por ejemplo, para
una agenda telefnica con nmeros de diez dgitos, donde el nmero sea la llave para
recuperar la informacin del dueo de ese telfono, entonces necesitaras alrededor de
entradas para poder guardar esa hipottica agenda telefnica, y lo peor es que gran parte
de ella estar vaca. Pero qu tal si te aferras un poco a la idea de un arreglo para tener
complejidad constante para recuperar la informacin, pero con menos llaves. Cmo puedes
hacer esto posible?
Una opcin, tal vez no muy buena, pero muy ilustrativa, es quedarte con los ltimos dos dgitos
de cada nmero y usar eso como llave del arreglo, por ejemplo:
y as para cada uno de los telfonos de tu agenda. Entonces, a travs de un mapeo ests
reduciendo el espacio de bsqueda de todos los posibles nmeros telefnicos para quedarte
nicamente con un elemento que funciona como la llave de un arreglo, y que los identifica con
complejidad ( ).
El problema radica en que se puede dar este caso
- en el que otro elemento sea mapeado a la misma entrada del arreglo y que ya est ocupado.
A este fenmeno se le denomina colisin, en tanto que al arreglo que ests construyendo se le
denomina tabla de hash, y a la funcin que se encarga de mapear el objeto de tu inters en
una entrada de la tabla se le llama funcin hash.
58
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Funcin hash
Formalmente una funcin de hash ( ) se define considerando que va a recibir un argumento
de entrada y producir un nmero de clase en el rango ,
-, donde es el nmero total de
clases. Esto es, requieres disear una funcin que mapee todo el dominio en un conjunto de
cardinalidad mucho menor; para esto requieres que el mapeo sea, por lo menos, inyectivo, y
aunque es imposible, tambin sera bueno que fuera suprayectivo, o por lo menos debes
procurar que el nmero de colisiones sea mnimo.
Ejemplo: El algoritmo MD5 produce un entero nico dado una cierta entrada de bits
siguiente algoritmo.
con el
)
)
)
)
(
(
) (
) (
(
)
)
)
Entonces, con estos cuatro bytes concatenados se obtiene un identificador nico de cada
entrada.
Un mal ejemplo podra ser el siguiente. Para identificar una cadena de nmeros, por ejemplo,
los nmeros telefnicos, podras sumar su valor entero, pero esto producira demasiadas
colisiones, ya que con mucha facilidad podras obtener el mismo entero a partir de una simple
suma.
Colisiones
Existen tres formas de lidiar con las colisiones en la tabla.
- Direccionamiento abierto: Se busca un espacio libre dentro de la tabla para colocar la
nueva entrada.
- Encadenamiento: La entrada de la tabla contiene una lista y cada nuevo elemento que
llega se coloca como elemento de la misma. Para no perder eficiencia no deben ser
demasiados elementos en cada lista.
- Encadenamiento ligado (coalesced chaining): Este es un hbrido de los dos primeros
mtodos en el que asignas el objeto a guardar en otra llave dentro de la tabla, pero
59
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
guardando la direccin en la entrada original y estableciendo una liga a la nueva
entrada.
Para saber ms
Know thy complexities. En lnea http://bigocheatsheet.com/
Data structures visualizations. En lnea http://www.cs.usfca.edu/~galles/visualization/
Morales Luna, G. Computabilidad y Complejidad. En lnea
http://cs.cinvestav.mx/~gmorales/complex/complex.html
Autoevaluacin
Para reforzar los conocimientos relacionados con los temas que se abordaron en esta unidad
del curso, es necesario que resuelvas la autoevaluacin.
Ingresa al Aula virtual para realizar tu actividad.
60
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
1. Descarga el archivo EA. Diseo de algoritmo.
2. Resuelve inciso que se presenta en el documento descargable.
3. Escribe tus preguntas y respuestas en un documento, y si existiese alguna funcin,
gurdala en un archivo .py
4. Guarda tu documento y archivo con la siguiente nomenclatura: MCOM2_U1_EA_XXYZ.
5. Enva tu archivo al Portafolio de evidencias y espera la retroalimentacin de tu
Facilitador(a). Una vez que la tengas, atiende sus comentarios y reenva la nueva versin
de tu evidencia.
Nota: No olvides consultar la Escala de evaluacin para conocer los criterios con que ser
evaluado tu trabajo.
Autorreflexiones
Como parte de cada unidad, es importante que ingreses al foro Preguntas de autorreflexin y
leas los cuestionamientos que formul tu Facilitador(a), ya que a partir de ellos debes elaborar
tu Autorreflexin y enviarla mediante la herramienta Autorreflexiones. No olvides que tambin
se toman en cuenta para la calificacin final.
Cierre de la Unidad
En toda esta unidad acabas de ver un panorama un tanto extenso, pero bsico, de la operacin
de una computadora y de la informacin que es capaz de manipular, as de cmo hacerlo
eficientemente. Las estructuras de datos presentadas aqu no son ni por asomo las ms
sofisticadas o las nicas; de hecho, cada una de estas estructuras se puede sofisticar bastante
ms. Lo mismo pasa con los fundamentos de computacin terica presentados.
Lo que viste en esta unidad es una base para el anlisis y entendimiento de la manipulacin de
datos en la computadora de manera eficiente.
Para saber ms
Puedes consultar las siguientes ligas para extender cada tema
Python Programming/Sequences. Wikibooks. En lnea
http://en.wikibooks.org/wiki/Python_Programming/Sequences
61
Computacin II
Unidad 1. Estructuras de datos y anlisis de algoritmos
Data Structures. The Python Tutorial. En lnea
http://docs.python.org/2/tutorial/datastructures.html
Built-in Types. The Python Tutorial. En lnea http://docs.python.org/2/library/stdtypes.html
Primitive Data Types. The Java Tutorials. En lnea
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Data Structures: Abstract Data Types. En lnea http://www.youtube.com/watch?v=HcxqzYsiJ3k
Crescenzi, Pierluigi. A compendium of NP optimization problems En lnea
http://www.csc.kth.se/~viggo/problemlist/
Bell R. A begginers guide to Big O Notation. En lnea http://rob-bell.net/2009/06/a-beginnersguide-to-big-o-notation/
Maas, Jos. Anlisis de algoritmos: Complejidad. En lnea
http://www.lab.dit.upm.es/~lprg/material/apuntes/o/index.html#s4
Zindros, Dyonisis. A gentle introduction to Algorithm Complexity Analysis. En lnea
http://discrete.gr/complexity/.
Know thy complexities. En lnea http://bigocheatsheet.com/
Data structures visualizations. En lnea http://www.cs.usfca.edu/~galles/visualization/
Morales Luna, G. Computabilidad y Complejidad. En lnea
http://cs.cinvestav.mx/~gmorales/complex/complex.html
Referencias Bibliogrficas
Leiserson, C. E., Rivest, R. L., & Stein, C. (2001). Introduction to algorithms. T. H. Cormen (Ed.).
The MIT press.
Aho, A. V., Hopcroft, J. E., & Ullman, J. D. (1988). Estructura de datos y algoritmos. Addison
Wesley Iberoamericana, SA Washington. Cp, 6, 200-251.
62