Universidad Mayor de San Andr´es

Facultad de Ciencias Puras y Naturales
Carrera de Inform´atica
Fundamentos de la Programaci´on
Jorge Humberto Ter´an Pomier
<teranj@acm.org>
La Paz - Bolivia, Diciembre 2006
ii
Prefacio
Motivaci´ on
Los conceptos presentados se estudian en muchas de las materias del
pregrado de la carrera de inform´atica, con el rigor necesario. Sin embargo,
en mi experiencia docente he podido ver que hay muchos estudiantes que
carecen de elementos pr´acticos con los que puedan aplicar directamente los
conceptos aprendidos y lo que se pretende es cubrir este vac´ıo.
El presente texto trata de introducir los conceptos de programaci´on, a
estudiantes de pregrado con un enfoque nuevo.
Para una adecuada compresi´on de la tem´atica presentada en el libro, el
lector debr´a tener alguna experiencia en el desarrollo de programas. El libro
no pretende ense˜ nar a codificar programas, sino a resolver problemas.
Contenido
Se presentan en el cap´ıtulo 1, los conceptos de algor´ıtmica elemental con
el prop´osito de introducir a los estudiantes, al concepto de la eficiencia de los
programas.
El cap´ıtulo dos introduce los conceptos de an´alisis de algoritmos con una
serie de ejercicios aplicados. Se incluyen algunos laboratorios que tienen el
prop´osito de que, los estudiantes asimilen estos conceptos en forma experi-
mental.
El cap´ıtulo tres introduce el concepto de la teor´ıa de n´ umeros, introdu-
ciendo las librer´ıas de Java. Se muestran ejemplos de n´ umeros grandes y
aplicaciones en la criptograf´ıa.
El cap´ıtulo 4 trata de la escritura de programas con miras a la prueba del
c´odigo. En este cap´ıtulo se introduce un concepto que es el dise˜ no por con-
iii
iv
tratos y la forma de aplicar en Java. Aunque este concepto fue introducido
inicialmente en el lenguaje Eifel, actualmente tiene mucho inter´es en el de-
sarrollo de aplicaciones. El texto no trata de trabajar en conceptos de l´ogica
formal en su totalidad, lo que propone es una introducci´on a estos conceptos
para facilitar la prueba del c´odigo en forma din´amica.
El cap´ıtulo 5 complementa el cap´ıtulo 4 con conceptos de clasificaci´on y
b´ usqueda . Se introducen laboratorios y las bibliotecas Java para clasificar.
El cap´ıtulo 6 est´a orientado a explicar como se encara la programaci´on
de problemas de combinatoria b´asica.
El cap´ıtulo 7 explica como utilizar las librer´ıas del lenguaje Java y como
resolver problemas con pilas, listas enlazadas, conjuntos, ´arboles y colas de
prioridad.
EL cap´ıtulo 8 introduce al estudiante a los problemas de retroceso (bac-
tracking) con problemas t´ıpicos, como recorrido de grafos y permutaciones.
El cap´ıtulo 9 introduce a la geometr´ıa computacional. Muestra como cons-
truir una librer´ıa de rutinas b´asicas para desarrollar aplicaciones relacionadas
a la geometr´ıa y muestra las librer´ıas Java as´ı como las posibilidades que se
tienen con las mismas.
El lenguaje que se escogi´o fue el Java, primero porque la formaci´on
est´a orientada a la programaci´on orientada a objetos. Segundo porque el
lenguaje es de amplia utilizaci´on en las empresas y en la educaci´on.
Los enunciados orientados a la programaci´on fueron tomados de los con-
cursos de programaci´on, fueron traducidos al espa˜ nol manteniendo los datos
de entrada y salida en ingl´es. Esto se hizo para permitir a los interesados
resolver los problemas y poder validar sus respuestas con el Juez en L´ınea
de Valladolid, en su p´agina web http://acm.uva.es. Estos ejercicios llevan
adelante el n´ umero de problema del Juez en L´ınea de Valladolid.
Aplicaci´ on en el aula
Esta tem´atica puede aplicarse en el transcurso de un semestre en clases
te´oricas, pr´acticas y de laboratorio.
Los laboratorios proponen ejercicios que tienen la finalidad de evaluar
experimentalmente la ejecuci´on de los algoritmos. Esto permite que los estu-
diantes obtengan una vivencia de los resultados te´oricos.
Se puede aplicar en una clase de teor´ıa de dos per´ıodos y una segunda
clase que ser´ıa de ejercicios o laboratorio.
v
Contenido del CD
El CD adjunto contiene los programas presentados en el texto. Hay que
aclarar que todos han sido codificados utilizando el compilador Java 1.5 de
Sun Microsystems. El cap´ıtulo 4 relacionado a JML fue codificado con la
versi´on 1.4, dado que a la fecha de la redacci´on de la obra no estaba disponible
una versi´on de JML que funcionara con la versi´on 1.5.
Agradecimientos
Quiero agradecer a mi esposa, a mis hijos por los aportes realizados y
finalmente al Dr. Miguel Angel Revilla por dejarme reproducir ejercicios del
Juez en L´ınea.
Lic. Jorge Ter´an Pomier, M.Sc.
vi
´
Indice general
Prefacio III
1. Algor´ıtmica elemental 1
1.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Algoritmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3. Problemas e instancias . . . . . . . . . . . . . . . . . . . . . . 2
1.4. Eficiencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5. Qu´e considerar y qu´e contar . . . . . . . . . . . . . . . . . . . 4
1.5.1. Operaciones elementales . . . . . . . . . . . . . . . . . 6
1.5.2. An´alisis del mejor caso, caso medio y peor caso . . . . 6
1.5.3. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5.4. Laboratorio . . . . . . . . . . . . . . . . . . . . . . . . 7
2. An´alisis de algoritmos 11
2.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2. Notaci´on orden de . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2.1. Propiedades de O grande de n . . . . . . . . . . . . . . 12
2.3. Notaci´on asint´otica condicional . . . . . . . . . . . . . . . . . 13
2.4. Notaci´on omega . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.5. Notaci´on teta . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.6. An´alisis de las estructuras de control . . . . . . . . . . . . . . 14
2.6.1. Secuenciales . . . . . . . . . . . . . . . . . . . . . . . . 14
2.6.2. Ciclos For . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.6.3. Llamadas recursivas . . . . . . . . . . . . . . . . . . . 15
2.6.4. Ciclos while y repeat . . . . . . . . . . . . . . . . . . . 15
2.6.5. An´alisis del caso medio . . . . . . . . . . . . . . . . . . 16
2.6.6. An´alisis amortizado . . . . . . . . . . . . . . . . . . . . 17
2.7. Soluci´on de recurrencias . . . . . . . . . . . . . . . . . . . . . 18
vii
viii
´
INDICE GENERAL
2.7.1. M´etodo por substituci´on . . . . . . . . . . . . . . . . . 18
2.7.2. Cambio de variables . . . . . . . . . . . . . . . . . . . 19
2.7.3. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.7.4. M´etodo iterativo . . . . . . . . . . . . . . . . . . . . . 20
2.7.5. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7.6. Teorema master . . . . . . . . . . . . . . . . . . . . . . 22
2.7.7. Soluci´on general de recurrencias lineales . . . . . . . . 23
2.8. Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . 27
2.9. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.10. Nota sobre el c´alculo integral . . . . . . . . . . . . . . . . . . 34
3. Teor´ıa de n´ umeros 35
3.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2. Variables del lenguaje Java . . . . . . . . . . . . . . . . . . . . 35
3.3. C´alculo del m´aximo com´ un divisor . . . . . . . . . . . . . . . 37
3.3.1. Divisibilidad . . . . . . . . . . . . . . . . . . . . . . . . 38
3.3.2. Algoritmos extendido de Euclides . . . . . . . . . . . . 41
3.4. M´ınimo com´ un m´ ultiplo . . . . . . . . . . . . . . . . . . . . . 43
3.5. Aritm´etica modular . . . . . . . . . . . . . . . . . . . . . . . . 43
3.5.1. Propiedades . . . . . . . . . . . . . . . . . . . . . . . . 44
3.5.2. Congruencias . . . . . . . . . . . . . . . . . . . . . . . 45
3.5.3. Inverso multiplicativo . . . . . . . . . . . . . . . . . . . 45
3.5.4. Soluci´on de ecuaciones . . . . . . . . . . . . . . . . . . 45
3.6. N´ umeros primos . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.6.1. Generaci´on de primos . . . . . . . . . . . . . . . . . . . 47
3.6.2. Factorizaci´on . . . . . . . . . . . . . . . . . . . . . . . 49
3.6.3. Prueba de la primalidad . . . . . . . . . . . . . . . . . 51
3.6.4. Teorema de Fermat . . . . . . . . . . . . . . . . . . . . 51
3.6.5. Prueba de Miller - Rabin . . . . . . . . . . . . . . . . . 52
3.6.6. Otras pruebas de primalidad . . . . . . . . . . . . . . . 52
3.7. Bibliotecas de Java . . . . . . . . . . . . . . . . . . . . . . . . 53
3.7.1. Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.8. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.8.1. Problema 136 - N´ umeros Feos . . . . . . . . . . . . . . 57
3.8.2. Problema 10042 - N´ umeros De Smith . . . . . . . . . . 58
3.8.3. Problema 10104 - El problema de Euclides . . . . . . . 59
3.8.4. Problema 10139 - Factovisors . . . . . . . . . . . . . . 59
3.8.5. Problema 106 - Fermat vs. Pit´agoras . . . . . . . . . . 60
´
INDICE GENERAL ix
4. Codificaci´on con miras a la prueba 61
4.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4.2. Algunos errores de programaci´on . . . . . . . . . . . . . . . . 62
4.3. Especificaci´on de programas . . . . . . . . . . . . . . . . . . . 66
4.3.1. ¿Por qu´e especificar? . . . . . . . . . . . . . . . . . . . 68
4.3.2. ¿Qu´e especificar? . . . . . . . . . . . . . . . . . . . . . 69
4.3.3. ¿C´omo especificar? . . . . . . . . . . . . . . . . . . . . 70
4.3.4. Invariantes . . . . . . . . . . . . . . . . . . . . . . . . . 71
4.3.5. Ejercicios propuestos . . . . . . . . . . . . . . . . . . . 74
4.4. Aplicaciones de las invariantes . . . . . . . . . . . . . . . . . . 75
4.4.1. Principio de correctitud . . . . . . . . . . . . . . . . . 84
4.5. Dise˜ no por contratos . . . . . . . . . . . . . . . . . . . . . . . 85
4.5.1. Especificaci´on de contratos . . . . . . . . . . . . . . . . 88
4.5.2. Invariantes . . . . . . . . . . . . . . . . . . . . . . . . . 90
4.6. Prueba est´atica . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.7. Prueba din´amica . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.7.1. Afirmaciones . . . . . . . . . . . . . . . . . . . . . . . 92
4.8. Programaci´on bajo contratos con JML . . . . . . . . . . . . . 95
4.8.1. Especificaci´on de invariantes . . . . . . . . . . . . . . . 97
4.8.2. Cuantificadores . . . . . . . . . . . . . . . . . . . . . . 98
4.8.3. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 99
5. Aplicaciones de b´ usqueda y clasificaci´on 101
5.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
5.2. Algoritmos de b´ usqueda . . . . . . . . . . . . . . . . . . . . . 101
5.2.1. Prueba exhaustiva . . . . . . . . . . . . . . . . . . . . 105
5.2.2. Representaci´on gr´afica de la b´ usqueda . . . . . . . . . 107
5.3. Clasificaci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.3.1. Clasificaci´on en Java . . . . . . . . . . . . . . . . . . . 113
5.3.2. Algoritmos de clasificaci´on . . . . . . . . . . . . . . . . 117
5.3.3. Laboratorio . . . . . . . . . . . . . . . . . . . . . . . . 127
5.3.4. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . 127
5.3.5. Ejemplo de aplicaci´on . . . . . . . . . . . . . . . . . . 127
5.4. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
5.4.1. Problema 10107 - Hallar la mediana . . . . . . . . . . . 131
5.4.2. Problema 10295 - C´alculo de salario . . . . . . . . . . . 132
5.4.3. Problema 331 - Contando los intercambios . . . . . . . 134
5.4.4. Problema 499 - Hallar la frecuencia . . . . . . . . . . . 135
x
´
INDICE GENERAL
6. Combinatoria b´asica 137
6.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
6.2. T´ecnicas b´asicas para contar . . . . . . . . . . . . . . . . . . . 137
6.3. Coeficientes binomiales . . . . . . . . . . . . . . . . . . . . . . 139
6.4. Algunas secuencias conocidas . . . . . . . . . . . . . . . . . . 141
6.4.1. N´ umeros de Fibonacci . . . . . . . . . . . . . . . . . . 141
6.4.2. N´ umeros Catalanes . . . . . . . . . . . . . . . . . . . . 142
6.4.3. N´ umero Eulerianos . . . . . . . . . . . . . . . . . . . . 143
6.4.4. N´ umeros de Stirling . . . . . . . . . . . . . . . . . . . . 146
6.4.5. Particiones enteras . . . . . . . . . . . . . . . . . . . . 146
6.5. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
6.5.1. Problema 357 - Formas de combinar monedas . . . . . 149
6.5.2. Problema 369 - Combinaciones . . . . . . . . . . . . . 150
6.5.3. Problema 10338 - Mal educados . . . . . . . . . . . . . 151
6.5.4. Problema 10183 - Secuencia de Fibonacci . . . . . . . . 152
7. Estructuras de datos elementales 153
7.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
7.2. Pilas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
7.3. Listas enlazadas . . . . . . . . . . . . . . . . . . . . . . . . . . 157
7.4. Conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
7.5. Clases map . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
7.6. Clases para ´arboles . . . . . . . . . . . . . . . . . . . . . . . . 164
7.7. Clases para colas de prioridad . . . . . . . . . . . . . . . . . . 166
7.8. Ejercicios para laboratorio . . . . . . . . . . . . . . . . . . . . 168
8. Backtracking 171
8.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
8.2. Recorrido de grafos . . . . . . . . . . . . . . . . . . . . . . . . 171
8.3. Constuir todos los subconjuntos . . . . . . . . . . . . . . . . . 175
8.4. Construir todas las permutaciones . . . . . . . . . . . . . . . . 179
8.5. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
8.5.1. Prolema 195 - Anagramas . . . . . . . . . . . . . . . . 182
8.5.2. Prolema 574 - Sum It Up . . . . . . . . . . . . . . . . 183
8.5.3. Problema 524 - Anillos de primos . . . . . . . . . . . . 185
8.5.4. Problema 216 - Hacer la l´ınea . . . . . . . . . . . . . . 186
´
INDICE GENERAL xi
9. Geometr´ıa computacional 189
9.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
9.2. Geometr´ıa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
9.3. Librer´ıas de Java . . . . . . . . . . . . . . . . . . . . . . . . . 196
9.4. Cercos convexos . . . . . . . . . . . . . . . . . . . . . . . . . . 198
9.5. Clase Java para pol´ıgonos . . . . . . . . . . . . . . . . . . . . 205
9.6. C´alculo del per´ımetro y ´area del pol´ıgo-no. . . . . . . . . . . . 207
9.7. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
9.7.1. Problema 378 - L´ıneas que intersectan . . . . . . . . . 211
9.7.2. Problema 273 - Juego de Palos . . . . . . . . . . . . . 212
9.7.3. Problema 218 - Erradicaci´on de moscas . . . . . . . . . 214
9.7.4. Problema 476 - Puntos en rect´angulos . . . . . . . . . 216
A. Fundamentos matem´aticos 219
A.1. Recordatorio de logaritmos . . . . . . . . . . . . . . . . . . . . 219
A.2. Recordatorio de series . . . . . . . . . . . . . . . . . . . . . . 220
A.2.1. Series simples . . . . . . . . . . . . . . . . . . . . . . . 220
A.2.2. Serie aritm´etica . . . . . . . . . . . . . . . . . . . . . . 220
A.2.3. Serie geom´etrica . . . . . . . . . . . . . . . . . . . . . . 220
A.2.4. Propiedades de la sumatorias . . . . . . . . . . . . . . 221
A.2.5. Series importantes . . . . . . . . . . . . . . . . . . . . 221
A.3. Combinatoria b´asica . . . . . . . . . . . . . . . . . . . . . . . 222
A.3.1. F´ormulas importantes . . . . . . . . . . . . . . . . . . 222
A.4. Probabilidad elemental . . . . . . . . . . . . . . . . . . . . . . 223
A.5. T´ecnicas de demostraci´on . . . . . . . . . . . . . . . . . . . . 224
A.5.1. Demostraci´on por contradicci´on . . . . . . . . . . . . . 224
A.5.2. Demostraci´on por inducci´on . . . . . . . . . . . . . . . 224
xii
´
INDICE GENERAL
Cap´ıtulo 1
Algor´ıtmica elemental
1.1. Introducci´ on
En este cap´ıtulo empezamos el estudio de los algoritmos. Empezaremos
definiendo algunos t´erminos tales como algoritmo, problema, instancia, efi-
ciencia e investigaremos m´etodos para probar la eficiencia de los mismos.
Existen m´etodos formales para realizar pruebas rigurosas sobre la correc-
ci´on de los programas ´esta tem´atica est´a fuera del alcance del texto pero
ser´a mencionada m´as adelante solo como referencia.
1.2. Algoritmo
Definimos como algoritmo a un conjunto de pasos necesarios para re-
solver un problema ya sea manualmente o por m´etodos mecanizados que,
son los m´as usuales en la actualidad. El concepto de algoritmos fue definido
inicialmente por el matem´atico Persa Al-Khowˆarizmˆı en el siglo diecinueve.
La ejecuci´on de un algoritmo no debe incluir procedimientos intuitivos o
que requieran creatividad. Por ejemplo, una receta de cocina puede denomi-
narse un algoritmo si contiene las instrucciones precisas para preparar algo,
siempre y cuando no tenga detalles tales como sal al gusto, o cocinar hasta
que est´e suave, que son apreciaciones subjetivas del que prepara la receta.
Debemos indicar que los algoritmos deben cumplir un requisito funda-
mental y es que todo algoritmo debe terminar en un n´ umero finito de pasos.
Si consideramos el sistema operativo veremos que no es un algoritmo porque
no termina nunca, dado que est´a en un ciclo infinito.
1
2 1. ALGOR
´
ITMICA ELEMENTAL
Podemos citar algunos ejemplos de algoritmos conocidos, el m´etodo de
multiplicar que aprendimos en la escuela, el algoritmo para verificar si un
n´ umero es primo y muchos otros.
1.3. Problemas e instancias
Si pensamos los procedimientos para multiplicar n´ umeros que conocemos
veremos que hay varias formas de resolver el problema de multiplicaci´on.
Tenemos los m´etodos que aprendimos en la escuela, m´etodos por divisi´on y
multiplicaci´on por 2 denominado multiplicaci´on a la rusa y otros. ¿Cu´al de
´estas posibles soluciones hay que implementar? Esta decisi´on corresponde a
un ´area muy desarrollada en el campo de la inform´atica denominada an´alisis
de algoritmos.
Una instancia particular ser´ıa por ejemplo multiplicar el n´ umero 123 por
el 4567 pero un algoritmo debe ser capaz de funcionar correctamente no solo
en una instancia del m´etodo sino m´as bien en todas las instancias posibles.
Para demostrar que un algoritmo es incorrecto, es suficiente demostrar
que es incorrecto para una instancia . As´ı como es dif´ıcil probar que un
teorema es correcto tambi´en es dif´ıcil probar que un algoritmo es correcto.
Existen limitaciones propias de las computadoras que ponen restriccio-
nes a los algoritmos. Estas pueden ser debido al tama˜ no de los n´ umeros,
espacio de memoria o almacenamiento. En el an´alisis de los algoritmos, se
trata de analizarlos en forma abstracta inicialmente, pero en el transcurso
del texto tambi´en tocaremos aspectos espec´ıficos sobre la implementaci´on y
la eficiencia de los mismos.
1.4. Eficiencia
Cuando tenemos que resolver un problema pueden existir muchos algo-
ritmos disponibles. Obviamente quisi´eramos escoger el mejor. De aqu´ı nos
viene la pregunta ¿Cu´al es mejor?
Si tenemos un problema sencillo con algunas pocas instancias escogemos,
lo m´as f´acil y nos despreocupados de la eficiencia.
Para analizar ´esto tenemos dos m´etodos. El m´etodo emp´ırico tambi´en
llamado a posteriori, consiste en programar todos los m´etodos y probarlos
con diferentes instancias y con la ayuda de la computadora analizamos y
1.4. EFICIENCIA 3
escogemos alguno.
El segundo llamado m´etodo apriori es el an´alisis te´orico del algoritmo,
que con la ayuda de las matem´aticas podemos determinar la cantidad de los
recursos requeridos por cada algoritmo en base del tama˜ no de las instancias
consideradas.
El tama˜ no de una instancia normalmente est´a definida por el n´ umero de
bits, en el caso de un grafo por el n´ umero de nodos y v´ertices, o en otros
por el n´ umero de elementos a procesar. La ventaja del m´etodo te´orico es que
no depende de la computadora, lenguaje de programaci´on o implementaci´on
particular.
En el tratamiento del tema utilizaremos en algunos casos un m´etodo
h´ıbrido donde se determinar´a la eficiencia en forma te´orica y se hallar´an los
valores num´ericos en forma experimental.
Retornando a la pregunta debemos indicar que la eficiencia se mide en
tiempo. Para esto diremos que un programa toma un tiempo del orden t(n)
para una instancia de tama˜ no n. M´as adelante trataremos un t´ermino m´as
riguroso que es la notaci´on asint´otica.
Si tratamos el tiempo en segundos uno podr´ıa pensar si tengo una m´aqui-
na m´as r´apida el tiempo ser´a menor. ¿C´omo es que este m´etodo te´orico llega
a ser efectivo?
Consideremos que el algoritmo toma un tiempo en segundos t
1
(n) para
una m´aquina en particular y t
2
(n) para otra. Para un n´ umero n suficiente-
mente grande podemos hallar unas constantes a y b tales que at(n) = bt(n)
esto nos dice que cualquier ejecuci´on del algoritmo est´a acotado por una
funci´on t(n) y existen unas constantes positivas de proporcionalidad que nos
dan el tiempo. Esto indica que si cambiamos de equipo podemos ejecutar el
algoritmo 10 o 100 veces m´as r´apido y que este incremento est´a dado solo
por una constante de proporcionalidad.
La notaci´on asint´otica dice que un algoritmo toma un tiempo del orden
de, en funci´on del tama˜ no de la instancia . Existen algoritmos que ocurren
muy frecuentemente y ameritan tener un nombre que a su vez se denominan
tasas de crecimiento.
Se denominan algoritmos:
Constantes los que cuyo tiempo de proceso no depende del tama˜ no de
la instancia.
Lineales a los que toman tiempos proporcionales a n.
4 1. ALGOR
´
ITMICA ELEMENTAL
Cuadr´aticos a los que toman tiempos proporcionales a n
2
.
C´ ubicos a los que toman tiempos proporcionales a n
3
.
Polinomiales o exponenciales a los que toman tiempos proporcionales
a n
3
, n
k
.
Logar´ıtmicos los proporcionales a log n.
Exponenciales los que toman tiempos proporcionales a 2
n
.
A´ un cuando es deseable siempre un algoritmo m´as eficiente desde el punto
de vista te´orico podemos en muchos casos escoger en la implementaci´on otro,
dado que las constantes ocultas pueden ser muy grandes y no llegar a ser tan
eficientes para las instancias que deseamos procesar. La figura 1.1 representa
las ordenes magnitud de los algoritmos.
1.5. Qu´e considerar y qu´e contar
Consideremos por ejemplo que queremos hallar el m´aximo de tres n´ umeros
a, b, c. Para resolver ´esto escribimos el siguiente c´odigo:
maximo=0
maximo=Max(a,b)
maximo=Max(c,maximo)
Max (a,b)
if a > b
return a
else
return b
Se puede ver que se requieren exactamente dos comparaciones para deter-
minar el valor m´aximo de a, b, c. Si escribi´eramos Max(Max(a,b),c) tambi´en
se realizar´ıan dos comparaciones. Este mismo algoritmo lo podemos escribir
como sigue:
maximo=0
if (a > b)
1.5. QU
´
E CONSIDERAR Y QU
´
E CONTAR 5
Figura 1.1: Ordenes de magnitud de algoritmos
if(a > c)
maximo = a
else
maximo = c
else
if b > c
maximo = b
else
maximo = c
Vemos que a´ un cuando hemos codificado m´as comparaciones en la ejecu-
ci´on solo se ejecutan dos como el caso anterior. Se hace necesario establecer
6 1. ALGOR
´
ITMICA ELEMENTAL
que es lo que debemos considerar en los programas, ´esto hace necesario defi-
nir, lo que se entiende por operaciones elementales.
1.5.1. Operaciones elementales
Es una operaci´on cuyo tiempo de ejecuci´on est´a acotado por una constante
que solo depende de una implementaci´on particular como ser la m´aquina, el
lenguaje de programaci´on, etc.
En el ejemplo que realizamos estaremos interesados en medir el n´ umero de
comparaciones necesarias para hallar el m´aximo. El resto de las operaciones
las consideramos operaciones elementales.
En el caso de la suma de elementos de un vector lo que deseamos medir
es la cantidad de sumas realizadas para resolver el problema y las operacio-
nes de comparaci´on necesarias para implementar una soluci´on, se consideran
operaciones elementales.
1.5.2. An´alisis del mejor caso, caso medio y peor caso
El tiempo que toma un algoritmo puede variar considerablemente en fun-
ci´on de diferentes instancias de un mismo tama˜ no. Para comprender esto
mejor consideremos el ejemplo del programa de clasificaci´on por inserci´on.
inserci´on(t)
for i=1 to n
x= t[i]
j=i-1
while j > 0 and x<t[j]
t[j+1]=t[j]
j=j-1
t[j+1]=x
Consideremos un conjunto A en el cual queremos procesar el algorit-
mo de ordenar. Para ordenar A utilizar´ıamos inserci´on(A). Si la instancia
A est´a previamente ordenada en forma ascendente podemos probar que el
tiempo de proceso es el ´optimo porque solo inserta valores en el vector y no
realiza intercambios.
En el caso de que el vector estuviera ordenado en orden descendente por
cada elemento hay que recorrer todo el vector intercambiando los valores.
Este claramente es el peor comportamiento que podemos tener.
1.5. QU
´
E CONSIDERAR Y QU
´
E CONTAR 7
Si el vector estuviera ordenado en forma ascendente no realizar´ıa ning´ un
intercambio y este es el mejor caso en el que se puede estar.
Sin embargo si el vector estuviera desordenado en forma aleatoria el com-
portamiento se considera del caso medio.
Cuando el tiempo de respuesta de un problema es cr´ıtico normalmente
analizamos el peor caso que es mucho m´as f´acil de analizar que el caso medio.
Por lo tanto un an´alisis ´ util de un algoritmo requiere un conocimiento a priori
de las instancias que vamos a procesar.
1.5.3. Ejercicios
1. Si deseamos verificar que un n´ umero es primo, explique si lo que se
desea contar para hallar la eficiencia del algoritmo es: a) el n´ umero de
d´ıgitos b) el n´ umero de divisiones que se deben realizar.
2. Indique que es lo que deber´ıamos contar en el caso de escribir un al-
goritmo para multiplicar dos n´ umeros a fin de hallar el n´ umero de
operaciones requeridas para completar el algoritmo.
3. Suponiendo que el tiempo de proceso de una instancia es un mili segun-
dos. ¿En qu´e porcentaje se incrementa el tiempo de proceso al doblar el
tama˜ no de la instancia ? si el algoritmo es a) exponencial, b) logar´ıtmi-
co, c) cuadr´atico?
1.5.4. Laboratorio
Se quiere analizar el comportamiento del algoritmo de ordenar por el
m´etodo de inserci´on en forma experimental. Para esto seguiremos los si-
guientes pasos:
1. Codificar el algoritmo.
2. Crear una instancia ordenada en forma ascendente.
3. Tomar el tiempo de proceso para diferentes tama˜ nos de instancias.
4. Repetir el proceso para una instancia ordenada en forma descendente.
5. Luego para una instancia generada aleatoriamente.
6. Tabular los datos.
8 1. ALGOR
´
ITMICA ELEMENTAL
7. Interpretar los resultados.
Para realizar ´este experimento construimos el siguiente programa Java:
import java.util.*;
public class Isort {
/**
* Rutina Principal para la prueba experimental del
* programa de ordenar por el m´etodo de inserci´on
*
* @param args
* 0 crear las instancias en forma descendente
* 1 crear las instancias en forma ascendente
* 2 crear las instancias en forma aleatoria
*/
public static void main(String[] args) {
int opcion = Integer.parseInt(args[0]);
int instanciaMaxima = 1000000;
long tiempoInicio, tiempoFin, tiempoTotal;
for (int i = 10; i < instanciaMaxima; i = i * 10) {
Arreglo arreglo = new Arreglo(opcion, i);
tiempoInicio = System.currentTimeMillis();
arreglo.Ordena();
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println("Tama~no de la instancia " + i
+ " Tiempo de proceso " + tiempoTotal);
}
}
}
class Arreglo {
int[] t = new int[100000];
Random generador = new Random();
int n;
1.5. QU
´
E CONSIDERAR Y QU
´
E CONTAR 9
Arreglo(int opcion, int n) {
this.n = n;
for (int i = 0; i < n; i++) {
switch (opcion) {
case 0:
t[i] = i;
break;
case 1:
t[i] = 10000 - i;
break;
case 2:
t[i] = generador.nextInt(10000);
}
}
}
void Ordena() {
int x, j;
for (int i = 1; i < n; i++) {
x = t[i];
j = i - 1;
while ((j > 0) && (x < t[j])) {
t[j + 1] = t[j];
j = j - 1;
t[j + 1] = x;
}
}
return;
}
}
El resultado de los tiempos de ejecuci´on, en mili segundos, obtenidos en
la prueba del programa se ven en el cuadro 1.1.
Como se ve el peor caso es cuando la instancia que creamos est´a ordenada
en forma descendente. El caso medio se da cuando el vector est´a ordenado
aleatoriamente. En diferentes ejecuciones del programa veremos que el tiempo
de proceso que se obtiene en el caso medio var´ıa. Esto se debe a que los datos
10 1. ALGOR
´
ITMICA ELEMENTAL
Tama˜ no Ordenada Ordenada instancia
Instancia Ascendente Descendente Aleatoria
10 0 0 0
100 0 0 0
1000 0 20 10
10000 0 1722 861
100000 10 237622 110229
Cuadro 1.1: Tiempo de ejecuci´on en milisegundos
que se generan no est´an en el mismo orden. Situaci´on que no se da en las
otras instancias generadas. Una buena aplicaci´on de ´este c´odigo se da en los
casos en que los conjuntos de datos a los que vamos aplicar el m´etodo, est´an
casi totalmente ordenados.
Cap´ıtulo 2
An´alisis de algoritmos
2.1. Introducci´ on
Para el an´alisis de los algoritmos es muy importante determinar la eficien-
cia de los mismos. Esto se logra a trav´es del c´alculo del tiempo de proceso o
complejidad . Como no existen mecanismos normalizados para el c´alculo de
estos tiempos, solo nos referimos al tiempo tomado por el algoritmo multi-
plicado por una constante. A esto denominamos notaci´on asint´otica. Existen
tres conceptos, la notaci´on omega, la notaci´on teta y la notaci´on O grande
simbolizadas por Ω, θ y O respectivamente. En el texto se enfocar´a al an´ali-
sis del tiempo de proceso con la notaci´on O. Se recomienda la bibliograf´ıa
[McC01] y [EH96]
2.2. Notaci´ on orden de
La notaci´on orden de nos permite especificar la magnitud m´axima de
una expresi´on. Sea por ejemplo una funci´on t(n) = 5n
2
y podemos pensar
que n es como el tama˜ no de una instancia de un algoritmo dado. Ahora
supongamos que esta funci´on representa la cantidad de recursos que gasta el
algoritmo, ya sea el tiempo de proceso, almacenamiento de memoria u otros.
Las constantes solo representan valores de una implementaci´on dada y no
tienen que ver con el tama˜ no de la instancia.
En este caso decimos que esta funci´on t(n) es del orden n
2
dado que
solo est´a acotado por una constante. Esto se denomina O grande de t(n) y
matem´aticamente lo representamos como O(n
2
).
11
12 2. AN
´
ALISIS DE ALGORITMOS
2.2.1. Propiedades de O grande de n
Para aclarar lo que representa O grande de n describamos sus propieda-
des:
1. Regla del valor m´aximo. Dadas dos funciones f(n) y g(n) que pertene-
cen a los n´ umeros reales positivos incluyendo el cero
O(f(n) + g(n) = max(f(n), g(n))
por ejemplo si se tiene la funci´on t(n) = 5n
3
+ log n − n aplicando
la regla del valor m´aximo tenemos que O(t(n)) = max(5n
3
, log n, −n)
cuyo valor es O(n
3
).
2. Igualdad de logaritmos. En la notaci´on O la expresi´on
O(log
a
n) = O(log
b
n)
que, claramente es incorrecto en las matem´aticas, pero es correcta en
la notaci´on O.
Esto se demuestra aplicando la propiedad de los logaritmos para el
cambio de base log
a
n = log
b
n/log
b
a. Notamos que el denominador es
una constante y como en la notaci´on O no se escriben las constantes
queda demostrado.
3. Propiedad reflexiva. La notaci´on O es reflexiva dado que:
f(n)O(f(n))
4. Propiedad transitiva.
Sif(n)O(g(n))yg(n)O(h(n))entoncesf(n)O(h(n)).
5. Propiedades de l´ımites.
a) si l´ım
n→∞
f(n)
g(n)
'
+
⇒ f(n)O(g(n)) y g(n)O(f(n))
b) si l´ım
n→∞
f(n)
g(n)
= 0 ⇒ f(n)O(g(n)) pero g(n)O(f(n))
c) si l´ım
n→∞
f(n)
g(n)
= +∞ ⇒
f(n)O(g(n)) pero g(n)O(f(n))
2.3. NOTACI
´
ON ASINT
´
OTICA CONDICIONAL 13
2.3. Notaci´ on asint´ otica condicional
Muchos algoritmos son m´as f´aciles de analizar si restringimos nuestra
atenci´on a instancias que cumplen alguna condici´on tales como ser una po-
tencia de 2, ser de un tama˜ no determinado. Consideremos por ejemplo, un
algoritmo cuyo resultado para n = 1 es t(n) = 1 y para otros valores to-
ma nt(n −1). Este algoritmo se expresa como una soluci´on recursiva que se
escribe como sigue:
T(n) =
_
1 si n = 1,
nT(n −1) en otros casos.
en las secciones siguientes estudiamos como resolver ´estas ecuaciones deno-
minadas recurrencias.
2.4. Notaci´ on omega
La notaci´on omega que la representamos por Ω se utiliza para representar
la cota inferior de un algoritmo. Por ejemplo el algoritmo de ordenamiento
por inserci´on demora O(n
2
) en el peor caso sin embargo la cota inferior para
los programas de clasificaci´on que trabajan ´ unicamente por comparaciones
es Ω(nlog n) por lo tanto podemos decir que no existen algoritmos de clasi-
ficaci´on que en su peor caso sean mejores que Ω(nlog n).
Sea t(n)Ω(f(n)) si existe una constante real y positiva d tal que la re-
laci´on t(n) ≥ df(n) sea cierta para una cantidad infinita de valores de n, si
buscamos que la relaci´on se cumpla para un n´ umero finito de valores de n,
entonces f(n) es el l´ımite inferior del algoritmo.
2.5. Notaci´ on teta
Cuando analizamos un algoritmo estar´ıamos muy satisfechos si nuestro
algoritmo estuviera acotado simult´aneamente por Ω y O. Por esta raz´on se
introduce la notaci´on θ. Decimos que un algoritmo es en θ(f(n)) o que f(n)
es de orden exacto si:
θ(f(n)) = O(f(n)) ∩ Ω(f(n))
14 2. AN
´
ALISIS DE ALGORITMOS
Esta notaci´on se utiliza muy poco y como podr´a apreciar tiene un mayor
grado de dificultad. Comunmente se utiliza la notaci´on O y para mostrar la
relaci´on contra el mejor algoritmo posible usamos la notaci´on Ω.
2.6. An´alisis de las estructuras de control
2.6.1. Secuenciales
Sean p
1
y p
2
dos fragmentos de un algoritmo y sean t
1
y t
2
los tiempos que
toman cada uno respectivamente. La regla de secuencias indica que el tiempo
de ejecuci´on de la secuencia p
1
; p
2
toma un tiempo t
1
+ t
2
. Por la regla del
valor m´aximo el tiempo es (max(O(t
1
), O(t
2
)). Este an´alisis considera que
p
1
y p
2
son independientes. Esto es que, el proceso p
2
no depende de los
resultados de p
1
.
2.6.2. Ciclos For
Consideremos el programa siguiente
for i = 1 to m
p(i)
En este programa no confundamos m con n que es el tama˜ no de una instancia.
Si p(i) toma un tiempo constante t y no depende de i entonces este tiempo
se repetir´a m veces y denotamos esto como:
m

i=1
t = t
m

i=1
1 = tm = O(m)
En un caso mas general donde t(i) no es constante y depende de i deber´ıamos
calcular el resultado de la siguiente sumatoria:
m

i=1
t(i)
2.6. AN
´
ALISIS DE LAS ESTRUCTURAS DE CONTROL 15
2.6.3. Llamadas recursivas
El an´alisis recursivo de un algoritmo es normalmente casi directo y una
simple inspecci´on normalmente nos da una ecuaci´on de recurrencia que re-
presenta el comportamiento del mismo. Consideremos el problema de buscar
un elemento t en un arreglo a recursivamente
busca (n)
if n =0 return -1
else
if a[n]= t
return n
else
return busca(n-1)
En este algoritmo podemos ver que para los casos en que n es 0 el tiempo
que toma es una constante, cuando encuentra el valor tambi´en el tiempo es
una constante. En los otros casos depende del valor n − 1. Esto podemos
representar por una funci´on recurrente de la siguiente forma:
T(n) =
_
_
_
−1 si n = 0,
0 si a[n] = t,
T(n −1) +h(n) en otros casos.
El valor de h(n) es el n´ umero de operaciones elementales requeridas en cada
recursi´on. Podemos resolver esta recurrencia y demostrar que la soluci´on es
O(n).
2.6.4. Ciclos while y repeat
Los ciclos while y repeat son mucho m´as dif´ıciles de analizar porque no
existe una forma de saber cuantas veces se va a ejecutar. Para terminar un
ciclo hay que probar alguna condici´on que nos dar´a un valor de termina-
ci´on.Consideremos el c´odigo siguiente :
ejemplo(n)
i=0
while n>1
if par(n)
n=n/2
16 2. AN
´
ALISIS DE ALGORITMOS
i=i+1
else
n=3n/2
i=i+1
return i
En este ejemplo no podemos decidir a simple vista cuantas veces se ejecuta
la instrucci´on i = i + 1 se ve que cada vez que n es una potencia de 2 se
pasar´a por la parte par(n) y cuya cantidad de veces ser´a el log
2
n. ¿Qu´e po-
demos decir cuando es impar?. ¿El algoritmo termina?. Estas interrogantes
las dejamos para el an´alisis del lector.
En muchos casos ser´a necesario aplicar la teor´ıa de probabilidades para
poder determinar las veces que una instrucci´on se ejecuta. Si podemos deducir
una recurrencia a partir del algoritmo podemos hallar f´acilmente su O(n).
ejemplo(n)
i=0
while n>1
n=n/2
i=i+1
return i
En este ejercicio vemos que los valores que toma n son n, n/2, n/4... por
lo tanto podemos escribir esta recurrencia como
T(n) =
_
1 si n < 2,
T(n/2) + 1 en otros casos.
y luego de resolverla podemos indicar que el resultado es O(log n). Los
m´etodos para resolver recurrencias se explicar´an m´as adelante.
2.6.5. An´alisis del caso medio
Consideremos el algoritmo de ordenar por el m´etodo de inserci´on
inserci´on(t)
for i=1 to n
x= t[i]
j=i-1
while j > 0 and x<t[j]
2.6. AN
´
ALISIS DE LAS ESTRUCTURAS DE CONTROL 17
t[j+1]=t[j]
j=j-1
t[j+1]=x
De este algoritmo podemos ver que en el mejor caso, vale decir cuando los
datos vienen ordenados en forma ascendente, el tiempo es lineal y el peor
caso es de orden cuadr´atico que se da en el caso inverso.¿Cu´al es el com-
portamiento en el caso promedio? Para resolver esta interrogante se hace
necesario conocer a priori la funci´on de distribuci´on de probabilidad de las
instancias que, el algoritmo debe resolver. La conclusi´on del an´alisis del caso
medio depende de esta suposici´on.
Supongamos que todas las permutaciones posibles de las instancias pue-
den ocurrir con la misma probabilidad para determinar el resultado en prome-
dio debemos sumar el tiempo que, toma ordenar cada uno de las n! posibles
instancias. Definamos el rango parcial de T[i] como la posici´on que, ocupar´ıa
en el arreglo si estuviera ordenado. Supongamos que 1 ≤ i ≥ n y estamos
ingresando en ciclo while, T[i −1] contiene los mismos elementos que antes,
dado que T[i] todav´ıa no se ha insertado. Este rango parcial estar´a entre 1 y
i y lo llamaremos k.
La cantidad de veces que los elementos del vector se desplazar´an es i −
k + 1 porque los elementos hasta i −1 ya est´an ordenados. Como tenemos i
elementos la probabilidad que i ocurra es 1/i de aqu´ı calculamos el tiempo
que toma el ciclo while
c
i
=
1
i
i

k=1
(i −k + 1) =
i + 1
2
como tenemos n elementos en el ciclo principal debemos sumar los tiempos
de las instrucciones interiores dando
n

i=1
c
i
=
n

i=1
i + 1
2
=
n

i=1
i
2
+
n

i=1
1
2
=
n
2
+ 3n
4
2.6.6. An´alisis amortizado
El an´alisis del peor caso es muchas veces muy pesimista. Supongamos que
tenemos un programa con un vector que almacena valores y queremos en-
contrar el valor m´ınimo. Si el vector est´a ordenado devolver el primero toma
un tiempo constante. Supongamos que enviamos a esta rutina un n´ umero
18 2. AN
´
ALISIS DE ALGORITMOS
y si existe devuelve el valor m´ınimo y si no existe inserta el valor y luego
devuelve el valor m´ınimo. ¿Cu´anto tiempo toma el algoritmo? En el peor
caso toma el tiempo de insertar y de buscar, sin embargo muchas veces so-
lamente tomar´a el tiempo de buscar. Para entender el tiempo amortizado de
este algoritmo podemos pensar que, en cada b´ usqueda ahorramos un poco
para gastarlo cuando tengamos que realizar un inserci´on. Esto nos muestra
claramente que el tiempo amortizado depende de la probabilidad de que ten-
gamos inserciones y cual la probabilidad de que tengamos solo b´ usquedas.
La esperanza matem´atica es una buena medida para estos an´alisis.
2.7. Soluci´ on de recurrencias
Como ya vimos los algoritmos se pueden representar en forma de ecua-
ciones recurrentes aqu´ı explicaremos tres m´etodos de soluci´on, substituci´on
o adivinaci´on, iterativos y un m´etdo general para casos especiales.
2.7.1. M´etodo por substituci´on
El m´etodo de substituci´on que bien puede llamarse m´etodo por adivi-
naci´on se basa en adivinar de que forma es la soluci´on, luego aplicamos la
hip´otesis inductiva para valores menores y demostrando que ´esto se cum-
ple, decimos que nuestra suposici´on es correcta. Consideremos el siguiente
ejemplo:
T(n) =
_
1 n = 1,
2T(n/2) +n otros casos.
(2.7.1)
La recurrencia 2.7.1 puede escribirse como la ecuaci´on
2T(n/2) +n (2.7.2)
Primero buscamos una soluci´on y suponemos que el tiempo asint´otico O(n)
de esta ecuaci´on es O(nlog n). Debemos probar que ´esta es una funci´on para
la cual todos los valores de T(n) son menores con lo cual se demuestra que
es una cota superior.
Suponiendo que esta soluci´on es aplicable a n/2 para una constante arbi-
2.7. SOLUCI
´
ON DE RECURRENCIAS 19
traria c en la ecuaci´on 2.7.2 tenemos:
T(n) ≤ 2c(
n
2
log
n
2
) + n
= cnlog
n
2
+ n
= cnlog n −cnlog 2 + n
= cnlog n −cn + n
≤ nlog n para c ≥ 1
Con lo cual estar´ıa probada nuestra suposici´on. Como ver´a en algunas con-
diciones es dif´ıcil de probar esta recursi´on. Por ejemplo, consideremos que
T(1) = 1 reemplazando nuestra hip´otesis se tiene T(1) = c1 log 1 que da
T(1) = c0 y para cualquier valor de c vemos que no es posible probar nues-
tra suposici´on por lo que, es usual imponer algunas restricciones tales como
probar desde T(2).
Realizar suposiciones acertadas es muy complicado, por lo que se hace
necesario realizar diferentes pruebas con valores m´aximos y m´ınimos para
hallar la soluci´on. Lo que estamos realizando es una hip´otesis inductiva y en
muchas ocasiones podemos agregar m´as constantes por ejemplo, T(n) ≤ cn−
b, el restar algunas constantes de los t´erminos de menor orden es considerada
por muchos como una soluci´on intuitiva.
Este m´etodo es un problema, la cota superior probada no garantiza que
existe otra cota superior que sea menor a la probada. Consideremos por
ejemplo que se hubiese elegido n
2
como una cota superior tambi´en se hubiera
probado cierta porque O(nlog(n)) ∈ O(n
2
).
2.7.2. Cambio de variables
En muchos casos las soluciones tienen formas que no hemos visto antes
por lo que no podemos plantear la soluci´on. Consideremos la ecuaci´on:
T(n) = 2T(

n) + log n
Podemos simplificar esta ecuaci´on reemplazando n por 2
m
que nos da
T(2
m
) = 2T(2
m
2
) + log 2
m
T(2
m
) = 2T(2
m
2
) + m
20 2. AN
´
ALISIS DE ALGORITMOS
ahora reemplacemos T(2
m
) por S(m)
S(m) = 2S(
m
2
) + m
Esta soluci´on ya la conocemos y sabemos que es O(nlog n) entonces reem-
plazando en esta respuesta las substituciones que hemos realizado
T(n) = T(2
m
) = S(m) = O(mlog m) = O(log nlog log n).
2.7.3. Ejercicios
1. Muestre que la soluci´on de T(n) = T(n/2) + 1 es O(log n)
2. Muestre que la soluci´on de T(n) = T(n/2 + 17) + 1 es O(log n)
3. Resuelva la recurrencia T(n) = T(

n) +1 realizando cambio de varia-
bles
2.7.4. M´etodo iterativo
El m´etodo iterativo es mucho mejor porque no requiere adivinanzas que,
pueden hacernos suponer verdaderos resultados err´oneos. Pero a cambio se
requiere un poco m´as de ´algebra. Consideremos la siguiente recursi´on:
T(n) =
_
1 n = 1,
T(
n
2
) + 1 otros casos.
para resolver ´esta vamos comenzar en T(n) y vamos a desarrollar la misma
T(n) = T(
n
2
) + 1 reemplazando n por
n
2
= T(
n
4
) + 2
= T(
n
8
) + 3
hasta hallar la forma general
= T(
n
2
k
) + k
cuando n = 1 termina y por lo tanto T(1) toma la forma de:
T(1) = 1 =
n
2
k
2.7. SOLUCI
´
ON DE RECURRENCIAS 21
reemplazando tenemos:
T(n) = 1 + k = 1 + log n
de aqu´ı sabemos que el tiempo asint´otico de esta recursi´on es O(log n). Re-
solvamos con este m´etodo la ecuaci´on 2.7.1
T(n) =
_
1 n = 1,
2T(
n
2
) + n otros casos.
desarrollando la recursi´on tenemos
T(n) = 2T(
n
2
) + n
= 2(2T(
n
4
) +
n
2
) + n
= 4T(
n
4
) + 2
n
2
+ n
= 4T(
n
4
) + 2n
= 4(2T(
n
8
) +
n
4
) + 2n
= 8T(
n
8
) + 3n termina cuando
= 2
k
T(1) + kn
Este algoritmo termina cuando llegamos a T(1); donde toma el valor de 1
cuando n/2
k
= 1. Despejando el valor de k tenemos k = log n reemplazando:
T(n) = 2
k
+ kn
= n + nlog n
= O(nlog n)
Ejemplo:
Dar las cotas superiores para T(n) en las siguiente recurrencia. Asumiendo
que T(n) es constante para n ≤ 1.
T(n) = T(n −1) +n
Soluci´on:
Desarrollando la recursi´on tenemos:
T(n) = T(n −2) + (n −1) +n
= T(n −3) + (n −2) + (n −1) +n
22 2. AN
´
ALISIS DE ALGORITMOS
que toma la forma de
n

i=1
i
resolviendo tenemos
n(n + 1)
2
por lo que la cota superior es O(n
2
)
2.7.5. Ejercicios
1. Resolver T(n) = 3T(n/2) +n.
2. Resolver T(n) = T(n/3) +T(2n/3) +n.
3. Resolver T(n) = T(n −a) + T(a) + n
2.7.6. Teorema master
Existen muchas recursiones que tienen la forma
T(n) = aT(
n
b
) + f(n) (2.7.3)
La ecuaci´on 2.7.3 es un caso t´ıpico de soluciones que aplican la t´ecnica divide
y vencer´as donde a representa el n´ umero de llamadas recursivas T(n/b) el
tama˜ no de las llamadas y f(n) el trabajo realizado en cada recursi´on. Esta
ecuaci´on nos da las siguientes soluciones:
T(n) =
_
¸
¸
¸
¸
¸
¸
¸
¸
¸
¸
_
¸
¸
¸
¸
¸
¸
¸
¸
¸
¸
_
si f(n) = n
log
b
a−
, ≥ 0 ⇒ O(n
log
b
a
),
si f(n) = n
log
b
a
⇒ O(n
log
b
a
log n),
si f(n) = n
log
b
a+
, ≥ 0 ⇒ O(f(n)),
para polinomios donde
f(n) = cn
k
se simplifica
si a > b
k
⇒ O(n
log
b
a
),
si a = b
k
⇒ O(n
k
log n),
si a < b
k
⇒ O(n
k
)
(2.7.4)
La demostraci´on del teorema se puede consultar en la bibliograf´ıa [GB96]
citada al final del texto.
Resuelva los siguientes ejercicios utilizando el teorema master:
2.7. SOLUCI
´
ON DE RECURRENCIAS 23
1.
T(n) = 2T(
n
2
) + n
En este caso vea que a = 2, b = 2, k = 1 y f(n) = n
k
aplicando el
teorema estamos en el caso a = b
k
por lo que la soluciones es T(n) =
O(n
k
log n) = O(nlog n)
2.
T(n) = 9T(n/3) +n
Veamos a = 9, b = 3, k = 1 por lo que a ≥ b
k
entonces la soluci´on es
n
log
3
9
= O(n2)
3.
T(n) = T(2n/3) + 1
Veamos a = 1, b = 2/3, k = 0 por lo que a = b
k
entonces la soluci´on es
O(n
k
log n) = O(log n)
Ejercicios
Resolver utilizando el teorema master.
1. T(n) = 4T(n/2) +n.
2. T(n) = 4T(n/2) +n
2
.
3. T(n) = 4T(n/2) +n
3
.
2.7.7. Soluci´on general de recurrencias lineales
Las recurrencias de la forma
a
0
t
n
+ a
1
t
n−1
+ .... + a
k
t
n−k
= f(n) (2.7.5)
se denominan: ecuaci´on l´ıneal, homog´enea y de coeficientes constantes. Cuan-
do f(n) es 0 se denomina homog´enea y en otros casos no homog´enea. Una
buena descripci´on de como resolver estas recurrencias pueden ver en los libros
de Grimaldi [Gri77] y Knuth [RLG94]
24 2. AN
´
ALISIS DE ALGORITMOS
Soluci´on de recurrencias homog´eneas
La soluci´on de una ecuaci´on t(n) puede representarse como la combinacion
lineal de funciones por ejemplo c
1
f(n) + c
2
g(n).Consideremos la expresi´on
p(x) = a
0
x
k
+ a
1
x
k−1
+ .... + a
k
= 0
La soluci´on trivial es cuando x = 0 no es de inter´es. Esta ecuaci´on se denomi-
na ecuaci´on caracter´ıstica o polinomio caracter´ıstico. Recordando el ´algebra,
un polinomio de orden k tiene exactamente k ra´ıces y puede factorizarse
como
p(x) =
k

i=1
(x −r
i
)
donde r
i
son las soluciones de p(x) = 0. Cualquier r
i
es una soluci´on a ´este
polinomio por lo que tambi´en son una soluci´on a t(n) porque cualquier com-
binacion lineal tambien conforma una soluci´on, por lo que podemos concluir
que
t(n) =
k

i=1
(c
i
r
n
i
)
las soluciones se dan para cualquier constante que se escoja, siempre que las
ra´ıces sean distintas.
Ejemplo
Consideremos la secuencia de Fibonacci:
f(n) =
_
n si n = 0, n = 1,
f(n −1) +f(n −2) otros casos.
reescribimos esta ecuaci´on para satisfacer la ecuaci´on 2.7.5
f(n) −f(n −1) −f(n −2) = 0
Esta ecuaci´on tiene un polinomio caracter´ıstico
x
2
−x −1 = 0
que tiene como soluci´on las ra´ıces
r
1
=
1 +

5
2
y r
2
=
1 −

5
2
2.7. SOLUCI
´
ON DE RECURRENCIAS 25
entonces la soluci´on general es
f(n) = c
1
r
n
1
+ c
2
r
n
2
ahora utilizando las condiciones iniciales podemos hallar las constantes c
1
, c
2
c
1
+ c
2
= 0
r
1
c
1
+ r
2
c
2
= 1
resolviendo obtenemos
c
1
=
1

5
y c
2
= −
1

5
reemplazando en la ecuaci´on obtenemos
f(n) =
1

5
[(
1 +

5
2
)
n
−(
1 −

5
2
)
n
]
Solucici´on de recurrencias no homog´eneas
La recurrencias de la forma
a
0
t
n
+ a
1
t
n−1
+ .... + a
k
t
n−k
= b
n
p(n) (2.7.6)
b es una constante
p(n) es un polinomio en n de grado d.
Consideremos la recurrencia siguiente:
t(n) −2t(n −1) = 3
n
(2.7.7)
en este caso b = 3 y p(n) = 1 es un polinomio de grado 0, para resolver
este problema primero lo convertimos a un problema familiar, la recurrencia
homog´enea. Multiplicamos por tres la ecuaci´on 2.7.7
3t(n) −6t(n −1) = 3
n+1
(2.7.8)
ahora cambiemos n −1 por n
3t(n −1) −6t(n −1) = 3
n
(2.7.9)
26 2. AN
´
ALISIS DE ALGORITMOS
restando 2.7.7 de 2.7.8 tenemos una ecuaci´on homog´enea
t(n) −5t(n −2) + 6t(n −2) = 0 (2.7.10)
el polinomio caracter´ıstico es
x
2
−5x + 6 = (x −2)(x −3)
por lo que, las soluciones son de la forma
t(n) = c
1
2
n
+ c
2
3
n
Sin embargo no es cierto que cualquier constante arbitraria producir´a la
soluci´on correcta porque la ecuaci´on 2.7.7 no es la misma que la 2.7.10.
Podemos resolver la ecuaci´on original en base de t(0) y t(1). La funci´on
original implica que t
1
= 2t
0
+ 3 por lo que, las ecuaciones a resolver son:
c
1
+ c
2
= t(0)
2c
1
+ 3c
2
= 2t(0) + 3
de donde obtenemos c
1
= t(0) −3 y c
2
= 3. Resolviendo esto tenemos
t(n) = (t(0) −3)2
n
+ 3
n+1
que es independiente de la soluci´on inicial t(n)O(3
n
)
2.8. EJERCICIOS RESUELTOS 27
2.8. Ejercicios resueltos
1. ¿Cu´anto tiempo toma el siguiente algoritmo?
l=0
for i=1 to n
for j=1 to n^2
for k=1 to n^3
l=l+1
Soluci´on:
Recordando que los ciclos for son las sumas de los tiempos individuales
de los procedimientos interiores podemos escribir
T(n) =
n

i=1
(
n
2

j=1
(
n
3

k=1
1))
=
n

i=1
(
n
2

j=1
n
3
)
= n
3
n

i=1
n
2
= n
3
n
2
n = n
6
2. ¿Cu´anto tiempo toma el siguiente algoritmo?
l=0
for i=1 to n
for j=1 to i
for k=1 to j
l=l+1
Soluci´on:
28 2. AN
´
ALISIS DE ALGORITMOS
En este caso no todas las sumas son hasta n
T(n) =
n

i=1
(
i

j=1
(
j

k=1
1))
=
n

i=1
(
i

j=1
j)
=
n

i=1
i
i + 1
2
=
n

i=1
(
i
2
2
+
i
2
)
=
n

i=1
i
2
2
+
n

i=1
i
2
=
n(n + 1)(2n + 1)
12
+
n + 1
2
=
(n
2
+ n)(2n + 1)
12
+
n + 1
2
=
2n
3
+ 3n
2
+ n
12
+
n + 1
2
= O(n
3
)
3. Resolver utilizando el teorema master
procedure DC(n)
if n < = 1
DC(n/2)
for j=1 to n^3
x[j]=0
Soluci´on
Del an´alisis vemos que
T(n) =
_
1 n = 1,
T(n/2) +n
3
otros casos.
De donde tenemos a = 1, b = 2, k = 3 lo que nos lleva al caso 1 < 2
3
dando como soluci´on O(n
k
) = O(n
3
).
2.8. EJERCICIOS RESUELTOS 29
4. Resolver utilizando el teorema master
procedure DC(n)
if n < = 1
for i=1 to 8
DC(n/2)
for j=1 to n^3
x[j]=0
Soluci´on
Del an´alisis vemos que hay la parte de algoritmo que divide el problema
DC(n/2) se procesa 8 veces lo que cambia el problema anterior a
T(n) =
_
1 n = 1,
8T(n/2) +n
3
otros casos.
De donde tenemos a = 8, b = 2, k = 3 lo que nos lleva al caso 8 = 2
3
dando como soluci´on O(n
k
log n) = O(n
3
log n).
5. Dar las cotas superiores para T(n) en las siguientes recurrencias. Asu-
miendo que T(n) es constante para n ≤ 1.
T(n) = 2T(
n
2
) + n
3
Soluci´on:
Desarrollando la recursi´on tenemos:
T(n) = 2T(
n
2
) + n
3
= 2(2T(
n
4
) + (
n
2
)
3
) + n
3
= 4T(
n
4
) + 2(
n
2
3
) + n
3
= 4(2T(
n
8
) + (
n
4
)
3
) + 2(
n
2
3
) + n
3
= 8T(
n
8
) + 4(
n
4
)
3
+ 2(
n
2
3
) + n
3
De aqu´ı vemos que para un t´ermino i toma la forma
T(n) = 2
i
T(
n
2
i
) +
i−1

k=0
2
k
(
n
2
k
)
3
30 2. AN
´
ALISIS DE ALGORITMOS
T(1) se da cuando
n
2
i
= 1 entonces i = log(n)
reemplazando tenemos:
T(n) = n + n
3
i−1

k=1
(
1
2
k
)
2
= n + n
3
i−1

k=1
(
1
4
k
)
i−1

k=1
(
1
4
k
) =
1 −(
1
4
)
i−1
1 −
1
4
=
4
3
(1 −
1
4
i−1
)
=
4
3

1
3
1
4
i−2
=
4
3

1
3
1
2
2i−2
=
4
3

1
3
1
2
2 log(n)−2
=
4
3

1
3
4
n
2
T(n) = n + n
3
(
4
3

1
3
4
n
2
)
= n + n
3
4
3

4
3
n)
por lo que, la cota superior es O(n
3
)
6. Dar las cotas superiores para T(n) en las siguientes recurrencias. Asu-
miendo que T(n) es constante para n ≤ 2.
T(n) = 2T(
n
4
) +

n
Soluci´on:
Desarrollando la recursi´on tenemos:
T(n) = 2(2T(
n
4
2
) +
_
n
4
) +

n
= 4T(
n
4
2
) + 2
_
n
4
+

n
2.8. EJERCICIOS RESUELTOS 31
De aqu´ı vemos que para un t´ermino i toma la forma
T(n) = 2
i
T(
n
4
i
) +
i−1

k=1
2
k
(
_
n
4
k
)
t(1) se da cuando
n
4
i
= 1 entonces i = log
4
(n) adem´as notamos que
4
i
= (2
i
)
2
reemplazando tenemos:
= 2
i
T(1) +
i−1

k=1
2
k
_
n
4
k
+

n
=
n
2
+

n +
i−1

k=1
2
k
_
n
2
k
2
=
n
2
+

n +
i−1

k=1

n
=
n
2
+

n + (i −1)

n
=
n
2
+

n + (log
4
(n) −1)

n
=
n
2
+

n + log
4
(n)

n −

n
por lo que la cota superior es O(log(n)

n).
7. Dar las cotas superiores para T(n) asumiendo que T(n) es constante
para n ≤ 2.
T(n) = 2T(

n) + 1
Soluci´on:
Desarrollando la recursi´on tenemos:
T(n) = 2T(n
1
2
) + 1
= 4T(n
(
1
2
)
2
) + 2 + 1
= 8T(n
(
1
2
)
3
) + 4 + 2 + 1
que toma la forma de
T(n) = 2
i
T(n
(
1
2
)
i
) +
k=i−1

k=0
2
k
= 2
i
T(n
(
1
2
)
i
) + 2
i
−i
32 2. AN
´
ALISIS DE ALGORITMOS
cuando n
(
1
2
)
i
= 2 estamos en T(2) que es constante
(
1
2
)
i
log(n) = log(2) = 1
2
i
= log(n)
T(n) = log(n)T(2) + log(n) −1 = 2 log(n) −1
la cota superior es O(log n)
2.9. Ejercicios
1. Resolver las siguientes recurrencias utilizando el teorema master, ve-
rificar con el m´etodo de substituci´on y desarrollando la recurrencia.
Asuma que T(1)=1.
a) T(n) = 2T(
n
2
) + log(n)
b) T(n) = 3T(
n
3
) + log(n)
c) T(n) = 4T(
n
4
) + log(n)
d) T(n) = 2T(
n
2
) + n
2
e) T(n) = 2T(
n
2
) + n
3
f ) T(n) = 2T(
n
2
) + n
4
g) T(n) =
_
(n)T(

n) + n
2. Hallar el O(n) del siguiente programa de b´ usqueda binaria.
int l,u,m;
l=0; u=n-1;
while(l<u) {
m=(l+u)/2
if (a[mid]< x)
l=m+1
else
if (a[mid]> x)
l=m-1
else
2.9. EJERCICIOS 33
return ("hallado")
}
return ("no existe">)
3. Hallar el O(n) del siguiente programa para hallar el m´aximo com´ un
divisor. Sugerencia escribir el tama˜ no de la instancia en cada iteraci´on
y aproximar a una serie arm´onica.
mcd(m,n) {
while (n> 0){
resto=m%n
m=n
n=resto
}
return (m)
}
4. Hallar el O(n) del siguiente programa de exponenciaci´on.
pot(x,n) {
if (n=0)
return 1
if (n==1)
return x
if (par(n))
return (pot(x*x,n/2))
else
return (pot(x*x,n/2)*x)
}
5. Realizar una prueba experimental para comprobar las cotas superiores
de los programas anteriormente propuestos.
6. Codificar el programa de b´ usqueda binaria en forma recursiva y hallar
el O(n)
7. Se tienen dos programas A y B cuyo tiempo de ejecuci´on es 150 log(n)
milisegundos y 150n
2
respectivamente. Indique que programa es mejor
para n < 100,n < 1, 000, n > 10, 000
34 2. AN
´
ALISIS DE ALGORITMOS
2.10. Nota sobre el c´alculo integral
Cuando tenemos una sumatoria, desde nuestras clases de c´alculo, asocia-
mos la misma a una integral. Como la sumatoria es acotada, se podr´ıa pensar
en utilizar una integral definida.
Consideremos por ejemplo la siguiente sumatoria y su resultado:
n

i=0
i
2
=
n(n + 1)(2n + 1)
6
(2.10.1)
Si suponemos que es posible hallar el resultado integrando la sumatoria
se tiene lo siguiente:
_
i = 0ni
2
=
i
3
3
[
n
0
=
n
3
3
+ c (2.10.2)
Claramente las ecuaciones 2.10.1 y 2.10.2 son diferentes. ¿Entonces para
qu´e podemos utilizar el c´alculo integral?
Bien, si queremos obtener la cota superior en la ejecuci´on de un algoritmo,
debemos obtener o(f(n)) de las 2.10.1 y 2.10.2
O(
n(n + 1)(2n + 1)
6
) = n
3
O(
n
3
3
+ c) = n
3
Como ve, ambos resultados nos dan la misma cota superior. En el libro
de matem´aticas concretas de Donald Knuth [RLG94] se puede encontrar un
m´etodo para hallar el resultado de una suma a trav´es del c´alculo.
Cap´ıtulo 3
Teor´ıa de n´ umeros
3.1. Introducci´ on
Se hace muy importante la teor´ıa de n´ umeros en el aprendizaje de la pro-
gramaci´on. Este conocimiento permite comprender los aspectos que hacen al
proceso computacional, tales como las capacidades de la m´aquina, el tama˜ no
m´aximo de n´ umeros que se pueden tratar y como trabajar con n´ umeros m´as
grandes.
En el tratamiento de este cap´ıtulo se toman en cuenta los aspectos rela-
tivos al tiempo de proceso para hacer eficiente los algoritmos expuestos.
3.2. Variables del lenguaje Java
El lenguaje de programaci´on Java tiene varios tipos de variables enteras
que se muestran en el cuadro 3.1.
tipo Nro. Bytes Nro. Bits Rango de n´ umeros permitido
byte 1 bytes 8 bits desde −(2
7
+ 1) hasta + 2
7
short 2 bytes 16 bits desde −(2
15
+ 1) hasta + 2
15
int 4 bytes 32 bits desde −(2
31
+ 1) hasta + 2
31
long 8 bytes 64 bits desde −(2
63
+ 1) hasta + 2
63
Cuadro 3.1: Tipos de variables enteras en Java
Para evaluar el tiempo de proceso de las operaciones de suma, multi-
plicaci´on y divisi´on construimos un programa que repita muchas veces una
35
36 3. TEOR
´
IA DE N
´
UMEROS
operaci´on, midiendo el tiempo de ejecuci´on. Esto permite determinar cuanto
tiempo consumen los diferentes tipos de variables y escoger la m´as adecuada
para mejorar el tiempo de proceso. El programa siguiente nos permite me-
dir el tiempo que toma la operaci´on de multiplicar realizando 10.000.000 de
operaciones de multiplicaci´on para una variable entera.
public class Tiempos {
/**
* Programa para medir el tiempo de proceso en
* milisegundos de las operaciones elementales
* suma , Multiplicaci´on y divisi´on
* @author Jorge Teran
* @param args
* none
*/
public static void main(String[] args) {
int j = 1;
long tiempoInicio, tiempoFin, tiempoTotal;
tiempoInicio = System.currentTimeMillis();
for (int i = 1; i < 10000000; i++) {
j = j * 3;
}
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(
"Tiempo de proceso de la Multiplicacion "
+ tiempoTotal);
tiempoInicio = System.currentTimeMillis();
}
}
Una vez procesado este programa contruimos el cuadro 3.2 para comparar
el tiempo de proceso para cada tipo de variable. Se puede observar que una
operaci´on de divisi´on demora mucho m´as que una operaci´on de multiplica-
ci´on. Tambi´en se observa que las operaciones de tipo long demoran casi el
doble de tiempo que las operaciones enteras.
3.3. C
´
ALCULO DEL M
´
AXIMO COM
´
UN DIVISOR 37
Operacion tipo Tiempo en mseg para 10.000.000 repeticiones
suma int 110
suma long 190
multiplicaci´on int 140
multiplicaci´on long 230
divisi´on int 771
divisi´on long 2334
Cuadro 3.2: Comparaci´on de los tiempos de ejecuci´on de las operaciones
b´asicas
3.3. C´alculo del m´aximo com´ un divisor
Dados dos n´ umeros enteros se denomina m´aximo com´ un divisor al m´axi-
mo n´ umero que es divisor de ambos n´ umeros. Como ejemplo, tomemos los
n´ umeros 20 y 8. Los divisiores del n´ umero 20 son: 20,10, 5,4 y 2. Los divi-
sores del n´ umero 8 son el 8, 4 y 2. De aqu´ı vemos que el m´aximo com´ un
divisor es el n´ umero 4. Para resolver adecuadamente este problema se con-
truye un programa, inicialmente con la idea explicada, calculamos su O(n)
para posteriormente buscar un soluci´on m´as eficiente.
Para realizar una primera aproximaci´on a la soluci´on del problema pro-
baremos todos los n´ umeros hallando el m´aximo n´ umero que divida a ambos.
Mcd(int a, int b) {
int mcd() {
int i;
for (i=b; i>1;i--){
if (((a%i==0) && (b%i==0))) {
break;
}
}
return (i);
}
}
An´alisis:
Se puede apreciar que primero a > b cuando hallamos el primer divisor
este ya es m´aximo porque comenzamos en b y vamos restando de uno en uno.
38 3. TEOR
´
IA DE N
´
UMEROS
En el peor caso cuando el m´aximo com´ un divisor es 1 el algoritmo realiza el
m´aximo n´ umero de operaciones. Para calcular el O(n) requerimos resolver
1

i=b
1 = b
o sea O(n). Para mejorar este algoritmo se hace necesario analizar algunas
propiedades matem´aticas.
3.3.1. Divisibilidad
En la teor´ıa de n´ umeros la notaci´on a[b se lee a divide b significa que
b = ka para alg´ un k > 0. Tambi´en se dice que b es m´ ultiplo de a.
Si a[b decimos que a es un divisor de b por ejemplo los divisores de 20
son: 1, 2,4,5 ,10 y 20.
Todo entero a, es divisible por el divisor trivial 1. Los divisores no triviales
se denominan factores.
Cuando un n´ umero tiene como ´ unico divisor el n´ umero 1 y a si mismo se
denomina n´ umero primo.
Teorema 1. Para cualquier entero a y un n´ umero positivo n existen enteros
k y r tal que 0 ≤ r < n y a = qn + r
El valor q = ¸a/n| se denomina cociente de la divisi´on y r de denomina
residuo o resto. El valor r tambi´en se expresa como r = a mod n. De esto
vemos que n[a si y solo si a mod n = 0
Si d[b y d[a entonces d es un com´ un divisor de a y b. En este caso, se
verifica
d[(a + b)
y en un caso m´as general d[(xa + yb)
si b[a y a[b significa que a = ±b
si b[a significa que b ≤ a o que a = 0
El m´aximo com´ un divisor de dos n´ umeros a, b ambos diferentes a cero, se
denomina al divisor com´ un m´as grande de a, b. Se lo denominamos como
mcd(a, b). Se define mcd(0, 0) = 0. Algunas propiedades son las siguientes:
3.3. C
´
ALCULO DEL M
´
AXIMO COM
´
UN DIVISOR 39
mcd(a, b) = mcd(b, a)
mcd(a, b) = mcd(−a, b)
mcd(a, b) = mcd([a[ , [b[)
mcd(a, ka) = a
mcd(a, 0) = [a[
Teorema 2. Si a, b son n´ umeros enteros, diferentes de cero el mcd(a, b) es
el elemento m´as peque˜ no del conjunto ¦ax + by¦ donde x, y ∈ Z.
Demostraci´on. Sea q = ¸a/s| y sea s el entero m´as peque˜ no de la combina-
ci´on lineal de a y b. Entonces
a mod s = a −qs
= a −q(ax + by)
= a(1 −qx) + b(qy)
Esto muestra que a mod s es una combinaci´on lineal de a y b. El n´ umero
m´as peque˜ no que puede dar a mod s es 0 dado que a mod s < s. Podemos
hacer un an´alisis similar y encontrar lo mismo para b. Esto indica que s[a y
que s[b por lo que s es un divisor com´ un de a y b.
De ac´a vemos que mcd(a, b) ≥ s. Dado que el mcd(a, b) > 0 y que s divide
a ambos a y b debe dividir tambi´en a una combinaci´on lineal de a y b por lo
que mcd(a, b) ≤ s. Si mcd(a, b) ≥ s y mcd(a, b) ≤ entonces mcd(a, b) = s
De este teorema podemos deducir las siguientes propiedades:
Dados los n´ umeros enteros positivos a, b, n
si n[ab y mcd(a, n) = 1 entonces b[n.
mcd(na, nb) = n mcd(a, b).
Si d[a y d[b entonces mcd(a, b)[d.
Teorema 3. (Teorema de Euclides) Para cualesquiera dos enteros no nega-
tivos a, b
mcd(a, b) = mcd(a, mcd(a mod b))
40 3. TEOR
´
IA DE N
´
UMEROS
Demostraci´on. Se puede escribir a como tb + r y reemplazando se tiene
mcd(a, b) = mcd(tb + r, b)
cualquier divisor com´ un de b y a debe dividir tb +r. Cualquier divisor de de
tb tambi´en es divisor de b que implica que cualqiuier divisor de b debe dividir
a r.
Ahora vamos a aplicar el algoritmo denominado de Euclides para hallar
el m´aximo com´ un divisor de dos n´ umeros. Primeramente escribiremos una
funci´on recursiva para hacer m´as simple el c´alculo de su complejidad.
Mcd(a,b)
if (b==0)
return (a)
else Mcd(b, a%b)
Esta recursi´on la podemos escribir como
T(n) =
_
1 si n = 0,
T(
n
b
) + 1 en otros casos.
Como ve toma la forma del teorema master
T(n) = aT(
n
b
) + n
k
donde b reduce su tama˜ no en a mod b en cada iteraci´on por lo que podemos
aplicar el teorema y se ve que a = 1, b = a mod b, k = 0 donde a = b
k
. Esto
nos dice que el tiempo que toma algoritmo en su peor caso es O(log n).
Para ahorrar la memoria utilizada por la recursi´on se presenta una solu-
ci´on recursiva
public class Euclides {
/**
* Programa para hallar el
* maximo comun divisor
* con el metodo de Euclides
* @author Jorge Teran
3.3. C
´
ALCULO DEL M
´
AXIMO COM
´
UN DIVISOR 41
*/
int a, b;
Euclides(int a, int b) {
if (a>b){
this.a = a;
this.b = b;
}
else
{
this.b = b;
this.a = a;
}
}
int mcd() {
int r=b;
while (b> 0){
r=a%b;
a=b;
b=r;
}
return (a);
}
}
3.3.2. Algoritmos extendido de Euclides
El algoritmo de Euclides Extendido muestra como calcular los valores x, y
de la expresi´on ax + by = mcd(a, b). Conocemos que
mcd(a, b) = mcd(b, r)
donde:
r = a −b ¸a/b|
suponiendo que conocemos x

y y

tal que
rx

+ by

= mcd(b, r) = mcd(a, b)
42 3. TEOR
´
IA DE N
´
UMEROS
reemplazando
(a −b ¸a/b|)x

+ by

+ = mcd(a, b)
reordenando
ax

+ b(y

−y

¸a/b|) = mcd(a, b)
Vemos que cuando a = 0 el valor de x debe ser 0 y y = 1
El siguiente programa realiza el c´alculo de los valores x, y
/*Programa para el algoritmo
* extendido de Euclides
* @author Jorge Teran
*
*/
void eMcd (int a, int b){
int x, yAnt, r, aIni, bIni, sr,q;
aIni = a;
bIni = b;
x = 1;
yAnt = 0;
while (b != 0)
{
r = a % b;
q=a/b;
a = b;
b = r;
sr = x - yAnt*q;
x = yAnt;
yAnt = sr;
}
System.out.print("mcd= "+a);
System.out.print(" x= "+x);
System.out.println(" y= "+((a-x*aIni)/bIni));
}
Para una mayor comprensi´on se muestra un ejemplo de una ejecuci´on.
Hallemos ax +by = mcd(a, b) con a = 97 y b = 66. El cuadro 3.3 ejemplifica
la ejecuci´on del programa.
Como se ve la ecuaci´on ax + by = mcd(a, b) se cumple con los ´ ultimos
valores obteniendo 97 (−17) + 66 25
3.4. M
´
INIMO COM
´
UN M
´
ULTIPLO 43
a b q=a/b r mcd sr x y 97*x+66*y
97 66 1 31 66 1 0 1 66
66 31 2 4 31 -2 1 -1 31
31 4 7 3 4 15 -2 3 4
4 3 1 1 3 -17 15 -22 3
3 1 3 0 1 66 -17 25 1
Cuadro 3.3: Prueba de ejecuci´on del algoritmo de extendido de Euclides
3.4. M´ınimo com´ un m´ ultiplo
El m´ınimo com´ un m´ ultiplo (mcm) de dos n´ umeros es el n´ umero m´as
peque˜ no que es divisible por ambos n´ umeros. Por ejemplo el m´ınimo com´ un
m´ ultiplo entre 9 y 6 es 18. Para el c´alculo del m´ınimo com´ un m´ ultiplo no
existe un algoritmo similar al de Euclides que facilite hallar este n´ umero.
Este n´ umero se expresa como sigue:
mcm(a, b) = min¦k, k > 0 y a[k y b[k¦
sin embargo es posible probar que
mcd(a, b)mcm(a, b) = ab
En el ejemplo podemos ver que el mcd(9, 6) es 3 y que 3x18 = 54 = 9x6
3.5. Aritm´etica modular
La aritm´etica modular es una de las aplicaciones m´as importantes de
la teor´ıa de n´ umeros. Est´a representada por la funci´on mod . La funci´on
m´odulo representa el resto de la divisi´on. Por ejemplo a mod b significa que
queremos hallar el resto de
a
b
que representamos como
a mod b = a −b
_
a
b
_
(3.5.1)
La aritm´etica modular tambi´en define un sistema de numeraci´on. Veamos
por ejemplo la secuencia:
0 mod 3, 1 mod 3, 2 mod 3, 3 mod 3, 4 mod 3....
evaluando tenemos 0, 2, 1, 0, 1... que equivale a la numeraci´on en base 3.
44 3. TEOR
´
IA DE N
´
UMEROS
3.5.1. Propiedades
Presentamos algunas propiedades importantes de la aritm´etica modular.
Suma (x + y) mod m = (x mod m + y mod m) mod m. Por ejemplo
(8 + 7) mod 3 = 15 mod 3 = 0 y por la propiedad de la suma (8
mod 3 + 7 mod 3) mod 3
Resta La resta es solo la suma con valores negativos por los que (x − y)
mod m = (x mod m−y mod m) mod m.
Multiplicaci´on La multiplicaci´on xy mod m = (x mod m)(y mod m)
mod m. Esto se da debido a que la multiplaci´on es simplemente una
suma repetida.
Divisi´on No existe el inverso de la multiplicaci´on como la conocemos por
ejemplo veamos dx mod m = dy mod m se puede pensar que pode-
mos simplificar d obteniendo x mod m = y mod m, que no se cumple
en todos los casos. Veamos un ejemplo
6 2 mod 3 = 6 1 mod 3 = 0
si simplificamos el 6 tenemos 2 mod 3 = 1 ,= 1 mod 3 = 2.
Solo es posible realizar estas simplificaciones cuando el mcd(d, m) = 1.
Existen muchas aplicaciones de la aritm´etica modular, por ejemplo en el
calendario los d´ıas de la semana correponden a una aritm´etica m´odulo 7, las
horas, minutos y segundos corresponden al m´odulo 60. Hallar el ´ ultimo d´ıgito
de un n´ umero decimal corresponde a una aritm´etica m´odulo 10.
El ejemplo que se presenta es extractado de [MAR03]. Hallar el ´ ultimo
d´ıgito del n´ umero 2
100
. Para ´esto no es necesario hallar el valor del exponente
y luego obtener el ´ ultimo d´ıgito se puede resolver como sigue:
2
3
mod 10 = 8
2
6
mod 10 = (8 8) mod 10 = 4
2
12
mod 10 = (4 4) mod 10 = 6
2
24
mod 10 = (6 6) mod 10 = 6
2
48
mod 10 = (6 6) mod 10 = 6
2
96
mod 10 = (6 6) mod 10 = 6
2
100
mod 10 = 2
9
6 2
3
2
1
mod 10 = 6 8 2 mod 10 = 6
3.5. ARITM
´
ETICA MODULAR 45
3.5.2. Congruencias
Se dice que a es congruente b m´odulo m cuando (a − b)/m = km. Se
escribe
a ≡ b mod m
Esto equivale a que a, b son m´ ultiplos de m Algunas propiedades de las con-
gruencias son:
Propiedad reflexiva a ≡ a
Propiedad sim´etrica a ≡ b ⇒ b ≡ a
Propiedad transitiva a ≡ b ≡ c ⇒ a ≡ c
Suma a ≡ b y c ≡ d ⇒ (a + c) ≡ (b + d) mod m
Multiplicaci´on a ≡ b y c ≡ d ⇒ (ac) ≡ (bd) mod m con b, c enteros
Potencias a ≡ b ⇒ a
n
≡ b
n
mod m
Si se quiere conocer si 2
n
−1 es m´ ultiplo de 3. Es decir que (2
n
−1) mod 3 = 0.
Podemos aplicar la propiedad de la potencia y escribir 2 ≡ −1 mod 3 de
donde 2
n
≡ (−1)
n
mod 3. Por lo tanto es m´ ultiplo de 3 cuando n es par.
3.5.3. Inverso multiplicativo
Consideremos que mcd(a, n) = 1 entonces existen enteros b y c tales que
ba + cn = 1. Esto se puede escribir como ba ≡ 1 mod n. De aqu´ı b se
denomina inverso multiplicativo de a.
3.5.4. Soluci´on de ecuaciones
La ecuaci´on de congruencia de primer orden est´a definida como:
ax ≡ b( mod m)
Estas ecuaciones tienen soluci´on solo si mcd(a, m)[b Para resolver este tipo
de ecuaci´on se sigue la siguiente estrategia.
ax −b = km
ax = b + km y buscamos un k tal que a[(b + km)
46 3. TEOR
´
IA DE N
´
UMEROS
hallamos x
Ejemplos:
1. Resolver 6x ≡ 5(mod/3). como mcd(6, 3) = 2 no es divisor de 5,no se
tiene una soluci´on.
2. Resolver 4x ≡ 10(mod/6)
4x = 10 + k6
4x = 10 + 6 con k = 1
x = 4
si reemplazamos el valor de x encontrado tenemos:
4 4 ≡ 6( mod 6)
tambi´en pueden plantearse sistemas de ecuaciones de congruencias, por ejem-
plo, si recogemos una cantidad de cajas en las cuales vienen 3 equipos y
tenemos 2 equipos sueltos. Por otro lado si recibimos la misma cantidad de
equipos, en cajas en las cuales vienen 5 equipos y tenemos 1 equipo suelto.
Se desea conocer cuantos equipos se recibieron. Esto se puede escribir como:
x ≡ 3( mod 7) (3.5.2)
5x ≡ 7( mod 12) (3.5.3)
si la soluci´on de 3.5.2 es x = 3 + k7 para alg´ un valor k podemos reemplazar
x en la segunda ecuaci´on obteniendo:
5(3 + k7) ≡ 7( mod 12)
15 + 35k ≡ 7( mod 12)
35k ≡ −8( mod 12)
significa que k = 8+12t para alg´ un t reemplazando en 3.5.2 x = 3+(8+12k)7
que da x = 59 + 84t de donde x = 59.
3.6. N
´
UMEROS PRIMOS 47
3.6. N´ umeros primos
La teor´ıa de los n´ umeros primos ha tenido un desarrollo muy intenso con
las aplicaciones de criptograf´ıa. En esta secci´on le dedicamos un especial in-
ter´es debido a las complejidades que lleva ´este cuando se trabaja con n´ umeros
grandes.
Se define como primo el n´ umero entero positivo que es divisible solamente
por 1 o por si mismo. Los primeros n´ umeros primos son 2, 3, 5, 7, 11, 19...
Como se ve el ´ unico n´ umero primo par es el n´ umero 2. El n´ umero 1 no
es parte de los n´ umeros primos, sin embargo, algunos autores amplian la
definici´on para incluirlo.
Para muchas aplicaciones es necesario realizar un test de primalidad que
significa verificar si el n´ umero es primo o no. Esto se puede realizar por
divisiones sucesivas sin embargo no es un m´etodo muy adecuado cuando se
trata de n´ umeros grandes.
3.6.1. Generaci´on de primos
Es posible probar la primalidad de un n´ umero n en un tiempo proporcio-
nal a O(

n) con el siguiente c´odigo de divisiones sucesivas
j = 2;
while (j * j <= n) {
if ((i%j)==0)
break; //no primo
j++;
}
El problema que representa este m´etodo es la cantidad de divisiones que
hay que realizar. Como ya vimos el tiempo que toma una divisi´on es mucho
mayor al de la suma. Para convertir ´estas divisiones en suma de n´ umeros, la
forma m´as f´acil es a trav´es del m´etodo denominado la criba de Erat´ostenes.
La criba de Erat´ostenes se contruye a partir de los m´ ultiplos de los n´ ume-
ros como sigue
1. Se marcan los m´ ultiplos de 2.
2. Luego los de 3, 5, 7, etc. sucesivamente.
48 3. TEOR
´
IA DE N
´
UMEROS
M´ ultiplo de 2 3 4 5 6 7 8 9 10 11 12 13 14 15
2 x x x x x x
3 x x x x
5 x x
Marcados x x x x x x x x
Cuadro 3.4: Ejemplo de una criba de Erat´ostenes
3. Una vez completado el marcado los no marcados son los n´ umeros pri-
mos.
Como se observa en el cuadro 3.4 se marcan en la primera pasada los
m´ ultiplos de 2, la segunda pasada los m´ ultiplos de 3 y as´ı sucesivamente.
Al terminar el proceso los d´ıgitos no marcados son los n´ umeros primos. El
siguiente programa muestra como contar cuantos n´ umeros primos hay hasta
100.000.000.
import java.util.*;
/**
* Programa contar los n´umeros primos
* hasta n = 100,000,000 utilizando la
* Criba de Eratostenes
* @author Jorge Teran
*/
public class Criba {
public static void main(String[] s) {
int n = 100000000;
long inicio = System.currentTimeMillis();
BitSet a = new BitSet(n + 1);
int contar = 0;
int i = 2, j = 0;
// construccion de la criba
for (i = 2; i * i <= n; i = i + 1) {
//el siguiente control es para no pasar
//por valores ya tomados en cuenta
if (!a.get(i)) {
for (j = i + i; j <= n; j = j + i) {
a.set(j);
3.6. N
´
UMEROS PRIMOS 49
}
}
}
// contar los n´umeros primos
for (i = 2; i <= n; i++) {
if (!a.get(i)) {
contar++;
}
}
long fin = System.currentTimeMillis();
System.out.println(contar + " primos");
System.out.println((fin - inicio) + " milisegundos");
}
}
En la computadora demor´o 78.013 milisegundos dando el resultado de
5.761.455 primos.
Los n´ umeros primos que pueden calcularse a trav´es de este m´etodo se
consideran n´ umeros peque˜ nos. El n´ umero m´aximo depende de la memoria
de la m´aquina, la implementaci´on realizada y el lenguaje de programaci´on.
Vea que si almacena solo los n´ umeros impares puede almacenar el doble de
n´ umeros en la criba.
La p´agina http://primes.utm.edu/ proporciona un acceso importante a la
teor´ıa de n´ umeros primos y publica la cantidad de primos por rango conocidos
a la fecha, est´an detallados en el cuadro 3.5.
3.6.2. Factorizaci´on
La factorizaci´on de un n´ umero consiste en descomponer el mismo en sus
divisores. Se demuestra que todos los factores son n´ umeros primos. Analice
que si uno de sus factores es un n´ umero compuesto tambi´en podr´ıa descom-
ponerse en factores. Para una demostraci´on m´as formal vean [THCR90].
La forma de expresar ´estos factores es como sigue: a
n
1
1
a
n
2
2
a
n
3
3
....
Los factores primos de 168 son 2, 2, 2, 3, 7 que se expresa como 2
3
3 7 =
168. El siguiente c´odigo muestra el proceso de factorizaci´on de n´ umeros. Hay
que indicar que este proceso es aplicable a n´ umeros peque˜ nos.
50 3. TEOR
´
IA DE N
´
UMEROS
Hasta Cantidad de Primos
10 4
100 25
1.000 168
10.000 1.229
100.000 9.592
1.000.000 78.498
10.000.000 664.579
100.000.000 5.761.455
1.000.000.000 50.847.534
10.000.000.000 455.052.511
100.000.000.000 4.118.054.813
1.000.000.000.000 37.607.912.018
10.000.000.000.000 346.065.536.839
100.000.000.000.000 3.204.941.750.802
1.000.000.000.000.000 29.844.570.422.669
10.000.000.000.000.000 279.238.341.033.925
100.000.000.000.000.000 2.623.557.157.654.233
1.000.000.000.000.000.000 24.739.954.287.740.860
10.000.000.000.000.000.000 234.057.667.276.344.607
100.000.000.000.000.000.000 2.220.819.602.560.918.840
1.000.000.000.000.000.000.000 21.127.269.486.018.731.928
10.000.000.000.000.000.000.000 201.467.286.689.315.906.290
Cuadro 3.5: Cantidad de primos por rango conocidos a la fecha
3.6. N
´
UMEROS PRIMOS 51
Factores (Long N){
/**
* Programa para hallar los factores Primos
* @author Jorge Teran
*/
System.out.print(
"Los factores primos de: " + N + " son: ");
for (long i = 2; i <= N / i; i++) {
while (N % i == 0) {
System.out.print(i + " ");
N = N / i;
}
}
// Si el primer factor ocurre una sola vez
if (N > 1) System.out.println(N);
else System.out.println();
}
3.6.3. Prueba de la primalidad
La prueba de primalidad es simple para n´ umeros primos peque˜ nos. Se
puede hacer por divisiones sucecivas, a´ un cuando, es mejor utilizar una criba
con n´ umeros precalculados. Las dificultades en el c´alculo de n´ umeros primos
radica cuando los n´ umeros a tratar son grandes. Esto hace necesario buscar
otros m´etodos para determinar la primalidad de los mismos. Analizamos
algunos m´etodos sin ahondar en las demostraciones que est´an ampliamente
desarrolladas en la teor´ıa de n´ umeros y el ´area de criptograf´ıa.
3.6.4. Teorema de Fermat
Este teorema indica que todo n´ umero primo cumple la relaci´on:
a
n−1
≡ 1 mod n ∀a ≤ n (3.6.1)
por lo que parece suficiente realizar este c´alculo para determinar la primali-
dad.
52 3. TEOR
´
IA DE N
´
UMEROS
Desafortunadamente solo sirve para conocer si un n´ umero es compuesto
dado que para algunos n´ umeros primos no se cumple. Estos n´ umeros se de-
nominan n´ umeros de Carmichael . Veamos por ejemplo el n´ umero compuesto
561:
2
561−1
mod 561 = 1
Algunos n´ umeros que no cumplen este teorema son el 561, 1105, 1729. Estos
n´ umeros se denominan pseudo primos.
Para determinar si un n´ umero es compuesto podemos comenzar un al-
goritmo con a = 2 y el momento que no se cumpla el teorema podemos
decir que el n´ umero es compuesto. En otros casos se indica que el n´ umero es
probablemente primo.
La utilidad de este m´etodo se ve en el tratamiento de n´ umeros grandes
donde la facilidad de la exponenciaci´on m´odulo es mucho m´as eficiente que
la divisi´on.
3.6.5. Prueba de Miller - Rabin
.- Este algorimo tiene su nombre por los autores del mismo. Esta prue-
ba provee un algoritmo probab´ılistico eficiente aprovechando algunas carac-
ter´ısticas de las congruencias.
Dado un entero n impar, hagamos n = 2
r
s + 1 con s impar. Escogemos
un n´ umero entero aleatoriamente y sea ´este 1 ≤ a ≤ n. Si a
s
≡ 1 mod (n) o
a
2
j
s
≡ −1 mod (n) para alg´ un j, que este en el rango 0 ≤ j ≤ r −1, se dice
que n pasa la prueba. Un n´ umero primo pasa la prueba para todo a.
Para utilizar este concepto se escoge un n´ umero aleatorio a. Si pasa la
prueba, probamos con otro n´ umero aleatorio. Si no pasa la prueba decimos
que el n´ umero es compuesto. Se ha probado que la probabilidad de que, un
n´ umero a pase la prueba, es de
1
4
por lo que hay que realizar varias pruebas
para tener m´as certeza.
El prop´osito de comentar este algoritmo es el hecho que la implementaci´on
de Java ya lo incluye en sus m´etodos para trabajar con n´ umeros grandes por
lo que, no desarrollaremos el algoritmo en extenso.
3.6.6. Otras pruebas de primalidad
En la (http://mathworld.wolfram.com/search/) enciclopedia de matem´a-
ticas Mathworld se pueden encontrar otras pruebas de primalidad tanto
3.7. BIBLIOTECAS DE JAVA 53
probabil´ısticas, como determin´ısticas de las que mencionamos: Curva el´ıpti-
ca, test de primalidad de Adleman-Pomerance-Rumely, AKS de Agragual,
Lucas-Lehmer, Ward’s y otros.
Muchos de ´estos m´etodos no se han visto efectivos para la prueba de
primalidad cuando se trata de n´ umeros grandes.
3.7. Bibliotecas de Java
La aritm´etica de n´ umeros grandes es esencial en varios campos tales como
la criptograf´ıa. Las bibliotecas de Java incluyen una variedad de funciones
para el tratamiento de ´estos n´ umeros.
Constructores
BigInteger(String val) Permite construir un n´ umero grande a partir
de una cadena
BigInteger(int largo, int certeza, Random r) Permite construir
un n´ umero probablemente primo de la longitud de bits especifica-
da, la certeza especificada y random es un generador de n´ umeros
aleatorios.
M´etodos
add(BigInteger val) Devuelve this + val
compareTo(BigInteger val) Compara this con val y devuelve
−1, 0, 1 para los casos que sean <, =, > respectivamente
intValue() Devuelve el valor entero de this
gcd(BigInteger val) Halla el m´aximo com´ un divisor entre this y val
isProbablePrime(int certeza) .- Prueba si el n´ umero es probable-
mente primo con el grado de certeza especificado. Devuelve falso
si el n´ umero es compuesto.
mod(BigInteger m) Devuelve el valor this mod m
modInverse(BigInteger m) Retorna el valor
this
−1
mod m
modPow(BigInteger exponente, BigInteger m) Devuelve
this
exponente
mod m
54 3. TEOR
´
IA DE N
´
UMEROS
multiply(BigInteger val) Devuelve this ∗ val
pow(int exponente) Devuelve this
exponente
probablePrime(int longitud, Random rnd) Devuelve un n´ umero
probablemente primo. El grado de certeza es 100. Y rnd es un
generador de n´ umeros aleatorios.
remainder(BigInteger val) Devuelve this %val
subtract(BigInteger val) Devuelve this −val
toString(int radix) Devuelve una cadena en la base especificada.
3.7.1. Ejemplo
Hallar un n´ umero primo aleatorio de 512 Bits. La funci´on probablePrime
utiliza para ´esto las pruebas de Miller-Rabin y Lucas-Lehmer.
/**
*Programa para hallar un numero
* primo de 512 bits
* @author Jorge Teran
*
*/
import java.math.BigInteger;
import java.util.Random;
public class PrimoGrande {
public static void main(String args[]) {
Random rnd = new Random(0);
// generar un probable primo de 512 bits
// con una probabilidad de que sea compuesto
// de 1 en 2 elevado a l00.
BigInteger prime =
BigInteger.probablePrime(512, rnd);
System.out.println(prime);
}
}
3.7. BIBLIOTECAS DE JAVA 55
Un ejemplo de ejecuci´on del programa es:
11768683740856488545342184179370880934722814668913767795511
29768394354858651998578795085800129797731017311099676317309
3591148833987835653326488053279071057
Veamos otro ejemplo. Supongamos que queremos desarrollar el algoritmo
de encriptaci´on de llave p´ ublica RSA . El algoritmo consiste en hallar dos
n´ umeros d, e que cumplan la propiedades siguientes: c = m
e
mod n y m =
c
d
mod n. Para resolver esto procedemos como sigue:
1. Escoger dos n´ umeros primos p y q con p ,= q
BigInteger p = new BigInteger(longitud/2, 100, r);
BigInteger q = new BigInteger(longitud/2, 100, r);
2. Calcular n = pq
n = p.multiply(q);
3. Escoger e que sea relativamete primo a (p-1)(q-1)
BigInteger m = (p.subtract(BigInteger.ONE))
.multiply(q.subtract(BigInteger.ONE));
e = new BigInteger("3");
while(m.gcd(e).intValue() > 1)
e = e.add(new BigInteger("2"));
4. Calcular el multiplicativo inverso de e
d = e.modInverse(m);
5. Publicar la clave p´ ublica como el par p = (e, n)
6. Publicar la clave privada como el par s = (d, n)
Veamos el c´odigo completo. Aqu´ı hay que hacer notar que en Java existen dos
clases para hallar n´ umeros aleatoreos, Random y SecureRandom. La difrencia
entre ambas est´a en que la clase SecureRandom hace la semilla inicial de
generaci´on de n´ umeros menos predecible. Esto significa que de una ejecuci´on
a otra la secuencia aleatoria no va a ser la misma.
56 3. TEOR
´
IA DE N
´
UMEROS
import java.math.BigInteger;
public class Principal {
/**
* Programa para utilizar la Clase RSA
* @author Jorge Teran
* @param args ninguno
*/
public static void main(String[] args) {
Rsa a = new Rsa (100); //Hallar d y e de 100 Bits
BigInteger mensaje=new BigInteger("64656667686970");
BigInteger cifrado= a.cifrado(mensaje);
BigInteger limpio= a.decifrado(cifrado);
System.out.println(mensaje);
System.out.println(cifrado);
System.out.println(limpio);
}
}
import java.math.BigInteger;
import java.security.SecureRandom;
class Rsa
{
private BigInteger n, d, e;
public Rsa(int longitud){
SecureRandom r = new SecureRandom();
BigInteger p = new BigInteger(longitud/2, 100, r);
BigInteger q = new BigInteger(longitud/2, 100, r);
n = p.multiply(q);
BigInteger m = (p.subtract(BigInteger.ONE))
.multiply(q.subtract(BigInteger.ONE));
e = new BigInteger("3");
while(m.gcd(e).intValue() > 1)
e = e.add(new BigInteger("2"));
d = e.modInverse(m);
}
3.8. EJERCICIOS 57
public BigInteger cifrar(BigInteger mensaje)
{
return mensaje.modPow(e, n);
}
public BigInteger decifrar(BigInteger mensaje)
{
return mensaje.modPow(d, n);
}
}
3.8. Ejercicios
A continuaci´on se presentan varios problemas que est´an asociados a la
tem´atica presentada. Estos problemas se pueden ver en su versi´on original en
ingl´es en el sitio de la Universidad de Valladolid http://online-judge.uva.es/.
El n´ umero de problema especificado es el n´ umero de problema publicado en
la UVA. Esto se utilizar´a tambi´en en cap´ıtulos posteriores.
3.8.1. Problema 136 - N´ umeros Feos
Los n´ umeros feos son n´ umeros cuyos ´ unicos factores primos son 2, 3, o 5.
La secuencia 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, .... Muestra los primeros 11 n´ u-
meros feos. Por convenci´on se incluye el 1.
Esto equivale a encontrar los n´ umeros que se pueden formar por 2
a
3
b
5
c
.
Escriba un programa que encuentre e imprima el n´ umero 1500.
Entrada y salida.- No existe entrada en este problema. La salida debe
consistir de una l´ınea reemplazando n´ umero con el n´ umero calculado.
Ejemplo de salida The 1500’th ugly number is n´ umero.
58 3. TEOR
´
IA DE N
´
UMEROS
3.8.2. Problema 10042 - N´ umeros De Smith
Mientras le´ıa su gu´ıa de tel´efonos en 1982, Albert Wilansky, un matem´ati-
co de la universidad de Lehigh, not´o que el n´ umero de tel´efono de su cu˜ nado
H. Smith ten´ıa la siguiente caracter´ıstica peculiar: La suma de los d´ıgitos de
ese n´ umero era igual a la suma de los d´ıgitos de los factores primos de ese
n´ umero. El n´ umero de tel´efono de Smith era 493-7775. Este n´ umero se pue-
de escribir como el producto de sus factores primos de la siguiente manera:
4937775 = 3 ∗ 5 ∗ 5 ∗ 65837.
La suma de todos los d´ıgitos del n´ umero de tel´efono es 4 + 9 + 3 + 7 +
7 + 7 + 5 = 42, y la suma de los d´ıgitos de los factores primos es igualmente
3 + 5 + 5 + 6 + 5 + 8 + 3 + 7 = 42. Wilansky fue as´ı que sorprendido por
su descubrimiento que nombr´o a este tipo de n´ umeros; con el nombre de su
cu˜ nado, N´ umeros de Smith. Una lista peque˜ na de n´ umeros de Smith es 4,
22, 27, 58, 85, 94, 121, 166, 202, 265.
Pues esta observaci´on es tambi´en verdad para cada n´ umero primo, Wi-
lansky decidi´o m´as adelante que el n´ umero primo no es igual que el n´ umero
de Smith y ´el los excluy´o de la definici´on.
Problema.- Wilansky public´o un art´ıculo acerca de los n´ umeros de Smith
en ”Two Year College Mathematics Journal”. Fue capaz de presentar una
colecci´on de diversos n´ umeros de Smith: Sin embargo, Wilansky no pod´ıa
dar un n´ umero de Smith que sea m´as grande que el n´ umero de tel´efono de
su cu˜ nado. Esta es su tarea, encontrar los n´ umeros de Smith que son m´as
grandes que 4937775.
Entrada.- El n´ umero que se introduce en la primera l´ınea de entrada es el
n´ umero de casos de prueba. Cada caso de prueba consiste de una l´ınea que
contiene un solo n´ umero entero positivo m´as peque˜ no que 10
9
.
Salida.- Para cada valor de n, se tiene que calcular el n´ umero de Smith
m´as peque˜ no, que sea mayor a n (o que est´e por encima de n) e imprimir
cada n´ umero en una sola l´ınea. Asumir que existe tal n´ umero.
Ejemplo de entrada Ejemplo de salida
1 4937775
4937774
3.8. EJERCICIOS 59
3.8.3. Problema 10104 - El problema de Euclides
Desde la ´epoca de Euclides se conoce que para cualquier entero positivo
A y B existen enteros X y Y que AX + BY = D, donde D es el m´aximo
com´ un divisor de A y B. El problema es encontrar los correspondientes X, Y
y D.
Entrada.- La entrada consiste de un conjunto de l´ıneas con n´ umeros en-
teros A y B, separados por un espacio (A, B < 1000000001).
Salida.- Para cada l´ınea de entrada la salida debe consistir de tres enteros
X, Y y D, separados por un espacio.Si hay m´ ultiples X y Y , debes imprimir
el par para el cual [X[ +[Y [ es m´ınimo (primordialmente).
Ejemplo de entrada Ejemplo de salida
4 6 -1 1 2
17 17 0 1 17
3.8.4. Problema 10139 - Factovisors
La funci´on factorial, n! est´a definida para todos los enteros no negativos
como sigue:
0! = 1n! = n ∗ (n −1)! (n > 0)
La entrada para el programa consiste de varias l´ıneas. Cada una conte-
niendo dos enteros no negativos, n y m, menores a 2
31
. Cada l´ınea de salida
consiste de una l´ınea indicando si m divide a n!, en el formato que se muestra.
Ejemplo de entrada Ejemplo de salida
6 9 9 divides 6!
6 27 27 does not divide 6!
20 10000 10000 divides 20!
20 100000 100000 does not divide 20!
1000 1009 1009 does not divide 1000!
60 3. TEOR
´
IA DE N
´
UMEROS
3.8.5. Problema 106 - Fermat vs. Pit´agoras
Las pruebas asistidas por computadora ocupan un verdadero nicho en
las ciencias de la computaci´on. La primera prueba de muchos problemas
fue completado con la ayuda de un programa de computadora. Esfuerzos
corrientes en verificaci´on han tenido ´exito en verificar la traducci´on de c´odigo
de alto nivel a nivel del chip.
Este problema trata de calcular cifras relacionadas a una parte del ´ ultimo
teorema de Fermat: que explica que no existen soluciones enteras para a
n
+
b
n
= c
n
con n > 2.
Problema Dado un entero positivo N, escriba un programa que calcule
dos valores respecto la soluci´on de
x
2
+ y
2
= z
2
donde x, y, y z son valores enteros positivos menores o iguales N. Se tiene
que computar el n´ umero de triples (x, y, z) que sean primos relativos, tal que
x < y < z, es decir no tienen un com´ un divisor mayor que 1. Tambi´en tiene
que calcular el n´ umero de valores tal que p no es parte de alg´ un triple.
Entrada.- La entrada consiste de una secuencia de enteros positivos, uno
por l´ınea. Cada entero en el archivo de entrada es menor o igual a 1, 000, 000.
La entrada termina con fin de archivo.
Salida.- Para cada entero N en el archivo de entrada imprime dos enteros
separados por un espacio. El primer entero es el n´ umero de primos relativos
triples (tal que cada componente del triple es ≤ N. El segundo n´ umero
es el n´ umero de enteros positivos que no son parte de alg´ un triple cuyos
componentes son ≤ N. Debe haber una l´ınea de salida por cada l´ınea de
entrada.
Ejemplo de entrada Ejemplo de salida
10 1 4
25 4 9
100 16 27
Cap´ıtulo 4
Codificaci´on con miras a la
prueba
4.1. Introducci´ on
La prueba de programas de software ha sido siempre un campo muy ´arido
y no se ha tomado en cuenta en el momento del desarrollo del c´odigo. Para
desarrollar programas m´as fiables se hace necesario planificar la verificaci´on
del c´odigo al momento de su construcci´on. Durante muchos a˜ nos se han
prometido programas que podr´ıan verificar a otros. Desde la d´ecada de los
60 seguimos esperando. A´ un no existe esta posibilidad.
Hoy en d´ıa se hace mucho m´as importante la verificaci´on de los progra-
mas. Existen programas en diferentes industrias que, en caso de fallas pueden
causar inclusive la muerte de personas y otros que no permiten pruebas ex-
perimentales.
Como ejemplo, podemos mencionar los programas que controlan el vuelo
de los aviones, servomecanismos asistidos por computadora e inclusive mu-
chos de los electrodom´esticos que existen en su hogar.
Tradicionalmente la prueba del software ha sido presentada como un de-
talle de pruebas denominadas de caja negra y caja blanca. Las pruebas de
caja negra son aquellas que se enfocan en el exterior del m´odulo sin importar
el c´odigo. Las pruebas de caja blanca son m´as amplias y tratan de verificar
el c´odigo probando partes indicando la cobertura del c´odigo probado. Estos
planes de prueba han dado como resultado que durante la explotaci´on del
software siguen apareciendo errores no detectados en la prueba.
61
62 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Hoy en d´ıa se tiene un conocimiento m´as profundo de la programaci´on y
se pueden realizar muchas m´as verificaciones que, solo las de la caja negra
que pueden indicarnos bien o mal.
El control de calidad y la verificaci´on de programas nos permite encontrar
errores de los programas. La codificaci´on es una de las habilidades requeridas
para esto.
En el presente cap´ıtulo presentaremos una serie de t´ecnicas que ayudan
a la prueba y mantenimiento del c´odigo. No se trata de ninguna manera
de entrar en el campo de la verificaci´on formal de programas, sin embargo,
espero que sirva de una buena introducci´on. Se presenta la especificaci´on
formal, las aserciones y la programaci´on por contrato.
4.2. Algunos errores de programaci´ on
Cuando revisaba las revistas Comunicati´on of the ACM [KBO
+
05] en-
contr´e una serie de preguntas sobre errores existentes en diferentes c´odigos.
Estos errores normalmente no son vistos por los programadores proveen una
puerta por donde se producen fallos mal intencionados durante la explotaci´on
del programa. Por este motivo quiero presentar este tema.
El desborde de la memoria se produce cuando se accede fuera de las
dimensiones de la variable definida. Por ejemplo salirse del tama˜ no de un
vector incrementando el tama˜ no del ´ındice fuera de los l´ımites del mismo.
Veamos un ejemplo:
void copia(char[] b) {
char[] datos = new char(100);
for (int i=1;i< b.length; i++)
datos[i]=b[i]
..
..
..
}
return
En el segmento de c´odigo expuesto se puede apreciar que se copia el vector
b a datos pudiendo causarse un desborde en datos si es que b es de mayor
tama˜ no que datos.
4.2. ALGUNOS ERRORES DE PROGRAMACI
´
ON 63
Normalmente, durante la ejecuci´on, se obtendr´a un error de ´ındice fuera
de rango. Cuando colocamos un programa en producci´on generalmente se
recompilan los c´odigos con argumentos de optimizaci´on y el control de ´ındices
fuera de rango queda eliminado. En estos casos al no producirse este error se
obtienen mensajes tales como error de segmentaci´on, error de bus.
Estos errores se producen al reescribir parte del c´odigo con datos, al salirse
del rango del vector datos. Como, se va ha reescribir parte del c´odigo, un
intruso puede enviar una serie de c´odigos que quiere ejecutar.
Veamos un ejemplo escrito en lenguaje C.
//programa para desplegar el primer
// argumento de la l´ınea de comando
// desp.c
// Autor Jorge Teran
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{ char copia[2];
strcpy(copia,argv[1]);
printf("%s\n", copia);
return 0;
}
Como se ve este programa despliega en pantalla el argumento introducido
en la l´ınea de comando, y la ejecuci´on del mismo se ve as´ı:
>desp 12
12
Que pasa si en la invocaci´on al mismo colocamos m´as de dos d´ıgitos?
>desp 12345
12345
Cuando llegamos a 6 d´ıgitos obtenemos una lista interminable de
64 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
>desp 123456
123456
123456
123456
....
Claramente hemos invadido el ´area de c´odigo y eliminado parte de la instruc-
ci´on return de la rutina printf. Si introducimos m´as valores se obtienen otros
errores. Como se dijo, ´esto puede ser un mecanismo para introducir c´odigos
a un programa y hacer que realice algo para lo que no ha sido dise˜ nado.
Es posible que se cambie el c´odigo para realizar un chequeo de ´ındice
fuera de rango durante la copia pero, consume m´as tiempo de proceso.
Lo que queremos expresar con este ejemplo es que a´ un cuando un pro-
grama haya sido probado y se supone que funciona correctamente puede
presentar fallas. Tal es el caso de la rutina strcpy mostrada.
Con respecto al lenguaje de programaci´on podemos preguntarnos cual
lenguaje ofrece mejores condiciones en el tiempo de proceso durante la eje-
cuci´on del programa. La respuesta es bastante obvia. Cuanto m´as controles
se tengan se demorar´a m´as tiempo de proceso. Y en caso contrario se tienen
algunas inseguridades a cambio de una mejora en la ejecuci´on.
En el caso del lenguaje Java al ejecutarse en un entorno cerrado provee
control sobre la ejecuci´on del c´odigo que es inexistente en el lenguaje C. Esto
hace que este tipo de problemas no se presenten en algunos lenguajes como
el Java.
Existen algunas soluciones que se pueden adoptar para resolver este tipo
de problemas por ejemplo, introducir un control de sub´ındices durante la
copia, proteger la memoria donde se encuentra la direcci´on de retorno a solo
lectura. Estas acciones hacen el tiempo de proceso m´as lento.
La programaci´on Java no est´a exenta de fallas que se producen en la eje-
cuci´on del c´odigo, por situaciones no previstas. Para ejemplificar supongamos
la clase Nombre que tiene un m´etodo para devolver el nombre.
class Nombre {
String nombre;
Nombre(String n) {
nombre=n;
}
4.2. ALGUNOS ERRORES DE PROGRAMACI
´
ON 65
String devuelveNombre() {
return (nombre);
}
}
Suponga que quiere utilizar la clase Nombre como sigue:
Nombre persona = new Nombre(nombrePersona);
int largo=persona.devuelveNombre().trim().length();
Analizando vemos que se trata de calcular la longitud del nombre.
¿Qu´e pasa cuando nombrePersona es un valor nulo?
Claramente obtendremos un error de ejecuci´on indicando la l´ınea donde
se produjo el error. El mensaje del sistema no dice cual es la causa del error.
Para solucionar este problema en medio de la ejecuci´on de un sistema
se tiene que corregir el programa para tomar en cuenta este posible error
modificando el c´odigo como sigue:
Nombre persona = new Nombre(nombrePersona);
int largo=0;
String dato = persona.devuelveNombre();
if (dato == null)
{
System.err.println("Error grave:
Falta la propiedad ’nombre’ ");
}
else
{
largo=dato.trim().length();
}
Ahora estamos seguros que el programa funciona y que, cuando da el error
identifica claramente el problema. Bien supongamos que, ahora que est´a se-
guro que el programa no falla se pone el programa en ejecuci´on en un sistema
distribu´ıdo, puede ocurrir que no se encuentre la clase persona y el sistema
falle. Para esto hay que volver a corregir el c´odigo adicionando un control:
66 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Nombre persona = new Nombre(nombrePersona);
if (persona == null)
{
System.err.println(
"Error grave: clase Persona no disponible");
}
int largo=0;
String dato = persona.devuelveNombre();
if (dato == null)
{
System.err.println(
"Error grave: Falta la propiedad ’nombre’ ");
}
else
{
largo=dato.trim().length();
}
Estas consideraciones hacen necesario especificar el c´odigo de una forma que,
se pueda determinar una serie de problemas con mucha anticipaci´on.
4.3. Especificaci´ on de programas
La especificaci´on de programas tienen su origen en Hoare [Hoa83] quien
desarroll´o las bases para la especificaci´on formal de programas. Tambi´en
puede ver un excelente trabajo que describe esta axiom´atica en [CK79].
Cuando se especifica un programa hay que considerar que no solo puede
tener errores, tambi´en puede ser que est´e equivocada la especificaci´on del
mismo. Por esta raz´on tambi´en deben verificarse las especificaciones de los
mismos. Aunque no es parte del texto un tratamiento riguroso de la verifica-
ci´on y prueba de programas, es necesario introducir este tema que se estudia
en los cursos de m´etodos formales.
4.3. ESPECIFICACI
´
ON DE PROGRAMAS 67
Precondici´on Son lo valores iniciales que toman las variables del programa,
o tambi´en los pre requisitos necesarios para su correcto funcionamiento.
Por ejemplo puede ser que una variable no sea nula, que los datos esten
ordenados, la existencia de una clase, etc.
Post condici´on Son los valores finales que toman las variables del programa
Todo programa consiste de tres partes:
1. Inicializaci´on
2. Preservaci´on de propiedades
3. Terminaci´on
La preservaci´on de propiedades se denomina invariante y es lo que nos permite
verificar el c´odigo.
Llamemos a ¦P¦ precondici´on, a ¦Q¦ post condici´on y C un programa.
La notaci´on
¦P¦C¦Q¦
significa que si partimos de un estado P despu´es de que el programa termine
llegaremos al estado Q. Esta notaci´on se debe a Hoare [Hoa83].
Ejemplo:
¦X = 1¦X = X + 1¦X = 2¦
Este peque˜ no c´odigo especifica que si X es inicialmente 1 una vez corrido el
programa X toma el valor de 2 que es claramente verdadero.
Normalmente en esta notaci´on las precondiciones y las variables se escri-
ben en letras may´ usculas. Las letras min´ usculas se utilizan para especificar
valores. Por ejemplo para indicar que la variable X toma una valor arbitrario
x se escribe X = x.
Una expresi´on del tipo ¦P¦C¦Q¦ es una especificaci´on de correctitud
parcial porque para verificar que es correcta, no es necesario que el programa
C termine.
Una especificaci´on m´as fuerte es la especificaci´on de correctitud total en
la que se pide la prueba de que el programa termine. La notaci´on que se
utiliza para esto es:
[P]C[Q]
68 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
la relaci´on que existe entre ambas definiciones es:
correctitud total = terminacion + correctitud parcial
Por ejemplo si queremos especificar la correctitud total de que los valores de
X, Y se intercambian podemos escribir:
[X = x ∧ Y = y] R = X; X = Y ; Y = R [X = y ∧ Y = x]
No todas las variables deben especificarse en una precondici´on, veamos
como ejemplo una divisi´on por restas sucesivas:
¦Y = y ∧ X = y¦
R = X;
Q = 0;
WHILE Y ≤ R
R = R −Y ; Q = Q + 1
¦R < y ∧ X = R + (Y xQ)¦
Este ejemplo es menos intuitivo para la verificaci´on pero nos indica clara-
mente que el resultado depende de los valores de X y Y . El valor de Q y R
est´an especificados solo en la post condici´on.
Como no se especificaron en la precondici´on no se puede decir nada de
ellos antes de la ejecuci´on del c´odigo.
4.3.1. ¿Por qu´e especificar?
La primera pregunta que uno se hace es por qu´e especificar?. Uno puede
especificar para tener mayor documentaci´on del sistema, desea una descrip-
ci´on m´as abstracta o porque desea realizar un an´alisis del mismo.
Lo que uno debe preguntarse es porque especificar formalmente y las
respuestas que se pueden conseguir de desarrolladores profesionales son:
1. Mostrar que una propiedad se mantiene globalmente en un programa
Se quiere caracterizar la condici´on de correctitud.
Se quiere mostrar que la propiedad es realmente una invariante.
Se quiere mostrar que mi sistema cumple alg´ un criterio de alto
nivel en el dise˜ no.
4.3. ESPECIFICACI
´
ON DE PROGRAMAS 69
2. Manejo de errores
Se quiere especificar que ocurre cuando se produce un error.
Se quiere especificar que las cosas correctas ocurren cuando se
produce un error.
Se quiere estar seguro que no exista este error.
3. Completitud
Se quiere estar seguro que se ha cubierto todos los casos, inclu-
yendo los casos de error.
Se quiere saber si el programa que he dise˜ nado es computacional-
mente completo.
4. Especificar interfases
Se quiere definir una jerarqu´ıa de clases.
Se quiere una descripci´on m´as formal de la interfase del usuario.
5. Manejar la complejidad
El dise˜ no est´a muy complicado para manejar todo en la cabeza y
necesitamos una forma de pensar en pedazos m´as peque˜ nos.
Cumplir los requisitos legales de algunos pa´ıses.
6. Cambiar el control
Cada vez que cambio un pedazo de c´odigo quisiera conocer que
otras partes son afectadas sin mirar todos los m´odulos y sin mirar
el c´odigo fuente.
4.3.2. ¿Qu´e especificar?
Los m´etodos formales no est´an desarrollados de tal forma que un sistema
entero y muy grande pueda ser especificado completamente. Solo se pueden
especificar algunos aspectos tales como funcionalidad y comportamiento de
un sistema de tiempo real.
Al escribir una especificaci´on uno debe decidir si la descripci´on es reque-
rida y permitida. ¿Puede o debe? Una vez que uno tiene claro lo que hay que
especificar uno puede determinar que puede formalizarse.
70 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Condiciones de correctitud
Esto implica la noci´on de una condici´on global de correctitud que el sis-
tema debe mantener.
Invariantes
La forma de caracterizar algunas condiciones que no cambian de un esta-
do a otro se denominan invariantes. Las invariantes son una buena forma de
caracterizar las propiedades deseadas de un sistema. Formalizar las transicio-
nes le permite probar que se mantienen durante la ejecuci´on del programa.
Comportamiento observable
Se denomina cuando se especifica el comportamiento del sistema cuando
interact´ ua con su ambiente.
Propiedades de entidades
Las propiedades m´as importantes de las entidades se expresan comunmen-
te por el tipo. La correspondencia entre este tipo de propiedades se verifica
por el compilador. Sin embargo, para entidades estructuradas podemos ver
otras propiedades de las que, podemos anotar por ejemplo:
Orden. ¿Los elementos est´an ordenados?
Duplicados. ¿Se Permiten?
Rangos. ¿Pueden acotarse los elementos de alguna manera?
Acceso asociativo. ¿Los elementos se recuperan por ´ındices o llaves?
Forma ¿El objeto tiene una estructura lineal, jer´arquica, arbitraria,
gr´afica, etc?
4.3.3. ¿C´omo especificar?
Dado que entiende lo que desea especificar y lo que desea obtener puede
empezar a especificar. La t´ecnica principal es la descomposici´on y abstracci´on.
Para ´esto damos algunas ideas:
4.3. ESPECIFICACI
´
ON DE PROGRAMAS 71
Abstraer. No piense como programador.
Piense en funci´on de la definici´on, no de la funcionalidad
Trate de construir teor´ıas, no solo modelos
No piense en forma computacional
4.3.4. Invariantes
Definamos con m´as claridad una invariante. Una invariante es una pro-
piedad que es verdadera y no cambia durante le ejecuci´on del programa. Esta
propiedad engloba a la mayor parte de los elementos o variables del progra-
ma. Cada ciclo tiene una propiedad invariante. Las invariantes explican las
estructuras de datos y algoritmos.
Las propiedades de las invariantes deben mantenerse cuando se modifica
el programa. La invariante obtenida se utiliza en un proceso est´atico para
verificar la correctitud del programa.
Las invariantes son ´ utilies en todos los aspectos de la programaci´on: di-
se˜ no, codificaci´on, prueba, mantenimiento y optimizaci´on. Presentamos una
lista de usos a fin de motivar a la utilizaci´on de las mismas por los progra-
madores.
Escribir mejores programas.- Muchos autores coinciden que se pueden
construir mejores programas cuando se utilizan especificaciones en el
dise˜ no de los programas. Las invariantes formalizan en forma precisa
el contrato de un trozo de c´odigo. El uso de invariantes informalmente
tambi´en ayuda a los programadores.
Documentar el programa.- Las invariantes caracterizan ciertos aspec-
tos de la ejecuci´on del programa y proveen una documentaci´on valiosa
sobre el algoritmo, estructura de datos y los conocimientos a un nivel
necesario para modificar el programa.
Verificar las suposiciones.- Teniendo las invariantes las podemos utilizar
en la verificaci´on del progrma observando que no cambian a medida que
se procesa.
Evitar errores.- Las invariantes pueden prevenir que el programa realice
cambios que accidentalmente cambien las suposiciones bajo las cuales
su funcionamiento es correcto.
72 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Formar un espectro.- El espectro de un programa son propiedades me-
dibles en el programa o su ejecuci´on. Algunas de ´estas son el n´ umero de
l´ıneas ejecutadas por el prgrama, el tama˜ no de la salida o propiedades
est´aticas como la complejidad. La diferencia entre varios aspectos nos
muestran cambios en los datos o el programa.
Ubicar condiciones inusuales.- Condiciones inusuales o excepcionales
deben llamar la atenci´on a los programadores porque pueden ser causa
de posibles errores.
Crear datos de prueba.- Las invariantes pueden ayudar en la generaci´on
de datos de prueba de dos maneras. Pueden infringir intencionalmente
las invariantes ampliando los datos de prueba. La otra es de mantener
las invariantes para caracterizar el uso correcto del programa.
Pruebas.- Prueba de teoremas, an´alisis de flujo de datos, chequeo del
modelo y otros mecanismos automatizados o semi automatizados pue-
den verificar la correctitud del programa con respecto a su especifica-
ci´on.
Ejemplos
1. Mostrar que la invariante es PX
N
= x
n
∧ x ,= 0
P:=1;
IF not (x=0)
while not (N=0)
IF IMPAR(N) P=PxX
N=N /2
X=X x X
ELSE
P=0
aqu´ı la precondici´on es ¦X = x∧N = n¦ y la post condici´on ¦P = x
n
¦.
Veamos varios detalles del programa:
Tiene tres variables P, N, X.
Los valores iniciales son un valor x, n cualesquiera, precondici´on.
La post condici´on indica que el resultado es x
n
.
4.3. ESPECIFICACI
´
ON DE PROGRAMAS 73
Iteraci´on N P X PX
N
1 9 1 2 512
- 9 2 2 –
- 4 2 4 512
2 2 2 4 –
- 2 2 16 512
3 1 2 16 –
- 1 2 256 512
4 1 512 256 512
- 0 512 256 –
- 0 512 65536 –
Cuadro 4.1: Valores que toman la variables durante la ejecuci´on
Para mostrar que PX
n
es una invariante tomamos dos valores X, N.
Supongamos que X = 2 y N = 9. Con estos valores contruimos el
cuadro 4.1 que muestra los valores que toman las variables durante la
ejecuci´on.
Como ve hemos anotado todos los valores que toman las variables in-
volucradas y anotado los valores que toman al final de cada iteraci´on
calculando la supuesta invariante . Comprobamos que es correcta por-
que sus valores no cambian.
2. Las invariantes pueden tomar diferentes formas, consideremos por ejem-
plo el siguiente programa
precondici´on ¦M ≥ 1 ∧ N = n¦
X=0;
for (N=1; N<M; M++)
X=X+M
post condici´on ¦X = (M(M −1))/2¦
En este ejemplo vemos que efectivamente X en cualquier momento
representa el resultado de la sumatoria hasta el n´ umero de iteraci´on en
que se encuentra. Esto indica que la invariante es:
X =
N−1

i=0
i
74 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
3. Indicar cuales son las precondiciones y post condiciones de un ciclo for.
for (I=1; I<=N; N++{
....
....
}
Aqu´ı vemos que I debe ser una variable definida, al principio del ciclo
toma el valor de 1 y al terminar el mismo toma en valor de N+1. No se
ha caracterizado una invariante dado que no se ha escrito un programa
al interior del ciclo.
4. Considere el algoritmo de Euclides para hallar el m´aximo com´ un divisor
y caracterice cu´al es la invariante del problema.
Mcd(a,b)
if (b==0)
return (a)
else Mcd(b, a%b)
Recordando el teorema de Euclides, dados dos n´ umeros a, b se cumple
Mcd(a, b) = Mcd(b, a %b)
por lo tanto esta expresi´on es la invariante que se cumple durante la
ejecuci´on de todo el programa.
4.3.5. Ejercicios propuestos
1. Determinar la invariante del ciclo siguiente:
X=0;
while (X < 20){
X=X+5;
}
2. Considere un programa de b´ usqueda secuencial que devuelve la posici´on
del elemento buscado, o −1 cuando no existe. Cu´al es la invariante
apropiada?
4.4. APLICACIONES DE LAS INVARIANTES 75
int buscar(int [] v, int t){
// precondici´on el vector v no esta ordenado
// precondici´on t es el valor a buscar
int i=0;
while ((i<v.length()&&(v[i]!=t){
i++;
}
if (i<n)
return (i)
else
return (-1)
}
//post condici´on devuelve -1 cuando no existe y
// devuelve la posici´on i cuando existe
3. Considere una clase que coloca y saca elementos en una estructura de
pila. Escriba un programa e indique cu´ales son las precondiciones, post
condiciones e invariantes de la clase?
4. Probar que la invariante del procedimiento de divisi´on por restas suce-
civas es X = R + (Y xQ)
¦Y = y ∧ X = y¦
R = X;
Q = 0;
WHILE Y ≤ R
R = R −Y ; Q = Q + 1
¦R < y ∧ X = R + (Y xQ)¦
4.4. Aplicaciones de las invariantes
Las aplicaciones de las invariantes se orientan basicamente en el desarrollo
y verificaci´on de los programas. Durante el proceso, el de verificar que las
propiedades se cumplen durante la ejecuci´on. En la verificaci´on est´an los
m´etodos formales que vienen de la l´ogica formal y de aquellos procedentes
del c´alculo de predicados [Red90].
76 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Lo que se presenta es el desarrollo de programas utilizando los principios
de verificaci´on para, posteriormente introducirnos a la tem´atica de verficar
el funcionamiento del programa en tiempo de ejecuci´on.
El m´etodo que se sigue consiste de los siguientes pasos:
1. Especificar el problema.
2. Escribir las pre y post condiciones .
3. Identificar las variables del problema.
4. Encontrar la invariante .
5. Codificar el ciclo, manteniendo la invariante en cada instante.
6. Prueba del programa.
Desarrollemos como ejemplo, el proceso de dividir un n´ umero por otro
hallando el residuo, utilizando restas sucesivas.
Planteamiento del problema.- Dados dos n´ umero X, Y hallar Q denomi-
nado cociente y R denominado residuo tal que Q sea el cociente de la divisi´on
y R sea el residuo.
Comenzamos escribiendo las pre y post condiciones
/* Programa que realiza una divisi´on por restas sucesivas
* Precondici´on: x toma un valor y la variable y es > 0
* Post condici´on: x=y*q +r
* Donde q es el cociente y
* r es el resto
*/
El proceso contin´ ua identificando las variables del programa que, las codi-
ficamos directamente:
/* Programa que realiza una divisi´on por restas sucesivas
* Precondici´on: x toma un valor entero
* y la variable entera y es > 0
* Post condici´on: x=y*q +r
* Donde q es el cociente y
* r es el resto
*/
4.4. APLICACIONES DE LAS INVARIANTES 77
divide(int x,int y) {
int q,r;
.....
.....
}
En este momento identificamos las caracter´ısticas y las invariantes del
problema utilizando las variables definidas en la pre y post condici´on . Pri-
mero el algoritmo consiste en restar sucecivamente el valor del divisor hasta
hallar el cociente y el resto. Segundo observamos que el resto debe ser menor
que el dividendo caso contrario se puede seguir restando. Los valores iniciales
de las variables q, r ser´an q = 0, y r = y respectivamente.
Codificando estas consideraciones
/* Programa que realiza una divisi´on por restas sucesivas
* Precondici´on: x toma un valor entero
* y la variable entera y es > 0
* Post condici´on: x=y*q +r
* Donde q es el cociente y
* r es el resto
*/
divide(int x,int y) {
int q=0;
int r=y;
while (r > = x) {
.....
.....
}
.....
.....
}
La invariante del ciclo debe mantenerse durante toda el ciclo. En nuestro
caso es obvio que la invariante es x = q y + r
/* Programa que realiza una divisi´on por restas sucesivas
* Precondici´on: x toma un valor entero
* y la variable entera y es > 0
78 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
* Post condici´on: x=y*q +r
* Donde q es el cociente y
* r es el resto
*/
divide(int x,int y) {
int q=0;
int r=y;
while (r > = x) {
//invariante x=y*q +r
r=r-y;
q++;
}
}
reacomodando los comentarios tenemos la versi´on final.
/* Programa que realiza una divisi´on por restas sucesivas
* Precondici´on: x toma un valor entero
* y la variable entera y es > 0
*/
divide(int x,int y) {
int q=0;
int r=y;
while (r > = x) {
//invariante x=y*q +r
r=r-y;
q++;
}
/* Post condici´on: x=y*q +r
* Donde q es el cociente y
* r es el resto
*/
}
La invariante se verifica que es matem´aticamente correcta. Tomando un
ejemplo de ejecuci´on para un caso particular se puede ver que la invariante
no cambia. Vemos por ejemplo 9/2 :
4.4. APLICACIONES DE LAS INVARIANTES 79
Iteraci´on x y q r x=y*q +r
0 9 2 0 9 9
1 9 2 1 7 9
2 9 2 2 5 9
3 9 2 3 3 9
4 9 2 4 1 9
Como se observa en cada iteraci´on se ha mantenido la invariante.
Veamos un ejemplo que utiliza dos bucles. Especifiquemos el programa
para construir la criba de Eratostenes. Lo que se quiere es un vector donde
los todos los m´ ultiplos de alg´ un n´ umero est´en marcados. Los que no son
m´ ultiplos son n´ umeros primos y no est´an marcados.
De aqu´ı se ve que, la precondici´on del problema es un vector que tiene dos
estados: marcado y no marcado. Los marcados son los n´ umeros no primos.
Al tener solo dos estados se puede utilizar un vector de bits. Escribimos la
precondici´on, post condici´on as´ı como, los elementos requeridos en el c´odigo.
import java.util.*;
/**
* Programa para construir los numeros primos
* hasta = 100.000.000
* utilizando la Criba de Eratostenes
* Precondici´on:
* Un vector de bits con todos sus valores en cero
*/
public class Criba {
public static void main(String[] s) {
int n = 100000000;
BitSet a = new BitSet(n + 1);
}
}
/**
* Post condici´on:
* Un vector de bits con los numeros primos en cero.
*/
Ahora debemos construir las invariantes del ciclo. Recordemos que lo que
se hace en el algoritmo es marcar todos los m´ ultiplos de 2, 3, 4, 5, .... hasta la
80 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
ra´ız cuadrada del n´ umero m´aximo. Como se requieren dos ciclos tambi´en se
requieren dos invariantes.
El resultado obtenido es:
import java.util.*;
/**
* Programa para construir los numeros primos
* hasta = 100.000.000
* utilizando la Criba de Eratostenes
* Precondici´on:
* Un vector de bits con todos sus valores en cero
*/
public class Criba {
public static void main(String[] s) {
int n = 100000000;
BitSet a = new BitSet(n + 1);
int i = 2, j = 0;
// construcci´on de la criba
for (i = 2; i * i <= n; i++) {
//Invariante hasta i-1 se han marcado todos los
//multiplos de i - 1 para i > 2
if (!a.get(i)) {
for (j = i + i; j <= n; j=j+i;) {
//Invariante j es multiplo de i
a.set(j);
}
}
}
}
}
/**
* Post condici´on:
* Un vector de bits con los numeros primos en cero.
*/
Ahora completemos con las pre y post condiciones de cada ciclo. Las
correspondientes al primer ciclo son las mismas del programa. Las corres-
4.4. APLICACIONES DE LAS INVARIANTES 81
pondientes al segundo ciclo son: Precondici´on: Los m´ ultiplos de i no han sido
marcados. Post condici´on: Los m´ ultiplos de i han sido marcados. Introdu-
ciendo las mismas tenemos la versi´on final.
import java.util.*;
/**
* Programa para construir los numeros primos
* hasta = 100,000,000
* utilizando la Criba de Eratostenes
* Precondici´on:
* Un vector de bits con todos sus valores en cero
*/
public class Criba {
public static void main(String[] s) {
int n = 100000000;
BitSet a = new BitSet(n + 1);
int i = 2, j = 0;
// construcci´on de la criba
for (i = 2; i * i <= n; i++) {
//Invariante hasta i-1 se han marcado todos los
//multiplos de i - 1 para i > 2
if (!a.get(i)) {
//Precondici´on:
// los multiplos de i no han sido marcados
for (j = i + i; j <= n; j=j+i;) {
//Invariante j es multiplo de i
a.set(j);
}
//Post condici´on:
//los multiplos de i han sido marcados
}
}
}
}
/**
* Post condici´on:
//Un vector de bits con los numeros primos en cero.
*/
82 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Una de las aplicaciones de las invariantes es caracterizar el desarrollo de
un programa. El siguiente ejemplo muestra el desarrollo de un programa que
eval´ ua la serie de Fibonacci que, como ver´a es dif´ıcil de comprender si no se
sigue el desarrollo.
La serie de Fibonacci es formada por la ecuaci´on t(n)+t(n−1) con t(0) =
1. Un programa para evaluar esta secuencia de n´ umeros ser´ıa el siguiente:
//Precondicion: N>=0
y=1;
n=0;
x=0;
while(n!=N){
x=y;
y=x+y;
n++;
}
//Post condicion x=Fibonacci(N)
Para mejorar el tiempo de proceso de este algoritmo, reescribimos las siguien-
tes l´ıneas de c´odigo: x = y y y = x + y como una ecuaci´on matricial:
_
x
y
_
=
_
0 1
1 1
__
x
y
_
(4.4.1)
Denominando estas matrices A, B tenemos
A =
_
x
y
_
B =
_
0 1
1 1
_
(4.4.2)
Si reemplazamos 4.4.2 en el programa la parte del ciclo se convierte en:
while(n!=N){
A=B*A
n++;
}
donde A y B son matrices. Analizando vemos que lo que se est´a calculando
es A = B
n
A. De aqu´ı se puede ver que la invariante del ciclo es:
_
x
y
_
=
_
0 1
1 1
_
n
_
0
1
_
(4.4.3)
4.4. APLICACIONES DE LAS INVARIANTES 83
Se ve que lo que tenemos es una potencia de una matriz. Con esta idea po-
demos aplicar el m´etodo que mostramos para hallar una potencia en tiempo
logar´ıtmico.
Inicialmente hallemos las siguientes potencias:
_
0 1
1 1
_
2
=
_
0 1
1 1
__
0 1
1 1
_
=
_
1 1
1 2
_
(4.4.4)
_
1 1
1 2
_
4
=
_
1 1
1 2
__
1 1
1 2
_
=
_
2 3
3 5
_
(4.4.5)
Esto nos lleva al hecho que, no demostraremos, de que todas las potencias
pares tienen la forma:
_
a b
b a + b
_
(4.4.6)
Calculando B B se tiene que:
a = a a + b by
b = b a + a b + b b.
Calculando A B se tiene que:
x = a x + b yy
y = b x + a y + b y.
Recordando que el algoritmo mejorado a O(log(n)) para hallar las poten-
cias trabaja bajo el siguiente m´etodo:
while(n!=N){
si par(n)
B=B*B
n=n/2
si impar(n)
A=A*B
n=n-1
}
Llevando ´esto al c´odigo se tiene el programa final:
84 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
public class Fibonacci {
/**
* Programa para hallar el Fibonacci 8,n=8
* @author Jorge Teran
* @param args
* none
*/
public static void main(String[] args) {
int n=8,a=0,b=1,x=0,y=1,temp=0;
while(n!=0){
if(n%2==0){
temp = a*a + b*b;
b = b*a + a*b + b*b;
a=temp;
n=n/2;
}
else {
temp = a*x + b*y;
y = b*x + a*y + b*y;
x=temp;
n=n-1;
}
}
System.out.println("x= "+x);
System.out.println("y= "+y);
}
}
Como se ve en la ejecuci´on del programa x = Fibonacci(n − 1) y y =
Fibonacci(n). En este programa se ve claramente que la especificaci´on de
la invariante es esencial para entender el programa final.
4.4.1. Principio de correctitud
El principio de correctitud se define como:
4.5. DISE
˜
NO POR CONTRATOS 85
inicializaci´on La invariante es verdadera cuando se ejecuta el programa
por primera vez.
preservaci´on la invariante se preserva al principio, al final de cada uno
de los ciclos del programa y cuando este termina.
terminaci´on El programa termina y produce los resultados esperados.
Esto puede probarse utilizando los hechos que hacen la invariante.
El proceso de prueba moderno consiste en verificar el principio de correcti-
tud. Puede realizarse, en forma est´atica (l´ogica formal) y en forma din´amica
durante la realizaci´on del c´odigo.
4.5. Dise˜ no por contratos
El dise˜ no por contratos tiene sus or´ıgenes en 1990 con los trabajos de
Bertrand Meyer y el lenguaje de programaci´on Eifel. Consiste en establecer
relaciones cuyo fundamento est´an en la l´ogica formal entre las diferentes
clases del programa.
La motivaci´on principal para desarrollar el dise˜ no por contratos es la reu-
tilizaci´on del c´odigo. El dise˜ no por contratos es un m´etodo de la ingenier´ıa de
software para la fiabilidad y aplicable a la programaci´on orientada a objetos.
La fiabilidad del software se puede ver como dos aspectos: primero la
correctitud y segundo la robustez.
Para describir la correctitud, supongamos que le traen 100,000 l´ıneas de
c´odigo y le preguntan si es correcto o no. Claramente no se puede decir mucho
al respecto, lo que se requiere es una especificaci´on detallada para verificar
que el producto satisface la especificaci´on.
Un elemento de software no es correcto o incorrecto por s´ı mismo. Es
correcto o incorrecto con respecto a su especificaci´on.
Definimos la correctidud como una tupla de pares de elementos:
correctitud = (especificacion, codigo).
La robustez es la facilidad que tiene un programa para reaccionar en
forma razonable a condiciones que no est´an en la especificaci´on.
En la construcci´on de programas existen dos metodolog´ıas principales
que, son la programaci´on defensiva y programaci´on por contratos.
86 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
La programaci´on defensiva se basa en ir agregando controles a fin de
verificar posibles errores durante la ejecuci´on del programa. En este tipo de
programaci´on se tiene cada vez m´as c´odigo, haciendo que el c´odigo nuevo
requiera introducir nuevos controles.
Sup´ongase que se tiene una rutina que devuelve el resultado de dividir
a/b el c´odigo podr´ıa ser
int divide (int a, int b){
return a/b;
}
Aplicando la programaci´on defensiva se tendr´ıa que codificar los posibles
errores, por ejemplo b > 0 o si a puede estar en un rango de valores y
as´ı sucecivamente todas las posibles situaciones que puedan ocurrir a fin de
que, la respuesta sea adecuada.
int Divide (int a, int b){
if (!(b>0)){
System.out.println("error b=0")
}
......
......
......
return a/b;
}
Como se ve el concepto de una simple divisi´on ha sido complicada con una
serie de operaciones que ocultan el pr´oposito de la rutina Divide.
La programaci´on por contratos toma los conceptos de la l´ogica formal
y la especificaci´on de programas. Esta metodolog´ıa de dise˜ no establece una
relaci´on contractual entre clases especificando los requerimientos y los resul-
tados esperados. Esto se realiza incluyendo precondiciones, post condiciones
e invariantes.
Se puede ver como un contrato entre personas donde cada una de las
partes tiene una obligaci´on que cumplir. En el ejemplo que vimos no es
obligaci´on de Divide que, los valores que recibe sean correctos, m´as bien el
de dividir correctamente. La obligaci´on del programa que llama a Divide es
el de pasar los datos correctos.
4.5. DISE
˜
NO POR CONTRATOS 87
Normalmente utilizamos la palabra bug para referirnos a cualquier tipo
de problema de software. Esta palabra es un poco ambigua por lo que hay
que definir los problemas que existen.
Un producto de software puede tener tres tipos de problemas: errores,
defectos y fallos. Error es una mala decisi´on realizada durante el desarrollo
del software. Un defecto es una propiedad que hace que no se adecue a su
especificaci´on. Un fallo es un evento incorrecto que, en su comportamiento
esperado, ocurre en alguna de sus ejecuciones.
La programaci´on por contratos divide en obligaciones y beneficios entre
proveedor y cliente.
Cliente Es un programa que hace uso de un objeto (programa) conoce la
interfaz de la clase y no sabe nada de la implementaci´on
Proveedor Es un programa (objeto) que es utilizado por un cliente, cons-
truye la documentaci´on, la mantiene y publica una interfaz.
El siguiente cuadro muestra los beneficios y obligaciones de clientes y
proveedores:
Obligaciones Beneficios
Cliente Satisfacer la precondici´on Obtener los resultados
de la post condici´on
Proveedor Satisfacer la post condici´on Un proceso m´as simple
gracias a que se pre-
sume que se satisface la
precondici´on
En nuestro caso el programa que llama a la rutina de dividir debe ga-
rantizar que los datos enviados son correctos y el programa que realiza la
divisi´on garantiza que la respuesta es correcta.
En el enfoque tradicional se presentan varios problemas:
El cliente no entiende en que situaciones puede utilizar una clase.
El cliente no entiende las consecuencias de utilizar un m´etodo.
Cuando se cambia un c´odigo, ¿C´omo se consigue que la interfaz se
mantenga?
88 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Si la interfaz cambia, ¿C´omo se entera el cliente?
Con esta metodolog´ıa es muy f´acil determinar la causa de un fallo en un
programa:
Una falla en la precondici´on es una manifestaci´on de una falla en el
cliente
Una falla en la post condici´on es una manifestaci´on de una falla en el
proveedor.
En un contrato entre cliente y proveedor se pueden dar dos situaciones,
la primera es que el contrato se cumpla con lo cual no hay que hacer abso-
lutamente nada, o puede que, el contrato se rompa en cuyo caso se puede
utilizar una clase especializada para manejar el error o simplemente terminar
el proceso indicando la causa de la falla.
En todo el proceso de dise˜ no por contratos se debe evitar la redundancia.
Esta regla es el opuesto de la programaci´on defensiva. No est´a por dem´as
realizar controles en el c´odigo, sin embargo, pueden hacer el c´odigo muy
poco entendible. En el dise˜ no bajo contratos se debe colocar estos controles
en las precondiciones.
El objetivo es la simplicidad, al agregar c´odigo redundante en la progra-
maci´on defensiva, se hace el software m´as complicado. Al agregar m´as c´odigo
hay que agregar m´as controles y as´ı sucesivamente.
4.5.1. Especificaci´on de contratos
Los contratos se especifican a trav´es de cla´ usulas que definen las pre y
post condiciones. Las precondiciones se especifican con la cla´ usula requires y
las post condiciones con la cla´ usula ensures.
Supongamos que se quiere especificar una clase Tiempo que tiene los
m´etodos ponerHora, ponerMinutos, ponerSegundos, tiempoTranscurrido.
Una posible implementaci´on puede ser crear tres variables hora, minutos,
segundos y a trav´es de un algoritmo hallar el tiempo transcurrido.
Otra implementaci´on puede ser hallar el tiempo transcurrido desde un
momento determinado, por ejemplo, el principio del a˜ no. De esta forma es
posible almacenar el tiempo en una sola variable entera. Con este m´etodo
se puede simplificar el hallar el tiempo transcurrido a restar dos variables
enteras.
4.5. DISE
˜
NO POR CONTRATOS 89
Con el sistema de dise˜ no por contrato solo se debe especificar el contrato
que las clases deben cumplir y no la implementaci´on. La clase ponerHora se
puede especificar como sigue:
void ponerHora(int h)
/* requieres 0 <= h <= 23
* ensures hora=h
* ensures old minutos = minutos
* ensures old segundos = segundos
*/
Esta especificaci´on garantiza que la hora est´a en un rango permitido, que
los minutos y segundos no cambian y que la variable h toma el valor de hora.
Una implementaci´on de esta especificaci´on podr´ıa ser
void ponerHora(int h)
/* requieres 0 <= h <= 23
* ensures hora=h
* ensures minutos = minutos
* ensures segundos = segundos
*/
hora=h;
}
Si analizamos el c´odigo propuesto, parece que la post condici´on es una
redundancia del c´odigo. Hay que hacer notar que la post condici´on hora=h
indica que lo que se espera, es que la variable hora tome el valor h. El c´odigo
indica como se hace esto.
Si se hubiera escogido la segunda forma de implementar, se tendr´ıa un
c´odigo m´as complejo y la misma especificaci´on. Esto permite que podamos
cambiar el c´odigo sin tener que avisar este cambio a todos los clientes, fa-
cilitando la reusabilidad y mantenimiento al haber mantenido los contratos
entre clientes y proveedores.
Cada pre y post condici´on debe satisfacer los siguientes requerimientos:
Las pre y post condici´on aparece en la documentaci´on oficial distribuida
a autores de m´odulos cliente.
Es posible justificar la precondici´on en base de la especificaci´on sola-
mente.
90 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Cada caracter´ıstica que aparece en la pre y post condici´on debe es-
tar disponible a cada cliente cuya ejecuci´on est´e disponible (regla de
disponibilidad).
4.5.2. Invariantes
El el dise˜ no por contratos se tienen dos tipos de invariantes, las invariantes
de clase y las invariantes de bucles o ciclos.
Las invariantes de clase describen propiedades globales que deben preser-
varse entre todas las rutinas. En cambio las invariantes de bucle describen
las propiedades que deben preservarse entre las variables de un bucle.
Una invariante es correcta si y solo si cumple:
La creaci´on de un procedimiento p, cuando se aplica a los argumentos
que satisfacen la precondici´on, satisface la invariante I.
Cuando termina una rutina exporta sus resultados, cuando satisface la
precondici´on dando un estado I, tambi´en satisface la invariante. Ter-
mina en uno estado que satisface la invariante
En la clase Tiempo la invariante quedar´ıa especificada como:
Tiempo (){
Invariant 0 < = hora < =24
Invariant 0 < = minutos < =59
Invariant 0 < = segundos < =59
}
El estado global de la clase especificada indica que cuando cambiamos la
hora, los valores hora, minutos y segundos est´an en el rango correcto.
Una especificaci´on de la clase tiempo puede ser como sigue:
public clase Tiempo (){
Invariant 0 < = hora < =24
Invariant 0 < = minutos < =59
Invariant 0 < = segundos < =59
ponerHora(int h){
}
4.6. PRUEBA EST
´
ATICA 91
/* requieres 0 <= h <= 23
* ensures hora=h
* ensures minutos = minutos
* ensures segundos = segundos
*/
}
ponerMinutos(int m){
}
/* requieres 0 <= h <= 23
* ensures minutos=m
* ensures hora = hora
* ensures segundos = segundos
*/
......
.......
En cada m´etodo se deber´a especificar las invariantes del ciclo apropiadas
en funci´on de la implementaci´on.
Como se ve estos conceptos simplifican la construcci´on del programa y lo
hacen m´as legible. En Java se puede implementar a trav´es de varios progra-
mas utilitarios que, se muestran en la siguiente secci´on.
4.6. Prueba est´atica
Las pruebas est´aticas de c´odigo utilizan la l´ogica formal para probar que
aplicando a la precondici´on la invariante se llega a la post condici´on. Es-
tas pruebas se realizan aplicando una serie de reglas de la l´ogica formal. El
prop´osito de presentar estas reglas es mostrar en forma simple como se apli-
can en el proceso de prueba. El texto de la Dra Tanja Vos [Vos01], provee la
prueba y un extensa explicaci´on de esta tem´atica.
A fin de ejemplificar el proceso que se sigue veamos un ejemplo muy
sencillo:
La regla de bloques indica que dada una precondici´on ¦P¦, con un c´odigo
C se llega a la post condici´on ¦Q¦. Las variables locales no deben figurar en
la precondici´on y post condici´on. Ejemplo:
¦X = x¦X = X + 1¦X = x + 1¦
92 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
El procedimiento de prueba consiste en reemplazar las variables de la
precondici´on en el c´odigo para obtener la post condici´on. En el ejemplo re-
emplazamos valor de la variable X obteniendo:
¦X = x¦x = x + 1¦X = x + 1¦
finalmente reemplazamos la x y se obtiene la post condici´on.
En el caso de las secuencias se procede de forma similar Dada una se-
cuencia de instrucciones
C
1
; C
2
; ...C
n
una precondici´on ¦P¦ y la post condici´on ¦Q¦, ´esta secuencia de instrucciones
puede expresarse como:
¦P¦
¦P
1
¦C
1
; ¦Q
1
¦¦P
2
¦C
2
; ¦Q
2
¦......¦P
n
¦C
n
; ¦Q
n
¦
¦Q¦
De este desarrollo se ve que P
1
es consecuencia de P y que P
2
es con-
secuencia de Q
1
y sucecivamente hasta llegar a Q que es consecuencia de
Q
n
.
Para este proceso existen reglas, para secuencias, bloques, condicionales,
bucles while, for y todos les elementos utilizados en la programaci´on.
4.7. Prueba din´amica
La prueba din´amica es la que se realiza en tiempo de ejecuci´on y el len-
guaje de programaci´on brinda el m´etodo de afirmaciones a trav´es de la ins-
trucci´on assert. Con aplicaciones adicionales se pueden verificar las precon-
diciones, post condicones e invariantes. Estos controles son insertados en el
c´odigo autom´aticamente con afirmaciones. En estos desarrollos se encuentra
iContract, JMSAssert [Fel05], y Java Modeling Language (JML).
4.7.1. Afirmaciones
Las afirmaciones son una forma de verificar en tiempo de ejecuci´on, ciertas
condiciones que se deben cumplir durante la ejecuci´on del programa. Esta
opci´on viene en Java despu´es de la versi´on 1.4. La utilizaci´on dentro del
4.7. PRUEBA DIN
´
AMICA 93
lenguaje Java se realiza con la instrucci´on assert que tiene las dos formas
siguientes:
assert expresion1;
assert expresion1 : expresion2;
En la primera forma expresion1 es una expresi´on booleana que el pro-
gramador afirma ser verdadera durante la ejecuci´on del programa.
En la segunda forma se agrega expresion2 que es un mecanismo para
pasar una cadena que ser´a mostrada en caso de fallar la afirmaci´on.
Cuando uno ejecuta un programa en modo de prueba est´a interesado
en que se procesen las afirmaciones, sin embargo, cuando est´a en modo de
producci´on se desea eliminar estas instrucciones para mejorar el tiempo de
proceso. Por este motivo al invocar la ejecuci´on del programa se debe incluir
la opci´on −ea para que se ejecuten. Por ejemplo se queremos ejecutar el
programa Ejemplo con las afirmaciones habilitadas se coloca
java −ea Ejemplo
El propio lenguaje Java trae la opci´on que permite habilitar las afirma-
ciones propias del lenguaje a fin de diagnosticar posibles errores propios del
Java, esto se hace con la opci´on −esa. Recordando el ejemplo de la secci´on
anterior:
Nombre persona = new Nombre(nombrePersona);
int largo=0;
String dato = persona.devuelveNombre();
if (dato == null) {
System.err.println("Error grave:
Falta la propiedad ’nombre’ ");
}
else
{
largo=dato.trim().length();
}
94 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
Se observa que el control sobre el nombre se hace permanentemente. Cuando
el sistema est´a completamente depurado es muy probable que no se requiera
realizar este control. Utilizando la instrucci´on assert queda como sigue:
Nombre persona = new Nombre(nombrePersona);
int largo=0;
String dato = persona.devuelveNombre();
assert dato == null : "Falta la propiedad ’nombre’ "
largo=dato.trim().length();
Como puede observar el programa ha quedado en formas m´as comprensi-
ble y la cantidad de c´odigo a revisar es menor, pudiendo habilitar o desabilitar
el control en tiempo de ejecuci´on.
Retomando el ejemplo de la criba de Eratostenes en versi´on final. Rees-
cribimos algunas invariantes y precondiciones en una instrucci´on assert para
obtener:
import java.util.*;
public class Criba {
public static void main(String[] s) {
int n = 100000000;
BitSet a = new BitSet(n + 1);
int i = 2, j = 0;
for (i = 2; i * i <= n; i++) {
//Invariante hasta i-1 se han marcado todos los
//multiplos de i - 1 para i > 2
if (!a.get(i)) {
//Precondici´on:
// los multiplos de i no han sido marcados
assert !a.get(i) :
"Procesando multiplos " + i +" dos veces"
for (j = i + i; j <= n; j=j+i;) {
//Invariante j es multiplo de i
assert i%j == 0: " J no es multiplo de I"
a.set(j);
}
}
4.8. PROGRAMACI
´
ON BAJO CONTRATOS CON JML 95
}
}
}
/**
* Post condici´on:
//Un vector de bits con los numeros primos en cero.
*/
Ahora en una ejecuci´on normal del programa se ve que no hay ning´ un pro-
blema. Sin embargo, al codificar el c´odigo se puede haber escrito con un
error:
for (j = i + i; j <= n; j++;) {
//Invariante j es multiplo de i
assert i%j == 0: " J no es multiplo de I"
Este error que puede pasar desapercibido por la costumbre de escribir el
c´odigo de esa forma. En el tiempo de ejecuci´on al habilitar las invariantes se
obtiene el mensaje de error.
Esta forma de describir el c´odigo requiere que se busquen formas de es-
pecificar las pre, post condiciones e invariantes del programa.
Como se ve ´estos conceptos simplifican la construcci´on del programa y lo
hace m´as legible.
4.8. Programaci´ on bajo contratos con JML
Existen varias herramientas que se pueden utilizar para implementar la
programaci´on bajo contratos en Java. La siguiente lista muestra una serie de
herramientas disponibles:
Herramienta Descripci´on
Jass Java with Asertions
Icontract Java Design by Contract
Jcontract Java Design by Contract
Jcontractor Java Design by Contract
JML Java Modeling Language
Esc/java Extended Static Checker
De estas herramientas hay que destacar que Esc/java trata de realizar
una verificaci´on est´atica del c´odigo utilizando principios de la l´ogica formal.
96 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
El JML aprovecha los mecanismos de la especificaci´on de programas y de
la documentaci´on para incluir los elementos del contrato incorporados en un
programa Java y herramientas para compilar y ejecutar el c´odigo.
La precondici´on se incluye con la instrucci´on requires y la post condici´on
con ensures. Las anotaciones se escriben en l´ıneas de comentarios con la forma
/ ∗ @....@∗ /. En el ejemplo el c´odigo completo queda como sigue:
public class Divide {
/*@ requires b > 0 ;
@ ensures \result * b <= a ;
@*/
public static int Div (int a, int b){
return (a/b);
}
}
En este caso probamos la clase desde la entrada principal y la clase Divide
tiene la obligaci´on de verificar la precondici´on y la post condici´on. En el
ejemplo la precondici´on es que b > 0 para evitar la divisi´on por cero y la post
condici´on para garantizar que el resultado de la divisi´on no sea incorrecto.
Para compilar el c´odigo con JML se procede como sigue:
jmlc Divide.java
Este proceso incluye todas las afirmaciones necesarias para verificar las inva-
riantes, pre y post condiciones. Para ejecutar el programa se procede de la
siguiente manera:
jmlrac Divide
Ahora supongamos que el programa de la divisi´on produce un resultado
err´oneo en el programa hemos colocado
return (a*b);
en lugar de
return (a/b);
4.8. PROGRAMACI
´
ON BAJO CONTRATOS CON JML 97
obtendremos un error explicando la causa de la falla
Exception in thread "main"
org.jmlspecs.jmlrac.runtime.JMLInternalNormal
PostconditionError: by method Divide.Div
regarding specifications at
File "Divide.java", line 4, character 23 when
’b’ is 3
’a’ is 10
’\result’ is 30
at Divide.Div(Divide.java:446)
at Divide.internal$main(Divide.java:14)
at Divide.main(Divide.java:548)
4.8.1. Especificaci´on de invariantes
En la programaci´on por contratos se tienen dos tipos de invariantes. Las
invariantes de ciclo que son las que se cumplen durante la ejecuci´on del ciclo y
las invariantes de clase que deben ser v´alidas antes y despu´es de la ejecuci´on
de la clase. La forma de especificar las invariantes es a trav´es de la cl´ausula
invariant. Para ejemplificar las invariantes de ciclo se utiliza la instrucci´on
loop invariant delante de la instrucci´on que especifica el ciclo. Por ejemplo:
static int Suma (int n) {
int suma=0;
//@ loop_invariant suma %5 == 0;
for (int i=0; i<n; i=i+5) {
suma+=i;
}
return suma;
}
En el c´odigo se ve que la invariante especifica que suma es m´ ultiplo de 5 en
cada instante durante el ciclo for.
Las invariantes de clase se especifican al principo de la clase con la cl´ausula
invariant Veamos un ejemplo:
98 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
public abstract class Inv1 {
boolean[] vector;
//@ invariant vector != null && vector.length == 7;
Invariant() {
vector = new boolean[7];
}
}
Esta especificaci´on indica que el vector no es nulo, tiene una longitud de 7 y
estos valores no se modifican en la ejecuci´on de la clase.
4.8.2. Cuantificadores
Los cuantificadores son los descritos en el cuadro 4.2: La sintaxis de los
Cuantificador Descripci´on
¸forall para todo
¸exists existe
¸sum suma
¸product producto
¸num of n´ umero de
¸max m´aximo
¸min m´ınimo
Cuadro 4.2: Cuantificadores
cuantificadores es como sigue:
¦¸cuantificador int V ariable; rango; codigo¦
Adicionalmente se incluye la ¸old(variable) para obtener el valor anterior a
la ejecuci´on del c´odigo.
Como ejemplo veamos una funci´on que suma los elementos de un vec-
tor. Antes de la ejecuci´on del c´odigo es necesario que el vector no sea nulo
(precondici´on), en la post condici´on hay que verificar que el vector no ha
cambiado y que el resultado es realmente la suma. Esto queda especificado
como sigue:
4.8. PROGRAMACI
´
ON BAJO CONTRATOS CON JML 99
public class Vector {
/*@ requires a != null;
@ ensures \result ==
@ (\sum int i; 0 <= i && i < a.length; a[i] )
@ && a == \old(a)
@ && (\forall int i;
@ 0 <= i && i< a.length; a[i] == \old(a[i]));
@*/
static int Suma (int[] a) {
int suma=0;
for (int i=0; i<a.length; i++) {
suma+=a[i];
}
return suma;
}
}
JML es un lenguaje mucho m´as completo. Se puede obtener el manual de
referencia de [LPC
+
02].
4.8.3. Ejercicios
Instalar JML en su equipo. Para ´esto es necesario que tome en cuenta
que, algunas versiones de JML solo funcionan con la versi´on 1.4 de Java. A
la hora de escribir el texto no funcionaba adecuadamente con la versi´on 1.5
de Java.
1. Programar los ejercicios de la secci´on 4.3.5 y comprobar las invariantes,
pre y post condiciones utilizando JML.
2. Especificar en JML una clase hora que tenga los m´etodos siguientes:
ponerHora, ponerMinutos, ponerSegundos, verHora, verMinutos, verSe-
gundos, tiempoTranscurrido. Tiempo transcurrido es la resta del tiempo
entre dos horas.
3. Realizar dos implementaciones diferentes de la clase hora en base a la
especificaci´on anterior.
100 4. CODIFICACI
´
ON CON MIRAS A LA PRUEBA
4. Crear un programa para utilizar la clase hora y verificar que ambas
implementaciones funcionan.
Cap´ıtulo 5
Aplicaciones de b´ usqueda y
clasificaci´on
5.1. Introducci´ on
La b´ usqueda y la clasificaci´on tienen una serie de aplicaciones que ser´an
descritas en las siguientes secciones. Se proceder´a, de m´etodos generales a
casos particulares que reducen el tiempo de proceso. El proceso de especi-
ficaci´on se realiza como se mostr´o en el cap´ıtulo anterior especificando las
invariantes, pre y post condiciones sin entrar en la demostraci´on de ´estas.
Los libros de Horstman [CSH05] proporcionan una buena descripci´on de las
librer´ıas de Java.
5.2. Algoritmos de b´ usqueda
La b´ usqueda de elementos ha sido analizada en diferentes entornos, me-
moria, bases de datos, texto plano y otros. Cada algoritmo de b´ usqueda da
como resultado una eficiencia diferente en funci´on de como se ha organizado
la informaci´on. La b´ usqueda en forma gen´erica se presenta como, el mecanis-
mo de hallar un elemento en un vector del cual solo conocemos, el n´ umero
de elementos que contiene. Este algoritmo, denominado b´ usqueda secuencial,
viene especificado como sigue:
public class Sec {
/* Programa de busqueda secuencial
101
102 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
*@ author Jorge Teran
*/
static int buscar(int[] v, int t) {
/*@ requires v != null ;
@ requires t != null ;
@ ensures (hallo = -1)
@ || (hallo < v.length && hallo >=0);
@*/
int hallo = -1;
// @ loop_invariant i < v.length && hallo = -1;
for (int i = 0; i < v.length; i++)
if (v[i] == t) {
hallo = i;
break;
}
return (hallo);
}
Aplicando la teor´ıa vista se determina que el tiempo de ejecuci´on del algo-
ritmo es proporcional
n

i=0
1 = n
Esto significa que es necesario conocer m´as sobre el conjunto de datos para
mejorar el tiempo de b´ usqueda. Este concepto hace que se puedan realizar
b´ usquedas espec´ıficas para cada conjunto de datos a fin de mejorar el tiempo
de proceso.
Sup´ongase que se tiene una lista de n´ umeros enteros entre 0 y n. Estos
n´ umeros corresponden al c´odigo de producto en un almac´en. Dado un n´ umero
se quiere conocer si este pertenece al almac´en. Para esto podemos organizar
los n´ umeros de varia formas. Se puede colocar la informaci´on en un vector y
proceder con el esquema de b´ usqueda anterior obteniento un tiempo O(n) =
n. ¿Ser´a posible obtener un tiempo O(n) = 1 ?.
La respuesta es s´ı. Consideremos un c´odigo n peque˜ no entonces podemos
armar un vector de bits en memoria, qu´e indique que n´ umeros existen y
cuales no.
Se quiere cambiar la b´ usqueda secuencial aprovechando algunas carac-
ter´ısticas particulares al problema, suponiendo que los datos est´an previa-
mente ordenados.
5.2. ALGORITMOS DE B
´
USQUEDA 103
Esta soluci´on debe funcionar tanto para enteros, cadenas y reales siempre
y cuando todos los elementos sean del mismo tipo. La respuesta se almacena
en un entero p que representa la posici´on en el arreglo donde se encuentra
el elemento t que estamos buscando, −1 indica que el elemento buscado no
existe en el arreglo.
Esta b´ usqueda denominada b´ usqueda binaria, resuelve el problema re-
cordando permanentemente el rango en el cual el arreglo almacena t. Inicial-
mente el rango es todo el arreglo y luego es reducido comparando t con el
valor del medio y descartando una mitad. El proceso termina cuando se halla
el valor de t o el rango es vac´ıo. En una tabla de n elementos en el peor caso
realiza log
2
n comparaciones.
La idea principal es que t debe estar en el rango del vector. Se utiliza la
descripci´on para construir el programa.
precondici´on el vector esta ordenado
inicializar el rango entre $0..n-1$
loop
{invariante: el valor a buscar debe estar en el rango}
si el rango es vacio
terminar y avisar que t no esta en el arreglo
calcular m que es el medio del rango
use m con una prueba para reducir el rango
si se encuentra t en el proceso de reducci´on
terminar y comunicar su posici´on
La parte esencial del programa es la invariante que al principio y final de cada
iteraci´on nos permite tener el estado del programa y formalizar la noci´on
intuitiva que ten´ıamos.
Se construye el programa utilizando refinamiento sucesivo haciendo que
todos los pasos respeten la invariante del mismo.
Primero buscaremos una representaci´on del rango digamos l..u entonces la
invariante es el rango debe estar entre l..u. El pr´oximo paso es la inicializaci´on
y debemos estar seguros que respeten la invariante, la elecci´on obvia es l =
0, u = n −1.
Codificando un programa con los conceptos detallados previamente tene-
mos:
precondici´on x debe estar ordenado
post condici´on p especifica la posici´on
104 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
o p es -1 cuando no existe
l=0; u=n-1
loop
{invariante: debe estar en el rango l,u}
si el rango es vacio
terminar y avisar que t no esta en el arreglo
calcular m que es el medio del rango
use m con una prueba para reducir el rango
si se encuentra t en el proceso de reducci´on
terminar y comunicar su posici´on
Continuando con el programa vemos que el rango es vac´ıo cuando l > u. en
esta situaci´on terminamos y devolvemos p = −1. Llevando esto al programa
tenemos:
precondici´on x debe estar ordenado
post condici´on p especifica la posici´on
o p es -1 cuando no existe
l=0; u=n-1
loop
{invariante: debe estar en el rango l,u}
if l > u
p=-1; break;
calcular m que es el medio del rango
use m con una prueba para reducir el rango
si se encuentra t en el proceso de reducci´on
terminar y comunicar su posici´on
Ahora calculamos m con m = (l + u)/2 donde / implementa la divisi´on
entera. Las siguientes l´ıneas implican el comparar t con x[m] en la que hay
tres posibilidades, por igual, menor y mayor. Con lo que el programa queda
como sigue:
precondici´on x debe estar ordenado
post condici´on p especifica la posici´on
o p es -1 cuando no existe
l=0; u=n-1
loop
{invariante: debe estar en el rango l,u}
5.2. ALGORITMOS DE B
´
USQUEDA 105
if l > u
p=-1; break;
m=(l+u)/2;
case
x[m]< t : l=m+1;
x[m]= t : p=m: break;
x[m]> t : u=m-1
Se deja como ejercicio para el lector comprobar que el tiempo de ejecuci´on
de este algoritmo es proporcional a log(n). Para resolver esto f´acilmente se
puede reescribir en forma recursiva y aplicar el teorema master.
5.2.1. Prueba exhaustiva
Ahora es necesario probar la b´ usqueda binaria. El primer paso es el de
convertir la invariante, pre y post condiciones con afirmaciones o utilizando
el lenguaje JML. Sin embargo, esto no garantiza que el programa funcione
correctamente para todos los casos.
Consideremos el siguiente pseudo c´odigo y realicemos una prueba de es-
critorio:
public class b´usqueda {
public static int BusquedaBinaria(int[] x, int t) {
int l = 0;
int u = x.length - 1;
int m = 0;
int p = -1;
while (l <= u) {
m = (l + u) / 2;
if (x[m] < t)
l= m ;
else if (x[m] == t) {
p = m;
break;
} else
u = m;
}
return p;
106 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
}
Aparentemente es correcto, pero una prueba de escritorio extensiva es
larga y aburrida. Por esto es conveniente construir un conjunto de datos de
prueba, para lo cual, utilizamos el siguiente c´odigo:
int[] x = new int[MAXIMO];
for (int i = 0; i < MAXIMO; i++) {
x[i] = i * 5;
}
En este conjunto de datos conocemos perfectamente el contenido del vector,
vale decir que, si buscamos un m´ ultiplo de 5 deber´ıa encontrarlo.
Un programa puede estar probado o certificado. Decimos que esta probado
cuando funciona correctamente con los datos de prueba utilizados.
Decimos que el programa est´a certificado cuando funciona correctamente
con todos los posibles casos que pueden ocurrir.
Por ejemplo, con el vector de datos construidos podemos probar con al-
gunos valores y ver que funciona adecuadamente. ¿Podremos decir lo mismo
para todo los valores?
Para realizar esta prueba vamos a buscar todos los elementos introducidos
al vector y verificar que los encuentra y devuelve el resultado correcto. El
c´odigo es el siguiente:
for (int i = 0; i < MAXIMO; i++) {
if (b´usqueda.BusquedaBinaria(x, i * 5) != i) {
System.out.println("Error al buscar " + i*5);
}
Ahora sabemos que se prueba la b´ usqueda de todos los valores existentes en
el vector y no produce errores.
Los valores que no existen en el vector pueden pertenecer a cualquier
rango de datos. Por esto se hace necesario buscar un elemento no existente
entre cada uno de los valores introducidos obteniendo el sigiente c´odigo:
for (int i = 0; i < MAXIMO; i++) {
if (b´usqueda.BusquedaBinaria(x, i * 5 + 1) != -1) {
System.out.println("Error al buscar " + i*5+1);
}
5.2. ALGORITMOS DE B
´
USQUEDA 107
Este c´odigo nos certifica que el programa es correcto en un determinado
conjunto de datos. Que podemos decir si ampliamos el tama˜ no del vector?
Solo que se ha probado y puede que funcione pero, no est´a certificado. El
c´odigo completo es:
public static final int MAXIMO = 1000;
public static void main(String[] args) {
System.out.println("Creando el vector");
int[] x = new int[MAXIMO];
for (int i = 0; i < MAXIMO; i++) {
x[i] = i * 5;
}
System.out.println("Buscando elementos existentes");
for (int i = 0; i < MAXIMO; i++) {
if (b´usqueda.BusquedaBinaria(x, i * 5) != i) {
System.out.println("Error al buscar " + i*5);
}
}
System.out.println("Buscando elementos no existentes");
for (int i = 0; i < MAXIMO; i++) {
if (b´usqueda.BusquedaBinaria(x, i * 5 + 1) != -1) {
System.out.println("Error al buscar " + i*5+1);
}
}
System.out.println("Fin de la prueba");
}
Nos preguntamos que es lo que se debe especificar. Generalmente se deben
colocar las invariantes, pre y post condiciones. Sin embargo es ´ util tambi´en
afirmar o especificar el O(n) para verificar el funcionamiento del programa
en los tiempos previstos o detectar bucles infinitos.
5.2.2. Representaci´on gr´afica de la b´ usqueda
Una representaci´on gr´afica puede ser adecuada para mostrar como fun-
ciona un programa. Esto hace que de un golpe de vista se determine que el
programa funcione, aparentemente sin errores.
108 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
Para realizar una representaci´on gr´afica del programa de b´ usqueda binaria
construimos una l´ınea para mostrar el rango de b´ usqueda. El programa debe
ser capaz de mostrar como se reduce el rango y contar el n´ umero de iteraciones
del mismo.
Para ejemplificar ´esto se muestra un programa que construye un vector
con los n´ umeros pares entre 0 y 60. Luego permite buscar un valor mostrando
el proceso seguido en la b´ usqueda.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import javax.swing.event.*;
public class Busbin {
public static void main(String[] args) {
TextFrame frame = new TextFrame();
frame.setSize(640,480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class TextFrame extends JFrame
{
public TextFrame(){
setTitle("b´usqueda Binaria");
DocumentListener listener = new TextoFieldListener();
// agregar un panel con el texto a buscar
JPanel panel = new JPanel();
panel.add(new JLabel("Buscar:"));
queBuscaField = new JTextField("30", 5);
panel.add(queBuscaField);
queBuscaField.getDocument().addDocumentListener(listener);
5.2. ALGORITMOS DE B
´
USQUEDA 109
add(panel, BorderLayout.NORTH);
// agregar el grafico
muestra = new DrawPanel();
add(muestra, BorderLayout.CENTER);
pack();
}
// recuperar el valor a buscar
public void setTexto(){
try {
int queBuscas = Integer.parseInt(
queBuscaField.getText().trim());
muestra.muestra(queBuscas);
}
catch (NumberFormatException e) {}
//no se reliza nada si no se puede interpretar los datos
}
public static final int DEFAULT_WIDTH = 640;
public static final int DEFAULT_HEIGHT = 480;
private JTextField queBuscaField;
private DrawPanel muestra;
private class TextoFieldListener
implements DocumentListener {
public void insertUpdate(DocumentEvent event)
{setTexto();}
public void removeUpdate(DocumentEvent event)
{setTexto();}
public void changedUpdate(DocumentEvent event) {}
}
}
class DrawPanel extends JPanel {
int t=30, incrementos=20,
medio=0,maximo=30;
110 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
int[] v = new int[maximo + 1];
public DrawPanel(){
for (int i = 0; i <= maximo; i++) {
v[i] = i * 2;
}
}
public void muestra(int x){
t=x;
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int desde=20, topY=100,
hasta=600,l=0,u=maximo,m=0;
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.WHITE);
g2.fillRect(0,0,640,480);
g2.setColor(Color.BLACK);
int hallo=-1,contador=0;
// dibujar
String explica="Las lineas representan el "+
"rango en el cual se busca";
g.drawString(explica,
((desde+hasta)/2 ) - (explica.length()*3), topY);
while (l <= u) {
topY += incrementos;
m = (l + u) / 2;
medio = (hasta + desde) / 2;
g.drawString("" + contador++, 5, topY);
g.drawString("" + v[l], desde, topY);
g.drawString("" + v[u], hasta, topY);
g.drawString("" + v[m], medio, topY);
g2.draw(new Line2D.Double(desde, topY, hasta, topY));
if (v[m] < t) {
l = m + 1;
desde = medio + 1;
} else if (v[m] == t) {
topY += incrementos;
5.3. CLASIFICACI
´
ON 111
Figura 5.1: Representaci´on gr´afica de la b´ usqueda binaria
g.drawString("" + contador++, 5, topY);
g.drawString("" + v[m],(hasta + desde)/ 2,topY);
hallo = m;
break;
} else {
u = m - 1;
hasta = medio - 1;
}
}
}
}
La salida del programa se ve en la figura 5.1 que, muestra como se va redu-
ciendo el rango de b´ usqueda hasta encontrar el valor. A la izquierda se ve un
contador con el n´ umero de iteraci´on.
5.3. Clasificaci´ on
La clasificaci´on o procedimiento de ordenar es uno de los problemas m´as
importantes en la computaci´on y existen un sin n´ umero de problemas de
programaci´on que requieren de ella. A continuaci´on se detallan una serie de
aplicaciones sin pretender que sean todas.
112 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
C´omo podemos probar que en un grupo de elementos no existen elemen-
tos duplicados? Bien para esto ordenamos el conjunto y posteriormente
verificamos que no existen valores tales que x[i] = x[i + 1] recorriendo
el conjunto para todos los valores de i permitidos.
C´omo podemos eliminar los duplicados? Ordenamos el conjunto de da-
tos y luego utilizamos dos ´ındices haciendo x[j] = x[i]. Se incrementa
el valor de i y j en cada iteraci´on. Cuando se halla un duplicado solo
incrementa i. Al finalizar ajustamos el tama˜ no del conjunto al valor de
j.
Supongamos que tenemos una lista de trabajos que tenemos que rea-
lizar con una prioridad espec´ıfica. Puede ser por ejemplo una cola de
impresi´on donde se ordenan los trabajos en funci´on de alguna priori-
dad. Para esto ordenamos los trabajos seg´ un la prioridad y luego se
los procesa en este orden. Por supuesto que hay que tomar recaudos al
agregar nuevos elementos y mantener la lista ordenada.
Una t´ecnica muy utilizada para agrupar ´ıtems es la denominada cor-
tes de control. Por ejemplo, si se desea obtener los totales de sueldo
por departamento en una organizaci´on, ordenamos los datos por el de-
partamento que, se convierte en el elemento de control y luego cada
vez que cambia imprimimos un total. Esto se denomina un corte de
control. Pueden existir varios cortes de control, por ejemplo secci´on,
departamento, etc.
Si deseamos hallar la mediana de un conjunto de datos podemos indicar
que la mediana est´a en el medio. Por ejemplo para hallar el elemento
k ´esimo mayor bastar´ıa en acceder a x[k].
Cuando queremos contar frecuencias y desconocemos el n´ umero de ele-
mentos existentes o este es muy grande, ordenando y aplicando el con-
cepto de control, con un solo barrido podemos listar todos las frecuen-
cias.
Para realizar uni´on de conjuntos se pueden ordenar los conjuntos, reali-
zar un proceso de intercalaci´on. Cuando hay dos elementos iguales solo
insertamos uno eliminando los duplicados.
En el caso de la intersecci´on intercalamos los dos conjuntos ordenados
y dejamos uno solo de los que existan en ambos conjuntos.
5.3. CLASIFICACI
´
ON 113
Para reconstruir el orden original es necessario crear un campo adicio-
nal que mantenga el original para realizar una nueva ordenaci´on para,
reconstruir el orden original.
Como vimos tambi´en se pueden ordenar los datos para realizar b´ usque-
das r´apidas.
5.3.1. Clasificaci´on en Java
Los m´etodos propios del Java proveen rutinas para ordenar objetos que
facilitan el desarrollo de aplicaciones.
Para ordenar vectores que pueden ser de tipos int, long, short, char, byte,
float o double es suficiente utilizar la clase Arrays con el m´etodo sort, el
siguiente ejemplo genera 10 n´ umeros al azar y los ordena.
import java.util.*;
/**
* Programa ordenar enteros
* utilizando el metodo de java
* @author Jorge Teran
*/
public class SortVect {
public static void main(String[] args) {
int[] x = new int[10];
Random gen = new Random();
//Generar 10 n´umeros enteros entre 0 y 100
for (int i = 0; i < 10; i++)
x[i] = gen.nextInt(100);
//Ordenar en forma ascendente
Arrays.sort(x);
//mostrar los n´umeros ordenados
for (int i = 0; i < 10; i++)
System.out.println(x[i]);
}
}
114 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
Cuando se requiere ordenar un objeto se hace necesario crear un mecanismo
para comparar los elementos del objeto. Construyamos una clase Persona
que almacene nombre, apellido y nota.
import java.util.*;
class Persona {
private String nombre;
private String apellido;
private int nota;
public Persona(String no, String ap, int n) {
nombre = no;
apellido = ap;
nota = n;
}
public String getNombre() {
return nombre;
}
public String getApellido() {
return apellido;
}
public int getNota() {
return nota;
}
}
Para crear diferentes instancias de Persona se procede como sigue:
Persona[] alumnos = new Persona[3];
alumnos[0] = new Persona("Jose","Meriles", 70);
alumnos[1] = new Persona("Maria","Choque",55);
alumnos[2] = new Persona("Laura","Laura", 85);
Si se requiere ordenar ´estos alumnos por nota no es posible utilizar direc-
tamente Arrays.sort(alumnos) dado que el m´etodo de clasificaci´on no conoce
cu´ales y qu´e campos comparar para realizar el ordenamiento.
5.3. CLASIFICACI
´
ON 115
Por esto es necesario primeramente escribir un m´etodo que resuelva el
problema. En nuestro ejemplo creamos el m´etodo compareTo. Este nombre
es un nombre reservado de Java y lo que realiza es una sobrecarga de m´etodo
reemplazando el m´etodo de Java con el nuestro.
Los valores que debe devolver son −1 cuando es menor, 0 cuando es igual
y 1 cuando es mayor. Lo que hace este m´etodo es comparar el valor presente
con otro pasado a la rutina. Esta rutina utiliza el m´etodo qsort para ordenar
los valores. Esta rutina queda como sigue:
public int compareTo(Persona otro){
if (nota < otro.nota) return -1;
if (nota > otro.nota) return 1;
return 0;
}
Ademas es necesario especificar que la clase persona incluye el m´etodo
Comparable y se especifica as´ı:
class Persona implements Comparable<Persona>
El programa final queda implementado en el siguiente c´odigo:
import java.util.*;
/**
* Programa ordenar objetos
* utilizando el metodo de java
* @author Jorge Teran
*/
public class OrdObjeto {
public static void main(String[] args) {
Persona[] alumnos = new Persona[3];
alumnos[0] = new Persona("Jose", "Meriles", 70);
alumnos[1] = new Persona("Maria", "Choque", 55);
alumnos[2] = new Persona("Laura", "Laura", 85);
Arrays.sort(alumnos);
for (Persona e : alumnos)
116 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
System.out.println("Nombre=" + e.getNombre()
+ ", Apellido= " + e.getApellido()
+ ", nota=" + e.getNota());
}
}
class Persona implements Comparable<Persona> {
private String nombre;
private String apellido;
private int nota;
public Persona(String no, String ap, int n) {
nombre = no;
apellido = ap;
nota = n;
}
public String getNombre() {
return nombre;
}
public String getApellido() {
return apellido;
}
public int getNota() {
return nota;
}
public int compareTo(Persona otro) {
if (nota < otro.nota)
return -1;
if (nota > otro.nota)
return 1;
return 0;
5.3. CLASIFICACI
´
ON 117
}
}
5.3.2. Algoritmos de clasificaci´on
Dado que el lenguaje ya incluye un soporte para realizar clasificaciones
con un algoritmo parece que no es necesario revisar algorimos de clasificaci´on.
En la realidad existen problemas que pueden ser resueltos m´as eficientemente
con un algoritmo espec´ıfico. Esto se logra conociendo como est´an los datos
que pretendemos procesar.
Los algoritmos para ordenar se clasifican en algoritmos generales y par-
ticulares. Los algoritmos generales se pueden aplicar sin importarnos como
son los datos, en cambio los algoritmos particulares son aplicables a casos
especiales para obtener un mejor tiempo de proceso.
Entre los algoritmos generales se explica el m´etodo de clasificaci´on por
inserci´on, el qsort, ordenaci´on por selecci´on y el de burbuja.
M´etodo de la burbuja
El m´etodo de la burbuja es el m´as simple y el m´as antiguo. Tambien hay
que mencionar que es el m´etodo m´as lento para ordenar.
El m´etodo consiste en comparar todos los elementos de la lista con el
elemento de su lado. Si se requiere se realiza un intercambio para que est´en en
el orden previsto. Este proceso se repite hasta que todos los elementos est´en
ordenados. Vale decir que, en alguna pasada no se realiza ning´ un intercambio.
El c´odigo para este algoritmo es el siguiente:
void Burbuja (int[] x) {
int i, j, temp;
int n=x.length;
for (i = (n - 1); i >= 0; i--) {
for (j = 1; j <= i; j++) {
if (x[j - 1] > x[j]) {
temp = x[j-1];
x[j-1] = x[j];
x[j] = temp; }
}
}
118 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
Como se ve en el programa en el primer ciclo se recorren todos los elementos.
El segundo ciclo se encarga de que el ´ ultimo elemento sea el mayor de todos.
Analizando el programa se puede determinar que, el tiempo de proceso
en el caso general es:
0

i=n−1
j=i

j=1
=
0

i=n−1
i = n
n −1
2
como se ve, demora un tiempo proporcional a O(n
2
) que lo hace impr´actico.
Podemos mencionar como una ventaja la simplicidad de la codificaci´on y
como desventaja la ineficiencia del algoritmo.
Existen otros m´etodos que tambi´en tienen un tiempo similar pero que
son mucho m´as eficientes que mencionamos a continuaci´on.
Clasificaci´on por inserci´on
Cuando se tiene un conjunto de cartas en la mano lo que hacemos es
tomar una carta y buscar su ubicaci´on e insertarla en su sitio hasta ordenar
todas. Para ´esto podemos suponer que el primer elemento est´a en su lugar y
proceder a colocar los siguientes en funci´on del primer elemento.
void Insercion(int[] x) {
int i, j, temp;
int n = x.length;
for (i = 1; i < n; i++) {
for (j = i; j > 0 && x[j - 1] > x[j]; j--) {
temp = x[j-1];
x[j-1] = x[j];
x[j] = temp;
}
}
}
Para explicar el funcionamiento del algoritmo supongamos que inicialmente
tenemos la siguiente secuencia de n´ umeros
62 46 97 0 30
Inicialmente suponemos que el primer valor es el menor y lo insertamos en
la primera posici´on que, es el lugar donde estaba inicialmente, luego se toma
5.3. CLASIFICACI
´
ON 119
el siguinte valor y se ve si le corresponde estar antes o despu´es, en el ejemplo
se produce un intercambio
46 62 97 0 30
En la siguiente iteraci´on tomamos el 97 y se ve que, no debe recorrerse
hacia adelante por lo que no se hace ning´ un intercambio. Luego se realiza lo
mismo con el siguiente elemento recorriendo todo el vector e insertando el
elemento en el lugar apropiado, obteniendo
0 46 62 97 30
esto se repite hasta obtener el vector ordenado.
Realizando el an´alisis del algoritmo se ve que el tiempo de ejecuci´on es
proporcional a
n−1

i=1
j=1

j=i
=
n−1

i=1
i = n
n −1
2
La ventaja de este algoritmo es que es m´as simple que, el anterior y a´ un
cuando su tiempo de proceso es tambi´en proporcional a n
2
es m´as eficiente
y puede afinarse para ser m´as eficiente. El c´odigo siguiente muestra el al-
goritmo mejorado para ser m´as eficiente. El tiempo de proceso sigue siendo
proporcional a O(n
2
)
void Insercion2(int[] x) {
int i, j, temp;
int n = x.length;
for (i = 1; i < n; i++) {
temp=x[i];
for (j = i; j > 0 && x[j - 1] > temp; j--) {
x[j] = x[j-1];
}
x[j] = temp;
}
}
Como se observa se ha mejorado la parte que corresponde a constuir el espacio
para introducir el elemento siguiente reduciendo el n´ umero de intercambios.
120 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
Ordenaci´on por selecci´on
Una alternativa al problema de ordenaci´on es el concepto de escoger el
elemento m´as peque˜ no y reemplazarlo por el primer elemento, luego repetir
el proceso para el segundo, tercero y as´ı sucesivamente. El resultado es el
siguiente programa
void Seleccion(int[] x) {
int i, j;
int min, temp;
int n = x.length;
for (i = 0; i < n - 1; i++) {
min = i;
for (j = i + 1; j < n; j++) {
if (x[j] < x[min])
min = j;
}
temp = x[i];
x[i] = x[min];
x[min] = temp;
}
}
Como se observa este algoritmo es similar al algoritmo de inserci´on con tiem-
po similar y proporcional a O(n
2
)
Algoritmo de clasificaci´on r´apida
El qsort cuyo nombre en ingl´es es QuickSort o tambi´en denominado al-
goritmo de clasificaci´on r´apida ya fue publicada por C.A.R. Hoare en 1962.
y se basa en dividir el vector en dos mitades utilizando un elemento denomi-
nado pivote de tal forma que todos los elementos mayores al pivote est´en en
un vector y los restantes en el segundo vector. Como inicial pivote se puede
tomar el primer elemento o uno al azar.
Este proceso se repite en forma recursiva hasta tener el vector ordenado.
A partir de este enfoque podemos realizar una primera aproximaci´on a lo
que viene ser el algoritmo:
Ordenar (l,u){
if (u >= l) {
5.3. CLASIFICACI
´
ON 121
hay como maximo un elemento
por lo tanto no hacer nada
}
hallar un pivote p para dividir en vector en dos
Ordenar (l,p-1)
Ordenar (p+1,u)
}
Aqu´ı como digimos el problema es encontrar el punto de partici´on denomi-
nado pivote. Utilizando el concepto que la invariante es que los valores entre
x[m] y x[i] son menores al pivote x[l] podemos contruir el siguiente c´odigo
para hallar el pivote.
int m = l;
//invariante los valores entre x[m] y x[i]
//son menores al pivote x[l]
for (int i = l + 1; i <= u; i++) {
if (x[i] < x[l])
{
temp = x[++m];
x[m] = x[i];
x[i] = temp;
}
}
temp = x[l];
x[l] = x[m];
x[m] = temp;
Supongamos que tenemos los siguientes datos:
27 2 81 81 11 87 80 7
Iniciamos un contador m en el primer valor y tomando x[l] = 27 como pivote
y se recorre el vector comparando cada uno de los valores con el pivote
haciendo un intercambio entre (m+1) y la posici´on del vector, obteniendo
en el primer intercambio entre el n´ umero 2 que es menor que el pivote y el
n´ umero de la posici´on m que es casualmente el 2, obteniendo:
27 2 81 81 11 87 80 7
122 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
El segundo intercambio es entre el 11 que es menor que el pivote y el 81
obteniento:
27 2 11 81 81 87 80 7
El tercer intercambio se produce con el 7 y el 81 obteniendo
27 2 11 7 81 87 80 81
Para finalizar intercambiamos el pivote con la posici´on del ´ ultimo n´ umero
menor al pivote Obteniendo un vector donde todos los elementos menores al
pivote est´an a la izquierda y los mayores a la derecha.
7 2 11 27 81 87 80 81
Este proceso se puede repetir recursivamente para el vector a la izquierda del
pivote y para el que est´a a la derecha obteniento finalmente:
private void qsort(int[] x, int l, int u) {
if (l >= u)
return;
int m = l, temp;
//invariante los valores entre x[m] y x[i]
// son menores al pivote x[l]
for (int i = l + 1; i <= u; i++) {
if (x[i] < x[l])
{
temp = x[++m];
x[m] = x[i];
x[i] = temp;
}
}
temp = x[l];
x[l] = x[m];
x[m] = temp;
qsort(x, l, m - 1);
qsort(x, m + 1, u);
}
Analizando el c´odigo anterior podemos ver que el tiempo de proceso se puede
calcular, utilizando los m´etodos vistos en los cap´ıtulos anteriores
T(n) =
_
1 si n = 1,
2T(n/2) +n en otros casos.
5.3. CLASIFICACI
´
ON 123
En la ecuaci´on anterior n corresponde al ciclo for que recorre todo los ele-
mentos del vector reordenando el vector seg´ un el pivote. Las siguientes dos
llamadas al programa hacen que 2T(n/2). Aplicando el teorema master ob-
tenemos que el tiempo de proceso es proporcional a nlog(n).
Aunque no se divide exactamente a la mitad se ha tomado este valor
para mostrar como mejora la eficiencia . En la realidad se puede mejorar en
funci´on de como est´a el conjunto de datos y como se elige al pivote.
En el caso de que el vector est´e previamente ordenado el tiempo de pro-
ceso ser´a mayor. El proceso de elegir un pivote aleatoriamente produce un
algoritmo m´as estable. Es posible optimizar el m´etodo de ordenaci´on r´apida
pero no se tratar´a en el texto. Cuando uno requiere un algoritmo de estas
caracter´ısticas normalmente recurre a las rutinas ya implementadas en las
librer´ıas del lenguaje.
Se pueden mejorar a´ un m´as los algoritmos de clasificaci´on? En casos par-
ticulares se puede obtener algoritmos proporcionales a O(n) en el caso m´as
general, el mejor algoritmo es proporcional a nlog(n). Una demostraci´on se
puede leer en el texto de [GB96]
Algoritmos de una pasada
Considere las siguientes condiciones para los datos de entrada, se dispone
de memoria, suficiente, los datos son enteros positivos sin repetici´on en el
rango de 0 a N, donde N es el n´ umero m´aximo existente. Para ordenar estos
n´ umeros se puede utilizar cualquiera de los algoritmos descritos para ordenar.
Para mejorar el proceso de ordenar consideremos la siguiente estructura
BitSet a = new BitSet(max + 1);
Si cada posici´on del vector representa a uno de los n´ umeros del vector se
utiliza un bit para almacenar cada uno de los n´ umeros. En este caso es
posible leer los n´ umeros de entrada y encender el bit que le corresponde.
Recorriendo el vector se pueden imprimir los n´ umeros a los que corresponden
los bits encendidos en forma ordenada.
El resultado proporciona el siguiente algoritmo.
public void bitSort(int[] x) {
int max=0, j=0;
for(int i =0; i< x.length; i++){
if (x[i] > max)
124 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
max=x[i];
}
BitSet a = new BitSet(max + 1);
// Hasta aqui todos los valores de
// a estan en cero
for(int i =0;i< x.length; i++)
a.set(x[i]);
for(int i =0;i<= max; i++){
if (a.get(i))
x[j++]=i ;
}
}
Analizando el algoritmo se ve que se tienen tres ciclos que recorren todos los
datos dando un tiempo de ejecuci´on proporcional a O(n).
Comparaci´on pr´actica de la eficiencia de los algoritmos
A fin de comparar los algoritmos de clasificaci´on es necesario hacer una
corrida de los mismos sobre el mismo conjunto de datos. Para esto realizamos
el siguiente programa:
/**Programa para probar los diferentes
* algoritmos de ordenaci´on
* @author Jorge Teran
*
*/
import java.util.*;
public class pruebaMetodos {
public static int MAXIMO = 10000;
public static void main(String[] args) {
//generar MAXIMO n´umeros sin repetidos
int[] x = new int[MAXIMO];
int[] y = new int[MAXIMO];
for (int i = 0; i < MAXIMO; i++)
x[i]=i;
5.3. CLASIFICACI
´
ON 125
Random gen = new Random();
int temp, j;
for (int i = 0; i < MAXIMO; i++){
j = gen.nextInt(MAXIMO);
temp = x[i];
x[i] = x[j];
x[j]=temp;
}
System.out.println("Tama~no de la instancia"+MAXIMO);
long tiempoInicio, tiempoFin, tiempoTotal;
Metodos sort =new Metodos();
//obtener una copia de x para ordenar
//para siempre utilizar el mismo conjunto de datos
System.arraycopy(x,0,y,0,MAXIMO);
tiempoInicio = System.currentTimeMillis();
sort.Burbuja(y);
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(" M´etodo Burbuja "
+ " Tiempo de proceso " + tiempoTotal);
System.arraycopy(x,0,y,0,MAXIMO);
tiempoInicio = System.currentTimeMillis();
sort.Insercion(y);
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(" M´etodo Insercion "
+ " Tiempo de proceso " + tiempoTotal);
System.arraycopy(x,0,y,0,MAXIMO);
tiempoInicio = System.currentTimeMillis();
sort.Insercion2(y);
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(" M´etodo Insercion2 "
+ " Tiempo de proceso " + tiempoTotal);
126 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
System.arraycopy(x,0,y,0,MAXIMO);
tiempoInicio = System.currentTimeMillis();
sort.Seleccion(y);
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(" M´etodo Seleccion "
+ " Tiempo de proceso " + tiempoTotal);
System.arraycopy(x,0,y,0,MAXIMO);
tiempoInicio = System.currentTimeMillis();
sort.quickSort(y);
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(" M´etodo quickSort "
+ " Tiempo de proceso " + tiempoTotal);
System.arraycopy(x,0,y,0,MAXIMO);
tiempoInicio = System.currentTimeMillis();
sort.bitSort(y);
tiempoFin = System.currentTimeMillis();
tiempoTotal = tiempoFin - tiempoInicio;
System.out.println(" M´etodo bitSort "
+ " Tiempo de proceso " + tiempoTotal);
}
}
obteniendo los siguientes resultados para el proceso de 100.000 n´ umeros ge-
nerados aleatoriamente.
M´etodo Tiempo de proceso en miliseg
Burbuja 265.251
Inserci´on 114.364
Inserci´on2 86.795
Selecci´on 155.854
quickSort 110
bitSort 30
Hay que observar que antes de cada proceso hemos realizado una copia del
vector original para que la comparaci´on sea adecuada al mismo conjunto de
5.3. CLASIFICACI
´
ON 127
datos. En funci´on del tama˜ no del conjunto el comportamiento de los algorit-
mos ser´a diferente y es posible comprobarlo experimentalmente. El tiempo
que demor´o el m´etodo de Java para 100.000 n´ umeros aleatorios 60 milise-
gundos.
5.3.3. Laboratorio
Para probar que el sort de burbuja toma un tiempo menor al qsort solo
se requiere hallar un n que cumpla la relaci´on
n
n −1
2
< nlog(n)
Algebraicamente podemos hallar ´estos valores. Pero sabemos que una im-
plementaci´on particular est´a afectada por una constante que var´ıa seg´ un el
grado de eficiencia con el que fue programado, el lenguaje o las caracter´ısticas
del conjunto de datos.
Lo que, se pide es que realice una implementaci´on de los algoritmos ex-
plicados y encuentre experimentalmente el n´ umero de elementos para los que
un algoritmo sea mejor que otro.
Este proceso debe realizarse tanto para un vector ordenado de manera
aleatorea, ascendente y descendente.
5.3.4. Ejercicios
1. Describir las invariantes de ciclo para el algoritmo de Burbuja.
2. Describir las invariantes de ciclo para el algoritmo de Inserci´on.
3. Describir las invariantes de ciclo para el algoritmo de Selecci´on.
5.3.5. Ejemplo de aplicaci´on
Se presenta el problema 120 publicado en el Juez de Valladolid Espa˜ na y
que es un t´ıpico problema de ordenaci´on.
Cocinar panqueques en una sart´en es bastante complicado porque sin
importar cuanto se esmere todos tendr´an un di´ametro diferente. Para la
presentaci´on de la pila usted los puede ordenar por tama˜ no de tal manera
que cada panqueque es m´as peque˜ no que los que est´an m´as abajo. El tama˜ no
est´a dado por el di´ametro.
128 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
La pila se ordena por una secuencia de volteos. Un volteo consiste en
insertar una esp´atula entre dos panqueques y volteando todos los panqueques
en la esp´atula (colocando en orden reverso la subpila). Un volteo se especifica
indicando la posici´on del panqueque en la base de la subpila a ser volteado.
El panqueque de la base tiene la posici´on 1 y el de encima n.
La pila se especifica dando el di´ametro de cada panqueque en orden en
que aparecen. Por ejemplo considere las tres pilas de panqueques en el cual
8 es el panqueque encima de la pila de la izquierda
8 7 2
4 6 5
6 4 8
7 8 4
5 5 6
2 2 7
La pila de la izquierda puede ser transformada a la pila del medio por
volteo(3). La del medio puede transformarse en la de la derecha con volteo(1).
Entrada La entrada consiste en secuencias de pilas de panqueques. Cada pila
consiste de 1 a 20 panqueques y cada panqueque tendr´a un di´ametro entero
entre 1 y 100, la entrada se termina con un fin de archivo. Cada pila est´a dada
en una fila con el panqueque de arriba primero y el de la base al final. Todos
ellos separados por un espacio.
Salida Para cada pila de panqueques su programa debe imprimir la pila
original en una l´ınea seguido de una secuencia de volteos que ordena la pila
de panqueques de tal forma que el panqueque m´as grande este abajo y el m´as
peque˜ no arriba, la secuencia de volteos debe terminar con un 0 indicando que
no se requieren m´as volteos. Cuando la pila est´a ordenada no se deben realizar
m´as volteos.
Ejemplo entrada
1 2 3 4 5
5 4 3 2 1
5 1 2 3 4
Ejemplo Salida
1 2 3 4 5
0
5 4 3 2 1
1 0
5.3. CLASIFICACI
´
ON 129
5 1 2 3 4
1 2 0
Soluci´on Para resolver el ejercicio en cuesti´on lo primero que se debe evaluar
es si se parece a alg´ un algoritmo, conocido de clasificaci´on. El segundo paso
es el de determinar si el algoritmo provisto por el lenguaje de programaci´on
resuelve el problema, pues no vamos a contruir un algoritmo existiendo uno
que resuelve el problema.
Como se ve es muy parecido al m´etodo de inserci´on por lo que codifica-
remos ´este y agregaremos los requerimientos del problema.
Primero un m´etodo para invertir la pila de panqueques que denominare-
mos reverso.
void reverso(int[] pan, int l) {
int temporal = 0;
int i = 0;
int j = l;
while (i < j) {
temporal = pan[i];
pan[i] = pan[j];
pan[j] = temporal;
i++;
j--;
}
return;
En segundo lugar codificamos el m´etodo buscando el lugar apropiado para
realizar la inserci´on que se consigue llamando a reverso
void inicio() {
...
...
c = 0;
l = l - 1;
ver(pan, l); // listar el orden original
for (int i = l; i > 0; i--) {
max = i;
for (int j = i - 1; j >= 0; j--)
if (pan[j] > pan[max])
130 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
max = j;
if (max != i) {
if (max == 0)
System.out.print((l + 1 - i) + " ");
else
System.out.print((l+1-max) + " " + (l+1-i)
+ " ");
reverso(pan, max);
reverso(pan, i);
}
}
System.out.println("0");
}
}
void ver(int[] pan, int l) {
//lista los datos instroducidos
for (int i = 0; i < l; i++)
System.out.print(pan[i] + " ");
System.out.print(pan[l] + "\n");
}
}
Intencionalmente hemos omitido la parte de la lectura de datos porque es
irrelevante en la explicaci´on del procedimiento de resoluci´on.
5.4. EJERCICIOS 131
5.4. Ejercicios
5.4.1. Problema 10107 - Hallar la mediana
La mediana juega un importante rol en el mundo de las estad´ısticas. Por
definici´on, esta es un valor que divide una colecci´on en dos partes iguales. En
este problema tiene que determinar el flujo medio de algunos enteros largos.
Supongamos que, tenemos cinco n´ umeros ¦1, 3, 6, 2, 7¦. En este caso, 3 es la
mediana como tiene exactamente dos n´ umeros en cada lateral. ¦1, 2¦ y ¦6, 7¦.
Si fueran un n´ umero par de valores como ¦1, 3, 6, 2, 7, 8¦, solamente un
valor n puede dividir esta colecci´on en dos partes iguales, as´ı nosotros con-
sideramos el promedio de la mitad de estos valores ¦3, 6¦. De esa manera,
la mediana ser´a (3 + 6)/2 = 4,5. En este problema tu tienes que imprimir
solamente la parte entera, no los decimales. Como resultado, acordado en
este problema, la mediana debe ser 4.
Entrada.- El archivo de entrada consiste de una serie de enteros X (0 <=
X < 2
31
) y el n´ umero total de enteros N es menor que 10.000. Los n´ umeros
pueden tener espacios blancos, antes o despu´es.
Salida.- Para cada entrada imprime el valor de la mediana con los valores
introducidos hasta el momento.
Ejemplo de entrada Ejemplo de salida
1 1
3 2
4 3
60 3
70 4
50 27
2 4
132 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
5.4.2. Problema 10295 - C´alculo de salario
Cada empleado en un trabajo burocr´atico tiene una descripci´on de su
trabajo en un peque˜ no p´arrafo, que describe las responsabilidades del mismo.
La descripci´on del trabajo est´a combinado con aspectos tales como expe-
riencia para definir su salario.
El sistema libera al personal de recursos humanos de tener que juzgar en
forma inteligente como valorar a un empleado. El proceso consiste en juzgar
al empleado en base de una serie de frases buscando las palabras que implican
responsabilidad.
Debe implementar un sistema simplificado de c´alculo de salarios. Dado
un diccionario de palabras y un n´ umero de descripciones de trabajos debe
calcular el salario de cada persona.
La primera entrada contiene dos n´ umeros enteros positivos m <= 1000
que corresponden al n´ umero de palabras en el diccionario y un n´ umero n <=
100 que indica el n´ umero de descripciones de trabajo.
Cada palabra del diccionario contiene una palabra y un valor que es un
n´ umero real entre 0 y 1.000.000. Seguidamente vienen las descripciones de
los puestos de trabajos que consisten en una o varias l´ıneas de texto que
terminan en un punto.
Para cada descripci´on del texto debe imprimir el salario calculado que es
la suma de los puntos asignados en las palabras de la descripci´on que figuran
en el diccionario.
Entrada.- 7 2
administer 100000
spending 200000
manage 50000
responsibility 25000
expertise 100
skill 50
money 75000
the incumbent will administer the spending of kindergarden milk money and
exercise responsibility for making change he or she will share responsibility for
the task of managing the money with the assistant whose skill and expertise
shall ensure the successful spending exercise
.
this individual must have the skill to perform a heart transplant and expertise
in rocket science
5.4. EJERCICIOS 133
.
Ejemplo de salida.-
700150
150
134 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
5.4.3. Problema 331 - Contando los intercambios
La clasificaci´on como se vi´o puede realizarse intercambiando valores ad-
yacentes utilizando el m´etodo de la burbuja
Si realizamos un listado de los pares de n´ umeros a ser intercambiados se
obtiene un mapa de intercambios y la secuencia en que se deben realizar. Por
ejemplo, si se quiere ordenar un vector cuyos elementos son 3, 2, 1 se puede
ordenar intercambiando los valores A2 y A3, despu´es A1 y A2, y finalmente
A2 con A3.
Si el par identificado en el mapa de intercambios por el ´ındice del vector
del primer elemento a ser intercambiado, el proceso anterior se caracteri-
zar´a como 2 1 2.
Es ´ util hacer notar que pueden existir muchas formas de intercambiar
objetos adyacentes para ordenar un vector. El vector anteriormente descripto
que, contiene 3 2 1, tambi´en puede ser ordenado intercambiando A1 y A2,
luego A2 y A3 y finalmente A1 y A2. El mapa de intercambios en esta
secuencia es 1 2 1.
Se pide que para, un arreglo se cuente el n´ umero de mapas de intercambio
diferentes que existen. Pensando un poco podemos llegar a la conclusi´on de
que existen infinitos mapas de intercambio. Con el ejemplo anterior podemos
escribir 1 1 1 2 1 que tambi´en dejar´a el vector en forma ascendente. La pre-
gunta se refiere a encontrar los mapas de intercambio existentes, que tengan
el m´ınimo de intercambios.
Entrada La entrada es un conjunto de casos arbitrarios seguidos de un 0.
Cada caso de entrada comienza con un n´ umero n que indica el tama˜ no del
arreglo.
Salida Para cada caso de entrada imprima un mensaje como los mostrados
indicando el n´ umero de mapas existentes, que en ning´ un caso pasar´a de 5.
Ejemplo de entrada
2 9 7
2 12 50
3 3 2 1
3 9 1 5
0
Ejemplo de salida
There are 1 swap maps for input data set 1.
5.4. EJERCICIOS 135
There are 0 swap maps for input data set 2.
There are 2 swap maps for input data set 3.
There are 1 swap maps for input data set 4.
5.4.4. Problema 499 - Hallar la frecuencia
El problema consiste en hallar las letras que ocurren con mayor frecuencia
en una l´ınea de texto.
La salida contiene la lista de letras que incurrieron con la m´axima fre-
cuencia seguido de la frecuencia.
La lista de letras debe estar en min´ usculas y en forma ordenada.
Ejemplo de entrada
When riding your bicycle backwards down a one-way street, if the
wheel falls of a canoe,how many ball bearings does it take to fill
up a water buffalo?
Hello Howard.
Ejemplo de salida
e 6
al 7
a 3
Hlo 2
136 5. APLICACIONES DE B
´
USQUEDA Y CLASIFICACI
´
ON
Cap´ıtulo 6
Combinatoria b´asica
6.1. Introducci´ on
La combinatoria es la disciplina de las matem´aticas que se refiere a las
t´ecnicas de contar. En realidad lo que trata de responder es a la pregunta
¿cu´antos son? sin tener que contarlos.
En general las t´ecnicas de contar proveen una serie de alternativas al
momento de tener que escribir programas complicados que cuenten todos los
valores y permiten tener expresiones, que solucionen el problema aplicando
f´ormulas simples.
6.2. T´ecnicas b´asicas para contar
En esta parte recordaremos una serie de f´ormulas de la combinatoria y
mostraremos como son aplicadas en la programaci´on. No desarrollaremos los
conceptos matem´aticos porque no corresponde a lo que el texto pretende,
que es mostrar la forma de resolver problemas.
Regla del Producto Si un conjunto A tiene [A[ posibilidades y el B tiene
[B[ posibilidades entonces existen [A[ x [B[ formas de combinar ´estos.
Por ejemplo si tengo 4 tipos de autom´oviles y 3 colores se tienen 12
combinaciones. Estas combinaciones pueden representarse en una ma-
triz cuadrada almacenando en cada celda una combinaci´on. En el caso
de tres conjuntos con una matriz de tres dimensiones, vea que el espacio
ocupado o el recorrido de los elementos se hace cada vez m´as grande
137
138 6. COMBINATORIA B
´
ASICA
Regla de la suma Si un conjunto A tiene [A[ posibilidades y el B tiene [B[
posibilidades entonces existen [A[ +[B[ posibles formas en las que A o
B pueden ocurrir. En el ejemplo anterior si uno de los autom´oviles, o
de los colores es errado, existen 4 + 3 = 7 posibles ´ıtems fallados.
Regla inclusi´on y exclusi´on Esta es una regla generalizada de la suma.
Supongamos que tenemos autom´oviles de 5 colores y minibuses de 6
colores y queremos conocer cu´antos colores diferentes existen. En este
caso tenemos dos conjuntos que se superponen. Esto significa sumar la
cantidad de colores de ambos y restar los que sean comunes a ambos
que se expresa como:
[A[ ∪ [B[ = [A[ +[B[ −[A[ ∩ [B[
Permutaciones Una permutaci´on es un arreglo de n´ıtems donde cada ´ıtem
aparece solo una vez. Existen 3! permutaciones para un conjunto de tres
elementos. Si los elementos son 123 las permutaciones vienen a ser 123
132 231 213 312 321. Para un n arbitrario son n!. hay que observar que
a medida que aumenta n el n´ umero de permutaciones aumenta muy
r´apidamente.
Subconjuntos Un subconjunto es la selecci´on de algunos elementos de n
posibles ´ıtems. Para un conjunto arbitrario existen 2
n
posibles subcon-
juntos, por ejemplo para 3 elementos existen 2
3
subconjuntos, ´esto es:
1,2,3,12,13,23,123 y el conjunto vac´ıo. A medida que crece n, r´apida-
mente se llega a tiempos de proceso muy grandes.
Cadenas Cuando tratamos con cadenas o sea una secuencia de ´ıtems con
repetici´on, se tienen m
n
distintas secuencias. Para 3 elementos con re-
petici´on se tienen 27 casos que son 111, 112, 113, 121, 122, 123, 131,
132, 133, 211, 212, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321,
322, 323, 331, 332, 333. El n´ umero crece m´as r´apidamente a medida
que crece m.
En muchos casos podemos encontrar que lo que tenemos es una funci´on
biyectiva o sea un asociaci´on uno a uno con otro conjunto. En este caso
podemos resolver el problema de contar cualquiera de los dos conjuntos. Por
ejemplo si decimos que cada planta est´a en una maceta da lo mismo contar
las plantas o las macetas. Si una maceta pudiera tener m´as de una planta
esto ya no es cierto.
6.3. COEFICIENTES BINOMIALES 139
6.3. Coeficientes binomiales
Los coeficientes binomiales se refieren a calcular
_
n
k
_
que es el n´ umero de formas posibles de escoger k elementos de n posibilidades.
Que elementos se cuentan m´as comunmente?
Comit´es Cuantas maneras hay de formar un comit´e de k miembros con n
personas. La respuesta se halla por la definici´on.
Caminos en un matriz C´ uantas maneras hay de viajar desde la esquina
superior hasta la esquina inferior derecha en una matriz de m x n
caminando solamente hacia abajo o hacia la izquierda? Cada camino
debe consistir de m + n pasos n hacia abajo y m a la derecha, por lo
que existen:
_
n + m
n
_
Coeficientes de (a + b)
n
Cu´al es el coeficiente de a
k
b
n−k
claramente
_
n
k
_
porque cuenta el n´ umero de formas que podemos utilizar para escoger
k elementos de n.
Tri´angulo de Pascal Para calcular los coeficientes binomiales de puede
realizar utilizando directamente la f´ormula
_
n
k
_
=
n!
k!(n −k)!
Sin embargo los c´alculos intermedios pueden hacer que el trabajo con
n´ umeros grandes sea inadecuado o de tiempo muy largo, una alternativa
es utilizar el tri´angulo de Pascal.
n p(n) p(n,1) p(n,2) p(n,3) p(n,4) p(n,5) p(n,6)
1 1
2 1 1
3 1 2 1
4 1 3 3 1
5 1 4 6 4 1
6 1 5 10 10 5 1
7 1 6 15 20 15 6 1
140 6. COMBINATORIA B
´
ASICA
Lo interesante de ´este tri´angulo es que calcula los coeficientes binomia-
les sin tener que realizar factoriales. Para calcular n tomados de k en
tiempo constante podemos construir el tri´angulo de Pascal
/**Programa para constuir el
* triangulo de Pascal
* @author Jorge Teran
*
*/
public static void tri´angulo(int[][] x) {
// Invariante cada linea debe comenzar con uno
for (int i=0;i<MAXIMO;i++)
x[i][0]=1;
// Invariante cada linea debe terminar con uno
for (int i=0;i<MAXIMO;i++)
x[i][i]=1;
for (int i=1;i<MAXIMO;i++)
// Invariante cada linea debe sumar 2**i
for (int j=1;j<=i;j++)
x[i][j]=x[i-1][j-1]+x[i-1][j];
}
}
luego es posible hallar n tomados de k
public static int nTomadosDek(
int [][] x,int n, int k) {
return x[n][k];
}
Ahora explicamos cu´ales son las invariantes del tri´angulo de Pascal.
Primero cada l´ınea debe comenzar y terminar con 1. Y en segundo
lugar en cada l´ınea la suma de sus valores da 2
i
. Esto es
k=i

k=0
_
i
k
_
= 2
i
6.4. ALGUNAS SECUENCIAS CONOCIDAS 141
F´ıjese que en ´esta implementaci´on se utiliza solo la mitad del arreglo
bidimensional creado.
Una propiedad interesante es que la suma de las diagonales del tri´angulo
da los n´ umeros de Fibonacci, que se presentan en la siguiente secci´on,
veamos esto con los datos del ejemplo:
Diagonal Suma
1 1 = 1
2 1 = 1
3 1 + 1 = 2
4 2 + 1 = 3
5 1 + 3 + 1 = 5
6 3 + 4 + 1 = 8
Otras propiedades del tri´angulo de Pascal pueden verse en
http://mathworld.wolfram.com/
6.4. Algunas secuencias conocidas
6.4.1. N´ umeros de Fibonacci
Los n´ umeros de Fibonacci son la secuencia de n´ umeros definidos por la
ecuaci´on:
T(n) = T(n −1) +T(n −2)
Teniendo definido que T(0) = 0 y T(1) = 1, se genera la siguiente secuencia
1, 1, 2, 3, 5, 8, 13, 21, ...
Los n´ umeros Fibonacci aparecen en diferentes ´ambitos, desde la cripto-
graf´ıa, como menciona Dan Brown en su novela C´odigo DaVinci, en la na-
turaleza existen ejemplos, en cristalograf´ıa y en la descripci´on de la posici´on
de las semillas en las plantas de girasol.
Para hallar el t´ermino en´esimo de la secuencia podemos utilizar los m´eto-
dos de resoluci´on de recurrencias obteniendo:
T(n) =
1

5
((
1 +

5
2
)
n
−(
1 −

5
2
n
)
Una explicaci´on detallada se halla en el texto de Matem´atica Discreta de
Grimaldi [Gri77].
142 6. COMBINATORIA B
´
ASICA
Los n´ umeros de Fibonacci satisfacen tambi´en la siguinte relaci´on del m´axi-
mo com´ un divisor
MCD(F
n
, F
m
) = F
MCD(n,m)
Tambi´en se puede ver que los n´ umeros de Fibonacci tienen la carater´ıstica
de que al dividirse m´odulo m, producen una secuencia c´ıclica.
Fibonacci mod 2 mod 3 mod 4
1 1 1 1
1 1 1 1
2 0 2 2
3 1 0 3
5 1 2 1
8 0 2 0
13 1 1 1
21 1 0 0 1
34 0 0 1 2
55 0 0 1 3
6.4.2. N´ umeros Catalanes
Los n´ umeros Catalanes son los n´ umeros que est´an asociados a la f´ormula
C
n
=
n−1

k=0
C
k
C
n−1−k
=
1
n + 1
_
2n
n
_
Los primeros n´ umeros Catalanes son: 1,1,2,5,14,42,132,429 y se pueden ob-
tener como sigue:
n´ umero Catalan Valor
C
0
1
C
1
1
C
2
C
0
C
1
+ C
1
C
0
= 2
C
3
C
0
C
2
+ C
1
C
1
+ C
2
C
0
= 5
C
4
C
0
C
3
+ C
1
C
2
+ C
2
C
1
+ C
3
C
0
= 14
Estos n´ umeros se presentan en diferentes problemas, veamos por ejemplo
la siguiente secuencia ¦−1, −1, −1, 1, 1, 1¦. ¿De cu´antas maneras se pueden
ordenar para que las sumas parciales de los elementos sea positiva?
6.4. ALGUNAS SECUENCIAS CONOCIDAS 143
Estos elementos son ¦1, 1, 1, −1, −1, −1¦, ¦1, 1, −1, 1, −1, −1¦,
¦1, 1, −1, −1, 1, −1¦, ¦1, −1, 1, 1, −1, 1¦ y ¦1, −1, 1, −1, 1, −1¦.
Esta secuencia corresponde al n´ umero Catal´an 3 que es 5, que tambi´en
podemos calcular de la combinatoria
1
3 + 1
_
6
3
_
= 5
Algunos otros ejemplos de aplicaci´on de los n´ umeros Catalanes son los
siguientes.
¿De cu´antas formas se pueden colocar 3 par´entesis de tal manera que
cada par´entesis de apertura tenga su respectivo de cierre? La respuesta
es el n´ umero Catal´an 3, veamos ((())), ()(()), (())(), (()()) y ()()()
Dado un pol´ıgono regular de n v´ertices, de cu´antas formas se puede
dividir en n−2 tri´angulos, si las diferentes orientaciones se cuentan en
forma diferente?. Un cuadrado se puede dividir en dos tri´angulos con
una l´ınea entre sus v´ertices las posibilidades son 2. En un pent´agono se
hace con, dos l´ıneas y se obtienen 3 tri´angulos y el n´ umero de casos es
n´ umero Catal´an 3 o sea 5.
Dados dos candidatos A y B que en una elecci´on, cada uno obtiene
n votos (empate). De cuantas maneras se puede contar los votos de
tal forma que al realizar el recuento, el candidato A siempre est´e por
delante del candidato B. Este tambi´en el n´ umero Catal´an n.
6.4.3. N´ umero Eulerianos
Sea p = ¦a
1
, a
2
, ...a
n
¦, deseamos conocer todas las permutaciones que
cumplen la relaci´on a
i
< a
i+1
. Por ejemplo si p = ¦1, 2, 3, 4¦ se construyen
todas las permutaciones de p y contamos los casos en los que se cumple la
relaci´on de orden:
144 6. COMBINATORIA B
´
ASICA
Permutaci´on Cu´antos cumplen Permutaci´on Cu´antos cumplen
1234 3 2134 2
1243 2 2143 1
1324 2 2314 2
1342 2 2341 2
1423 2 2413 2
1432 1 2431 1
3124 2 4123 2
3142 1 4132 1
3214 1 4213 1
3241 1 4231 1
3412 2 4312 1
3421 1 4321 0
por ejemplo la permutaci´on 2341 tiene 2 < 3 y 3 < 4 que son dos casos que
cumplen la relaci´on de orden. Cu´antas permutaciones de 4 elementos tienen
dos casos que cumplen la relaci´on de orden?. Este valor est´a representado
por n´ umero Euleriano
_
n
k
_
=
k+1

j=0
(−1)
j
_
n + 1
j
_
(k −j + 1)
n
si contamos los valores del ejemplo vemos que son 11.
Si organizamos estos n´ umeros en un tri´angulo se obtiene el tri´angulo
Euleriano
n
_
n
0
_ _
n
1
_ _
n
2
_ _
n
3
_ _
n
4
_ _
n
5
_
1 1
2 1 1
3 1 4 1
4 1 11 11 1
5 1 26 66 26 1
6 1 57 302 302 57 1
Analizando la tabla de permutaciones realizada vemos que
_
4
0
_
= 1
_
4
1
_
= 11
_
4
2
_
= 11
_
4
3
_
= 1
6.4. ALGUNAS SECUENCIAS CONOCIDAS 145
corresponden al tri´angulo presentado.
Este tri´angulo puede generarse de la siguiente relaci´on de recurrencia:
_
n
k
_
= k
_
n −1
k
_
+ (n −k + 1)
_
n −1
k −1
_
(6.4.1)
Una propiedad interesante de los n´ umeros Eulerianos que, puede utilizarse
como invariante es que:
n

k=0
_
n
k
_
= n!
El presente programa genera dicho tri´angulo utilizando la recurrencia
6.4.1
/**Programa para construir el
* triangulo Euleriano
* @author Jorge Teran
*
*/
public class Eulerian {
public final static int MAXIMO=6;
public static void main(String[] args) {
int [][] x = new int [MAXIMO][MAXIMO];
for (int i=0;i<MAXIMO;i++)
x[i][1]=1;
for (int i=0;i<MAXIMO;i++)
x[i][i]=1;
for (int i=2;i<MAXIMO;i++)
for (int j=2;j<=i;j++)
x[i][j]=(i-j+1)*x[i-1][j-1]
+j*x[i-1][j];
for (int i=1;i<MAXIMO;i++){
System.out.println(" ");
for (int j=1;j<=i;j++)
System.out.print(x[i][j]+" ");
}
}
}
146 6. COMBINATORIA B
´
ASICA
6.4.4. N´ umeros de Stirling
Consideremos un conjunto con n elementos, el n´ umero total de subcon-
juntos que podemos formar es 2
n
. Nos preguntamos cu´antos conjuntos de k
subconjuntos podemos formar que excluyan el elemento vac´ıo y la uni´on de
ellos, nos da el conjunto original?
Para comprender el problema considere el conjunto p = ¦1, 2, 3, 4¦ todos
los conjuntos de 2 elementos son:
1 ¦(1),(2,3,4)¦
2 ¦(2),(1,3,4)¦
3 ¦(3),(2,1,4)¦
4 ¦(4),(2,3,1)¦
5 ¦(1,2),(3,4)¦
6 ¦(1,3),(2,4)¦
7 ¦(1,4),(2,3)¦
Como podemos calcular este valor?. Primeramente veamos que un conjunto
de n elementos se puede dividir en dos conjuntos ¦A,
¯
A¦ y ¦
¯
A, A¦ Como
tenemos dos conjuntos existen dos conjuntos vac´ıos, entonces el total de sub-
conjuntos que puede tener A y
¯
A son 2
n
−2. Como no nos importa el orden,
vale decir que el complemento est´e antes o despu´es hay que tomar la mitad
de los elementos, esto es:
2
n
−2
2
= 2
n
−1
En el caso de dividir en dos subconjuntos es relativamente simple de
hallar el resultado. En cambio cuando tenemos un n´ umero mayor se hace
m´as complicado.
Estos n´ umeros se denominan n´ umeros de Stirling de segundo orden. Pa-
ra calcular S(n, k) se puede utilizar, al igual que los ejemplos anteriores la
siguiente recurrencia:
S(n, k) = S(n −1, k) + kS(n −1, k)
Hay que tomar en cuenta que los l´ımites son: S(n, 1) = 1, y S(n, n) = 1.
6.4.5. Particiones enteras
Se quiere contar de cu´antas formas se puede escribir un n´ umero entero
positivo como la suma de enteros positivos. Ahora el orden de los sumandos
6.4. ALGUNAS SECUENCIAS CONOCIDAS 147
es irrelevante. Cada una de estas formas se denomina partici´on y cada uno
de los sumandos parte. Por ejemplo:
1 5 = 1 + 1 + 1 + 1 + 1
2 5 = 1 + 1 + 1 + 2
3 5 = 1 + 2 + 2
4 5 = 1 + 1 + 3
5 5 = 2 + 3
6 5 = 1 + 4
7 5 = 5
En este caso la partici´on de 5 tiene 7 posibles particiones. Este problema no
lo desarrollaremos y mencionaremos la recurrencia
As´ı analizamos este ejemplo veremos que hay 1 partici´on de 5 elementos,
1 de 4, 2 de 3, 2 de 2 y 1 de 1. Sea p(n, k) el n´ umero total de elementos de
una partici´on de k elementos entonces el n´ umero de particiones
p(n) =
k=n

k=1
p(n, k)
Estos valores tambi´en nos proporcionan un tri´angulo que puede armarse con
la siguiente recurrencia:
p(n, k) = p(n −1, k −1) +p(n −k, k)
Considerando que p(1, 1) = 1 y que p(n, k) = siendo k > n. El siguiente
programa produce el resultado deseado.
/**Programa para hallar las
* particiones enteras
* @author Jorge Teran
*
*/
public class ParticionEntera {
public final static int MAXIMO = 8;
public static void main(String[] args) {
int[][] x = new int[MAXIMO][MAXIMO];
for (int i = 1; i < MAXIMO; i++)
148 6. COMBINATORIA B
´
ASICA
n p(n) p(n,1) p(n,2) p(n,3) p(n,4) p(n,5) p(n,6) p(n,7)
1 1 1
2 2 1 1
3 3 1 1 1
4 5 1 2 1 1
5 7 1 2 2 1 1
6 11 1 3 3 2 1 1
7 15 1 3 4 3 2 1 1
Cuadro 6.1: Tri´angulo para hallar las particiones
for (int j = 1; j <= i; j++) {
if (j == 1 || j == i)
x[i][j] = 1;
else
x[i][j] = x[i - j][j] + x[i - 1][j - 1];
}
for (int i = 1; i < MAXIMO; i++) {
System.out.println(" ");
for (int j = 1; j <= i; j++)
System.out.print(x[i][j] + " ");
}
}
}
El resultado del proceso produce el tri´angulo que mostramos en el cuadro
6.1 donde la p(n,k) esta representado por la fila y la columna. Para hallar
el n´ umero total de particiones solo hay que sumar los elementos de una fila.
Estos est´an sumarizados en la columna p(n).
6.5. EJERCICIOS 149
6.5. Ejercicios
6.5.1. Problema 357 - Formas de combinar monedas
Despu´es de realizar la compra en una tienda de departamentos, el cambio
fue de 17 centavos. El recibi´o una moneda de 10 centavos una de 5 centavos
y dos de dos centavos. D´ıas despues realizando compras recibi´o otra vez
17 centavos de cambio, en dos monedas de 5 centavos y 7 de un centavo.
Luego se pregunt´o ¿en cuantas tiendas puedo comprar y recibir cambio de
17 centavos, en diferentes combinaciones de monedas? Despu´es de pensar
obtuvo la respuesta, que es 6.
Considere el problema general, realice un programa para determinar el
n´ umero de combinaciones de monedas de 1c, 5c, 10c, 25c, y 50c que se pueden
utilizar para dar esa cantidad de cambio.
Entrada.- La entrada consiste de una serie de n´ umeros entre 1 y 30.000 in-
clusive, una por l´ınea de entrada.
Salida.- La salida consiste en una frase que indica el n´ umero de formas que
existen de dar cambio.
There are $m$ ways to produce n cents change.
There is only 1 way to produce n cents change.
Ejemplo de entrada.-
17
11
4
Ejemplo de salida.-
There are 6 ways to produce 17 cents change.
There are 4 ways to produce 11 cents change.
There is only 1 way to produce 4 cents change.
150 6. COMBINATORIA B
´
ASICA
6.5.2. Problema 369 - Combinaciones
Calcular el n´ umero de formas que N objetos tomados de M, en un tiempo
dado pueden ser un gran desaf´ıo cuando N y/o M llegan a ser muy grandes.
Por consiguiente hay que hacer un programa que calcule los siguientes: datos:
5 ≤ n ≤ 100 y 5 ≤ m ≤ 100 y m ≤ n
Calcule el valor exacto de:
c =
n!
(n −m)!m!
Se puede asumir que el valor final de C no sobrepasa un entero de 32 bits.
Como antecendente, el valor exacto de 100! es:
93,326,215,443,944,152,681,699,238,856,266,700,490,715,
968,264,381,621,468,592,963,895,217,599,993,229,915,608,
941,463,976,156,518,286,253,697,920,827,223,758,251,185,
210,916,864,000,000,000,000,000,000,000,000
Entrada y salida La entrada de este programa puede ser una o m´as l´ıneas
que contienen 0 ´o m´as espacios, un valor para N, uno ´o m´as espacios y un
valor para M . La ´ ultima l´ınea de la entrada dos ceros. El programa debe
terminar cuando lee esta l´ınea.
La salida para el programa debe estar en la forma:
N things taken M at a time is C exactly.
Ejemplo de entrada
100 6
20 5
18 6
0 0
Ejemplo de salida
100 things taken 6 at a time is 1192052400 exactly.
20 things taken 5 at a time is 15504 exactly.
18 things taken 6 at a time is 18564 exactly.
6.5. EJERCICIOS 151
6.5.3. Problema 10338 - Mal educados
Se coloc´o un letrero en un panel consistente en casillas individuales para
cada letra. Durante el evento algunos estudiantes decidieron cambiar el orden
de las letras. De cu´antas formas ´ unicas y sin repetici´on se pueden organizar
las letras?
Entrada y salida En la primera l´ınea viene un entero que indica el n´ umero
de conjuntos de datos de prueba. Este valor es inferior a 30.001.
Cada entrada consiste de letras escritas todas en may´ usculas. Para ca-
da palabra, escriba el n´ umero de formas diferentes, en las que se pueden
reorganizar las letras contando el arreglo original.
Cada palabra tiene un m´aximo de 20 letras y no incluye caracteres de
puntuaci´on.
El n´ umero de arreglos siempre podr´a almacenarse en un entero de tipo
long. Tome en cuenta que el n´ umero m´as grande que se puede almacenar en
una variable entera es 12!.
Ejemplo de entrada
3
HAPPY
WEDDING
ADAM
Ejemplo de salida
Data set 1: 60
Data set 2: 2520
Data set 3: 12
152 6. COMBINATORIA B
´
ASICA
6.5.4. Problema 10183 - Secuencia de Fibonacci
Utilizando la secuencia de Fibonaci se quiere calcular cu´antos n´ umeros
caben en un determinado rango.
Entrada y salida La entrada consiste en varios casos de prueba. Cada caso
de prueba consiste en dos n´ umeros a,b con a, b ≤ 10
100
. El proceso termina
cuando a,b estan en 0. Ejemplo de entrada
10 100
1234567890 9876543210
0 0
Ejemplo de salida
5
4
Cap´ıtulo 7
Estructuras de datos
elementales
7.1. Introducci´ on
En el presente cap´ıtulo se hace una introducci´on a las estructuras de datos
b´asicas. La intenci´on de ´este cap´ıtulo es orientar en el uso de estructuras que
vienen implementadas en el lenguaje de programaci´on Java. No se trata de
introducir los conceptos que corresponden a los cursos de estructura de datos,
sino m´as bien, de reutilizar las herramientas provistas.
7.2. Pilas
Una de las estructuras m´as simples es la pila. La estructura de pila es una
lista en la que solo se pueden ingresar y sacar valores por un solo lugar. Estas
pilas se denominan tambi´en listas LIFO (last in first out). Esto significa que
el ´ ultimo valor introducido es el primero en salir.
En esta estructura solo se pueden insertar objetos al final, extraer el
´ ultimo objeto o mirar el ´ ultimo. En Java ´esto equivale a los m´etodos push,
pop y peek.
Para mostrar como se realiza esta implementaci´on utilizaremos la clase
Alumno, que almacena nombre y c´odigo.
public class Alumno {
String nombre;
153
154 7. ESTRUCTURAS DE DATOS ELEMENTALES
int c´odigo;
public Alumno(String nombre, int c´odigo) {
this.nombre=nombre;
this.c´odigo=c´odigo;
}
public String verNombre() {
return nombre;
}
public int verCodigo() {
return c´odigo;
}
}
El siguiente c´odigo implementa la clase pila, ingresando objetos de tipo
Alumno y luego list´andolos. El siguiente programa realiza lo indicado.
import java.io.*;
import java.util.*;
/**
* Ejemplo de manejo de pilas
* @author Jorge Teran
* @param args
* none
*/
public class pila {
public static void main(String[] args) {
// definir una pila de alumnos
Stack<Alumno> pila = new Stack();
// almacenar los alumnos
Alumno alm1 = new Alumno("Juan", 11);
pila.push(alm1);
alm1 = new Alumno("Maria", 17);
pila.push(alm1);
alm1 = new Alumno("Jose", 25);
pila.push(alm1);
// Recuperar el elemento de encima
System.out.println(pila.peek().verNombre());
// Imprimir la pila
7.2. PILAS 155
while (!pila.isEmpty())
System.out.println(pila.pop().verNombre());
}
}
Para ejemplificar la utilizaci´on de pilas supongamos que queremos verifi-
car si una secuencia de par´entesis y corchetes est´a bien anidada. Considere-
mos algunos casos
La secuencia (([])) es una secuencia bien anidada.
La secuencia (([)]) es una secuencia mal anidada, un corchete no puede
cerrarse con un par´entesis.
La secuencia ((()) est´a mal, porque le falta un par´entesis de cierrre.
Para resolver este tipo de problemas una pila es un m´etodo apropiado. La
estrategia de soluci´on es el almacenar en la pila todas las llaves de apertura y
cada vez que aparece una de cierre obtenemos un elemento de la pila y debe
ser una llave de apertura correspondiente a la de cierre.
Cuando se quiere recuperar un elemento de la pila y est´a vac´ıa, indica que
sobran llaves de cierre. Cuando se termina el proceso la pila debe estar vac´ıa,
caso contrario, quiere decir que hay m´as llaves de apertura que de cierre en
la expresi´on a ser analizada.
Esto nos lleva al siguiente c´odigo:
import java.io.*;
import java.util.*;
/**
* Ejemplo de manejo de pilas
* Comprobaci´on de parentisis bien anidados
* @author Jorge Teran
* @param args
* parentesis y corchetes
* EjemploPila ()()(((()[)
*/
public class EjemploPila {
public static void main(String[] args) {
//String cadena="(([]))(";
156 7. ESTRUCTURAS DE DATOS ELEMENTALES
String cadena=args[0];
String caracter,delapila;
// definir una pila de cadena
Stack<String> pila = new java.util.Stack();
for (int i=0; i< cadena.length();i++){
caracter=cadena.substring(i,i+1);
if (caracter.compareTo("(")==0)
pila.push(")");
else
if (caracter.compareTo("[")==0)
pila.push("]");
else
{
if (pila.isEmpty()){
System.out.println("Sobran llaves de cierre");
System.exit(0);
}
delapila=pila.pop();
if (delapila.compareTo(caracter)==1){
System.out.println("Mal anidada");
System.exit(0);
}
}
}
if (!pila.isEmpty())
System.out.println("Sobran llaves de apertura");
else
System.out.println("Bien anidada");
}
}
Los m´etodos disponibles para pilas son:
M´etodo Descripci´on
push(E elemento) Agrega un elemento a la pila.
pop() Extrae el ´ ultimo elemento introducido.
peek() Lee el ´ ultimo elemento introducido.
isEmpty() Devuelve true si la pila est´a vac´ıa.
7.3. LISTAS ENLAZADAS 157
7.3. Listas enlazadas
Las listas enlazadas tienen la ventaja de que permiten ingresar elementos
en cualquier lugar de la lista sin necesidad de tener que hacer un espacio como
en los vectores. En una lista enlazada existen varias posiciones en las que se
puede introducir un elemento, supongamos la lista que tiene los elementos
abc existen cuatro lugares donde se pueden insertar los nuevos valores, estos
son: |abc, a|bc, ab|c y abc|.
El lenguaje Java provee una clase denominada iterador que permite re-
correr la clase. Cuando insertamos elementos consecutivos se introducen en
el orden que se env´ıan. Cuando el iterador apunta al principio se introducen
al principio, si est´a apuntando al final de la lista se introducen despu´es del
´ ultimo elemento. El interador, es el que indica donde se puede introducir el
elemento.
Los m´etodos de Java para listas enlazadas son los siguientes:
M´etodo Descripci´on
add(E elemento) Agrega un elemento a la lista.
add(int i, E elemento) Agrega un elemento en la
posici´on i.
addFirst(E elemento) Agrega un elemento al principio.
addLast(E elemento) Agrega un elemento al final.
clear() Borra la lista.
addAll(int i,coleccion) Agrega toda una colecci´on en la
posici´on i.
remove(int i) Quita y devuelve el elemento de la
posici´on i.
removeFirst() Quita y devuelve el primer elemento.
removeLast() Quita y devuelve el ´ ultimo elemento.
set(int i, E elemento) Cambia el elemento de la posici´on i.
isEmpty() Devuelve true si la lista esta vac´ıa.
contains(E elemento) Devuelve true si la lista contiene el
elemento.
size() Devuelve el n´ umero de elementos.
Hay que hacer notar que las listas no son una estructura de datos ade-
cuadas para el acceso aleatoreo. Cada vez que se busca un elemento o recorre
la lista siempre comienza desde el principio.
158 7. ESTRUCTURAS DE DATOS ELEMENTALES
La colecci´on para listas enlazadas provee una clase para recorrer la lista
llamada iterador que tiene los siguientes m´etodos:
M´etodo Descripci´on
ListIterator(E) Crea un iterador para visitar elementos de la lista.
set(E elemento) Cambia el ´ ultimo elemento visitado.
hasPrevious() Devuelve true si tiene un elemento anterior.
previous() Devuelve el elemento anterior.
nextIndex() Devuelve el ´ındice que ser´ıa llamado en la
pr´oxima iteraci´on.
En el siguiente ejemplo se crean dos listas y se introducen elementos de la
clase Alumno. Luego se utiliza el iterador para recorrer la lista. Finalmente
se muestra el m´etodo removeAll que permite remover todos los elementos
de una lista que est´an en la otra.
public class ListaEnlazada {
/**
* Ejemplo de lista enlazada
* @author Jorge Teran
* @param args
* none
*/
public static void main(String[] args) {
Alumno alm;
LinkedList<Alumno> uno = new LinkedList<Alumno>();
uno.add(new Alumno("Juan", 11));
uno.add(new Alumno("Maria", 17));
ListIterator<Alumno> aIter = uno.listIterator();
// desplegar la lista uno
System.out.println("Listar la lista UNO");
while (aIter.hasNext()) {
alm = aIter.next();
System.out.println(alm.verNombre());
}
7.3. LISTAS ENLAZADAS 159
List<Alumno> dos = new LinkedList<Alumno>();
dos.add(new Alumno("Jose", 25));
dos.add(new Alumno("Laura", 8));
ListIterator<Alumno> bIter = dos.listIterator();
// agregar los alumnos de lista dos
// a la lista uno
while (bIter.hasNext()) {
uno.add(bIter.next());
}
System.out.println(
"Despues de agregar la lista DOS");
// Reiniciar el iterador y listar la lista uno
aIter = uno.listIterator();
while (aIter.hasNext()) {
alm = aIter.next();
System.out.println(alm.verNombre());
}
// quitar los elementos de la lista dos de uno en uno
uno.removeAll(dos);
System.out.println(
"Listar despues de quitar la lista DOS");
// Reiniciar el iterador y listar la lista uno
aIter = uno.listIterator();
while (aIter.hasNext()) {
System.out.println(aIter.next().verNombre());
}
}
}
Para realizar listas doblemente enlazadas es suficiente crear una lista con una
clase de tipo lista. De esta forma se pueden crear listas con cualquier nivel
de anidamiento.
160 7. ESTRUCTURAS DE DATOS ELEMENTALES
7.4. Conjuntos
El manejo de conjuntos es similar, al de las listas con la condici´on que,
no se permiten elementos repetidos y el orden no es relevante.
La implementaci´on de un conjunto se hace como una estructura de ti-
po Set y esta estructura viene implementada en HashSet. Para definir un
conjuto conjA hay que escribir lo siguiente:
Set<String> conjA = new HashSet<String>();
Los m´etodos disponibles para la clase set son los siguientes:
M´etodo Descripci´on
add(E elemento) Agrega un elemento al conjunto.
clear() Borra el conjunto.
addAll(coleccion) Agrega toda una colecci´on.
removeAll(coleccion) Elimina todos los elementos de la
colecci´on que existan en el conjunto.
remove(Object objeto) Elimina el objeto del conjunto.
Devuelve true si ha sido eliminado.
isEmpty() Devuelve true si el conjunto esta vac´ıo.
contains(E elemento) Devuelve true si el conjunto contiene el
elemento.
size() Devuelve el n´ umero de elementos del
conjunto.
Los m´etodos para recorrer los conjuntos se realizan con la clase Iterator
que tiene los siguientes m´etodos:
M´etodo Descripci´on
Iterator(E) Crea un iterador para visitar elementos
del conjunto.
hasNext() Si existe un pr´oximo elemento devuelve true.
next() Avanza al pr´oximo elemento.
Para utilizar la clase Iterator se procede como sigue:
Primero creamos el iterador sobre el conjunto
7.4. CONJUNTOS 161
Iterator<String> iter = conjA.iterator();
Para recorrer el conjunto
while (iter.hasNext())
Finalmente para acceder a elementos individuales podemos utilizar
iter.next(). Por ejemplo para desplegar el elemento:
System.out.println(iter.next());
En el siguiente ejemplo se muestra como introducir elementos, recorrer el
conjunto y como hallar la intersecci´on de dos conjuntos.
import java.util.*;
/**
* Ejemplo manejo de conjuntos
* @author Jorge Teran
* @param args
* none
*/
public class Conjuntos {
public static void main(String[] args) {
Set<String> conjA = new HashSet<String>();
conjA.add("aaa");
conjA.add("bbb");
conjA.add("aaa");
conjA.add("ccc");
conjA.add("ddd");
Set<String> conjB = new HashSet<String>();
conjB.add("aaa");
conjB.add("bbb");
conjB.add("bbb");
conjB.add("xxx");
162 7. ESTRUCTURAS DE DATOS ELEMENTALES
conjB.add("yyy");
//hallar conjB interseccion conjA
Set<String> conjC = new HashSet<String>();
conjC.addAll(conjA);
// para intersectar A y B
// hacemos C=A-B y luego A-C
conjC.removeAll(conjB);
conjA.removeAll(conjC);
//listar
Iterator<String> iter = conjA.iterator();
while (iter.hasNext())
System.out.println(iter.next());
}
}
7.5. Clases map
Las clases donde se almacenan los valores como clave y valor se denomina
clase Map por ejemplo, si se quiere almacenar color=rojo donde color es la
clave y rojo es el valor se puede almacenar y recuperar por la clave.
Los m´etodos de la clase Map est´an descriptos en el cuadro 7.1.
El recorrido de la clase Map se puede realizar por clave, valor o por ambos.
Para definir un recorrido de una clase Map por clave se procede como sigue:
Iterator<String> iter = preferencias.keySet().iterator();
Para definir un recorrido por valor:
Iterator<String> iter = preferencias.values().iterator();
Para recorrer por ambos hay que tomar en cuenta que Iterator no permi-
te definir dos cadenas como es la definici´on de Map. Por esto es necesario
cambiar el recorrido como sigue:
Map.Entry<String, String> datos : preferencias.entrySet()
Luego podemos acceder a la clave con datos.getKey() y a los valores a
trav´es de datos.getValue().
En el siguiente ejemplo, se introducen pares de elementos y luego se re-
corre el conjunto Map listando clave y valor.
7.5. CLASES MAP 163
M´etodo Descripci´on
put(Clave, Valor) Agrega un elemento Map.
get(Clave) Devuelve el elemento Map con
la clave especificada.
clear() Borra el conjunto Map.
remove(Object objeto) Elimina el objeto del conjunto
con la clave especificada.
Devuelve true si es eliminado.
isEmpty() Devuelve true si el conjunto Map
esta vac´ıo.
containsValue(Object elemento) Devuelve true si el conjunto
contiene el valor.
containsKey(Object elemento) Devuelve true si el conjunto
contiene la clave.
size() Devuelve el n´ umero de elementos
del conjunto Map.
Cuadro 7.1: M´etodos de la clase map
import java.util.*;
/**
* Ejemplo de la estructura map
* @author Jorge Teran
* @param args
* none
*/
public class PruebaMap {
public static void main(String[] args) {
Map<String, String> preferencias =
new HashMap<String, String>();
preferencias.put("color", "rojo");
preferencias.put("ancho", "640");
preferencias.put("alto", "480");
//listar todo
System.out.println(preferencias);
// Quitar color
164 7. ESTRUCTURAS DE DATOS ELEMENTALES
preferencias.remove("color");
// cambiar una entrada
preferencias.put("ancho", " 1024");
// recuperar un valor
System.out.println("Alto= "
+ preferencias.get("alto"));
// iterar por todos los elementos
for (Map.Entry<String, String> datos :
preferencias.entrySet()) {
String clave = datos.getKey();
String valor = datos.getValue();
System.out.println(
"clave=" + clave + ", valor=" + valor);
}
}
}
7.6. Clases para ´arboles
En el Java tenemos la clase de ´arboles que permite mantener ordenados
los elementos de un conjunto a medida que, se introducen los elementos.
Para poder implementar ´esto es necesario tener una clase de comparaci´on
que permita decidir en que rama del ´arbol corresponde insertar un elemento,
para esto agregamos a la clase Alumno el siguiente m´etodo.
public int compareTo(Alumno other) {
return c´odigo - other.c´odigo;
}
que superpone el m´etodo de comparaci´on que solo se utiliza con los tipos
de datos b´asicos; vea que, lo que se est´a comparando es el c´odigo y la res-
7.6. CLASES PARA
´
ARBOLES 165
puesta puede ser 0,1 o -1. En la definici´on de la clase es necesario agregar
implements Comparable<Alumno> quedando como sigue:
public class Alumno implements Comparable<Alumno> {
Luego el siguiente c´odigo ingresa Alumnos a un ´arbol organizado por c´odigo
import java.util.*;
/**
* Ejemplo de la estructura de Arboles
* @author Jorge Teran
* @param args
* none
*/
public class Arbol {
public static void main(String[] args) {
TreeSet<Alumno> alm = new TreeSet<Alumno>();
alm.add(new Alumno("Juan", 11));
alm.add(new Alumno("Maria", 17));
alm.add(new Alumno("Jose", 25));
alm.add(new Alumno("Laura", 8));
System.out.println(alm);
}
No siempre es el ´ unico orden que deseamos tener, por ejemplo si se desea
ordenar por nombre, no es posible especificar dos clases de comparaci´on. Por
este motivo podemos crear otro ´arbol especificando su clase de comparaci´on.
TreeSet<Alumno> ordenarPorNombre = new TreeSet<Alumno>(
new Comparator<Alumno>() {
public int compare(Alumno a, Alumno b) {
String nombreA = a.verNombre();
String nombreB = b.verNombre();
return nombreA.compareTo(nombreB);
}
});
ordenarPorNombre.addAll(alm);
System.out.println(ordenarPorNombre);
}
}
166 7. ESTRUCTURAS DE DATOS ELEMENTALES
La instrucci´on ordenarPorNombre.addAll(alm) permite insertar todo el
´arbol alm en el ´arbol ordenarPorNombre. Los m´etodos de la clase TreeSet
son los siguientes:
M´etodo Descripci´on
add(E elemento) Agrega un elemento al ´arbol.
clear() Borra el ´arbol.
addAll(coleccion) Agrega toda una colecci´on.
remove(Object objeto) Elimina el objeto del ´arbol.
Devuelve true si ha sido eliminado
isEmpty() Devuelve true si el ´arbol est´a vac´ıo.
contains(E elemento) Devuelve true si el conjunto contiene el
elemento.
size() Devuelve el n´ umero de elementos del ´arbol.
Los m´etodos para recorrer el ´arbol elemento por elemento se realiza con
la clase Iterator especificando que el iterador es alumno y se procede como
sigue:
Iterator<Alumno> iter = alm.iterator();
while (iter.hasNext())
System.out.println(iter.next());
7.7. Clases para colas de prioridad
Las colas de prioridad tienen la caracter´ıstica de estar basadas en la es-
tructura de datos denominada mont´ıculo. La caracter´ıstica principal es que
cada elemento introducido est´a asociado a una prioridad. A medidad que
se van introduciendo valores se van organizando para que al recuperar uno,
siempre se recupere primero, el que tiene menos prioridad.
La aplicaci´on t´ıpica de ´esta cola es por ejemplo el organizar una lista
de impresi´on por prioridad a medida que se introducen y procesan trabajos,
siempre se procesa primero el de menor prioridad.
Para ejemplificar el uso en Java presentamos el siguiente ejemplo que
muestra como se introducen y obtienen uno a uno lo elementos comenzando
del valor m´ınimo.
7.7. CLASES PARA COLAS DE PRIORIDAD 167
import java.util.*;
/**
* Ejemplo de Cola de prioridad
* @author Jorge Teran
* @param args
* none
*/
public class ColaPrioridad {
public static void main(String[] args) {
PriorityQueue<Alumno> cp = new PriorityQueue<Alumno>();
cp.add(new Alumno("Juan", 11));
cp.add(new Alumno("Maria", 17));
cp.add(new Alumno("Jose", 25));
cp.add(new Alumno("Laura", 8));
System.out.println("Sacando elementos...");
Alumno datos;
while (!cp.isEmpty()) {
datos = cp.remove();
System.out.println(
datos.verCodigo() + " = " + datos.verNombre());
}
}
}
Analizando el c´odigo vemos que los datos ingresados ser´an extra´ıdos seg´ un
la prioridad. En este ejemplo, hemos tomado como prioridad el c´odigo, dado
que a la clase Alumno se ha adicionado el m´etodo comparTo del ejemplo
anterior que utiliza el campo c´odigo en la comparaci´on. Por esto, la salida
del programa est´a en el orden 8, 11, 18, 25.
Los m´etodos disponibles para las colas de prioridad est´an descriptos en
el cuadro 7.2.
168 7. ESTRUCTURAS DE DATOS ELEMENTALES
M´etodo Descripci´on
add(E elemento) Agrega un elemento a la cola
de prioridad.
clear() Borra la cola de prioridad.
addAll(coleccion) Agrega toda una colecci´on.
remove() Elimina el elemento m´as peque˜ no.
isEmpty() Devuelve true si est´a vac´ıa.
contains(E elemento) Devuelve true si el conjunto contiene el
elemento.
size() Devuelve el n´ umero de elementos.
Cuadro 7.2: M´etodos de las colas de prioridad
7.8. Ejercicios para laboratorio
Los siguientes ejercicios de laboratorio tienen el objetivo de determinar en
la pr´actica las estructuras m´as eficientes para resolver diferentes problemas.
Para esto se deben tomar los tiempos de ejecuci´on de cada estructura de
datos, construir la siguiente tabla y analizar los resultados.
Estructura Tiempo de ejecuci´on
Pila
Lista enlazada
Arbol
Cola de prioridad
Conjuntos
Map
1. Hallar el tiempo de insertar 10.000 datos a una pila, lista enlazada,
´arbol, cola de prioridad. Explicar la ventaja de cada una de ellas.
2. Insertar 10.000 n´ umeros aleatorios a cada una de las estructuras es-
tructuras presentadas en el cap´ıtulo y encontrar cual es m´as eficiente
para hallar los 100 m´as peque˜ nos.
3. En una combinaci´on de operaciones: 10 % recorrer ordenado, 30 % bus-
car, 40 % insertar y 20 % remover un valor arbirario. Realice un ejercicio
con 10.000 valores y analice tres estructuras de datos. Escoja las m´as
adecuada.
7.8. EJERCICIOS PARA LABORATORIO 169
4. Repetir el ejercicio tres para 10.100, 1.000, 10.000 y 100.000 valores.
Indicar en qu´e casos es m´as conveniente cada estructura.
170 7. ESTRUCTURAS DE DATOS ELEMENTALES
Cap´ıtulo 8
Backtracking
8.1. Introducci´ on
Backtracking significa ir atr´as. Esto implica llevar un registro de los even-
tos pasados, con el prop´osito, de realizar un proceso m´as inteligente. Aunque
este m´etodo aparenta una b´ usqueda exhaustiva, no examina todas las com-
binaciones posibles.
Este tema es introducido mostrando el recorrido de un grafo que muestra
el concepto de volver a un estado anterior.
Posteriormente se trabaja construyendo subconjuntos y permutaciones.
Para este tipo de problemas se desarrolla una implementaci´on b´asica que
consiste de tres partes: una que determina si hemos hallado una soluci´on, la
segunda que procesa la soluci´on y la tercera que realiza el proceso.
8.2. Recorrido de grafos
Un ejemplo t´ıpico de algoritmo de retroceso es el hallar un camino desde
un origen hasta un destino en grafo. Consideremos el grafo de la figura 8.1:
Si partimos del nodo A y queremos llegar al nodo G tenemos dos estra-
teg´ıas para hallar un camino. Una de ellas es hacer todas las combinaciones
posibles partiendo del origen. La segunda es empezar a recorrer el grafo re-
trocediendo un lugar cada vez que se llegue a un nodo del que no podamos
avanzar m´as.
El proceso comienza en nodo A, y se va al primer nodo que encontramos
el nodo B. Ver figura 8.2.
171
172 8. BACKTRACKING
Figura 8.1: Ejemplo de un grafo
Figura 8.2: Muestra el recorrido del nodo A a B
Del nodo B se procede hasta el nodo E que es el primer nodo que encon-
tramos.
No hay forma en ´este momento de elegir el nodo F porque no sabemos
si nos lleva al destino. De esta forma llegamos al nodo C y posteriormente a
D. Ver figura 8.3.
Cuando llegamos al nodo D ya no se puede seguir (figura 8.4), por lo que,
es necesario regresar al nodo anterior C y vemos que no hay ning´ un otro
nodo para visitar, retrocedemos una vez m´as llegando a E y continuamos.
Cuando llegamos al punto final imprimimos el recorrido. Cuando el al-
goritmo llega al inicio y no hay nodos que no hayamos visitado termina sin
encontrar un camino.
Para programar hemos construido una matriz para representar el grafo.
En esta matriz la filas y columnas representan los nodos y la posici´on (i,j)
indica que existe un camino cuando tiene un 1 y un 0 cuando no existe un
camino. Para el grafo de ejemplo la matriz que constuimos es:
8.2. RECORRIDO DE GRAFOS 173
Figura 8.3: Muestra el recorrido hasta el nodo C
Figura 8.4: Muestra el proceso de retorceso
A B C D E F G
A 0 1 0 0 1 0 0
B 0 0 0 0 1 1 0
C 0 0 0 1 0 0 0
D 0 0 0 0 0 0 0
E 0 0 1 0 0 1 0
F 0 0 0 1 0 0 1
G 0 0 0 0 0 0 0
Para el proceso se comienza con la posici´on 0. Cada vez que pasamos por
un nodo lo marcamos como visitado. Esto es para evitar ciclos y volver a
realizar un recorrido anterior. Cuando se llega a un nodo que no va a ning´ un
lado regresamos (bactrack) al nodo anterior para buscar una nueva ruta. El
nodo anterior se ha guardado en una estructura de pila.
El programa recorre el grafo mostrado y produce la ruta en orden inverso
listando: 6 5 4 1 0.
174 8. BACKTRACKING
/**Programa para mostrar el
* recorrido de un grafo
* @author Jorge Teran
*/
import java.util.Stack;
import java.util.Vector;
public class Grafo2 {
static void Camino(int[][] g) {
int i = 0;
Stack<Integer> pila = new Stack();
// visitados
int[] v = new int[g[0].length];
i = 0;
while (v[v.length - 1] == 0) {
pila.push(i);
v[i] = 1;
i = Buscar(g, v, i);
if ((i == -1) && (v[v.length - 1] == 0)) {
if (pila.empty()) {
System.out.println("No Hay Ruta ");
System.exit(0);
} else {
//bactracking al anterior
i = (int) pila.pop();
i = (int) pila.pop();
}
}
}
System.out.println("Ruta en Orden Inverso ");
while (!pila.empty()) {
i = (int) pila.pop();
System.out.print(" " + i);
}
}
static int Buscar(int[][] g, int[] v, int fila) {
int hallo = -1, i;
8.3. CONSTUIR TODOS LOS SUBCONJUNTOS 175
for (i = 0; i < g[0].length; i++) {
// System.out.println("busca ="+g[fila][i]);
if ((g[fila][i] == 1) && (v[i] == 0)) {
hallo = i;
break;
}
}
// System.out.println("Hallo ="+hallo);
return hallo;
}
public static void main(String[] args) {
int[][] g = new int[7][7];
// Nodos A=0,B=1,C=2,D=3,E=4,F=5,G=6
g[0][1] = 1;
g[0][4] = 1;
g[1][4] = 1;
g[1][5] = 1;
g[2][3] = 1;
g[3][0] = 0;
g[4][2] = 1;
g[4][5] = 1;
g[5][3] = 1;
g[5][6] = 1;
g[6][0] = 0;
Camino(g);
}
}
8.3. Constuir todos los subconjuntos
Consideremos el problema de construir todos los subconjuntos de un con-
junto de tama˜ no n. El n´ umero total de subconjuntos es 2
n
−1 sin contar el
conjunto vac´ıo. Por ejemplo si n = 3 existen 7 subconjuntos.
Consideremos el conjunto ¦1,2,3¦ los 7 posibles subconjuntos son: ¦1 2 3
¦, ¦1 2 ¦, ¦1 3 ¦, ¦1 ¦, ¦2 3 ¦, ¦2 ¦ y ¦3 ¦.
Para construir un programa que construya ´estos subconjuntos inicialmen-
176 8. BACKTRACKING
te se construye un vector de unos y ceros para representar las posibles solu-
ciones. Al inicio de cada recursi´on preguntamos si hemos hallado una soluci´on
para procesar. Si no se hall´o una soluci´on guardamos el vector de soluciones
y probamos una nueva soluci´on. En este problema hemos considerado una
soluci´on cuando llegamos al ´ ultimo elemento del conjunto.
Luego regresamos a un estado anterior y comenzamos la b´ usqueda de una
nueva soluci´on. La instrucci´on subset[cur] = true; se usa para indicar que
este elemento puede ser parte de la soluci´on. Luego se procesa recursivamente
una nueva soluci´on.
Cuando hallamos una soluci´on se retorna al estado anterior y marcamos
el ´ ultimo elemento como procesado. EL c´odigo que halla esta soluci´on es el
siguiente:
/**Programa para hallar todos los
* subconjuntos
* @author Jorge Teran
*/
public class Subconjuntos {
private static void procesarSolucion(
boolean[] conjuntos) {
// imprimir la solucion,
// conjuntos indica cuales imprimir
System.out.print("{");
for (int i = 0; i < conjuntos.length; i++)
if (conjuntos[i])
System.out.print((i + 1) + " ");
System.out.println("}");
}
public static boolean esSolucion(
boolean[] conjuntos, int posicionActual) {
// cuando se llego al final del vector
// no se puede seguir iterando
return (conjuntos.length == posicionActual);
}
8.3. CONSTUIR TODOS LOS SUBCONJUNTOS 177
public static void imprimeSubconjuntos(
boolean[] conjuntos,int posicionActual) {
if (esSolucion(conjuntos, posicionActual)) {
procesarSolucion(conjuntos);
} else {
conjuntos[posicionActual] = true;
// procesar una nueva solucion
imprimeSubconjuntos(conjuntos, posicionActual + 1);
// retornar (bactrack) al caso anterior
conjuntos[posicionActual] = false;
imprimeSubconjuntos(conjuntos, posicionActual + 1);
}
}
public static void main(String[] args) {
boolean[] conjuntos = new boolean[3];
// Inicialmente conjuntos esta todo en false
imprimeSubconjuntos(conjuntos, 0);
}
}
Al analizar el proceso se observa que se procede a marcar las posibles solu-
ciones cambiando el arreglo que hemos denominado conjuntos cambiando el
estado de 000 a 100, 110 y 111. Cuando se llega a marcar tres elementos se
imprime la primera soluci´on ¦1, 2, 3 ¦.
En ´este momento la pila de la recurci´on contiene los valore 000, 100, 110
y 111. En el proceso recursivo la pila es la que guarda los resultados previos.
Ahora se produce un retroceso, el arreglo que almacena los estados con-
tiene 111 que se recupera de la pila. Luego se cambia el estado del ´ ultimo bit
a 0 para indicar que ya fue procesado y volvemos a llamar recursivamente
al programa almacenando en la pila el 110, que produce la soluci´on ¦1, 2
¦. Al terminar sale este valor de la pila y regresa al valor almacenado 100.
Se procede a marcar el 101 el bit 2 y se contin´ ua el proceso. El proceso del
programa se muestra en el cuadro 8.1.
178 8. BACKTRACKING
b
Bits de Estado Posici´on Actual Retroceso Soluci´on
100 0
110 1
111 2 ¦1, 2, 3 ¦
111 2 Fin Recursi´on 1
110 2 ¦1, 2 ¦
110 Fin Recursi´on 2
100 1 Fin Recursi´on 1
101 2 ¦1, 3 ¦
100 2 Fin Recursi´on 1
100 2 ¦1 ¦
100 2 Fin Recursi´on 2
100 1 Fin Recursi´on 2
000 0 Fin Recursi´on 1
010 1
011 2 ¦2,3¦
010 2 Fin Recursi´on 1
010 2 ¦2¦
010 2 Fin Recursi´on 2
000 1 Fin Recursi´on 1
001 2 ¦3¦
Fin Recursi´on 2
Cuadro 8.1: Proceso realizado para construir todos los subconjuntos
8.4. CONSTRUIR TODAS LAS PERMUTACIONES 179
8.4. Construir todas las permutaciones
Para construir todas las permutaciones de un conjunto tambi´en se utiliza
la t´ecnica de backtrackig. En este ejemplo se ha constru´ıdo un programa
similar al anterior con una clase que procesa la soluci´on y otra que determina
si ha llegado la soluci´on.
El programa intercambia valores empezando del primer valor en forma
recursiva al igual que el programa de hallar todos los subconjuntos. Comienza
intercambiando el primer elemento con el ´ ultimo, en un ciclo. Recursivamente
retornando al estado anterior cuando se halla una permutaci´on.
/**Programa para hallar todas
* las permutaciones
* @author Jorge Teran
*/
public class Permutaciones {
// imprimir las n! permutaciones en desorden
private static void procesarSolucion(String[] a) {
for (int i = 0; i < 3; i++) {
System.out.print(a[i]);
}
System.out.println(" ");
}
public static boolean esSolucion(int posicionActual) {
// cuando se llego al final del vector
// no se puede seguir iterando
return (posicionActual == 1);
}
private static void permutar(
String[] a, int n) {
if (esSolucion(n)) {
procesarSolucion(a);
return;
}
for (int i = 0; i < n; i++) {
swap(a, i, n-1);
180 8. BACKTRACKING
permutar(a, n-1);
swap(a, i, n-1);
}
}
private static void swap(String[] a, int i, int j) {
String c;
c = a[i]; a[i] = a[j]; a[j] = c;
}
public static void main(String[] args) {
String[] a = new String[3];
a[0]="a";
a[1]="b";
a[2]="c";
permutar(a,3);
}
}
El resultado que se obtiene del programa es: bca, cba, cab, acb, bac, abc.
Como se ve en el ejemplo anterior los resultados no est´an en orden. En
orden significa que los resultados deben estar en la siguiente secuencia: abc,
acb, bac, bca, cab, cba. Esto significa realizar todos los intercambios man-
teniendo el primer elemento, luego llevar el segundo elemento al principio y
as´ı sucesivamente.
Para realizar ´esto hemos utilizado una estructura de vector que, permite
insertar y extraer objetos. Se crearon dos vectores, uno para almacenar las
combinaciones que se van formando y otro que mantiene el vector original.
El siguiente c´odigo permite realizar estas permutaciones.
/**Programa para hallar todas
* las permutaciones en orden
* @author Jorge Teran
*/
import java.util.Vector;
public class PermutacionesEnOrden {
private static void procesarSolucion(Vector a) {
System.out.println(a);
}
8.4. CONSTRUIR TODAS LAS PERMUTACIONES 181
public static boolean esSolucion(int posicionActual) {
// cuando se llego al final del vector
// no se puede seguir iterando
return (posicionActual == 0);
}
private static void permutar(
Vector auxiliar, Vector original) {
int N = original.size();
if (esSolucion(N)) {
procesarSolucion(auxiliar);
} else {
for (int i = 0; i < N; i++) {
String proximo = (String) original.remove(i);
auxiliar.add(proximo);
permutar(auxiliar, original);
original.add(i, proximo);
auxiliar.remove(proximo);
}
}
public static void main(String[] args) {
Vector v = new Vector();
String[] a = new String[3];
a[0] = "a";
a[1] = "b";
a[2] = "c";
for (int i = 0; i < a.length; i++) {
String s = a[i];
v.add(s);
}
permutar(new Vector(), v);
}
}
182 8. BACKTRACKING
8.5. Ejercicios
8.5.1. Prolema 195 - Anagramas
Se pide que escriba un programa que genere todas las posibles palabras
de un conjunto de letras, por ejemplo: dada la palabra abc su programa debe
explorar las diferentes combinaciones de tres letras y escribir estas palabras
abc, acb, bac, bca, cab and cba.
En las palabras le´ıdas de la entrada, algunas pueden aparecer repetidas.
Para una palabra de entrada su programa no debe producir palabras repeti-
das, y las palabras deben escribirse en orden alfab´etico.
Entrada El archivo de entrada consiste de varias palabras. La prime-
ra l´ınea contiene un n´ umero que indica el n´ umero de palabras del archivo.
Cada l´ınea siguiente contiene una palabra. Una palabra consiste de letras
min´ usculas y may´ usculas de la A a la Z. Las letras may´ usculas y min´ usculas
se consideran diferentes.
Salida Para cada palabra del archivo de entrada el archivo debe conte-
ner todas las palabras diferentes que pueden ser generadas con las letras de
una palabra. Las palabras generadas de una palabra de entrada deben im-
primirse en orden alfab´etico. Las letras may´ usculas van adelante de las letras
min´ usculas.
Ejemplo de entrada
2
aAb
acba
Ejemplo de salida
Aab aabc
Aba aacb
aAb abac
abA abca
bAa acab
baA acba
baac
baca
bcaa
caab
caba
cbaa
8.5. EJERCICIOS 183
8.5.2. Prolema 574 - Sum It Up
Dado un total n y una lista n de enteros, hallar todas las distintas sumas
que suman t. Por ejemplo si t = 4, n = 6 y la lista es [4, 3, 2, 2, 1, 1], existen 4
sumas diferentes que suman 4. Estas son: 4, 3+1, 2+2, y 2+1+1. Un n´ umero
puede utilizarse tantas veces como ocurre en la lista. Un solo n´ umero puede
utilizarse como una suma.
Entrada EL archivo de entrada contiene uno o m´as casos de prueba. Uno
por l´ınea. Cada caso de prueba contiene el total t, seguido de n que es el
n´ umero de enteros de la lista, seguidos de n enteros. Si n = 0 se termina el
archivo de entrada. En otros casos t es un entero positivo t ≤ 1000. El tama˜ no
de la lista es de 1 a 12, 1 ≤ n ≤ 12. Los enteros positivos son menores a 100.
Los n´ umeros est´an separados por un espacio. Los n´ umeros de la lista est´an
en orden descendente y existen n´ umeros repetidos
Salida Para cada caso de prueba primero escriba la l´ınea Sums of el total
y dos puntos. Luego escriba cada suma, una por l´ınea. Si no hay sumas
escriba la l´ınea NONE. Los n´ umeros en cada suma deben aparecer en orden
descendente. Las sumas deben ordenarse en orden descendente. En otras
palabras las sumas con el mismo primer n´ umero deben ordenarse por el
segundo. Si los dos primeros n´ umeros igualan debe ordenarse por el tercero y
as´ı sucesivamente. Todas las sumas deben ser diferentes y no pueden aparecer
m´as de dos veces.
Ejemplo de entrada
4 6 4 3 2 2 1 1
5 3 2 1 1
400 12 50 50 50 50 50 50 25 25 25 25 25 25
0 0
Ejemplo de salida
Sums of 4:
4
3+1
2+2
2+1+1
Sums of 5:
NONE
Sums of 400:
184 8. BACKTRACKING
50+50+50+50+50+50+25+25+25+25
50+50+50+50+50+25+25+25+25+25+25
8.5. EJERCICIOS 185
8.5.3. Problema 524 - Anillos de primos
Un anillo est´a compuesto de n c´ırculos como se muestra en el diagrama.
Se pide colocar un n´ umero natural en cada uno de los c´ırculos, la condici´on es
que la suma de los n´ umeros de dos c´ırculos adyacentes deben ser un n´ umero
primo. Se pide que el n´ umero del primer c´ırculo debe ser siempre 1.
Entrada n, (0 < n <= 16)
Salida En la salida cada l´ınea representa una serie de n´ umeros del c´ırculo.
Comenzando con el n´ umero 1 los n´ umeros deben satisfacer la condici´on tanto
en el sentido del reloj y como en el sentido contrario.
Ejemplo de Entrada
6
8
Ejemplo de salida
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
186 8. BACKTRACKING
8.5.4. Problema 216 - Hacer la l´ınea
Una red de computadoras requiere que las computadoras de una red est´en
interconectadas.
El problema considera una red lineal de tipo bus, en la que las computado-
ras est´an conectadas exactamente a otras dos, excepto a las computadoras
de los extremos.
La imagen muestra las computadoras como puntos negros y sus ubicacio-
nes en la red est´an identificadas como coordenadas en el plano.
Las distancias entre las computadores est´an puestas en pies. Por varias
razones, es necesario minimizar la distancia del cable.
Debe construir un programa que determine como debe establecerse di-
cha cadena a fin de minimizar el total del cable requerido. En la instalaci´on
que se est´a construyendo, el cable se instalar´a por el piso. La distancia total
ser´a igual a la distancia entre las computadoras adyacentes m´as 16 pies adi-
cionales para conectar del piso a las computadoreas y facilitar la instalaci´on.
La figura muestra la forma ´optima de conectar las computadoras y la
distancia total de cable requerida para ´esta configuraci´on es (4 + 16) + (5 +
16) + (5,83 + 16) + (11,18 + 16) = 90,01 pies.
Entrada El archivo de entrada consiste de una serie de conjuntos de datos.
Cada conjunto comienza con el n´ umero que indica el n´ umero de computado-
8.5. EJERCICIOS 187
ras en la red. Cada red tiene al menos 2 computadoras y un m´aximo de 8.
Un n´ umero cero en el n´ umero de computadoras indica el final de la entrada.
Despu´es de especificar el n´ umero de computadoras en la red, cada l´ınea
adicional le dar´a las coordenadas de cada computadora. Estas coordenadas
son enteros en el rango de 0 a 150. No existen dos computadoras en el mismo
lugar, y cada una est´a listada una sola vez.
Salida
La salida para cada red debe tener una l´ınea que incluya el n´ umero de la
red, determinada por su posici´on en los datos de entrada. Luego una l´ınea que
especifica la longitud del cable que ser´a cortado para conectar dos compu-
tadoras adyacentes. Al final se incluir´a una oraci´on indicando la cantidad de
cable utilizado.
En el listado las longitudes de cable a recortar que, van de un extremo al
otro de la red. Utilice un formato similiar a la provista. Separe los datos de
una red imprimiento una l´ınea de asteriscos e imprima las distancias con dos
decimales.
Ejemplo de Entrada
6
5 19
55 28
38 101
28 62
111 84
43 116
5
11 27
84 99
142 81
88 30
95 38
3
132 73
49 86
72 111
0
Ejemplo de Salida
188 8. BACKTRACKING
**********************************************************
Network #1
Cable requirement to connect (5,19) to (55,28) is 66.80 feet.
Cable requirement to connect (55,28) to (28,62) is 59.42 feet.
Cable requirement to connect (28,62) to (38,101) is 56.26 feet.
Cable requirement to connect (38,101) to (43,116) is 31.81 feet.
Cable requirement to connect (43,116) to (111,84) is 91.15 feet.
Number of feet of cable required is 305.45.
**********************************************************
Network #2
Cable requirement to connect (11,27) to (88,30) is 93.06 feet.
Cable requirement to connect (88,30) to (95,38) is 26.63 feet.
Cable requirement to connect (95,38) to (84,99) is 77.98 feet.
Cable requirement to connect (84,99) to (142,81) is 76.73 feet.
Number of feet of cable required is 274.40.
**********************************************************
Network #3
Cable requirement to connect (132,73) to (72,111) is 87.02 feet.
Cable requirement to connect (72,111) to (49,86) is 49.97 feet.
Number of feet of cable required is 136.99.
Cap´ıtulo 9
Geometr´ıa computacional
9.1. Introducci´ on
La geometr´ıa computacional trata de una serie conceptos que se definen
a continuaci´on:
Triangulaci´on de pol´ıgonos Triangulaci´on es la divisi´on de un pol´ıgono
plano en un conjunto de tri´angulos, usualmente con la restricci´on de que
cada lado del tri´angulo sea compartido por dos tri´angulos adyacentes.
Problemas de partici´on La triangulaci´on es un caso especial de la par-
tici´on de un pol´ıgono. Lo que trata normalmente es de particionar el
pol´ıgono en objetos convexos m´as peque˜ nos, porque es m´as f´acil traba-
jar con objetos peque˜ nos.
Problemas de intersecci´on En el plano los problemas de intersecci´on es-
t´an relacionados con encontrar los puntos de intersecci´on de todos los
segmentos que se forman con los puntos especificados. En dimensiones
superiores se analizan tambi´en la intersecci´on de poliedros.
Cerco convexo o convex hull Un cerco convexo crea un subconjunto de
un plano denominado plano convexo, s´ı y solo s´ı cualquier segmento de
recta de los puntos especificado est´a en este subconjunto.
B´ usqueda geom´etrica La b´ usqueda geom´etrica se refiere a tres problemas
principales: ubicaci´on de un punto en un pol´ıgono, visibilidad para
conocer las ´areas visibles al iluminar con un rayo de luz y las b´ usquedas
en un subconjunto espec´ıfico.
189
190 9. GEOMETR
´
IA COMPUTACIONAL
Areas de pol´ıgonos Comprende los m´etodos para calcular el ´area de un
pol´ıgono, dada una lista de puntos.
Una descripci´on de las tem´aticas que trata el campo de la geometr´ıa compu-
tacional se puede encontrar en [Cha94].
Iniciaremos el desarrollo de ´este cap´ıtulo con concepto de geometr´ıa y
luego se describir´a la geometr´ıa computacional. En ambos casos se mostrar´an
algunos algoritmos y la implementaci´on de las librer´ıas de Java.
9.2. Geometr´ıa
La geometr´ıa es el estudio matem´atico de elementos en el espacio, por
ejemplo puntos, l´ıneas, planos y vol´ umenes. A´ un cuando esta geometr´ıa ha
sido estudiada ampliamente se quiere mostrar como se implementa compu-
tacionalmente y c´omo un conjunto b´asico de m´etodos nos ayuda a resolver
una variedad de problemas si tener que resolver cada uno, reduciendo signi-
ficativamente el tiempo de desarrollo. Una buena bibliograf´ıa para temas de
geometr´ıa se puede leer en [Leh88].
Bien para definir un punto crearemos la clase Punto con dos par´ametros
el valor del eje x y el valor del eje y. El c´odigo para definir este objeto es:
/* Clase para definir un punto
* @author Jorge Teran
*/
public Punto(double x, double y) {
super();
this.x = x;
this.y = y;
}
Los valores se han definido como double para permitir la implementaci´on de
los m´etodos que efect´ uan c´alculos cuyos resultados no son enteros.
En el desarrollo de ´esta clase se han definido una serie de m´etodos ge-
nerales que nos permiten resolver una variedad de problemas. Tomando los
conceptos de la geometr´ıa, se presenta la distancia a otro punto y el ´area de
un tri´angulo que est´a formada por tres puntos.
El resultado da la siguiente clase:
9.2. GEOMETR
´
IA 191
/* Clase para definir un punto
* @author Jorge Teran
*/
public class Punto {
double x, y;
public Punto(double x, double y) {
super();
this.x = x;
this.y = y;
}
double X() {
return (x);
}
double Y() {
return (y);
}
public String toString() {
return ("(" + x + "," + y + ")");
}
double Distancia(Punto p) {
double d = 0;
d = (x - p.X()) * (x - p.X())
+ (y - p.Y()) * (y - p.Y());
d = Math.sqrt(d);
return d;
}
double areaTriangulo(Punto b, Punto c) {
double d = 0;
d = x * b.X() - y * b.X() + y * c.X()
- x * c.Y() + b.X() * c.Y()
-c.X() * b.Y();
192 9. GEOMETR
´
IA COMPUTACIONAL
d = Math.abs(d / 2);
return d;
}
}
Para definir una recta en el plano existen varias alternativas, se puede utilizar
la expresi´on y = ax + b sin embargo tiene el problema que cuando la recta
es paralela al eje y dado que la pendiente es infinita haciendo que haya que
tomar algunos recaudos.
Existe una representaci´on m´as apropiada que es ax+by +c = 0 que es la
que se construy´o en este ejemplo. Tambi´en puede definirse la recta con dos
puntos. En la clase que se ha construido se ha tomado las dos anteriores y la
que se define por un punto m´as una pendiente. Cuando se dan los dos puntos
constru´ımos los valores a, b, c desde ´esta especificaci´on.
A fin de poder comparar dos n´ umeros no enteros hemos construido una
variable que la hemos llamado ERROR. Esto se hace porque las operaciones
de punto flotante no dan un valor exacto.
Los m´etodos implementados son: punto de intersecci´on, prueba de l´ıneas
paralelas, pendiente, l´ınea perpendicular que pasa por un punto. La clase
completa queda como sigue:
public class Linea {
/* Clase para definir una linea
* @author Jorge Teran
*/
double a, b, c;
public Linea(double a, double b, double c) {
this.a = a;
this.b = b;
this.c = c;
}
public Linea(Punto p1, Punto p2) {
this.a = p1.Y() - p2.Y();
this.b = -p1.X() + p2.X();
this.c = p1.X() * p2.Y() - p1.Y() * p2.X();
}
9.2. GEOMETR
´
IA 193
public Linea(Punto p, double m) {
double a, b;
a = m;
b = 1;
c = -(a * p.X() + b * p.Y());
}
public static final double ERROR = 0.0001;
double A() {
return a;
}
double B() {
return b;
}
double C() {
return c;
}
Punto Interseccion(Linea l) {
double x, y;
if (Paralelas(l)) {
System.out.println("Error: Lineas parelas");
// System.exit(0);
}
x = (l.B() * c - b * l.C()) / (l.A() * b - a * l.B());
if (Math.abs(b) > ERROR)
y = -(a * x + c) / b;
else
y = -(l.A() * x + l.C()) / l.B();
194 9. GEOMETR
´
IA COMPUTACIONAL
return (new Punto(x, y));
}
Boolean Paralelas(Linea l) {
return ((Math.abs(a - l.A()) <= ERROR)
&& ((Math.abs(b - l.B()) <= ERROR)));
}
double Pendiente() {
if (b == 0) // pendiente infinita
return (0);
else
return (a / b);
}
Linea lineaPerpendicularPunto(Punto l) {
return (new Linea(-b, a, (b * l.X() - a * l.Y())));
}
public String toString() {
return (a + "x+" + b + "y+" + c + "=0");
}
}
Se pueden construir una variedad de clases para manejar diferentes figuras
geom´etricas que incluyan funciones b´asicas que, combinadas permiten resol-
ver algunos problemas utilizando sus funciones.
Como ejemplo, consideremos una lista de puntos de la cu´al queremos
hallar cu´ales son los dos puntos m´as cercanos.
9.2. GEOMETR
´
IA 195
Para resolver ´esto definimos un vector de puntos y con dos ciclos compara-
mos exaustivamente todas las posibilidas hallando la distancia m´ınima. Este
c´odigo con tiempo de ejecuci´on proporcional a O(n
2
) es el siguiente:
public class minimoPuntos {
/*
* @author Jorge Teran
*/
public static void main(String[] args) {
Punto[] p = new Punto[5];
double minimo = 999999, d = 0;
int punto1 = 0, punto2 = 0;
p[0] = new Punto(8, 16);
p[1] = new Punto(8, 11);
p[2] = new Punto(12, 16);
p[3] = new Punto(24, 10);
p[4] = new Punto(13, 8);
for (int i = 0; i < 5; i++) {
for (int j = i + 1; j < 5; j++) {
d = p[i].Distancia(p[j]);
if (d < minimo) {
minimo = d;
punto1 = i;
punto2 = j;
}
}
}
System.out.println("Los puntos m´as cercanos son :");
System.out.println(p[punto1] + " y " + p[punto2]);
System.out.println("Con distancia :" + minimo);
}
}
Para mostrar la utilizaci´on de los m´etodos construidos hallaremos la distancia
de un punto al punto con el cual una recta tiene la distancia m´as corta, esto
es:
196 9. GEOMETR
´
IA COMPUTACIONAL
Como se ve en el dibujo lo que se quiere hallar es el punto con el cual una l´ınea
trazada desde el punto forman un ´angulo recto. Para ´esto primero hallamos
una recta perpendicular, a la recta que pase por el punto especificado. Luego
hallamos la intersecci´on de las dos rectas, y finalmente la distancia entre ´estos
dos puntos. Como ve no es necesario resolver matem´aticamente este problema
a fin de codificarlo, lo que se hace es utilizar las funciones disponibles. El
resultado es el siguiente:
public class PruebaGeo {
/*
* @author Jorge Teran
*/
public static void main(String[] args) {
Punto p4 = new Punto(4,-1);
Linea l4 = new Linea(3,-4,12);
Linea l5 = l4.lineaPerpendicularPunto(p4);
Punto p5 = l5.Interseccion(l4);
System.out.println("Distancia = "+p5.Distancia(p4));
}
}
9.3. Librer´ıas de Java
En el lenguaje Java se cuentan con funciones trigonom´etricas en la clase
Math, Se presentan las principales en el cuadro 9.1
Tambi´en se dispone del paquete java.awt.geom que provee una serie de
clases que facilitan el desarrollo de programas que tratan con problemas
geom´etricos. Existen clases para puntos, l´ıneas , rect´angulos, ´areas, y pol´ıgo-
nos. Algunos de ´estos m´etodos se muestran en el cuadro 9.2.
9.3. LIBRER
´
IAS DE JAVA 197
Constante PI Math.PI
Arco coseno Math.acos(double a)
Arco seno Math.asin(double a)
Arco tangente Math.atan(double a)
Seno Math.sin(double a)
Coseno Math.cos(double a)
Tangente Math.tan(double a)
Coseno hiperb´olico Math.cosh(double x)
Seno hiperb´olico Math.sinh(double x)
Valor de la hipotenusa Math.hypot(double x, double y)
Convertir a grados toDegrees(double anguloRadianes)
Convertir a radianes toRadians(double anguloGrados)
Cuadro 9.1: Funciones trigonom´etricas del Java
Construir un punto Point2D.Double(double x, double y)
Distancia a otro punto distance(Point2D p)
Construir una l´ınea Line2D.Double(Point2D p1,
Point2D p2)
Contiene el punto p contains(Point2D p)
Intersecta con el rect´angulo intersects(Rectangle2D r)
Intersecta la l´ınea intersectsLine(Line2D l)
Distancia al punto p ptLineDist(Point2D p)
Cuadro 9.2: Funciones para puntos y l´ıneas
198 9. GEOMETR
´
IA COMPUTACIONAL
El siguiente programa muestra el uso de ´este paquete de Java.
import java.awt.geom.*;
/*
* @author Jorge Teran
*/
public class ClasesJava {
public static void main(String[] args) {
Point2D.Double p1 = new Point2D.Double(3, 5);
Point2D.Double p2 = new Point2D.Double(3, 35);
System.out.println("p1= " + p1);
System.out.println("p2= " + p2);
System.out.println("Distancia de p1 a p2= "
+ p1.distance(p2));
Line2D.Double l = new Line2D.Double(p1, p2);
Point2D.Double p3 = new Point2D.Double(7, 5);
System.out.println("Distancia al punto P3= "
+ l.ptLineDist(p3));
Line2D.Double l2 = new Line2D.Double(p3, p2);
System.out.println("l intersecta a l2= "
+ l.intersectsLine(l2));
System.out.println("l contiene a p2= "
+ l.contains(p2));
}
}
9.4. Cercos convexos
Dado un conjunto de puntos S se define un el cerco convexo, el conjunto
convexo m´as peque˜ no que contenga a todos los puntos de S.
Cuando graficamos en la pantalla los puntos (x,y) hay que tomar en cuen-
ta que el (0,0) es el extremo superior izquierdo de la pantalla. Consideremos
los siguientes puntos:
9.4. CERCOS CONVEXOS 199
El cerco convexo se forma con los puntos (86,34), (57,39), (41,98), (110,85).
Una propiedad del cerco convexo es que todos los segmentos de recta confor-
mada por los puntos del conjunto est´an en el interior del cerco convexo. La
figura siguiente muestra el cerco y se puede observar que todos los puntos
est´an contenidos por el cerco.
Para hallar cercos convexos existen varios algoritmos desarrollados. Con-
sideremos inicialmente que comparemos un punto con cada uno de los seg-
mentos de recta que se pueden formar y decidir si est´a al interior del cerco.
Este proceso claramente involucra tres ciclos, uno para cada punto y dos para
armar los segmentos de recta a probar. Esto genera un algorimo proporcional
a O(n
3
).
200 9. GEOMETR
´
IA COMPUTACIONAL
Figura 9.1: Alternativas para comparar un punto con una l´ınea
A fin de implementar la comparaci´on de un punto con respecto a una
l´ınea es necesario tomar en cuenta diferentes alternativas. Supongamos que
el segmento de recta entre los puntos p1 y p2 donde el p1.x = p2.x, o sea
paralelas al eje y. En este caso con referencia al primer punto obtendremos la
respuesta verdadera cuando p1.x < p2.x. Esto significa que el punto est´a m´as
a la izquierda de p1. La figura 9.1 lo esquematiza.
La figura 9.2 muestra el caso cuando el punto se encuentra en el segmento
de recta. Cuando el segmento de recta no es perpendicular al eje y se pre-
sentan varios casos de los que solo mostramos algunos en la figura 9.3. Para
hallar la posici´on de un punto con relaci´on a un segmento de recta se ha
agregado un m´etodo de la clase L´ınea que da true si el punto esta m´as a la
izquierda del segmento de recta. El c´odigo es el siguiente:
public boolean aIzquierda(Punto p) {
double pendiente=Pendiente();
if (this.sinPendiente) {
if (p.x < p1.x)
return true;
else {
if (p.x == p1.x) {
if (((p.y > p1.y) && (p.y < p2.y))
|| ((p.y > p2.y) && (p.y < p1.y)))
9.4. CERCOS CONVEXOS 201
Figura 9.2: Punto en el segmento de la recta
Figura 9.3: Caso en que el segmento de recta no es perpendicular al eje Y
202 9. GEOMETR
´
IA COMPUTACIONAL
return true;
else
return false;
} else
return false;
}
} else {
double x3 = (((p.x + pendiente
* (pendiente * p1.x - p1.y + p.y))
/ (1 + pendiente * pendiente)) );
double y3 = ((pendiente * (x3 / 1 - p1.x) + p1.y));
if (pendiente == (double) 0) {
if ((p.y ) > y3)
return true;
else
return false;
} else {
if (pendiente > (double) 0) {
if (x3 > (p.x ))
return true;
else
return false;
} else {
if ((p.x * 1) > x3)
return true;
else
return false;
}
}
}
}
Para construir el c´odigo que halle el cerco convexo se ha realizado un pro-
grama de ejemplo, que es el siguiente:
9.4. CERCOS CONVEXOS 203
import java.awt.Graphics;
import java.util.Vector;
/* Programa oara hallar un
* cerco convexo
* @author Jorge Teran
*/
public class Convexo {
public static void main(String[] args) {
Vector puntos = new Vector();
Vector cerco = new Vector();
int i, j, k;
puntos.addElement(new Punto(57, 39));
puntos.addElement(new Punto(41, 98));
puntos.addElement(new Punto(60, 75));
puntos.addElement(new Punto(64, 59));
puntos.addElement(new Punto(110, 85));
puntos.addElement(new Punto(86, 34));
puntos.addElement(new Punto(87, 71));
System.out.println("Punto");
for (k = 0; k < puntos.size(); k++) {
System.out.println((Punto) puntos.elementAt(k));
}
boolean masIzquierdo, masDerecho;
for (i = 0; i < puntos.size(); i++) {
for (j = (i + 1); j < puntos.size(); j++) {
masIzquierdo = true;
masDerecho = true;
Linea temp = new Linea(
(Punto) puntos.elementAt(i),
(Punto) puntos.elementAt(j));
for (k = 0; k < puntos.size(); k++) {
if ((k != i) && (k != j)) {
if (temp.aIzquierda(
(Punto)puntos.elementAt(k)))
204 9. GEOMETR
´
IA COMPUTACIONAL
masIzquierdo = false;
else
masDerecho = false;
}
}
if (masIzquierdo || masDerecho) {
cerco.addElement(new
Linea((Punto) puntos.elementAt(i),
(Punto) puntos.elementAt(j)));
}
}
}
System.out.println("Cerco Convexo");
for (k = 0; k < cerco.size(); k++) {
System.out.println(((Linea) cerco.elementAt(k)).p1
+ "," + ((Linea) cerco.elementAt(k)).p2);
}
}
}
Existen varios algoritmos m´as eficientes para hallar el cerco convexo de
los que se mencionan Graham,Jarvis Quick hull.
Alejo Hausner del departamento del ciencias de la computaci´on de la
universidad de Princeton ha desarrollado unas animaciones que, muestran la
ejecuci´on de estos algoritmos.
Se pueden ver en su p´agina web:
http://www.cs.princeton.edu/ah/alg anim/version1/ConvexHull.html
El m´etodo de Graham de basa en
Encontrar el punto m´as extremo. Se escoge el punto con una coordenada
y m´as grande. Se denomina pivote y se garantiza que est´a en el cerco
convexo.
Se ordenan los puntos en forma ascendente en funci´on del ´angulo que
forman con el pivote, terminamos con un pol´ıgono con forma de estrella.
Luego se construye el cerco recorriendo el contorno del pol´ıgono.
9.5. CLASE JAVA PARA POL
´
IGONOS 205
El m´etodo de Jarvis de basa en:
Se inicializa en alg´ un punto que, se garantiza pertenece al cerco
Se recorren los puntos buscando cual est´a m´as a la izquierda, ese es-
tar´a en el cerco.
El m´etodo de Quick hull de basa en:
Dado un segmento de l´ınea AB cuyos dos puntos que conocemos est´an
en el cerco convexo.
Se halla el punto m´as alejado a este segmento formando un tri´angulo
ABC.
Los puntos que est´an en el interior del tri´angulo no pueden ser del arco
convexo. Con los puntos que est´an afuera del segmento AB se crea un
conjunto y con los que est´an fuera del segmento BC otro. Con estos
dos conjuntos se repite el proceso recursivamente.
9.5. Clase Java para pol´ıgonos
Las clases de Java para el manejo de pol´ıgonos es la clase Polygon() que
crea un pol´ıgono vac´ıo. Los m´etodos de esta clase son:
Agregar un punto addPoint(int x, int y)
Verifica si el punto est´a al interior
del pol´ıgono contains(Point p)
Obtiene las coordenadas de un
rect´angulo que contiene al pol´ıgono getBounds()
Verifica si el pol´ıgono intersecta con
el rect´angulo intersects(Rectangle2D r)
Cuando construimos un pol´ıgono la forma de la figura est´a dada por el orden
en el que ingresamos los puntos. El siguiente c´odigo ejemplifica el uso de la
clase Polygon().
import java.awt.Polygon;
import java.awt.Point;
/*
206 9. GEOMETR
´
IA COMPUTACIONAL
* @author Jorge Teran
*/
public class pol´ıgono {
public static void main(String[] args) {
Polygon puntos = new Polygon();
int i, j, k;
puntos.addPoint(57, 39);
puntos.addPoint(41, 98);
puntos.addPoint(60, 75);
puntos.addPoint(64, 59);
puntos.addPoint(110, 85);
puntos.addPoint(86, 34);
puntos.addPoint(87, 71);
Point p= new Point (60,75);
System.out.println(puntos.getBounds());
System.out.println(p);
System.out.println(puntos.contains(p));
}
}
Este c´odigo inserta los puntos del ejemplo de cerco convexo, produciendo un
rect´angulo que incluye todos los puntos.
java.awt.Rectangle[x=41,y=34,width=69,height=64]
Si realizamos la prueba
Point p= new Point (60,75);
System.out.println(puntos.contains(p));
Veremos que las respuesta es false debido a que la clase pol´ıgono no halla un
cerco convexo, y este punto no es interior al pol´ıgono. En cambio si creamos
un pol´ıgono con los puntos (57, 39), (41, 98), (110, 85), (86, 34) obtendremos
true dado que el punto est´a en el interior del pol´ıgono.
9.6. C
´
ALCULO DEL PER
´
IMETRO Y
´
AREA DEL POL
´
IGO-NO. 207
9.6. C´alculo del per´ımetro y ´area del pol´ıgo-
no.
Para hallar el per´ımetro de un pol´ıgono, es suficiente con hallar la distan-
cia entre dos puntos consecutivos y sumar. Cuando se quiere hallar el ´area
no es tan simple. Consideremos el siguiente pol´ıgono
Para poder determinar el ´area de ´este se requiere triangulizar el mismo. Esto
es dividir en tri´angulos y sumar.
El proceso de triangular se inicia numerando los v´ertices del pol´ıgono de
0 a n − 1. Luego tomamos la l´ınea entre los puntos 0 y n − 1 como base y
buscamos un punto con el cual producen un tri´angulo que no contenga puntos
interiores. De esta forma se divide el pol´ıgono en tres partes. Un tri´angulo y
dos subpol´ıgonos uno a la izquierda y otro a la derecha. Si un subpol´ıgono
208 9. GEOMETR
´
IA COMPUTACIONAL
tiene tres lados es un tri´angulo y no requiere m´as subdivisiones. Luego este
proceso se repite hasta terminar todos los subpol´ıgonos.
Cada triangulizaci´on de un pol´ıgono de n v´ertices tiene n −2 tri´angulos
y n −3 diagonales.
El c´odigo para triangular el pol´ıgono de ejemplo es el siguiente:
import java.awt.Graphics;
import java.util.Vector;
/* Programa para triangular el poligono
* @author Jorge Teran
*/
public class T {
public static void main(String[] args) {
Vector puntos = new Vector();
Vector triangulo = new Vector();
puntos.addElement(new Punto(57, 39));
puntos.addElement(new Punto(41, 98));
puntos.addElement(new Punto(60, 75));
puntos.addElement(new Punto(64, 59));
puntos.addElement(new Punto(110, 85));
puntos.addElement(new Punto(86, 34));
puntos.addElement(new Punto(87, 71));
Proceso(puntos,triangulo);
return;
}
static void Proceso(Vector puntos, Vector triangulo){
Vector iPuntos = new Vector();
Vector dPuntos = new Vector();
Punto t1,t2,t3;
int i, j, k;
i=0; j= puntos.size()-1;
if (j<2) return;
if (j==2){
t1=(Punto) puntos.elementAt(0);
t2=(Punto) puntos.elementAt(1);
9.6. C
´
ALCULO DEL PER
´
IMETRO Y
´
AREA DEL POL
´
IGO-NO. 209
t3=(Punto) puntos.elementAt(2);
triangulo.addElement(new Linea(t1,t2));
triangulo.addElement(new Linea(t1,t3));
trangulo.addElement(new Linea(t2,t3));
return;
}
k=buscaTriangulo(puntos);
iPuntos=new Vector();
iPuntos.add((Punto)puntos.elementAt(0));
for (i=k;i<puntos.size();i++)
iPuntos.add((Punto)puntos.elementAt(i));
Proceso(iPuntos,triangulo);
new DibujarPuntos(iPuntos, triangulo);
dPuntos=new Vector();
for (i=0;i<=k;i++)
dPuntos.add((Punto)puntos.elementAt(i));
Proceso(dPuntos,triangulo);
new DibujarPuntos(dPuntos, triangulo);
}
static int buscaTriangulo(Vector puntos){
int i,pi,ult;
ult=puntos.size()-1;
for (i = 1;i<puntos.size()-1;i++){
pi=tienePuntoInterior(puntos,i,ult);
return pi;
}
return 0;
}
static int tienePuntoInterior
(Vector puntos,int k,int ult){
Punto t1,t2,t3,t4;
t1 = (Punto)puntos.elementAt(0);
t2 = (Punto)puntos.elementAt(ult);
t3 = (Punto)puntos.elementAt(k);
Linea l1 = new Linea(t1,t2);
Linea l2 = new Linea(t1,t3);
Linea l3 = new Linea(t2,t3);
210 9. GEOMETR
´
IA COMPUTACIONAL
int i=-1;
for (i = 1;i<puntos.size()-1;i++){
if ((i!=k)&&(i!=ult)){
t4 = (Punto)puntos.elementAt(i);
if (l1.aIzquierda(t4)) return i;
if (l2.aIzquierda(t4)) return i;
if (l3.aIzquierda(t4)) return i;
}
}
return i;
}
}
En el libro [Mis97] se muestran diversos algoritmos para triangular pol´ıgonos.
De los que hay que mencionar el algoritmo de Chazelles que puede triangular
pol´ıgonos simples en tiempo lineal.
9.7. EJERCICIOS 211
9.7. Ejercicios
9.7.1. Problema 378 - L´ıneas que intersectan
Se sabe que todo par de puntos distintos en el plano definen una l´ınea.
Un par de l´ıneas en el plano pueden intersectarse de tres maneras 1) no hay
intersecci´on porque son paralelas, 2) intersectan en una l´ınea cuando est´an
sobrepuestas y 3) intersectan en un punto.
El programa lee repetidamente una serie de cuatro puntos que definen
dos l´ıneas x y y y determina como intersectan las l´ıneas. Todos los n´ umeros
de este problema estaran entre −1000 y 1000
Entrada.- La primera l´ınea contiene un n´ umero N entre 1 y 10 indicando
el n´ umero de pares de l´ıneas que est´an representadas. Las siguientes N l´ıneas
contienen los ocho puntos que representan las coordenadas de las l´ıneas en
el formato x
1
y
1
, x
2
y
2
,x
3
y
3
,x
4
y
4
. El punto x
1
y
1
es distinto del punto x
2
y
2
. De
la misma forma los puntos x
3
y
3
y x
4
y
4
.
Salida.- La salida debe ser N + 2 l´ıneas. La primera l´ınea de salida es
decir INTERSECTING LINES OUTPUT. Las siguientes l´ıneas corresponden
a una l´ınea de entrada describiendo la forma en la que se intersectan las
l´ıneas, a) NONE cuando no intersectan b) LINE cuando se sobreponen y c)
POINT seguido de las coordenadas x,y del punto de intersecci´on cuando se
intersectan, y al final como ´ ultima l´ınea END OF OUTPUT.
Ejemplo de Entrada.-
5
0 0 4 4 0 4 4 0
5 0 7 6 1 0 2 3
5 0 7 6 3 -6 4 -3
2 0 2 27 1 5 18 5
0 3 4 0 1 2 2 5
Ejemplo de Salida.-
INTERSECTING LINES OUTPUT
POINT 2.00 2.00
NONE
LINE
POINT 2.00 5.00
POINT 1.07 2.20
END OF OUTPUT
212 9. GEOMETR
´
IA COMPUTACIONAL
9.7.2. Problema 273 - Juego de Palos
En este juego un n´ umero de palos pl´asticos se esparcen en una mesa y los
jugadores tratan de removerlos sin mover los otros. En este problema solo
se quiere conocer si varios pares de palos est´an conectados por un camino
de palos que se tocan. Dada una lista de puntos terminales para algunos
palos se pregunta si varios pares de palos est´an conectados o si ninguno
est´a conectado. Dos palos pueden estar conectados indirectamente por otros
palos.
Entrada La entrada comienza con un n´ umero entero positivo en una l´ınea
el n´ umero de casos que siguen. Esta l´ınea est´a seguida por una l´ınea en blanco.
Tambi´en existe una l´ınea en blanco entre dos entradas consecutivas.
Un caso de prueba consiste en m´ ultiples l´ıneas de entrada. La primera
l´ınea ser´a un n´ umero entero n > 1 dando el n´ umero de palos en la mesa.
Las siguientes n l´ıneas contienen las coordenadas x,y de los dos puntos que
definen las coordenadas de inicio y fin de los palos.
Todas las coordenadas son menos de 100. Los palos son de longitud va-
riable. El primer palo se denominara #1, el segundo #2 y as´ı sucesivamente.
Las siguientes l´ıneas contendr´an dos enteros positivos a y b. Debe determinar
si el palo a puede conectarse con el palo b. Cuando a = 0 y b = 0 termina la
entrada. No existen palos de longitud 0.
Salida Para cada caso de prueba la salida debe seguir la descripci´on. La
salida de dos casos consecutivos se separaran por una l´ınea en blanco.
Excepto si la ´ ultima l´ınea donde a, b = 0 debe generar una l´ınea que diga
C¸ ONNECTED”si el palo a se puede conectar al palo b, o ”NOT CONNEC-
TED”, si no pueden conectarse. Un palo se considera conectado a s´ı mismo.
Ejemplo de Entrada
1
7
1 6 3 3
4 6 4 9
4 5 6 7
1 4 3 5
3 5 5 5
5 2 6 3
5 4 7 2
1 4
9.7. EJERCICIOS 213
1 6
3 3
6 7
2 3
1 3
0 0
Ejemplo de salida
CONNECTED
NOT CONNECTED
CONNECTED
CONNECTED
NOT CONNECTED
CONNECTED
214 9. GEOMETR
´
IA COMPUTACIONAL
9.7.3. Problema 218 - Erradicaci´on de moscas
Los entimologistas en el noreste han colocado trampas para determinar la
influencia de una variedad de moscas en el ´area. Se planea estudiar programas
de erradicaci´on que tienen posibilidades de controlar el crecimiento de la
poblaci´on.
El estudios deben organizar las trampas en las que se agarraron moscas
en regiones compactas que luego ser´an utilizadas para probar los programas
de erradicacci´on. Una regi´on se define como un pol´ıgono con el per´ımetro
m´ınimo que puede encerrar a todas las trampas.
Por ejemplo, las trampas de una regi´on particular son representadas por
puntos, el pol´ıgono asociado ser´ıa el siguiente:
Lo que se debe hacer es un programa que, tome como entrada la ubicaci´on
de las trampas en cada regi´on e imprimir las ubicaciones de las trampas que
figuran en el per´ımetro de la regi´on y la longitud total del per´ımetro.
Entrada El archivo de entrada contiene los datos de varias regiones. La
primera l´ınea contiene el n´ umero de trampas de una regi´on. Los siguientes
registros contienen dos n´ umeros reales que son las coordenadas de ubicaci´on
x,y de las trampas. Los datos en un registro no son duplicados y el fin de los
datos de una regi´on se indica con 0.
Salida La salida para una regi´on son tres l´ıneas: La primera l´ınea es el
n´ umero de la regi´on, la segunda lista los puntos del per´ımetro, y la tercera
la longitud del mismo.
Una l´ınea en blanco debe separar las diferentes regiones. Ejemplo de en-
trada
3
1 2
4 10
5 12.3
9.7. EJERCICIOS 215
6
0 0
1 1
3.1 1.3
3 4.5
6 2.1
2 -3.2
7
1 0.5
5 0
4 1.5
3 -0.2
2.5 -1.5
0 0
2 2
0
Ejemplo de salida
Region \#1:
(1.0,2.0)-(4.0,10.0)-(5.0,12.3)-(1.0,2.0)
Perimeter length = 22.10
Region \#2:
(0.0,0.0)-(3.0,4.5)-(6.0,2.1)-(2.0,-3.2)-(0.0,0.0)
Perimeter length = 19.66
Region \#3:
(0.0,0.0)-(2.0,2.0)-(4.0,1.5)-(5.0,0.0)-(2.5,-1.5)-(0.0,0.0)
Perimeter length = 12.52
216 9. GEOMETR
´
IA COMPUTACIONAL
9.7.4. Problema 476 - Puntos en rect´angulos
Dado una lista de rect´angulos y puntos en el plano determinar cu´ales
puntos est´an en que rect´angulos.
Entrada La entrada est´a formada for n < 10 rect´angulos descriptos uno
en cada l´ınea. Cada rect´angulo esta descripto por dos puntos especificados
por sus coordenadas en n´ umeros reales. Estos puntos representan la esquina
superior izquierda y la esquina inferior derecha.
El final de la lista ser´a indicada por un asterisco en la columna uno.
Las siguientes l´ıneas contienen las coordenadas x,y de los puntos, una por
l´ınea. El final de la lista ser´a indicada por un punto con coordenadas 9999.9,
9999.9, que no se incluyen en la salida.
Los puntos que coinciden con el borde del cuadrado, se consideran in-
teriores al cuadrado..
Ejemplo de entrada
r 8.5 17.0 25.5 -8.5
r 0.0 10.3 5.5 0.0
r 2.5 12.5 12.5 2.5
*
2.0 2.0
4.7 5.3
6.9 11.2
20.0 20.0
17.6 3.2
-5.2 -7.8
9999.9 9999.9
Ejemplo de salida
Point 1 is contained in figure 2
Point 2 is contained in figure 2
Point 2 is contained in figure 3
Point 3 is contained in figure 3
Point 4 is not contained in any figure
Point 5 is contained in figure 1
Point 6 is not contained in any figure
Bibliograf´ıa
[Cha94] Bernard Chazelle. Computational geometry: a retrospective. In
STOC ’94: Proceedings of the twenty-sixth annual ACM sympo-
sium on Theory of computing, pages 75–94, New York, NY, USA,
1994. ACM Press.
[CK79] John C. Cherniavsky and Samuel
˜
N. Kamin. A complete and con-
sistent hoare axiomatics for a simple programming language. J.
ACM, 26(1):119–128, 1979.
[CSH05] Gary Cornell Cay S. Horstman. Core Java 2 J2SE 5.0 Volume 1.
Sun Microsystems Press, 2005.
[EH96] Sartaj Sahni Ellis Horowits. Fundamentals of Algoritms. Com-
puter Science Press, 1996.
[Fel05] Yishai A. Feldman. Teaching quality object-oriented program-
ming. J. Educ. Resour. Comput., 5(1):1–16, 2005.
[GB96] Paul Bratley Gilles Brassard. Fundamentals of Algoritms. Prin-
tice Hall, 1996.
[Gri77] Ralph P. Grimaldi. Matematica Discreta. Addison Wessley, 1977.
[Hoa83] C. A. R. Hoare. Communicating sequential processes. Commun.
ACM, 26(1):100–106, 1983.
[KBO
+
05] Benjamin A. Kuperman, Carla E. Brodley, Hilmi Ozdoganoglu,
T.
˜
N. Vijaykumar, and Ankit Jalote. Detection and prevention
of stack buffer overflow attacks. Commun. ACM, 48(11):50–56,
2005.
217
218 BIBLIOGRAF
´
IA
[Leh88] Charles H. Lehmann. Geometr´ıa Anal´ıtica. Editorial Limusa,
1988.
[LPC
+
02] G. Leavens, E. Poll, C. Clifton, Y. Cheon, and C. Ruby. Jml
reference manual, 2002.
[MAR03] Steven S. Skiena Miguel A. Revilla. Programming Challenges.
Springer, 2003.
[McC01] Jeffrey J. McConnell. Analysis of Algorithms: An Active Learning
Approach. Jones and Bartlett Pub, 2001.
[Mis97] Mishra. Computational real algebraic geometry. In Jacob E.
Goodman and Joseph O’Rourke, editors, Handbook of Discrete
and Computational Geometry, CRC Press, 1997. 1997.
[Red90] Uday S. Reddy. Formal methods in transformational derivation
of programs. In Conference proceedings on Formal methods in
software development, pages 104–114, New York, NY, USA, 1990.
ACM Press.
[RLG94] Oren Patashnik Ronald L. Graham, Donald E. Knuth. Concrete
Mathematics. Addison Wessley, 1994.
[THCR90] Charles E. Leiserson Thomas H. Cormen and Ronald L. Rivest.
Introduction to Algorithms. Massachusetts Institute of Techno-
logy, 1990.
[Vos01] Tanja Vos. M´etodos Formales Especificaci´on y Verificaci´on. Um-
sa, 2001.
Ap´endice A
Fundamentos matem´aticos
Para el correcto an´alisis de los programas se requiere recordar algunos
conceptos de las matem´aticas. Se presentan las f´ormulas y m´etodos que se
requieren en una forma simple sin ahondar en desarrollos te´oricos y demos-
traciones.
En el mismo, introducimos las ecuaciones m´as utilizadas y cuyos desarro-
llos rigurosos los encontrar´a en los libros de matem´aticas. Algunas referencias
a ´estos textos est´an en la bibliograf´ıa.
A.1. Recordatorio de logaritmos
Es necesario recordar los siguientes conceptos de logaritmos que son de
uso com´ un.
1. a
b
= c significa que log
a
c = b donde a se denomina la base de los lo-
garitmos, en el estudio que nos interesa normalmente trabajamos con
logaritmos en base 2, pero como se explic´o en cap´ıtulos anteriores sim-
plemente se utiliza log sin importarnos la base.
2. log(ab) = log(a) + log(b)
3. log(a/b) = log(a) −log(b)
4. log(a
b
) = b log(a)
5. log
b
(x) = log
a
(x)/ log
a
(b)
6. a
log b
= b
log a
219
220 A. FUNDAMENTOS MATEM
´
ATICOS
A.2. Recordatorio de series
A.2.1. Series simples
Supongamos que u(n) es una funci´on definida para n valores. Si sumamos
estos valores obtenemos:
s(n) = u(1) + u(2) + u(3)........ + u(n).
Es muy com´ un el cambiar la notaci´on a la siguiente forma
s
n
= u
1
+ u
2
+ u
3
........ + u
n
.
o simplemente
s
n
=
n

i=1
u
i
.
A.2.2. Serie aritm´etica
Una serie aritm´etica puede expresarse como una secuencia en la que existe
una diferencia constante, llamada raz´on, entre dos elementos contiguos. La
notaci´on matem´atica para describirla es como sigue:
s
n
= a, a + d, a + 2d, ........, a + (n −1)d.
La suma de los primeros n t´erminos de una serie aritm´etica puede expresarse
como
s
n
=
n

i=1
a
i
=
n(a
1
+ a
n
)
2
= an + n(n −1)
d
2
donde d es la raz´on ´o sea la diferencia entre dos t´erminos.
A.2.3. Serie geom´etrica
Una serie geom´etrica es una secuencia de t´erminos donde los t´erminos
tiene la forma
a, ar, ar
2
, ar
3
...., ar
n
la suma de ´esta serie podemos expresarla como sigue:
s
n
=
n

i=0
ar
i
=
a(1 −r
n
)
(1 −r)
A.2. RECORDATORIO DE SERIES 221
en general la suma de una serie geom´etrica tiende a un l´ımite solo si r
n
tambi´en tiende a un l´ımite. De esto podemos decir que una serie geom´etrica
es convergente s´ı y solo s´ı −1 < r < 1.
A.2.4. Propiedades de la sumatorias
Propiedad distributiva
n

i=1
ci = c
n

i=1
i (A.2.1)
Propieadad asociativa
n

i=1
(a
i
+ b
i
) =
n

i=1
a
i
+
n

i=1
b
i
(A.2.2)
Propiedad conmutativa

i∈K
a
i
=

p(i)∈K
a
p
(i) (A.2.3)
A.2.5. Series importantes
s
n
=
n

i=1
1 = n (A.2.4)
s
n
=
n

i=1
i = n(n + 1)/2 (A.2.5)
s
n
=
n

i=1
i
2
= n(n + 1)(2n + 1)/6 (A.2.6)
s
n
=
n

i=1
i
r
= n
r+1
/r + 1 +p
r
(n) (A.2.7)
donde r es un entero positivo y p
r
(n) es un polinomio de grado r.
H
n
=
n

i=1
1
i
(A.2.8)
´esta serie se denomina serie arm´onica serie arm´onica y log(n + 1) < H
n

1 + log n
222 A. FUNDAMENTOS MATEM
´
ATICOS
A.3. Combinatoria b´asica
Una permutaci´on de n objetos es un arreglo ordenado de los objetos. Por
ejemplo si tenemos 3 objetos a, b, c los podemos ordenar de 6 maneras:
a b c a c b
b a c b c a
c a b c b a
El primer elemento se puede escoger de n formas, luego el segundo de
n −1 maneras, y as´ı sucesivamente por lo que
n(n −1)(n −2)...,2,1 = n!
Una combinaci´on de r objetos de n objetos es una selecci´on de r objetos sin
importar el orden y se escribe:
_
n
r
_
=
n!
r!(n −r)!
A.3.1. F´ormulas importantes
_
n
r
_
=
_
n −1
r −1
_
+
_
n −1
r
_
(A.3.1)
(1 +x)
n
= 1 +
n

i=1
_
n
i
_
x
i
(A.3.2)
n

i=0
_
n
i
_
= 2
n
(A.3.3)
n

i=0,i impar
_
n
i
_
=
n

i=0,i par
_
n
i
_
(A.3.4)
A.4. PROBABILIDAD ELEMENTAL 223
A.4. Probabilidad elemental
La teor´ıa de la probabilidad est´a asociada a los fen´omenos aleatorios, esto
significa, los fen´omenos cuyo futuro no es predecible con exactitud.
Todas las posibles salidas de un experimento al azar se denomina espacio
muestral. Por ejemplo cuando lanzamos un dado com´ un existen seis posibles
salidas que son los n´ umeros del 1 al 6. Para este experimento el espacio
muestral es S = ¦1, 2, 3, 4, 5, 6¦. El espacio muestral puede ser finito o infinito,
contin´ uo o discreto. Se dice que es discreto cuando el n´ umero de puntos de la
muestra es finito o si pueden ser etiquetados como 1,2,3,4 y as´ı sucesivamente.
Un evento es una colecci´on de puntos de una muestra que a su vez un
subconjunto del espacio muestral. Se dice que un evento ocurre cuando al
realizar un experimento aleatorio obtenemos un elemento de un conjunto.
Por ejemplo si lanzamos un dado el resultado obtenido es parte del conjunto
de n´ umeros impares. Denominamos al conjunto ¸ el evento imposible y a
todo el conjunto muestral al evento universal.
La probabilidad es una medida que asigna a cada evento A del espacio
muestral un valor num´erico un valor Pr[A] que da la medida de que A pueda
ocurrir.
1. Para cada evento de A ≥ 0
2. Pr[S] = 1
3. Si A y B son mutuamente excluyentes vale decir A ∩ B = ¸ entonces
Pr[A ∪ B] = Pr[A] + Pr[B]
4. Pr[
¯
A] = 1 −Pr[A]
5. Pr[A ∪ B] = Pr[A] + Pr[B] −Pr[A ∩ B]
6. Pr[A[B] =
Pr[A∩B]
Pr[B]
7. Dos eventos son independientes si Pr[A ∩ B] = Pr[A]Pr[B]
8. Para indicar la suma de los eventos de S utilizamos la notaci´on:
Pr[X = x] = Pr[A
x
] =

∀sεS
Pr[s]
224 A. FUNDAMENTOS MATEM
´
ATICOS
9. La esperanza matem´atica la representamos como
E[X] =

x
xp(x) =

∀sεS
X(s)Pr[s]
10. La varianza escribimos como σ
2
x
y la definimos como
E[X] =

x
x(p(x) −E[X])
2
11. La desviaci´on standard se define como la ra´ız cuadrada de la varianza
y se representa por el s´ımbolo σ
x
A.5. T´ecnicas de demostraci´ on
A.5.1. Demostraci´on por contradicci´on
La prueba por contradicci´on es conocida como prueba indirecta y consiste
en demostrar que la negaci´on de una aseveraci´on nos lleva a una contradic-
ci´on.
Por ejemplo si deseamos probar que la proposici´on S es correcta debemos
primeramente negar S y luego demostrar que S es falso.
Ejemplo: Demostrar que existe un n´ umero infinito de n´ umeros primos.
Para resolver esto se ve que S est´a dada por la frase existe un n´ umero
infinito de n´ umeros primos y la negaci´on de ´esta seria existe un n´ umero finito
de n´ umeros primos. si demostramos que esto es una contradicci´on entonces
la aseveraci´on inicial S es verdadera.
Demostraci´on: Supongamos que existe un n´ umero finito de n´ umeros pri-
mos P = p
1
, p
2
, ...., p
n
entonces si encontramos un n´ umero primo P
n+1
habr´ı-
amos demostrado que el conjunto no contiene a todos los primos por lo cual
S es falso. Sea P
n+1
= p
1
∗ p
2
....p
n
+ 1 claramente se ve que el resultado
es un n´ umero primo, por lo tanto se demuestra que el conjunto de n´ umeros
primos no es finito y queda demostrada nuestra hip´otesis original el conjunto
de n´ umeros primos es infinito.
A.5.2. Demostraci´on por inducci´on
Existen dos t´ecnicas que normalmente se utilizan que son la deducci´on y la
inducci´on. La deducci´on consiste en ir de un caso general a un caso particular.
A.5. T
´
ECNICAS DE DEMOSTRACI
´
ON 225
En cambio la inducci´on matem´atica trata de establecer una ley general en
base a instancias particulares. Este razonamiento puede llevar a resultados
err´oneos si no se plantea adecuadamente. Sin embargo la deducci´on siempre
lleva a resultados correctos.
El principio de inducci´on matem´atica se basa, primeramente demostrar
la validez de nuestras suposiciones para valores de 0, 1, 2, .. y luego de que,
nos hacemos alguna idea de como se comporta suponemos que, para un valor
arbitrario n es correcto. En base de ´esta suposici´on demostramos que para
n −1 es correcto con lo cual se demuestra nuestra suposici´on original.
´
Indice alfab´etico
´arbol, 164
ejemplo, 165
, 221
afirmaciones, 92
assert, 93
Java, 93
algor´ıtmica elemental, 1
Algoritmo, 1
an´alisis amortizado, 17
apriori, 3
b´ usqueda, 101
binaria, 103, 105
eficiencia, 101
secuencial, 101, 102
eficiencia, 102
Backtracking, 171
cadenas, 138
Carmichael, 52
Cercos convexos, 198
ejemplo, 202
m´etodos, 204
clasificaci´on, 101, 111
arrays, 113
burbuja, 117
eficiencia, 118
comparaci´on, 124
compareTo, 115
inserci´on, 118
Java, 113
pivote, 121
r´apida, 120
eficiencia, 122
selecci´on, 120
eficiencia, 120
sort, 113
una pasada, 123
eficiencia, 124
coeficientes binomiales, 139
aplicaciones, 139
cola prioridad, 166
ejemplo, 166
combinatoria, 137
contar, 137
complejidad, 11
congruencias, 45
ecuaciones, 45, 46
inverso, 45
potencias, 45
propiedades, 45
reflexiva, 45
sim´etrica, 45
suma, 45
transitiva, 45
conjuntos, 160
ejemplo, 161
Construir permutaciones, 179
en desorden, 179
226
´
INDICE ALFAB
´
ETICO 227
en orden, 180
demostraci´on por contradicci´on, 224
demostraci´on por Inducci´on, 224
desviaci´on standard, 224
divide y vencer´as, 22
divisibilidad, 38
divisor com´ un, 38
eficiencia, 1–3, 7, 11, 101, 123, 124,
127
emp´ırico, 2
Eratostenes, 47, 94
errores de programaci´on, 62
ejemplo, 62, 64
ejemplo C, 63
espacio muestral, 223
especificaci´on, 66
especificar, 107
estructuras de datos, 153
estructuras recursivas, 15
estructuras secuenciales, 14
Euclides, 39, 40, 74
Euclides complejidad, 40
Euclides extendido, 41
factores primos, 49
factorizaci´on, 49
Fermat, 51
Fibonacci, 24, 82, 141
geom´etrica, 221
geometr´ıa, 189, 190
Java, 196
l´ınea, 192
punto, 190
grafo, 171
grafos
ejemplo, 172
recorrido, 171
ineficiencia, 118
instancia, 2, 3, 6, 7, 9–11
invariante, 67, 68, 70–80, 85
aplicaciones, 75
Java Modeling Language, 96
JML, 96
anotaciones, 96
compilar, 96
cuantificadores, 98
ejecutar, 96
ensures, 96
invariante, 97
invariante ciclo, 97
invariante clase, 97
requires, 96
listas enlazadas, 157
ejemplo, 158
m´etodos, 157
logaritmos, 12, 219
m´aximo com´ un divisor, 37, 38, 40
m´etodo iterativo, 20
m´etodo te´orico, 3
m´ınimo com´ un m´ ultiplo, 43
map, 162
ejemplo, 162
master, 22
Miller - Rabin, 52
modular, 43, 44
n´ umero Euleriano, 143
invariante, 145
tri´angulo, 144
n´ umero Stirling, 146
n´ umeros Catalanes, 142
228
´
INDICE ALFAB
´
ETICO
aplicaciones, 143
n´ umeros grandes, 53
n´ umeros primos, 47, 49
generaci´on, 47
notaci´on asint´otica, 3, 13
notaci´on omega, 13
notaci´on teta, 13
O grande
igualdad logaritmos, 12
l´ımites, 12
propiedades, 12
transitiva, 12
operaciones elementales, 6
orden de, 11
permutaci´on, 138, 222
pila, 153
ejemplo Java, 153
lista LIFO, 153
pol´ıgono, 189
´area, 190
b´ usqueda, 189
convexo, 189
intersecci´on, 189
partici´on, 189
pol´ıgonos
Java, 205
Post condici´on, 67, 68, 72, 74–77, 79–
81
post condici´on, 91, 96
precondici´on, 66, 67, 74, 75, 91, 96
probabilidad, 223
probable primo, 54
programa certificado, 106, 107
programa probado, 106
prueba de primalidad, 51
prueba de programas, 61
caja blanca, 61
caja negra, 61
verificaci´on, 61
prueba din´amica, 92
prueba est´atica, 91
proceso, 91
prueba exaustiva, 105
recurrencias, 18
recurrencias lineales, 23
regla de la suma, 138
regla del producto, 137
regla exclusi´on, 138
regla inclusi´on, 138
representaci´on gr´afica, 108
RSA, 55
Serie aritm´etica, 220
Serie geom´etrica, 220
Series Simples, 220
Subconjuntos, 175
ejemplo, 176
subconjuntos, 138
substituci´on, 18
sumatoria
propiedades, 221
te´orica, 3
teor´ıa de n´ umeros, 35
tiempo proceso operaciones, 35
tipos de algoritmos, 3
tri´angulo de Pascal, 139
invariante, 140
triangulaci´on, 189
triangular, 207
variables Java, 35

ii

Prefacio
Motivaci´n o
Los conceptos presentados se estudian en muchas de las materias del pregrado de la carrera de inform´tica, con el rigor necesario. Sin embargo, a en mi experiencia docente he podido ver que hay muchos estudiantes que carecen de elementos pr´cticos con los que puedan aplicar directamente los a conceptos aprendidos y lo que se pretende es cubrir este vac´ ıo. El presente texto trata de introducir los conceptos de programaci´n, a o estudiantes de pregrado con un enfoque nuevo. Para una adecuada compresi´n de la tem´tica presentada en el libro, el o a lector debr´ tener alguna experiencia en el desarrollo de programas. El libro a no pretende ense˜ar a codificar programas, sino a resolver problemas. n

Contenido
Se presentan en el cap´ ıtulo 1, los conceptos de algor´ ıtmica elemental con el prop´sito de introducir a los estudiantes, al concepto de la eficiencia de los o programas. El cap´ ıtulo dos introduce los conceptos de an´lisis de algoritmos con una a serie de ejercicios aplicados. Se incluyen algunos laboratorios que tienen el prop´sito de que, los estudiantes asimilen estos conceptos en forma experio mental. El cap´ ıtulo tres introduce el concepto de la teor´ de n´meros, introduıa u ciendo las librer´ de Java. Se muestran ejemplos de n´meros grandes y ıas u aplicaciones en la criptograf´ ıa. El cap´ ıtulo 4 trata de la escritura de programas con miras a la prueba del c´digo. En este cap´ o ıtulo se introduce un concepto que es el dise˜o por conn iii

iv tratos y la forma de aplicar en Java. Aunque este concepto fue introducido inicialmente en el lenguaje Eifel, actualmente tiene mucho inter´s en el dee sarrollo de aplicaciones. El texto no trata de trabajar en conceptos de l´gica o formal en su totalidad, lo que propone es una introducci´n a estos conceptos o para facilitar la prueba del c´digo en forma din´mica. o a El cap´ ıtulo 5 complementa el cap´ ıtulo 4 con conceptos de clasificaci´n y o b´squeda . Se introducen laboratorios y las bibliotecas Java para clasificar. u El cap´ ıtulo 6 est´ orientado a explicar como se encara la programaci´n a o de problemas de combinatoria b´sica. a El cap´ ıtulo 7 explica como utilizar las librer´ del lenguaje Java y como ıas resolver problemas con pilas, listas enlazadas, conjuntos, ´rboles y colas de a prioridad. EL cap´ ıtulo 8 introduce al estudiante a los problemas de retroceso (bactracking) con problemas t´ ıpicos, como recorrido de grafos y permutaciones. El cap´ ıtulo 9 introduce a la geometr´ computacional. Muestra como consıa truir una librer´ de rutinas b´sicas para desarrollar aplicaciones relacionadas ıa a a la geometr´ y muestra las librer´ Java as´ como las posibilidades que se ıa ıas ı tienen con las mismas. El lenguaje que se escogi´ fue el Java, primero porque la formaci´n o o est´ orientada a la programaci´n orientada a objetos. Segundo porque el a o lenguaje es de amplia utilizaci´n en las empresas y en la educaci´n. o o Los enunciados orientados a la programaci´n fueron tomados de los cono cursos de programaci´n, fueron traducidos al espa˜ol manteniendo los datos o n de entrada y salida en ingl´s. Esto se hizo para permitir a los interesados e resolver los problemas y poder validar sus respuestas con el Juez en L´ ınea de Valladolid, en su p´gina web http://acm.uva.es. Estos ejercicios llevan a adelante el n´mero de problema del Juez en L´ u ınea de Valladolid.

Aplicaci´n en el aula o
Esta tem´tica puede aplicarse en el transcurso de un semestre en clases a te´ricas, pr´cticas y de laboratorio. o a Los laboratorios proponen ejercicios que tienen la finalidad de evaluar experimentalmente la ejecuci´n de los algoritmos. Esto permite que los estuo diantes obtengan una vivencia de los resultados te´ricos. o Se puede aplicar en una clase de teor´ de dos per´ ıa ıodos y una segunda clase que ser´ de ejercicios o laboratorio. ıa

Hay que aclarar que todos han sido codificados utilizando el compilador Java 1. a . Jorge Ter´n Pomier. o o Agradecimientos Quiero agradecer a mi esposa. M. a mis hijos por los aportes realizados y finalmente al Dr.v Contenido del CD El CD adjunto contiene los programas presentados en el texto.5 de Sun Microsystems.4.Sc. dado que a la fecha de la redacci´n de la obra no estaba disponible o o una versi´n de JML que funcionara con la versi´n 1. Miguel Angel Revilla por dejarme reproducir ejercicios del Juez en L´ ınea.5. Lic. El cap´ ıtulo 4 relacionado a JML fue codificado con la versi´n 1.

vi .

. Algoritmo . . . . .1. . . . Introducci´n . . e e 1. . caso a 1. .2. . . . .6. . . . . . . . . . . . . a 2. . . . . . . . Operaciones elementales . . . . . . . . . . Notaci´n asint´tica condicional . . . . . . . 1. . .4. . . . .3. . . . . . . . .5. 2. Ciclos For . o 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o vii . o 2. . . . . 1. Notaci´n omega . . Secuenciales . . . . . . 2.´ Indice general Prefacio 1. . .3. . . . . . o o 2. . . . . . . .6. . . .5. . . . . . . An´lisis amortizado . . . . . . . . . . .6. 1. . . . . . . . . . Soluci´n de recurrencias . 1 1 1 2 2 4 6 6 7 7 11 11 11 12 13 13 13 14 14 14 15 15 16 17 18 2. . . . . . . 1. .4. . . . . . .4. .1. . . . .5. . . . . . . . . . . . . . . . . . . . . . . . Ciclos while y repeat . . . . . . . . . . . . . . . . . . . . . . medio y peor caso . . . . . . . . . . . . . . . . .2. . . III . . Problemas e instancias . .2. . . . . . . . . . Notaci´n teta . . . . . . . . . . . . . . . . . . Ejercicios .6. .6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1. . . . An´lisis del mejor caso. .1. . . . . o 2. . . . . . . . . . . . . . . . . An´lisis de algoritmos a 2. . Eficiencia . . . . . . . . . . . . a 2. . . . . . . . . . . . . . . . .2. . .5. . 2. . . . . . . . . . . . . . . . . .6. . . . . . . . . .7.1. . . . . . .2. . Laboratorio . 2. . . . . . . . . . . . . . . . Notaci´n orden de . .6. . . . . . . o 1. . An´lisis de las estructuras de control a 2. 1. . . . . . . . o 2. . . . . . . . . . . . . . . . . .3.4. . .5. . . .5. Introducci´n . .3. . .5. . . . . . . . . . Algor´ ıtmica elemental 1. An´lisis del caso medio . Llamadas recursivas . . . . . . .6. . . . . . . . . . . Propiedades de O grande de n 2. . . . . . . . . . Qu´ considerar y qu´ contar . . . . . .

Algoritmos extendido de Euclides . . . . . . . . . . . . . . . . 3. . 2. . . . . . . . . . . . 3. . . Bibliotecas de Java . . . . . 2. . . u 3. . u 3. . . . M´ ınimo com´n m´ltiplo . . 2. 2.6. . e 2. .8.6. . . . . . . .1. . . . . . C´lculo del m´ximo com´n divisor . . . .El problema de Euclides 3. . . . . . . . . . . . . 18 19 20 20 22 22 23 27 32 34 35 35 35 37 38 41 43 43 44 45 45 45 47 47 49 51 51 52 52 53 54 57 57 58 59 59 60 2. . . . . . . . .2. . . .7. . . . . .5. Factorizaci´n . . 3. . o 3.3. . . . . . . . . .2. . . . . . . 3. . . .8. .7. . . . . . Ejercicios . . . . Congruencias . . . Variables del lenguaje Java . . . . . . . . . . .2. . Teorema de Fermat . . . . . Generaci´n de primos . Inverso multiplicativo . . . . . . 3. . . . . . . 2. . . . . . . Problema 10104 . .7.5. . .4. . Prueba de Miller . Ejemplo . . . . . . . . . . . . .2. . . . . . . . .5.3. . . . . . . u u 3.1. . . . . . . . . . . . . . . . 3. . . . . . .N´meros De Smith . . .N´meros Feos . Ejercicios resueltos . . . Cambio de variables . . Problema 10139 . . . . . . . . . .4. . . . . .5. . Propiedades . . . . Soluci´n general de recurrencias lineales o 2. . . .8. . . . . Ejercicios . . . .6. . . . . . . . . e 3. . . . 3. .7. . . . .Rabin . .3. . .Factovisors . . . .6. . . . . . .6. . . . . . . . . . . .7. . . . Problema 10042 . . . . 3. . .10. . . . . . Introducci´n . . . . . . . . . . . o 3.7. 3. . . . . . . .1. . . . . . . . . . . . . . . . . . . . . .4. . o 3. .5. . Nota sobre el c´lculo integral . . . . . . . . . . . N´meros primos .9.7. .viii ´ INDICE GENERAL . . . . . . . . . . . . .7. . . . . .5. .2. . . . . . . . . . . . . . . . . . o 3. . . . . a 3. .6. Ejercicios . . . . . . . Problema 136 . . Divisibilidad . . . . . .1. . . . . . Otras pruebas de primalidad . . .5. . . . . .1. M´todo iterativo . . . . . . Aritm´tica modular .Fermat vs. . a a u 3.1. . . . . . . . . . Teor´ de n´ meros ıa u 3. . . . . . . . . . . . . .3. . . . . . . . . . . . . . . . . . . . . . Soluci´n de ecuaciones . . . . . . . . . . . . . . . . Prueba de la primalidad . . .6. . . . . a . . . . . . . . .5. . . .6. . e o 2. . . . . . . . . . . . . . .4. . . 3. . . . . . . . . . . . . . . . . . . . .3. 3.7. . . . . . . .2. 3. . . . . . . . . . . . Teorema master . . . . . . . . . . . . . . . . . . . . . . . .3. . . .1. . . . . . . . . . .8. . . . .4. .3. . . . . . . . . 2. . . . . . . . Pit´goras . . . . . . . . . . . u 3. . . . . . . . .8. . . . . 3. . . . . . . . . . . . . . . . . . . . . . . . . . Ejercicios . . . . . . . .8. . 3. . . .7. . . .8.6. . . . . . M´todo por substituci´n . Problema 106 . . . . . . . . . . . . . . .

Principio de correctitud . . . . 4.4. Introducci´n .8. . . . . . . .3. . . .1. .4. . . ¿Qu´ especificar? . . . . . . . . . .3. . . Algoritmos de clasificaci´n . . . . . . . . 4. 5. o a u 5. . Afirmaciones .1. . . . . . . . . . . . . . .4.2. . . . . Problema 499 . . . . . . . . . . . . . . .1. . . . . . o 4. . . . .3. . . . . . . e 4. . . . . . . . .3. . . . . .2. . Clasificaci´n . . .3. . . . . . . . . .2. . Laboratorio . .3.3. . . Ejercicios . . . e 4. 4. . . . . . . . . . . . . . . . . . Especificaci´n de programas . . . . . .1. . . u 5. .7. Prueba din´mica . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6. .8. . . . . . .3. . . . . . . . Especificaci´n de invariantes . . . . . .4. . . . . . . . . . . Cuantificadores . . . Ejercicios . . . . . . . . . a 4. Problema 10107 .2. . . . . . . .4. . . . . . . . . . . . . . . 4.1. . . . . . o 5. . . . . . .3. .1. . Introducci´n . o 4. a 4. . . .3. . . . . . . Algunos errores de programaci´n . . 4. . . . . . . . . . . n 4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .´ INDICE GENERAL 4. . . . . . . . . . . . . o 5. .7. . .5. . . . . . . . . . . .2. . . . . . . Especificaci´n de contratos . . . . . o 5. . . . . . . . . Problema 10295 . . . . . 4. o 4. . . . Ejemplo de aplicaci´n . . . . . . o 5. . Invariantes . 5. 5. . . . . . . . Ejercicios propuestos . . . . . . . . . Algoritmos de b´squeda . . . . . . . . . . . .2.4. . . . . . . Prueba est´tica . . . .8. . . . . . . . . . . . . . . . . . . . . . . . a 5. . . . . . . . . . . . . . . . . . . Prueba exhaustiva . o 4. . . . . . Invariantes . . . Ejercicios . Representaci´n gr´fica de la b´squeda .1. .5. . . . . Problema 331 . . . . . . . . Clasificaci´n en Java . . . . . . . . . . . . . .2. . . . . . . . . .5. .4. . . . . . . . . . . .2. . . ¿Por qu´ especificar? . . . . . . . . o 4. .Hallar la mediana . . . . . . . . . . . .3. .4. Dise˜o por contratos . .3. . . . . . . . . . . . . . . . . . . . . . . . .5.4. . . . . . . . . . . .1. . . . . . . . o 5. 5. . . . . . . . . Codificaci´n con miras a la prueba o 4. . . . . . . . . . . . . . . . . . . .3. . . . . . . . . . .1. .1. .C´lculo de salario . ix 61 61 62 66 68 69 70 71 74 75 84 85 88 90 91 92 92 95 97 98 99 101 101 101 105 107 111 113 117 127 127 127 131 131 132 134 135 . . . . . . . .2. . ¿C´mo especificar? .Contando los intercambios 5. . Aplicaciones de las invariantes .8. . . . . . . 4. . . . . . . 5. . . . o 4. . . . .3. . . .Hallar la frecuencia . . . .3. . . . . . . Programaci´n bajo contratos con JML o 4. . 5. . . . .5. . . . . . . .4. . . . . . . .2. . . . . . . . . . . . . . . . . . .3. Aplicaciones de b´ squeda y clasificaci´n u o 5. .

. 7. . . . . . . . . . . . . . . . . . . . . . . N´meros de Fibonacci . . . . . 179 . . . . . . . . . . . . . . . .5. . . . . . . . . .5. . . . . . e a 6. . . . . . .Anagramas . . . Coeficientes binomiales . . . . . . . . Construir todas las permutaciones . . . . . . 7. . 7.1. . . . . . Particiones enteras . Constuir todos los subconjuntos .5. . . . 8. . . . . . .2. . . . . . . Introducci´n . . Introducci´n . .Mal educados . . . . . . . . . . . .4. . 8. . . . . . . . . . . . . Problema 216 . u 6. . . . . . . . . T´cnicas b´sicas para contar . . . .Combinaciones . . . . . .5. . . . . .5. Algunas secuencias conocidas . . 171 . . . .4. . . . . .3. . .1. . . . . . .5.5. . . . . . . . 7. . .3. . . . .Formas de combinar monedas 6. . . . . . . .7.1. . . . . . . .Sum It Up . . . . . . o 6. Problema 10338 . Ejercicios . . . . . . . . . . 171 . . . . . . 6.Hacer la l´ ınea . . . . . Problema 10183 . . . . . . 6. . u 6. . . . . . . . . . . . 8. . .3. . . . . Prolema 574 . . . . . . . . . . . . 6. Problema 369 . . 186 . . N´meros Catalanes . . .2. . . . . . . . . . . . . . Ejercicios . Pilas . . . . . . . . . . . . . 175 . 7. 171 . Listas enlazadas . . 6. . . . . . o 8. . . . . . o 7.Anillos de primos 8. . . .2.5. . . . . . . . . . . . Introducci´n . 185 . . . . . . . . . . . . . u 6. . . . . . . . . . . . . . 6. . . 183 . . . . . . Problema 357 . .1. . . . Clases para ´rboles . . . . . . . . .4. .1. . . . . . . . . Backtracking 8. . . . . . . . . . . . . 7. . . Clases map . . .4. . . Problema 524 . . . . Estructuras de datos elementales 7. . . . . . . . . . . . . . . . . . . . . . . .5. . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . Combinatoria b´sica a 6. . . . . . . . . a 7. .3. . . .4. .4. . . . . . . . . Recorrido de grafos . . . . . 6. . . Prolema 195 . . u 6. . . . . . . . . . . . . . . . . 8. . . . . . . . .4. . . . . . . . . . . . . . N´mero Eulerianos .Secuencia de Fibonacci . . . .2. . . . . .8. . N´meros de Stirling .5. . . . . . . . . . . . . .4. .5. . . . . . . . 182 . . . . . . . .4. . . . .3. . . .5. Clases para colas de prioridad . . . . 8. . . . . . . . . . . .x ´ INDICE GENERAL 137 137 137 139 141 141 142 143 146 146 149 149 150 151 152 153 153 153 157 160 162 164 166 168 6.3. 8. . . . .2. 182 . . . . . . . . .2. . . . . . . Conjuntos . . . . .6. . . . . . .1. . . . . . . . . . . . 8. . .4. . Ejercicios para laboratorio . .

. . . . . . . . . . .3. . . . ıas 9. . . . . . . . 9. . . . . . . . . . .4. Recordatorio de series . Series importantes . . . . . . . Geometr´ . . . . . . . . . . . . . . Serie aritm´tica . . . . . . . . . . .7. . . . . ıa 9. . .2. . .7. . . . . Problema 273 . . . . . . . . . . e A. A. . . . . . . e A. . .4. . . . . Demostraci´n por contradicci´n o o A. . . . . . . .2. .L´ ıneas que intersectan 9. . . . . .2. . . . . . . . . . . . . a A. . Serie geom´trica . . . . . . . . . . . . . . . Recordatorio de logaritmos . . Demostraci´n por inducci´n . . A. . . .2. .2. . . . . . . .1. . . . . . . . . . . . . . . . . . Problema 378 . . . . Ejercicios . . . . . . . . . . .Juego de Palos . . . . . . . . . . . . . . . . . . . Geometr´ computacional ıa 9.3. . Propiedades de la sumatorias . . . . .2. .4. . . .4. . .2. . . . . . . . . . . . . . . . . A. . . . . Series simples .3. . . . . Problema 476 . . . . . . . . . . . . . . .7. . . .1. . . . .Erradicaci´n de moscas o 9. . . . o o xi 189 189 190 196 198 205 207 211 211 212 214 216 219 219 220 220 220 220 221 221 222 222 223 224 224 224 . . . . . . . . . . C´lculo del per´ a ımetro y ´rea del pol´ a ıgo-no. . . . . . 9. .7. . . . F´rmulas importantes . . A. . . .1. . . . . .5. . . . . . . . A. . . . . . . . . . . . . . o 9. . . . . . . . . . . . . . . . . . . . Librer´ de Java . . .1. T´cnicas de demostraci´n .3. .7. . . . . . . . . . Probabilidad elemental . . . . . . . Cercos convexos . 9. . . 9. . . . . . e o A.5. . . . . . . . . . . . . . . . . . . . Clase Java para pol´ ıgonos .´ INDICE GENERAL 9.1. . .2. . . . . . o A. . . . . . . . . . .5.1. . . . . Combinatoria b´sica . . . . . . . . . . . Fundamentos matem´ticos a A. . . Introducci´n .2.5. . . . . . . . . . .3. . . . . . . . . . . . . . . . . . . . . . . .6. . .5. . . .2. . A. . . . . 9. .Puntos en rect´ngulos a A. . . Problema 218 . .

xii ´ INDICE GENERAL .

siempre y cuando no tenga detalles tales como sal al gusto. problema. efie ciencia e investigaremos m´todos para probar la eficiencia de los mismos. que son apreciaciones subjetivas del que prepara la receta. Algoritmo Definimos como algoritmo a un conjunto de pasos necesarios para resolver un problema ya sea manualmente o por m´todos mecanizados que. e Existen m´todos formales para realizar pruebas rigurosas sobre la correce ci´n de los programas ´sta tem´tica est´ fuera del alcance del texto pero o e a a ser´ mencionada m´s adelante solo como referencia. dado que est´ en un ciclo infinito. a a ı La ejecuci´n de un algoritmo no debe incluir procedimientos intuitivos o o que requieran creatividad.Cap´ ıtulo 1 Algor´ ıtmica elemental 1. Por ejemplo. El concepto de algoritmos fue definido a inicialmente por el matem´tico Persa Al-Khowˆrizmˆ en el siglo diecinueve. una receta de cocina puede denominarse un algoritmo si contiene las instrucciones precisas para preparar algo. o cocinar hasta que est´ suave. u Si consideramos el sistema operativo veremos que no es un algoritmo porque no termina nunca. a a 1. Empezaremos definiendo algunos t´rminos tales como algoritmo. a 1 . instancia. Introducci´n o En este cap´ ıtulo empezamos el estudio de los algoritmos. e Debemos indicar que los algoritmos deben cumplir un requisito fundamental y es que todo algoritmo debe terminar en un n´mero finito de pasos.1. e son los m´s usuales en la actualidad.2.

3. a a Para analizar ´sto tenemos dos m´todos. Eficiencia Cuando tenemos que resolver un problema pueden existir muchos algoritmos disponibles. De aqu´ nos e ı viene la pregunta ¿Cu´l es mejor? a Si tenemos un problema sencillo con algunas pocas instancias escogemos. o Tenemos los m´todos que aprendimos en la escuela. e ıcil Existen limitaciones propias de las computadoras que ponen restricciones a los algoritmos. se a trata de analizarlos en forma abstracta inicialmente. pero en el transcurso del texto tambi´n tocaremos aspectos espec´ e ıficos sobre la implementaci´n y o la eficiencia de los mismos. ¿Cu´l de o o a ´stas posibles soluciones hay que implementar? Esta decisi´n corresponde a e o un ´rea muy desarrollada en el campo de la inform´tica denominada an´lisis a a a de algoritmos. n u espacio de memoria o almacenamiento. 1. Estas pueden ser debido al tama˜o de los n´meros.2 1. e a Para demostrar que un algoritmo es incorrecto. u 1.4. es suficiente demostrar que es incorrecto para una instancia . El m´todo emp´rico tambi´n e e e ı e llamado a posteriori. ALGOR´ ITMICA ELEMENTAL Podemos citar algunos ejemplos de algoritmos conocidos. lo m´s f´cil y nos despreocupados de la eficiencia. el algoritmo para verificar si un n´mero es primo y muchos otros. consiste en programar todos los m´todos y probarlos e con diferentes instancias y con la ayuda de la computadora analizamos y . Una instancia particular ser´ por ejemplo multiplicar el n´mero 123 por ıa u el 4567 pero un algoritmo debe ser capaz de funcionar correctamente no solo en una instancia del m´todo sino m´s bien en todas las instancias posibles. As´ como es dif´ probar que un ı ıcil teorema es correcto tambi´n es dif´ probar que un algoritmo es correcto. Problemas e instancias Si pensamos los procedimientos para multiplicar n´meros que conocemos u veremos que hay varias formas de resolver el problema de multiplicaci´n. el m´todo de e multiplicar que aprendimos en la escuela. m´todos por divisi´n y e e o multiplicaci´n por 2 denominado multiplicaci´n a la rusa y otros. Obviamente quisi´ramos escoger el mejor. En el an´lisis de los algoritmos.

¿C´mo es que este m´todo te´rico llega a a a o e o a ser efectivo? Consideremos que el algoritmo toma un tiempo en segundos t1 (n) para una m´quina en particular y t2 (n) para otra. en funci´n del tama˜o de la instancia . El segundo llamado m´todo apriori es el an´lisis te´rico del algoritmo. La ventaja del m´todo te´rico es que u e o no depende de la computadora. e Retornando a la pregunta debemos indicar que la eficiencia se mide en tiempo. Esto indica que si cambiamos de equipo podemos ejecutar el algoritmo 10 o 100 veces m´s r´pido y que este incremento est´ dado solo a a a por una constante de proporcionalidad. o en otros u e por el n´mero de elementos a procesar. lenguaje de programaci´n o implementaci´n o o particular. . En el tratamiento del tema utilizaremos en algunos casos un m´todo e h´ ıbrido donde se determinar´ la eficiencia en forma te´rica y se hallar´n los a o a valores num´ricos en forma experimental. El tama˜o de una instancia normalmente est´ definida por el n´mero de n a u bits.4. Para esto diremos que un programa toma un tiempo del orden t(n) para una instancia de tama˜o n. M´s adelante trataremos un t´rmino m´s n a e a riguroso que es la notaci´n asint´tica. La notaci´n asint´tica dice que un algoritmo toma un tiempo del orden o o de. e a o que con la ayuda de las matem´ticas podemos determinar la cantidad de los a recursos requeridos por cada algoritmo en base del tama˜o de las instancias n consideradas.1. o o Si tratamos el tiempo en segundos uno podr´ pensar si tengo una m´quiıa a na m´s r´pida el tiempo ser´ menor. Para un n´mero n suficientea u mente grande podemos hallar unas constantes a y b tales que at(n) = bt(n) esto nos dice que cualquier ejecuci´n del algoritmo est´ acotado por una o a funci´n t(n) y existen unas constantes positivas de proporcionalidad que nos o dan el tiempo. Existen algoritmos que ocurren o n muy frecuentemente y ameritan tener un nombre que a su vez se denominan tasas de crecimiento. Lineales a los que toman tiempos proporcionales a n. Se denominan algoritmos: Constantes los que cuyo tiempo de proceso no depende del tama˜o de n la instancia. en el caso de un grafo por el n´mero de nodos y v´rtices. EFICIENCIA 3 escogemos alguno.

Qu´ considerar y qu´ contar e e Consideremos por ejemplo que queremos hallar el m´ximo de tres n´meros a u a.b). c. La figura 1. o o dado que las constantes ocultas pueden ser muy grandes y no llegar a ser tan eficientes para las instancias que deseamos procesar. A´n cuando es deseable siempre un algoritmo m´s eficiente desde el punto u a de vista te´rico podemos en muchos casos escoger en la implementaci´n otro. u Polinomiales o exponenciales a los que toman tiempos proporcionales a n3 . ALGOR´ ITMICA ELEMENTAL Cuadr´ticos a los que toman tiempos proporcionales a n2 . a C´bicos a los que toman tiempos proporcionales a n3 . Para resolver ´sto escribimos el siguiente c´digo: e o maximo=0 maximo=Max(a. b. Este mismo algoritmo lo podemos escribir ıan como sigue: maximo=0 if (a > b) .b) maximo=Max(c. Logar´ ıtmicos los proporcionales a log n. c. nk .1 representa las ordenes magnitud de los algoritmos.b) if a > b return a else return b Se puede ver que se requieren exactamente dos comparaciones para determinar el valor m´ximo de a.4 1.maximo) Max (a. Exponenciales los que toman tiempos proporcionales a 2n . b.c) tambi´n a e e se realizar´ dos comparaciones. 1. Si escribi´ramos Max(Max(a.5.

Se hace necesario establecer o .1: Ordenes de magnitud de algoritmos if(a > c) maximo = else maximo = else if b > c maximo else maximo a c = b = c Vemos que a´n cuando hemos codificado m´s comparaciones en la ejecuu a ci´n solo se ejecutan dos como el caso anterior.´ ´ 1.5. QUE CONSIDERAR Y QUE CONTAR 5 Figura 1.

1. Este claramente es el peor comportamiento que podemos tener. Operaciones elementales Es una operaci´n cuyo tiempo de ejecuci´n est´ acotado por una constante o o a que solo depende de una implementaci´n particular como ser la m´quina. Para ordenar A utilizar´ ıamos inserci´n(A). se consideran o o operaciones elementales. o En el ejemplo que realizamos estaremos interesados en medir el n´mero de u comparaciones necesarias para hallar el m´ximo. ´sto hace necesario defie nir. 1. Para comprender esto o n mejor consideremos el ejemplo del programa de clasificaci´n por inserci´n. ALGOR´ ITMICA ELEMENTAL que es lo que debemos considerar en los programas.5.6 1.5.2. El resto de las operaciones a las consideramos operaciones elementales. En el caso de que el vector estuviera ordenado en orden descendente por cada elemento hay que recorrer todo el vector intercambiando los valores. lo que se entiende por operaciones elementales. En el caso de la suma de elementos de un vector lo que deseamos medir es la cantidad de sumas realizadas para resolver el problema y las operaciones de comparaci´n necesarias para implementar una soluci´n. caso medio y peor caso a El tiempo que toma un algoritmo puede variar considerablemente en funci´n de diferentes instancias de un mismo tama˜o. An´lisis del mejor caso. el o a lenguaje de programaci´n. etc. o o inserci´n(t) o for i=1 to n x= t[i] j=i-1 while j > 0 and x<t[j] t[j+1]=t[j] j=j-1 t[j+1]=x Consideremos un conjunto A en el cual queremos procesar el algoritmo de ordenar. . Si la instancia o A est´ previamente ordenada en forma ascendente podemos probar que el a tiempo de proceso es el ´ptimo porque solo inserta valores en el vector y no o realiza intercambios. 1.

b) logar´ n ıtmico. Repetir el proceso para una instancia ordenada en forma descendente. Luego para una instancia generada aleatoriamente. .3. a a Por lo tanto un an´lisis util de un algoritmo requiere un conocimiento a priori a ´ de las instancias que vamos a procesar.4. 3.5. Tabular los datos. Codificar el algoritmo. 1. Ejercicios 1. Sin embargo si el vector estuviera desordenado en forma aleatoria el comportamiento se considera del caso medio. 6. Cuando el tiempo de respuesta de un problema es cr´ ıtico normalmente analizamos el peor caso que es mucho m´s f´cil de analizar que el caso medio. Para esto seguiremos los sie o guientes pasos: 1. ¿En qu´ porcentaje se incrementa el tiempo de proceso al doblar el e tama˜o de la instancia ? si el algoritmo es a) exponencial. Suponiendo que el tiempo de proceso de una instancia es un mili segundos. u 2. Tomar el tiempo de proceso para diferentes tama˜os de instancias. explique si lo que se u desea contar para hallar la eficiencia del algoritmo es: a) el n´mero de u d´ ıgitos b) el n´mero de divisiones que se deben realizar. Indique que es lo que deber´ ıamos contar en el caso de escribir un algoritmo para multiplicar dos n´meros a fin de hallar el n´mero de u u operaciones requeridas para completar el algoritmo. c) cuadr´tico? a 1. Laboratorio Se quiere analizar el comportamiento del algoritmo de ordenar por el m´todo de inserci´n en forma experimental.´ ´ 1. 5. n 4.5. 3. 2. QUE CONSIDERAR Y QUE CONTAR 7 Si el vector estuviera ordenado en forma ascendente no realizar´ ning´n ıa u intercambio y este es el mejor caso en el que se puede estar. Crear una instancia ordenada en forma ascendente.5. Si deseamos verificar que un n´mero es primo.

tiempoFin = System. tiempoInicio = System. ALGOR´ ITMICA ELEMENTAL Para realizar ´ste experimento construimos el siguiente programa Java: e import java. for (int i = 10. tiempoTotal. int n.currentTimeMillis(). i). arreglo.util.tiempoInicio. . Interpretar los resultados. } } } class Arreglo { int[] t = new int[100000]. i < instanciaMaxima. tiempoFin.out. tiempoTotal = tiempoFin . public class Isort { /** * Rutina Principal para la prueba experimental del * programa de ordenar por el m´todo de inserci´n e o * * @param args * 0 crear las instancias en forma descendente * 1 crear las instancias en forma ascendente * 2 crear las instancias en forma aleatoria */ public static void main(String[] args) { int opcion = Integer.8 7. System. 1.parseInt(args[0]).currentTimeMillis(). long tiempoInicio. Random generador = new Random(). i = i * 10) { Arreglo arreglo = new Arreglo(opcion.Ordena().println("Tama~o de la instancia " + i n + " Tiempo de proceso " + tiempoTotal). int instanciaMaxima = 1000000.*.

En diferentes ejecuciones del programa veremos que el tiempo de proceso que se obtiene en el caso medio var´ Esto se debe a que los datos ıa.i. case 2: t[i] = generador. for (int i = 1.1.1. t[j + 1] = x. i++) { x = t[i]. j. QUE CONSIDERAR Y QUE CONTAR 9 Arreglo(int opcion. case 1: t[i] = 10000 . int n) { this. while ((j > 0) && (x < t[j])) { t[j + 1] = t[j].nextInt(10000). break.1. break. i < n. . } } El resultado de los tiempos de ejecuci´n.´ ´ 1. obtenidos en o la prueba del programa se ven en el cuadro 1.n = n. El caso medio se da cuando el vector est´ ordenado a aleatoriamente.5. en mili segundos. Como se ve el peor caso es cuando la instancia que creamos est´ ordenada a en forma descendente. i++) { switch (opcion) { case 0: t[i] = i. } } } void Ordena() { int x. j = i . for (int i = 0. } } return. j = j . i < n.

. Una buena aplicaci´n de ´ste c´digo se da en los o e o casos en que los conjuntos de datos a los que vamos aplicar el m´todo. Situaci´n que no se da en las a o otras instancias generadas. ALGOR´ ITMICA ELEMENTAL Ordenada Descendente 0 0 20 1722 237622 instancia Aleatoria 0 0 10 861 110229 Cuadro 1.10 Tama˜o n Ordenada Instancia Ascendente 10 0 100 0 1000 0 10000 0 100000 10 1.1: Tiempo de ejecuci´n en milisegundos o que se generan no est´n en el mismo orden. est´n e a casi totalmente ordenados.

la notaci´n omega. solo nos referimos al tiempo tomado por el algoritmo multiplicado por una constante.2. n En este caso decimos que esta funci´n t(n) es del orden n2 dado que o solo est´ acotado por una constante. Ahora n supongamos que esta funci´n representa la cantidad de recursos que gasta el o algoritmo. Las constantes solo representan valores de una implementaci´n dada y no o tienen que ver con el tama˜o de la instancia. ya sea el tiempo de proceso. θ y O respectivamente. Notaci´n orden de o La notaci´n orden de nos permite especificar la magnitud m´xima de o a una expresi´n. Esto se denomina O grande de t(n) y a matem´ticamente lo representamos como O(n2 ). Se recomienda la bibliograf´ o ıa [McC01] y [EH96] 2. Existen o o tres conceptos. Como no existen mecanismos normalizados para el c´lculo de a estos tiempos. A esto denominamos notaci´n asint´tica. Esto se logra a trav´s del c´lculo del tiempo de proceso o e a complejidad . a 11 .1.Cap´ ıtulo 2 An´lisis de algoritmos a 2. Sea por ejemplo una funci´n t(n) = 5n2 y podemos pensar o o que n es como el tama˜o de una instancia de un algoritmo dado. la notaci´n teta y la notaci´n O grande o o o simbolizadas por Ω. Introducci´n o Para el an´lisis de los algoritmos es muy importante determinar la eficiena cia de los mismos. almacenamiento de memoria u otros. En el texto se enfocar´ al an´lia a sis del tiempo de proceso con la notaci´n O.

log n. Propiedades de l´ ımites. o Esto se demuestra aplicando la propiedad de los logaritmos para el cambio de base loga n = logb n/logb a. pero es correcta en a la notaci´n O. Igualdad de logaritmos. Regla del valor m´ximo. claramente es incorrecto en las matem´ticas. −n) a 3 cuyo valor es O(n ). a) si l´ n→∞ ım b) si l´ n→∞ ım f (n) g(n) f (n) g(n) + ⇒ f (n) O(g(n)) y g(n) O(f (n)) = 0 ⇒ f (n) O(g(n)) pero g(n)¬ O(f (n)) c) si l´ n→∞ f (n) = +∞ ⇒ ım g(n) f (n)¬ O(g(n)) pero g(n) O(f (n)) . Notamos que el denominador es una constante y como en la notaci´n O no se escriben las constantes o queda demostrado. ANALISIS DE ALGORITMOS 2.2. 3. 5. En la notaci´n O la expresi´n o o O(loga n) = O(logb n) que. Propiedad reflexiva. Propiedades de O grande de n Para aclarar lo que representa O grande de n describamos sus propiedades: 1. Dadas dos funciones f (n) y g(n) que pertenea cen a los n´meros reales positivos incluyendo el cero u O(f (n) + g(n) = max(f (n). Propiedad transitiva.1. La notaci´n O es reflexiva dado que: o f (n) O(f (n)) 4.12 ´ 2. 2. g(n)) por ejemplo si se tiene la funci´n t(n) = 5n3 + log n − n aplicando o la regla del valor m´ximo tenemos que O(t(n)) = max(5n3 . Sif (n) O(g(n))yg(n) O(h(n))entoncesf (n) O(h(n)).

Notaci´n teta o Cuando analizamos un algoritmo estar´ ıamos muy satisfechos si nuestro algoritmo estuviera acotado simult´neamente por Ω y O. Por esta raz´n se a o introduce la notaci´n θ. en las secciones siguientes estudiamos como resolver ´stas ecuaciones denoe minadas recurrencias. Por ejemplo el algoritmo de ordenamiento por inserci´n demora O(n2 ) en el peor caso sin embargo la cota inferior para o los programas de clasificaci´n que trabajan unicamente por comparaciones o ´ es Ω(n log n) por lo tanto podemos decir que no existen algoritmos de clasificaci´n que en su peor caso sean mejores que Ω(n log n).´ ´ 2.3. un n algoritmo cuyo resultado para n = 1 es t(n) = 1 y para otros valores toma nt(n − 1). Decimos que un algoritmo es en θ(f (n)) o que f (n) o es de orden exacto si: θ(f (n)) = O(f (n)) ∩ Ω(f (n)) . si o buscamos que la relaci´n se cumpla para un n´mero finito de valores de n. nT (n − 1) en otros casos. o u entonces f (n) es el l´ ımite inferior del algoritmo. 2. Notaci´n asint´tica condicional o o Muchos algoritmos son m´s f´ciles de analizar si restringimos nuestra a a atenci´n a instancias que cumplen alguna condici´n tales como ser una poo o tencia de 2.5. NOTACION ASINTOTICA CONDICIONAL 13 2. 2. Consideremos por ejemplo. ser de un tama˜o determinado. Notaci´n omega o La notaci´n omega que la representamos por Ω se utiliza para representar o la cota inferior de un algoritmo.3.4. Este algoritmo se expresa como una soluci´n recursiva que se o escribe como sigue: T (n) = 1 si n = 1. o Sea t(n) Ω(f (n)) si existe una constante real y positiva d tal que la relaci´n t(n) ≥ df (n) sea cierta para una cantidad infinita de valores de n.

14 ´ 2. Por la regla del o valor m´ximo el tiempo es (max(O(t1 ). o o 2. Comunmente se utiliza la notaci´n O y para mostrar la o relaci´n contra el mejor algoritmo posible usamos la notaci´n Ω.2. el proceso p2 no depende de los resultados de p1 . p2 toma un tiempo t1 + t2 .1. Este an´lisis considera que a a p1 y p2 son independientes. O(t2 )).6. La regla de secuencias indica que el tiempo de ejecuci´n de la secuencia p1 . ANALISIS DE ALGORITMOS Esta notaci´n se utiliza muy poco y como podr´ apreciar tiene un mayor o a grado de dificultad. Ciclos For Consideremos el programa siguiente for i = 1 to m p(i) En este programa no confundamos m con n que es el tama˜o de una instancia. An´lisis de las estructuras de control a Secuenciales Sean p1 y p2 dos fragmentos de un algoritmo y sean t1 y t2 los tiempos que toman cada uno respectivamente. 2. n Si p(i) toma un tiempo constante t y no depende de i entonces este tiempo se repetir´ m veces y denotamos esto como: a m m t=t i=1 i=1 1 = tm = O(m) En un caso mas general donde t(i) no es constante y depende de i deber´ ıamos calcular el resultado de la siguiente sumatoria: m t(i) i=1 .6. Esto es que.6. 2.

6. 2. En los otros casos depende del valor n − 1. Esto podemos representar por una funci´n recurrente de la siguiente forma: o  si n = 0.´ 2. Podemos resolver esta recurrencia y demostrar que la soluci´n es o o O(n). ANALISIS DE LAS ESTRUCTURAS DE CONTROL 15 2. El valor de h(n) es el n´mero de operaciones elementales requeridas en cada u recursi´n. Llamadas recursivas El an´lisis recursivo de un algoritmo es normalmente casi directo y una a simple inspecci´n normalmente nos da una ecuaci´n de recurrencia que reo o presenta el comportamiento del mismo. T (n) =  T (n − 1) + h(n) en otros casos. Consideremos el problema de buscar un elemento t en un arreglo a recursivamente busca (n) if n =0 return -1 else if a[n]= t return n else return busca(n-1) En este algoritmo podemos ver que para los casos en que n es 0 el tiempo que toma es una constante.4. cuando encuentra el valor tambi´n el tiempo es e una constante.  −1 0 si a[n] = t. Para terminar un ciclo hay que probar alguna condici´n que nos dar´ un valor de terminao a ci´n. Ciclos while y repeat Los ciclos while y repeat son mucho m´s dif´ a ıciles de analizar porque no existe una forma de saber cuantas veces se va a ejecutar.6.6.Consideremos el c´digo siguiente : o o ejemplo(n) i=0 while n>1 if par(n) n=n/2 .3.

6.. a En muchos casos ser´ necesario aplicar la teor´ de probabilidades para a ıa poder determinar las veces que una instrucci´n se ejecuta. ANALISIS DE ALGORITMOS i=i+1 else n=3n/2 i=i+1 return i En este ejemplo no podemos decidir a simple vista cuantas veces se ejecuta la instrucci´n i = i + 1 se ve que cada vez que n es una potencia de 2 se o pasar´ por la parte par(n) y cuya cantidad de veces ser´ el log2 n. An´lisis del caso medio a Consideremos el algoritmo de ordenar por el m´todo de inserci´n e o inserci´n(t) o for i=1 to n x= t[i] j=i-1 while j > 0 and x<t[j] . Los m´todos para resolver recurrencias se explicar´n m´s adelante. T (n/2) + 1 en otros casos. n/4. ¿El algoritmo termina?.. ¿Qu´ poa a e demos decir cuando es impar?. y luego de resolverla podemos indicar que el resultado es O(log n). Si podemos deducir o una recurrencia a partir del algoritmo podemos hallar f´cilmente su O(n). a ejemplo(n) i=0 while n>1 n=n/2 i=i+1 return i En este ejercicio vemos que los valores que toma n son n. n/2.16 ´ 2. e a a 2. por lo tanto podemos escribir esta recurrencia como T (n) = 1 si n < 2. Estas interrogantes las dejamos para el an´lisis del lector.5.

6. toma ordenar cada uno de las n! posibles instancias.´ 2. ANALISIS DE LAS ESTRUCTURAS DE CONTROL 17 t[j+1]=t[j] j=j-1 t[j+1]=x De este algoritmo podemos ver que en el mejor caso. Supongamos que enviamos a esta rutina un n´mero u . el algoritmo debe resolver. Definamos el rango parcial de T [i] como la posici´n que.¿Cu´l es el coma a portamiento en el caso promedio? Para resolver esta interrogante se hace necesario conocer a priori la funci´n de distribuci´n de probabilidad de las o o instancias que. Este rango parcial estar´ entre 1 y ıa a i y lo llamaremos k.6. vale decir cuando los datos vienen ordenados en forma ascendente. Como tenemos i a elementos la probabilidad que i ocurra es 1/i de aqu´ calculamos el tiempo ı que toma el ciclo while 1 ci = i i (i − k + 1) = k=1 i+1 2 como tenemos n elementos en el ciclo principal debemos sumar los tiempos de las instrucciones interiores dando n n ci = i=1 i=1 i+1 = 2 n i=1 i + 2 n i=1 1 n2 + 3n = 2 4 2. Supongamos que 1 ≤ i ≥ n y estamos ingresando en ciclo while. An´lisis amortizado a El an´lisis del peor caso es muchas veces muy pesimista.6. ocupar´ o ıa en el arreglo si estuviera ordenado. Si el vector est´ ordenado devolver el primero toma a un tiempo constante. T [i − 1] contiene los mismos elementos que antes. dado que T [i] todav´ no se ha insertado. La cantidad de veces que los elementos del vector se desplazar´n es i − a k + 1 porque los elementos hasta i − 1 ya est´n ordenados. Supongamos que a tenemos un programa con un vector que almacena valores y queremos encontrar el valor m´ ınimo. o Supongamos que todas las permutaciones posibles de las instancias pueden ocurrir con la misma probabilidad para determinar el resultado en promedio debemos sumar el tiempo que. el tiempo es lineal y el peor caso es de orden cuadr´tico que se da en el caso inverso. La conclusi´n del an´lisis del caso o a medio depende de esta suposici´n.

Esto nos muestra o claramente que el tiempo amortizado depende de la probabilidad de que tengamos inserciones y cual la probabilidad de que tengamos solo b´squedas. en cada b´squeda ahorramos un poco u para gastarlo cuando tengamos que realizar un inserci´n. a a 2.7.7. sin embargo muchas veces solamente tomar´ el tiempo de buscar. substituci´n ı e o o o adivinaci´n. (2.7. luego aplicamos la o o hip´tesis inductiva para valores menores y demostrando que ´sto se cumo e ple. Soluci´n de recurrencias o Como ya vimos los algoritmos se pueden representar en forma de ecuaciones recurrentes aqu´ explicaremos tres m´todos de soluci´n. iterativos y un m´tdo general para casos especiales.1.1) La recurrencia 2. 2T (n/2) + n otros casos. o e 2. ¿Cu´nto tiempo toma el algoritmo? En el peor a caso toma el tiempo de insertar y de buscar.18 ´ 2. decimos que nuestra suposici´n es correcta. Consideremos el siguiente o ejemplo: T (n) = 1 n = 1. ANALISIS DE ALGORITMOS y si existe devuelve el valor m´ ınimo y si no existe inserta el valor y luego devuelve el valor m´ ınimo.2) Primero buscamos una soluci´n y suponemos que el tiempo asint´tico O(n) o o de esta ecuaci´n es O(n log n).1 puede escribirse como la ecuaci´n o 2T (n/2) + n (2.7. Debemos probar que ´sta es una funci´n para o e o la cual todos los valores de T (n) son menores con lo cual se demuestra que es una cota superior. M´todo por substituci´n e o El m´todo de substituci´n que bien puede llamarse m´todo por adivie o e naci´n se basa en adivinar de que forma es la soluci´n. u La esperanza matem´tica es una buena medida para estos an´lisis. Para entender el tiempo amortizado de a este algoritmo podemos pensar que. Suponiendo que esta soluci´n es aplicable a n/2 para una constante arbio .7.

SOLUCION DE RECURRENCIAS 19 traria c en la ecuaci´n 2. es usual imponer algunas restricciones tales como o probar desde T (2). T (n) ≤ cn− a b.7.7. 2. consideremos que ıcil o T (1) = 1 reemplazando nuestra hip´tesis se tiene T (1) = c1 log 1 que da o T (1) = c0 y para cualquier valor de c vemos que no es posible probar nuestra suposici´n por lo que. el restar algunas constantes de los t´rminos de menor orden es considerada e por muchos como una soluci´n intuitiva. Consideremos la ecuaci´n: o o √ T (n) = 2T ( n) + log n Podemos simplificar esta ecuaci´n reemplazando n por 2m que nos da o T (2m ) = 2T (2 2 ) + log 2m T (2m ) = 2T (2 2 ) + m m m . la cota superior probada no garantiza que e existe otra cota superior que sea menor a la probada. por lo que se hace necesario realizar diferentes pruebas con valores m´ximos y m´ a ınimos para hallar la soluci´n. Por ejemplo.2 tenemos: o n n T (n) ≤ 2c( log ) + n 2 2 n = cn log + n 2 = cn log n − cn log 2 + n = cn log n − cn + n ≤ n log n para c ≥ 1 Con lo cual estar´ probada nuestra suposici´n. Consideremos por ejemplo que se hubiese elegido n2 como una cota superior tambi´n se hubiera e 2 probado cierta porque O(n log(n)) ∈ O(n ). o Este m´todo es un problema.7.´ 2.2. Como ver´ en algunas conıa o a diciones es dif´ de probar esta recursi´n. Lo que estamos realizando es una hip´tesis inductiva y en o o muchas ocasiones podemos agregar m´s constantes por ejemplo. Cambio de variables En muchos casos las soluciones tienen formas que no hemos visto antes por lo que no podemos plantear la soluci´n. Realizar suposiciones acertadas es muy complicado.

ANALISIS DE ALGORITMOS m )+m 2 Esta soluci´n ya la conocemos y sabemos que es O(n log n) entonces reemo plazando en esta respuesta las substituciones que hemos realizado T (n) = T (2m ) = S(m) = O(m log m) = O(log n log log n). Consideremos la siguiente recursi´n: a a o T (n) = 1 n = 1.7.20 ahora reemplacemos T (2m ) por S(m) S(m) = 2S( ´ 2. Muestre que la soluci´n de T (n) = T (n/2 + 17) + 1 es O(log n) o √ 3.3. 2 para resolver ´sta vamos comenzar en T (n) y vamos a desarrollar la misma e n n T (n) = T ( ) + 1 reemplazando n por 2 2 n = T( ) + 2 4 n = T( ) + 3 8 hasta hallar la forma general n = T( k) + k 2 cuando n = 1 termina y por lo tanto T (1) toma la forma de: n T (1) = 1 = k 2 . Muestre que la soluci´n de T (n) = T (n/2) + 1 es O(log n) o 2. e pueden hacernos suponer verdaderos resultados err´neos.7. T ( n ) + 1 otros casos.4. M´todo iterativo e El m´todo iterativo es mucho mejor porque no requiere adivinanzas que. Ejercicios 1. Pero a cambio se o requiere un poco m´s de ´lgebra. 2. Resuelva la recurrencia T (n) = T ( n) + 1 realizando cambio de variables 2.

Reı o o solvamos con este m´todo la ecuaci´n 2. Despejando el valor de k tenemos k = log n reemplazando: T (n) = 2k + kn = n + n log n = O(n log n) Ejemplo: Dar las cotas superiores para T(n) en las siguiente recurrencia.1 e o T (n) = 1 n = 1. 2 desarrollando la recursi´n tenemos o n T (n) = 2T ( ) + n 2 n n = 2(2T ( ) + ) + n 4 2 n n = 4T ( ) + 2 + n 4 2 n = 4T ( ) + 2n 4 n n = 4(2T ( ) + ) + 2n 8 4 n = 8T ( ) + 3n termina cuando 8 = 2k T (1) + kn Este algoritmo termina cuando llegamos a T (1).7.´ 2. Asumiendo que T(n) es constante para n ≤ 1. 2T ( n ) + n otros casos. T (n) = T (n − 1) + n Soluci´n: o Desarrollando la recursi´n tenemos: o T (n) = T (n − 2) + (n − 1) + n = T (n − 3) + (n − 2) + (n − 1) + n . donde toma el valor de 1 cuando n/2k = 1. SOLUCION DE RECURRENCIAS 21 reemplazando tenemos: T (n) = 1 + k = 1 + log n de aqu´ sabemos que el tiempo asint´tico de esta recursi´n es O(log n).7.

22 que toma la forma de n ´ 2.7. ≥ 0 ⇒ O(nlogb a ).    si a < bk ⇒ O(nk ) La demostraci´n del teorema se puede consultar en la bibliograf´ [GB96] o ıa citada al final del texto.7. 2. Resolver T (n) = 3T (n/2) + n.7.     si a = bk ⇒ O(nk log n).5. Esta n o ecuaci´n nos da las siguientes soluciones: o   si f (n) = nlogb a− .3) La ecuaci´n 2.6.     si f (n) = nlogb a+ . ANALISIS DE ALGORITMOS i i=1 resolviendo tenemos n(n + 1) 2 2 por lo que la cota superior es O(n ) 2.3 es un caso t´ o ıpico de soluciones que aplican la t´cnica divide e y vencer´s donde a representa el n´mero de llamadas recursivas T (n/b) el a u tama˜o de las llamadas y f (n) el trabajo realizado en cada recursi´n. Resolver T (n) = T (n/3) + T (2n/3) + n. ≥ 0 ⇒ O(f (n)). Resuelva los siguientes ejercicios utilizando el teorema master: . Ejercicios 1. 3. Teorema master n T (n) = aT ( ) + f (n) b Existen muchas recursiones que tienen la forma (2. Resolver T (n) = T (n − a) + T (a) + n 2.7.    para polinomios donde T (n) = (2.7.    si f (n) = nlogb a ⇒ O(nlogb a log n).4)  f (n) = cnk se simplifica    si a > bk ⇒ O(nlogb a ).

7... T (n) = T (2n/3) + 1 Veamos a = 1.. b = 2/3. Soluci´n general de recurrencias lineales o Las recurrencias de la forma a0 tn + a1 tn−1 + . Una e e buena descripci´n de como resolver estas recurrencias pueden ver en los libros o de Grimaldi [Gri77] y Knuth [RLG94] . T (n) = 4T (n/2) + n. 2. k = 1 y f (n) = nk aplicando el teorema estamos en el caso a = bk por lo que la soluciones es T (n) = O(nk log n) = O(n log n) 2. + ak tn−k = f (n) (2. 3. T (n) = 4T (n/2) + n3 . b = 3. SOLUCION DE RECURRENCIAS 23 1. T (n) = 9T (n/3) + n Veamos a = 9.7. b = 2. homog´nea y de coeficientes constantes.5) se denominan: ecuaci´n l´ o ıneal. T (n) = 4T (n/2) + n2 .´ 2. k = 0 por lo que a = bk entonces la soluci´n es o O(nk log n) = O(log n) Ejercicios Resolver utilizando el teorema master.7. k = 1 por lo que a ≥ bk entonces la soluci´n es o log3 9 n = O(n2) 3. n T (n) = 2T ( ) + n 2 En este caso vea que a = 2.7. 1. Cuane do f (n) es 0 se denomina homog´nea y en otros casos no homog´nea. 2.

. ANALISIS DE ALGORITMOS La soluci´n de una ecuaci´n t(n) puede representarse como la combinacion o o lineal de funciones por ejemplo c1 f (n) + c2 g(n). n = 1. f (n − 1) + f (n − 2) otros casos. Recordando el ´lgebra. siempre que las ra´ sean distintas. ıces Ejemplo Consideremos la secuencia de Fibonacci: f (n) = n si n = 0. reescribimos esta ecuaci´n para satisfacer la ecuaci´n 2. por lo que podemos concluir o que k t(n) = i=1 n (ci ri ) las soluciones se dan para cualquier constante que se escoja..Consideremos la expresi´n o p(x) = a0 xk + a1 xk−1 + . Cualquier ri es una soluci´n a ´ste o e polinomio por lo que tambi´n son una soluci´n a t(n) porque cualquier come o binacion lineal tambien conforma una soluci´n.. a un polinomio de orden k tiene exactamente k ra´ ıces y puede factorizarse como k p(x) = i=1 (x − ri ) donde ri son las soluciones de p(x) = 0. + ak = 0 La soluci´n trivial es cuando x = 0 no es de inter´s.5 o o f (n) − f (n − 1) − f (n − 2) = 0 Esta ecuaci´n tiene un polinomio caracter´ o ıstico x2 − x − 1 = 0 que tiene como soluci´n las ra´ o ıces √ √ 1+ 5 1− 5 r1 = y r2 = 2 2 . Esta ecuaci´n se denomio e o na ecuaci´n caracter´ o ıstica o polinomio caracter´ ıstico.7.24 Soluci´n de recurrencias homog´neas o e ´ 2.

Consideremos la recurrencia siguiente: t(n) − 2t(n − 1) = 3n (2.7.´ 2.7) (2. c2 c1 + c2 = 0 r1 c 1 + r2 c 2 = 1 resolviendo obtenemos 1 1 c1 = √ y c2 = − √ 5 5 reemplazando en la ecuaci´n obtenemos o √ √ 1− 5 n 1 1+ 5 n f (n) = √ [( ) −( ) ] 2 2 5 Solucici´n de recurrencias no homog´neas o e La recurrencias de la forma a0 tn + a1 tn−1 + .6) en este caso b = 3 y p(n) = 1 es un polinomio de grado 0.9) (2.. + ak tn−k = bn p(n) b es una constante p(n) es un polinomio en n de grado d. SOLUCION DE RECURRENCIAS 25 entonces la soluci´n general es o n n f (n) = c1 r1 + c2 r2 ahora utilizando las condiciones iniciales podemos hallar las constantes c1 .7.7.7. Multiplicamos por tres la ecuaci´n 2.7 e o 3t(n) − 6t(n − 1) = 3n+1 ahora cambiemos n − 1 por n 3t(n − 1) − 6t(n − 1) = 3n (2. para resolver este problema primero lo convertimos a un problema familiar.7.7..8) .. la recurrencia homog´nea.

7. las ecuaciones a resolver son: c1 + c2 = t(0) 2c1 + 3c2 = 2t(0) + 3 de donde obtenemos c1 = t(0) − 3 y c2 = 3.7.7.7 no es la misma que la 2. La funci´n o o original implica que t1 = 2t0 + 3 por lo que. las soluciones son de la forma t(n) = c1 2n + c2 3n Sin embargo no es cierto que cualquier constante arbitraria producir´ la a soluci´n correcta porque la ecuaci´n 2.7.7.8 tenemos una ecuaci´n homog´nea o e t(n) − 5t(n − 2) + 6t(n − 2) = 0 el polinomio caracter´ ıstico es x2 − 5x + 6 = (x − 2)(x − 3) por lo que.7 de 2. ANALISIS DE ALGORITMOS restando 2.10) . Resolviendo esto tenemos t(n) = (t(0) − 3)2n + 3n+1 que es independiente de la soluci´n inicial t(n) O(3n ) o (2. o o Podemos resolver la ecuaci´n original en base de t(0) y t(1).26 ´ 2.10.

¿Cu´nto tiempo toma el siguiente algoritmo? a l=0 for i=1 to n for j=1 to i for k=1 to j l=l+1 Soluci´n: o .8. ¿Cu´nto tiempo toma el siguiente algoritmo? a l=0 for i=1 to n for j=1 to n^2 for k=1 to n^3 l=l+1 Soluci´n: o Recordando que los ciclos for son las sumas de los tiempos individuales de los procedimientos interiores podemos escribir n n2 n3 T (n) = n ( n2 ( 1)) i=1 j=1 k=1 = =n ( n n3 ) i=1 j=1 n 3 2 i=1 3 2 = n n n = n6 2. Ejercicios resueltos 1.2.8. EJERCICIOS RESUELTOS 27 2.

28 ´ 2. De donde tenemos a = 1. b = 2. o . Resolver utilizando el teorema master procedure DC(n) if n < = 1 DC(n/2) for j=1 to n^3 x[j]=0 Soluci´n o Del an´lisis vemos que a T (n) = 1 n = 1. k = 3 lo que nos lleva al caso 1 < 23 dando como soluci´n O(nk ) = O(n3 ). 3 T (n/2) + n otros casos. ANALISIS DE ALGORITMOS En este caso no todas las sumas son hasta n n i j T (n) = n ( i ( 1)) i=1 j=1 k=1 = = i=1 n ( i=1 j=1 n j) i+1 2 i ( i=1 n = = i=1 i2 i + ) 2 2 n i2 + 2 i=1 i 2 n(n + 1)(2n + 1) n + 1 = + 12 2 2 (n + n)(2n + 1) n + 1 + = 12 2 2n3 + 3n2 + n n + 1 = + 12 2 3 = O(n ) 3.

2.8. EJERCICIOS RESUELTOS 29 4. Asumiendo que T(n) es constante para n ≤ 1. 8T (n/2) + n3 otros casos. o 5. Dar las cotas superiores para T(n) en las siguientes recurrencias. De donde tenemos a = 8. n T (n) = 2T ( ) + n3 2 Soluci´n: o Desarrollando la recursi´n tenemos: o n T (n) = 2T ( ) + n3 2 n n = 2(2T ( ) + ( )3 ) + n3 4 2 n n3 = 4T ( ) + 2( ) + n3 4 2 n n n3 = 4(2T ( ) + ( )3 ) + 2( ) + n3 8 4 2 n n3 n 3 = 8T ( ) + 4( ) + 2( ) + n3 8 4 2 De aqu´ vemos que para un t´rmino i toma la forma ı e n n T (n) = 2 T ( i ) + 2k ( k )3 2 2 k=0 i i−1 . b = 2. k = 3 lo que nos lleva al caso 8 = 23 dando como soluci´n O(nk log n) = O(n3 log n). Resolver utilizando el teorema master procedure DC(n) if n < = 1 for i=1 to 8 DC(n/2) for j=1 to n^3 x[j]=0 Soluci´n o Del an´lisis vemos que hay la parte de algoritmo que divide el problema a DC(n/2) se procesa 8 veces lo que cambia el problema anterior a T (n) = 1 n = 1.

30 ´ 2. ANALISIS DE ALGORITMOS n T(1) se da cuando 2i = 1 entonces i = log(n) reemplazando tenemos: i−1 T (n) = n + n3 k=1 i−1 ( 1 2 ) 2k 1 ) 4k = n + n3 k=1 i−1 ( ( k=1 1 − ( 1 )i−1 1 4 )= 1 4k 1− 4 4 1 = (1 − i−1 ) 3 4 4 1 1 = − 3 3 4i−2 4 1 1 = − 3 3 22i−2 4 1 1 = − 2 log(n)−2 3 32 4 1 4 = − 3 3 n2 4 1 4 ) T (n) = n + n3 ( − 3 3 n2 4 4 = n + n3 − n) 3 3 por lo que. la cota superior es O(n3 ) 6. √ n T (n) = 2T ( ) + n 4 Soluci´n: o Desarrollando la recursi´n tenemos: o T (n) = 2(2T ( = 4T ( n )+ 42 √ n )+ n 4 n √ + n 4 n )+2 42 . Asumiendo que T(n) es constante para n ≤ 2. Dar las cotas superiores para T(n) en las siguientes recurrencias.

EJERCICIOS RESUELTOS 31 De aqu´ vemos que para un t´rmino i toma la forma ı e n T (n) = 2 T ( i ) + 2k ( 4 k=1 i i−1 n ) 4k n t(1) se da cuando 4i = 1 entonces i = log4 (n) adem´s notamos que a i i 2 4 = (2 ) reemplazando tenemos: i−1 = 2 T (1) + i 2k k=1 i−1 n √ + n 4k n 2k2 = n √ 2k + n+ 2 k=1 n 2 n 2 n 2 n 2 + + + √ √ √ i−1 = = = n+ k=1 √ n √ n + (i − 1) n √ n + (log4 (n) − 1) n √ √ √ = + n + log4 (n) n − n √ por lo que la cota superior es O(log(n) n).8.2. Dar las cotas superiores para T(n) asumiendo que T(n) es constante para n ≤ 2. √ T (n) = 2T ( n) + 1 Soluci´n: o Desarrollando la recursi´n tenemos: o T (n) = 2T (n 2 ) + 1 = 4T (n( 2 ) ) + 2 + 1 = 8T (n( 2 ) ) + 4 + 2 + 1 que toma la forma de k=i−1 1 3 1 2 1 T (n) = 2 T (n = 2 T (n i i 1 ( 2 )i )+ k=0 2k 1 ( 2 )i ) + 2i − i . 7.

e o Asuma que T(1)=1.32 1 i ´ 2. u=n-1. Hallar el O(n) del siguiente programa de b´squeda binaria.m. while(l<u) { m=(l+u)/2 if (a[mid]< x) l=m+1 else if (a[mid]> x) l=m-1 else . verificar con el m´todo de substituci´n y desarrollando la recurrencia.9. ANALISIS DE ALGORITMOS cuando n( 2 ) = 2 estamos en T(2) que es constante 1 ( )i log(n) = log(2) = 1 2 2i = log(n) T (n) = log(n)T (2) + log(n) − 1 = 2 log(n) − 1 la cota superior es O(log n) 2. Resolver las siguientes recurrencias utilizando el teorema master.u. Ejercicios 1. u int l. a) T (n) = 2T ( n ) + log(n) 2 b) T (n) = 3T ( n ) + log(n) 3 c) T (n) = 4T ( n ) + log(n) 4 d ) T (n) = 2T ( n ) + n2 2 e) T (n) = 2T ( n ) + n3 2 f ) T (n) = 2T ( n ) + n4 2 √ g) T (n) = (n)T ( n) + n 2. l=0.

n) { if (n=0) return 1 if (n==1) return x if (par(n)) return (pot(x*x. 000 .n/2)*x) } 5. o pot(x. Hallar el O(n) del siguiente programa para hallar el m´ximo com´n a u divisor. Sugerencia escribir el tama˜o de la instancia en cada iteraci´n n o y aproximar a una serie arm´nica.n/2)) else return (pot(x*x. o mcd(m. 000. Hallar el O(n) del siguiente programa de exponenciaci´n.n) { while (n> 0){ resto=m%n m=n n=resto } return (m) } 4.2. Se tienen dos programas A y B cuyo tiempo de ejecuci´n es 150 log(n) o 2 milisegundos y 150n respectivamente. 6.n < 1. EJERCICIOS 33 return ("hallado") } return ("no existe">) 3. Codificar el programa de b´squeda binaria en forma recursiva y hallar u el O(n) 7. n > 10. Realizar una prueba experimental para comprobar las cotas superiores de los programas anteriormente propuestos. Indique que programa es mejor para n < 100.9.

Como la sumatoria es acotada. ¿Entonces para qu´ podemos utilizar el c´lculo integral? e a Bien. se podr´ pensar ıa en utilizar una integral definida. e e a .34 ´ 2.10. Consideremos por ejemplo la siguiente sumatoria y su resultado: n i2 = i=0 n(n + 1)(2n + 1) 6 (2.10.10.10.2 O( n(n + 1)(2n + 1) ) = n3 6 O( n3 + c) = n3 3 Como ve. Nota sobre el c´lculo integral a Cuando tenemos una sumatoria.10. desde nuestras clases de c´lculo.1 y 2. si queremos obtener la cota superior en la ejecuci´n de un algoritmo. asociaa mos la misma a una integral.2 son diferentes.10.2) Claramente las ecuaciones 2. ambos resultados nos dan la misma cota superior. o debemos obtener o(f (n)) de las 2. ANALISIS DE ALGORITMOS 2. En el libro de matem´ticas concretas de Donald Knuth [RLG94] se puede encontrar un a m´todo para hallar el resultado de una suma a trav´s del c´lculo.1) Si suponemos que es posible hallar el resultado integrando la sumatoria se tiene lo siguiente: i3 n n 3 +c i = 0ni = |0 = 3 3 2 (2.1 y 2.10.

Introducci´n o Se hace muy importante la teor´ de n´meros en el aprendizaje de la proıa u gramaci´n. el tama˜o a n m´ximo de n´meros que se pueden tratar y como trabajar con n´meros m´s a u u a grandes. 3. En el tratamiento de este cap´ ıtulo se toman en cuenta los aspectos relativos al tiempo de proceso para hacer eficiente los algoritmos expuestos. tipo byte short int long Nro.Cap´ ıtulo 3 Teor´ de n´ meros ıa u 3. Bits 8 bits 16 bits 32 bits 64 bits Rango de n´meros permitido u 7 desde − (2 + 1) hasta + 27 desde − (215 + 1) hasta + 215 desde − (231 + 1) hasta + 231 desde − (263 + 1) hasta + 263 Cuadro 3.1: Tipos de variables enteras en Java Para evaluar el tiempo de proceso de las operaciones de suma. tales como las capacidades de la m´quina.1. multiplicaci´n y divisi´n construimos un programa que repita muchas veces una o o 35 . Este conocimiento permite comprender los aspectos que hacen al o proceso computacional. Variables del lenguaje Java El lenguaje de programaci´n Java tiene varios tipos de variables enteras o que se muestran en el cuadro 3. Bytes 1 bytes 2 bytes 4 bytes 8 bytes Nro.2.1.

tiempoInicio. tiempoFin.000. o public class Tiempos { /** * Programa para medir el tiempo de proceso en * milisegundos de las operaciones elementales * suma . TEOR´ DE NUMEROS IA operaci´n.println( "Tiempo de proceso de la Multiplicacion " + tiempoTotal).36 ´ 3. Esto permite determinar cuanto o o tiempo consumen los diferentes tipos de variables y escoger la m´s adecuada a para mejorar el tiempo de proceso. . tiempoInicio = System. i++) { j = j * 3. } tiempoFin = System. Multiplicaci´n y divisi´n o o * @author Jorge Teran * @param args * none */ public static void main(String[] args) { int j = 1. Tambi´n se observa que las operaciones de tipo long demoran casi el o e doble de tiempo que las operaciones enteras. El programa siguiente nos permite medir el tiempo que toma la operaci´n de multiplicar realizando 10.currentTimeMillis().currentTimeMillis(). Se puede observar que una operaci´n de divisi´n demora mucho m´s que una operaci´n de multiplicao o a o ci´n.2 para comparar el tiempo de proceso para cada tipo de variable. midiendo el tiempo de ejecuci´n.out. tiempoTotal = tiempoFin . for (int i = 1. long tiempoInicio. System. tiempoInicio = System.currentTimeMillis().000 de o operaciones de multiplicaci´n para una variable entera. i < 10000000. tiempoTotal. } } Una vez procesado este programa contruimos el cuadro 3.

u a u Mcd(int a. } } return (i). De aqu´ vemos que el m´ximo com´n u ı a u divisor es el n´mero 4.´ ´ ´ 3. for (i=b.i--){ if (((a%i==0) && (b%i==0))) { break.4 y 2. Los divisiores del n´mero 20 son: 20. i>1. calculamos su O(n) para posteriormente buscar un soluci´n m´s eficiente. a . tomemos los u u n´meros 20 y 8.000. int b) { int mcd() { int i.3.3. 4 y 2. CALCULO DEL MAXIMO COMUN DIVISOR 37 Operacion suma suma multiplicaci´n o multiplicaci´n o divisi´n o divisi´n o tipo int long int long int long Tiempo en mseg para 10. 5.2: Comparaci´n de los tiempos de ejecuci´n de las operaciones o o b´sicas a 3. Para resolver adecuadamente este problema se conu truye un programa. } } An´lisis: a Se puede apreciar que primero a > b cuando hallamos el primer divisor este ya es m´ximo porque comenzamos en b y vamos restando de uno en uno. o a Para realizar una primera aproximaci´n a la soluci´n del problema proo o baremos todos los n´meros hallando el m´ximo n´mero que divida a ambos. C´lculo del m´ximo com´ n divisor a a u Dados dos n´meros enteros se denomina m´ximo com´n divisor al m´xiu a u a mo n´mero que es divisor de ambos n´meros. inicialmente con la idea explicada. Los diviu u sores del n´mero 8 son el 8. Como ejemplo.10.000 repeticiones 110 190 140 230 771 2334 Cuadro 3.

Cuando un n´mero tiene como unico divisor el n´mero 1 y a si mismo se u ´ u denomina n´mero primo. Los divisores no triviales se denominan factores. Se lo denominamos como u a mcd(a. u e u Si a|b decimos que a es un divisor de b por ejemplo los divisores de 20 son: 1. TEOR´ DE NUMEROS IA En el peor caso cuando el m´ximo com´n divisor es 1 el algoritmo realiza el a u m´ximo n´mero de operaciones. Algunas propiedades son las siguientes: . b). es divisible por el divisor trivial 1.10 y 20. u Teorema 1. Todo entero a. se a u u denomina al divisor com´n m´s grande de a.1. Para cualquier entero a y un n´mero positivo n existen enteros u k y r tal que 0 ≤ r < n y a = qn + r El valor q = a/n se denomina cociente de la divisi´n y r de denomina o residuo o resto.3.38 ´ 3. 2. Para calcular el O(n) requerimos resolver a u 1 1=b i=b o sea O(n). En este caso.5 . se u verifica d|(a + b) y en un caso m´s general d|(xa + yb) a si b|a y a|b significa que a = ±b si b|a significa que b ≤ a o que a = 0 El m´ximo com´n divisor de dos n´meros a. b. Divisibilidad En la teor´ de n´meros la notaci´n a|b se lee a divide b significa que ıa u o b = ka para alg´n k > 0. Tambi´n se dice que b es m´ltiplo de a.4. Se define mcd(0. a 3. Para mejorar este algoritmo se hace necesario analizar algunas propiedades matem´ticas. De esto e vemos que n|a si y solo si a mod n = 0 Si d|b y d|a entonces d es un com´n divisor de a y b. b ambos diferentes a cero. El valor r tambi´n se expresa como r = a mod n. 0) = 0.

Si mcd(a. b) mcd(a. b) = s De este teorema podemos deducir las siguientes propiedades: Dados los n´meros enteros positivos a. |b|) mcd(a. b son n´meros enteros. b) es u el elemento m´s peque˜o del conjunto {ax + by} donde x. Si d|a y d|b entonces mcd(a. Sea q = a/s y sea s el entero m´s peque˜o de la combinao a n ci´n lineal de a y b. n) = 1 entonces b|n. diferentes de cero el mcd(a. b.´ ´ ´ 3. b) ≥ s. b) = mcd(−a. Si a. a n Demostraci´n. b). ka) = a mcd(a.3. b) ≤ entonces mcd(a. b) ≥ s y mcd(a. Dado que el mcd(a. Esto indica que s|a y a que s|b por lo que s es un divisor com´n de a y b. b) = mcd(b. b) = mcd(|a| . b) = mcd(a. b)|d. CALCULO DEL MAXIMO COMUN DIVISOR 39 mcd(a. (Teorema de Euclides) Para cualesquiera dos enteros no negativos a. b mcd(a. Teorema 3. b) > 0 y que s divide a a ambos a y b debe dividir tambi´n a una combinaci´n lineal de a y b por lo e o que mcd(a. Entonces o a mod s = a − qs = a − q(ax + by) = a(1 − qx) + b(qy) Esto muestra que a mod s es una combinaci´n lineal de a y b. Podemos a n hacer un an´lisis similar y encontrar lo mismo para b. El n´mero o u m´s peque˜o que puede dar a mod s es 0 dado que a mod s < s. a) mcd(a. u De ac´ vemos que mcd(a. nb) = n mcd(a. n u si n|ab y mcd(a. y ∈ Z. mcd(na. mcd(a mod b)) . 0) = |a| Teorema 2. b) ≤ s.

Primeramente escribiremos una a u u funci´n recursiva para hacer m´s simple el c´lculo de su complejidad. k = 0 donde a = bk . b) = mcd(tb + r. a%b) Esta recursi´n la podemos escribir como o T (n) = 1 si n = 0.40 ´ 3. b) cualquier divisor com´n de b y a debe dividir tb + r. o a a Mcd(a. n T ( b ) + 1 en otros casos. Esto nos dice que el tiempo que toma algoritmo en su peor caso es O(log n). Ahora vamos a aplicar el algoritmo denominado de Euclides para hallar el m´ximo com´n divisor de dos n´meros. Se puede escribir a como tb + r y reemplazando se tiene o mcd(a. Como ve toma la forma del teorema master n T (n) = aT ( ) + nk b donde b reduce su tama˜o en a mod b en cada iteraci´n por lo que podemos n o aplicar el teorema y se ve que a = 1. b = a mod b. Cualquier divisor de de u tb tambi´n es divisor de b que implica que cualqiuier divisor de b debe dividir e a r. Para ahorrar la memoria utilizada por la recursi´n se presenta una soluo ci´n recursiva o public class Euclides { /** * Programa para hallar el * maximo comun divisor * con el metodo de Euclides * @author Jorge Teran .b) if (b==0) return (a) else Mcd(b. TEOR´ DE NUMEROS IA Demostraci´n.

Conocemos que o mcd(a. y de la expresi´n ax + by = mcd(a.b = b. Euclides(int a. b) = mcd(b. } } int mcd() { int r=b. } } 3. b) . } else { this. Algoritmos extendido de Euclides El algoritmo de Euclides Extendido muestra como calcular los valores x.´ ´ ´ 3.a = a. b). r) donde: r = a − b a/b suponiendo que conocemos x y y tal que rx + by = mcd(b. b. r) = mcd(a.2.3.b = b.3. this. int b) { if (a>b){ this. b=r. a=b. while (b> 0){ r=a%b. CALCULO DEL MAXIMO COMUN DIVISOR 41 */ int a.a = a. } return (a). this.

yAnt = sr.out.yAnt*q. yAnt = 0.println(" y= "+((a-x*aIni)/bIni)). x = yAnt. x = 1. int b){ int x. sr = x . System. bIni. a = b. b) reordenando ax + b(y − y a/b ) = mcd(a.print(" x= "+x). System. while (b != 0) { r = a % b. } Para una mayor comprensi´n se muestra un ejemplo de una ejecuci´n. q=a/b.42 reemplazando ´ 3. o Como se ve la ecuaci´n ax + by = mcd(a.print("mcd= "+a). o o Hallemos ax + by = mcd(a. r. TEOR´ DE NUMEROS IA (a − b a/b )x + by + = mcd(a.out. b) con a = 97 y b = 66. b = r. yAnt. b) Vemos que cuando a = 0 el valor de x debe ser 0 y y = 1 El siguiente programa realiza el c´lculo de los valores x. y a /*Programa para el algoritmo * extendido de Euclides * @author Jorge Teran * */ void eMcd (int a. bIni = b. sr. } System. aIni. El cuadro 3.out.3 ejemplifica la ejecuci´n del programa. aIni = a.q. b) se cumple con los ultimos o ´ valores obteniendo 97 · (−17) + 66 · 25 .

. u Este n´mero se expresa como sigue: u mcm(a. 4 mod 3. que equivale a la numeraci´n en base 3. 3 mod 3.3: Prueba de ejecuci´n del algoritmo de extendido de Euclides o 3.4. Por ejemplo a mod b significa que o o queremos hallar el resto de a que representamos como b a mod b = a − b a b (3. Aritm´tica modular e La aritm´tica modular es una de las aplicaciones m´s importantes de e a la teor´ de n´meros. k > 0 y a|k y b|k} sin embargo es posible probar que mcd(a.. La funci´n ıa u a o o m´dulo representa el resto de la divisi´n. b) = min{k. b) = ab En el ejemplo podemos ver que el mcd(9.´ ´ 3. 1.. evaluando tenemos 0. b)mcm(a. Veamos e e o por ejemplo la secuencia: 0 mod 3.4. Para el c´lculo del m´ u a ınimo com´n m´ltiplo no u u existe un algoritmo similar al de Euclides que facilite hallar este n´mero. 1. 2 mod 3. M´ INIMO COMUN MULTIPLO 43 mcd 66 31 4 3 1 sr 1 -2 15 -17 66 x 0 1 -2 15 -17 y 1 -1 3 -22 25 97*x+66*y 66 31 4 3 1 a 97 66 31 4 3 b 66 31 4 3 1 q=a/b 1 2 7 1 3 r 31 4 3 1 0 Cuadro 3.. 6) es 3 y que 3x18 = 54 = 9x6 3.5. 2. 0.1) La aritm´tica modular tambi´n define un sistema de numeraci´n. o .5. Est´ representada por la funci´n mod . Por ejemplo el m´ n u ınimo com´n u m´ltiplo entre 9 y 6 es 18. 1 mod 3.. M´ ınimo com´ n m´ ltiplo u u El m´ ınimo com´n m´ltiplo (mcm) de dos n´meros es el n´mero m´s u u u u a peque˜o que es divisible por ambos n´meros.

Por ejemplo (8 + 7) mod 3 = 15 mod 3 = 0 y por la propiedad de la suma (8 mod 3 + 7 mod 3) mod 3 Resta La resta es solo la suma con valores negativos por los que (x − y) mod m = (x mod m − y mod m) mod m. e Suma (x + y) mod m = (x mod m + y mod m) mod m. por ejemplo en el e calendario los d´ de la semana correponden a una aritm´tica m´dulo 7. m) = 1.44 ´ 3. Hallar el ultimo ´ 100 d´ ıgito del n´mero 2 . Esto se da debido a que la multiplaci´n es simplemente una o suma repetida. minutos y segundos corresponden al m´dulo 60. Existen muchas aplicaciones de la aritm´tica modular.5. TEOR´ DE NUMEROS IA 3. Multiplicaci´n La multiplicaci´n xy mod m = (x mod m)(y mod m) o o mod m. Propiedades Presentamos algunas propiedades importantes de la aritm´tica modular. Solo es posible realizar estas simplificaciones cuando el mcd(d. Para ´sto no es necesario hallar el valor del exponente u e y luego obtener el ultimo d´ ´ ıgito se puede resolver como sigue: 23 26 212 224 248 296 2100 mod 10 = 8 mod 10 = (8 · 8) mod 10 = 4 mod 10 = (4 · 4) mod 10 = 6 mod 10 = (6 · 6) mod 10 = 6 mod 10 = (6 · 6) mod 10 = 6 mod 10 = (6 · 6) mod 10 = 6 mod 10 = 29 6 · 23 · 21 mod 10 = 6 · 8 · 2 mod 10 = 6 . que no se cumple en todos los casos. u e o El ejemplo que se presenta es extractado de [MAR03]. Hallar el ultimo d´ o ´ ıgito de un n´mero decimal corresponde a una aritm´tica m´dulo 10.1. las ıas e o horas. Veamos un ejemplo 6 · 2 mod 3 = 6 · 1 mod 3 = 0 si simplificamos el 6 tenemos 2 mod 3 = 1 = 1 mod 3 = 2. Divisi´n No existe el inverso de la multiplicaci´n como la conocemos por o o ejemplo veamos dx mod m = dy mod m se puede pensar que podemos simplificar d obteniendo x mod m = y mod m.

3.5. b son m´ltiplos de m Algunas propiedades de las conu gruencias son: Propiedad reflexiva a ≡ a Propiedad sim´trica a ≡ b ⇒ b ≡ a e Propiedad transitiva a ≡ b ≡ c ⇒ a ≡ c Suma a ≡ b y c ≡ d ⇒ (a + c) ≡ (b + d) mod m Multiplicaci´n a ≡ b y c ≡ d ⇒ (ac) ≡ (bd) mod m con b.5. c enteros o Potencias a ≡ b ⇒ an ≡ bn mod m Si se quiere conocer si 2n −1 es m´ltiplo de 3.5. De aqu´ b se ı denomina inverso multiplicativo de a.5. Inverso multiplicativo Consideremos que mcd(a.4. Es decir que (2n −1) mod 3 = 0. Congruencias Se dice que a es congruente b m´dulo m cuando (a − b)/m = km. ARITMETICA MODULAR 45 3. u 3. Se o escribe a ≡ b mod m Esto equivale a que a. m)|b Para resolver este tipo o de ecuaci´n se sigue la siguiente estrategia. Por lo tanto es m´ltiplo de 3 cuando n es par.´ 3.2. o ax − b = km ax = b + km y buscamos un k tal que a|(b + km) . u Podemos aplicar la propiedad de la potencia y escribir 2 ≡ −1 mod 3 de donde 2n ≡ (−1)n mod 3. Soluci´n de ecuaciones o ax ≡ b( mod m) La ecuaci´n de congruencia de primer orden est´ definida como: o a Estas ecuaciones tienen soluci´n solo si mcd(a.3. n) = 1 entonces existen enteros b y c tales que ba + cn = 1. Esto se puede escribir como ba ≡ 1 mod n.

Por otro lado si recibimos la misma cantidad de equipos. como mcd(6. si recogemos una cantidad de cajas en las cuales vienen 3 equipos y tenemos 2 equipos sueltos. TEOR´ DE NUMEROS IA 1. 3) = 2 no es divisor de 5.46 hallamos x Ejemplos: ´ 3. por ejeme plo.5. Resolver 4x ≡ 10(mod/6) 4x = 10 + k6 4x = 10 + 6 con k = 1 x=4 si reemplazamos el valor de x encontrado tenemos: 4 · 4 ≡ 6( mod 6) tambi´n pueden plantearse sistemas de ecuaciones de congruencias.5.2 x = 3+(8+12k)7 u que da x = 59 + 84t de donde x = 59.5.3) si la soluci´n de 3.5. o 2. .no se tiene una soluci´n. Resolver 6x ≡ 5(mod/3). en cajas en las cuales vienen 5 equipos y tenemos 1 equipo suelto. Se desea conocer cuantos equipos se recibieron.2) (3. Esto se puede escribir como: x ≡ 3( mod 7) 5x ≡ 7( mod 12) (3.2 es x = 3 + k7 para alg´n valor k podemos reemplazar o u x en la segunda ecuaci´n obteniendo: o 5(3 + k7) ≡ 7( mod 12) 15 + 35k ≡ 7( mod 12) 35k ≡ −8( mod 12) significa que k = 8+12t para alg´n t reemplazando en 3.

o ter´s debido a las complejidades que lleva ´ste cuando se trabaja con n´meros e e u grandes. 19.6. 3. Esto se puede realizar por u divisiones sucesivas sin embargo no es un m´todo muy adecuado cuando se e trata de n´meros grandes.6. a a e e o La criba de Erat´stenes se contruye a partir de los m´ltiplos de los n´meo u u ros como sigue 1. 5. o Para muchas aplicaciones es necesario realizar un test de primalidad que significa verificar si el n´mero es primo o no. while (j * j <= n) { if ((i%j)==0) break. 11. u 3. Generaci´n de primos o Es posible probar la primalidad de un n´mero n en un tiempo proporciou √ nal a O( n) con el siguiente c´digo de divisiones sucesivas o j = 2.´ 3. u 2. 7. Como ya vimos el tiempo que toma una divisi´n es mucho o mayor al de la suma. etc. 5.. NUMEROS PRIMOS 47 3. . sucesivamente. Se marcan los m´ltiplos de 2.6. Luego los de 3.. 7. Los primeros n´meros primos son 2. u Como se ve el unico n´mero primo par es el n´mero 2. la e u forma m´s f´cil es a trav´s del m´todo denominado la criba de Erat´stenes. Se define como primo el n´mero entero positivo que es divisible solamente u por 1 o por si mismo. sin embargo. } El problema que representa este m´todo es la cantidad de divisiones que e hay que realizar. Para convertir ´stas divisiones en suma de n´meros. algunos autores amplian la u definici´n para incluirlo. N´ meros primos u La teor´ de los n´meros primos ha tenido un desarrollo muy intenso con ıa u las aplicaciones de criptograf´ En esta secci´n le dedicamos un especial inıa. El n´mero 1 no ´ u u u es parte de los n´meros primos.1. //no primo j++.

// construccion de la criba for (i = 2. u u ı Al terminar el proceso los d´ ıgitos no marcados son los n´meros primos. la segunda pasada los m´ltiplos de 3 y as´ sucesivamente.set(j).4 se marcan en la primera pasada los m´ltiplos de 2.000 utilizando la * Criba de Eratostenes * @author Jorge Teran */ public class Criba { public static void main(String[] s) { int n = 100000000. El u siguiente programa muestra como contar cuantos n´meros primos hay hasta u 100. BitSet a = new BitSet(n + 1).4: Ejemplo de una criba de Erat´stenes o 3. i = i + 1) { //el siguiente control es para no pasar //por valores ya tomados en cuenta if (!a. import java. TEOR´ DE NUMEROS IA 2 3 4 5 6 7 8 9 10 11 12 13 14 15 x x x x x x x x x x x x x x x x x x x x Cuadro 3. . /** * Programa contar los n´meros primos u * hasta n = 100. long inicio = System. int i = 2.get(i)) { for (j = i + i. j = j + i) { a.000. i * i <= n. j = 0. int contar = 0.util. j <= n.000.000. Como se observa en el cuadro 3. Una vez completado el marcado los no marcados son los n´meros priu mos.48 M´ltiplo de u 2 3 5 Marcados ´ 3.*.currentTimeMillis().

System.013 milisegundos dando el resultado de o 5.. e 1 2 3 Los factores primos de 168 son 2. System. o a La forma de expresar ´stos factores es como sigue: an1 an2 an3 .6. i <= n. El n´mero m´ximo depende de la memoria u n u a de la m´quina. Los n´meros primos que pueden calcularse a trav´s de este m´todo se u e e consideran n´meros peque˜os..get(i)) { contar++. u La p´gina http://primes. } } En la computadora demor´ 78.455 primos.println((fin . NUMEROS PRIMOS 49 } } } // contar los n´meros primos u for (i = 2. } } long fin = System. Hay o o u que indicar que este proceso es aplicable a n´meros peque˜os. 2.utm.2. i++) { if (!a.5.´ 3.inicio) + " milisegundos").761. la implementaci´n realizada y el lenguaje de programaci´n. u n . Factorizaci´n o La factorizaci´n de un n´mero consiste en descomponer el mismo en sus o u divisores. a o o Vea que si almacena solo los n´meros impares puede almacenar el doble de u n´meros en la criba. El siguiente c´digo muestra el proceso de factorizaci´n de n´meros.currentTimeMillis(). a 3.6. est´n detallados en el cuadro 3..out. Para una demostraci´n m´s formal vean [THCR90].edu/ proporciona un acceso importante a la a teor´ de n´meros primos y publica la cantidad de primos por rango conocidos ıa u a la fecha. 3.out. Se demuestra que todos los factores son n´meros primos. 7 que se expresa como 23 · 3 · 7 = 168. 2.println(contar + " primos"). Analice u que si uno de sus factores es un n´mero compuesto tambi´n podr´ descomu e ıa ponerse en factores.

534 455.689.802 29.000.000 10.052.065.602.000.761.511 4.906.607.000.000 10.341.118.536.018.667.731.000.000.000 100.290 Cuadro 3.127.157.557.840 21.000 1.925 2.000 10.000 1.057.000.000.000.000.000.204.000 10.000 100.000.054.000 100.000 1.000.000.000.000.941.000 Cantidad de Primos 4 25 168 1.000.000.000.740.287.000.000 10.000.000 10.344.000 1.018 346.455 50.5: Cantidad de primos por rango conocidos a la fecha .000.286.000.000.912.000.000.000.000.000.000.000.954.000 100.607 2.000.570.238.813 37.220.592 78.498 664.000.000.000.000.000.422.315.739.000 1.000.033.000.928 201.560.839 3.000.000.467.000 10. TEOR´ DE NUMEROS IA Hasta 10 100 1.486.233 24.000 1.229 9.844.000.847.000.000 100.000.623.000.50 ´ 3.269.000.669 279.918.000.000.000.000.276.000.000.000.860 234.000.000.579 5.000.000.819.654.000 100.750.000.

i <= N / i.println(). NUMEROS PRIMOS 51 Factores (Long N){ /** * Programa para hallar los factores Primos * @author Jorge Teran */ System.6. .out.3.6. Teorema de Fermat Este teorema indica que todo n´mero primo cumple la relaci´n: u o an−1 ≡ 1 mod n ∀a ≤ n (3.out.1) por lo que parece suficiente realizar este c´lculo para determinar la primalia dad. for (long i = 2.print(i + " "). Se u n puede hacer por divisiones sucecivas.out. Esto hace necesario buscar u otros m´todos para determinar la primalidad de los mismos. a´n cuando. } } // Si el primer factor ocurre una sola vez if (N > 1) System. es mejor utilizar una criba u con n´meros precalculados. 3. i++) { while (N % i == 0) { System.4. else System. N = N / i. } 3.println(N).6.´ 3.out. Analizamos e algunos m´todos sin ahondar en las demostraciones que est´n ampliamente e a desarrolladas en la teor´ de n´meros y el ´rea de criptograf´ ıa u a ıa. Las dificultades en el c´lculo de n´meros primos u a u radica cuando los n´meros a tratar son grandes. Prueba de la primalidad La prueba de primalidad es simple para n´meros primos peque˜os.6.print( "Los factores primos de: " + N + " son: ").

1729. Si as ≡ 1 mod (n) o u e 2j s a ≡ −1 mod (n) para alg´n j.52 ´ 3. Escogemos un n´mero entero aleatoriamente y sea ´ste 1 ≤ a ≤ n. a El prop´sito de comentar este algoritmo es el hecho que la implementaci´n o o de Java ya lo incluye en sus m´todos para trabajar con n´meros grandes por e u lo que. Prueba de Miller . es de 1 por lo que hay que realizar varias pruebas u 4 para tener m´s certeza. Esta prueba provee un algoritmo probab´ ılistico eficiente aprovechando algunas caracter´ ısticas de las congruencias.Rabin . Estos u n´meros se denominan pseudo primos. un u n´mero a pase la prueba. probamos con otro n´mero aleatorio.5. Otras pruebas de primalidad En la (http://mathworld.6. Si no pasa la prueba decimos u que el n´mero es compuesto.wolfram.6. o 3. TEOR´ DE NUMEROS IA Desafortunadamente solo sirve para conocer si un n´mero es compuesto u dado que para algunos n´meros primos no se cumple.6. hagamos n = 2r s + 1 con s impar. Un n´mero primo pasa la prueba para todo a. no desarrollaremos el algoritmo en extenso. que este en el rango 0 ≤ j ≤ r − 1.. Estos n´meros se deu u nominan n´meros de Carmichael . Se ha probado que la probabilidad de que. Veamos por ejemplo el n´mero compuesto u u 561: 2561−1 mod 561 = 1 Algunos n´meros que no cumplen este teorema son el 561. 3. La utilidad de este m´todo se ve en el tratamiento de n´meros grandes e u donde la facilidad de la exponenciaci´n m´dulo es mucho m´s eficiente que o o a la divisi´n. En otros casos se indica que el n´mero es u u probablemente primo.com/search/) enciclopedia de matem´a ticas Mathworld se pueden encontrar otras pruebas de primalidad tanto .Este algorimo tiene su nombre por los autores del mismo. u Para determinar si un n´mero es compuesto podemos comenzar un alu goritmo con a = 2 y el momento que no se cumpla el teorema podemos decir que el n´mero es compuesto. se dice u que n pasa la prueba. u Para utilizar este concepto se escoge un n´mero aleatorio a. 1105. Dado un entero n impar. Si pasa la u prueba.

int certeza. BIBLIOTECAS DE JAVA 53 probabil´ ısticas. Lucas-Lehmer. BigInteger m) Devuelve thisexponente mod m . Muchos de ´stos m´todos no se han visto efectivos para la prueba de e e primalidad cuando se trata de n´meros grandes. test de primalidad de Adleman-Pomerance-Rumely. 0. como determin´ ısticas de las que mencionamos: Curva el´ ıptica. para el tratamiento de ´stos n´meros. Random r) Permite construir un n´mero probablemente primo de la longitud de bits especificau da.7. AKS de Agragual.3. =. Ward’s y otros. Devuelve falso si el n´mero es compuesto. u mod(BigInteger m) Devuelve el valor this mod m modInverse(BigInteger m) Retorna el valor this−1 mod m modPow(BigInteger exponente.Prueba si el n´mero es probableu mente primo con el grado de certeza especificado.. u 3. e u Constructores BigInteger(String val) Permite construir un n´mero grande a partir u de una cadena BigInteger(int largo. Bibliotecas de Java La aritm´tica de n´meros grandes es esencial en varios campos tales como e u la criptograf´ Las bibliotecas de Java incluyen una variedad de funciones ıa. la certeza especificada y random es un generador de n´meros u aleatorios. 1 para los casos que sean <.7. > respectivamente intValue() Devuelve el valor entero de this gcd(BigInteger val) Halla el m´ximo com´n divisor entre this y val a u isProbablePrime(int certeza) . M´todos e add(BigInteger val) Devuelve this + val compareTo(BigInteger val) Compara this con val y devuelve −1.

TEOR´ DE NUMEROS IA multiply(BigInteger val) Devuelve this ∗ val pow(int exponente) Devuelve thisexponente probablePrime(int longitud. Y rnd es un generador de n´meros aleatorios. 3.math.Random.println(prime). u remainder(BigInteger val) Devuelve this %val subtract(BigInteger val) Devuelve this − val toString(int radix) Devuelve una cadena en la base especificada. e /** *Programa para hallar un numero * primo de 512 bits * @author Jorge Teran * */ import java.out.util. public class PrimoGrande { public static void main(String args[]) { Random rnd = new Random(0). System. // generar un probable primo de 512 bits // con una probabilidad de que sea compuesto // de 1 en 2 elevado a l00.1. } } .BigInteger. El grado de certeza es 100. rnd). import java.54 ´ 3. Ejemplo Hallar un n´mero primo aleatorio de 512 Bits. BigInteger prime = BigInteger. La funci´n probablePrime u o utiliza para ´sto las pruebas de Miller-Rabin y Lucas-Lehmer.probablePrime(512.7. Random rnd) Devuelve un n´mero u probablemente primo.

n) Veamos el c´digo completo. 3. e = new BigInteger("3"). La difrencia u entre ambas est´ en que la clase SecureRandom hace la semilla inicial de a generaci´n de n´meros menos predecible. Calcular el multiplicativo inverso de e d = e.subtract(BigInteger.modInverse(m). 100. 2.ONE)) . Para resolver esto procedemos como sigue: 1. 5. Supongamos que queremos desarrollar el algoritmo de encriptaci´n de llave p´blica RSA . 4. r).multiply(q). Escoger dos n´meros primos p y q con p = q u BigInteger p = new BigInteger(longitud/2. Esto significa que de una ejecuci´n o u o a otra la secuencia aleatoria no va a ser la misma. . El algoritmo consiste en hallar dos o u n´meros d.gcd(e). Escoger e que sea relativamete primo a (p-1)(q-1) BigInteger m = (p.subtract(BigInteger. Publicar la clave privada como el par s = (d. BigInteger q = new BigInteger(longitud/2.add(new BigInteger("2")). while(m. Random y SecureRandom. BIBLIOTECAS DE JAVA 55 Un ejemplo de ejecuci´n del programa es: o 11768683740856488545342184179370880934722814668913767795511 29768394354858651998578795085800129797731017311099676317309 3591148833987835653326488053279071057 Veamos otro ejemplo.ONE)). n) u 6.multiply(q. r).intValue() > 1) e = e. Publicar la clave p´blica como el par p = (e.7. 100. e que cumplan la propiedades siguientes: c = me mod n y m = u cd mod n.3. Calcular n = pq n = p. Aqu´ hay que hacer notar que en Java existen dos o ı clases para hallar n´meros aleatoreos.

decifrado(cifrado). e = new BigInteger("3"). while(m.math. BigInteger cifrado= a.println(cifrado).out. 100. d = e. BigInteger q = new BigInteger(longitud/2.add(new BigInteger("2")). //Hallar d y e de 100 Bits BigInteger mensaje=new BigInteger("64656667686970").println(limpio).cifrado(mensaje). System.BigInteger. BigInteger p = new BigInteger(longitud/2.subtract(BigInteger.BigInteger.subtract(BigInteger. 100.modInverse(m). } } import java.56 ´ 3.intValue() > 1) e = e.out.ONE)).SecureRandom.gcd(e).ONE)) . class Rsa { private BigInteger n.security. public class Principal { /** * Programa para utilizar la Clase RSA * @author Jorge Teran * @param args ninguno */ public static void main(String[] args) { Rsa a = new Rsa (100). System. BigInteger limpio= a. import java. d.multiply(q).math. public Rsa(int longitud){ SecureRandom r = new SecureRandom(). r). TEOR´ DE NUMEROS IA import java.out. BigInteger m = (p.multiply(q. } . e. r). n = p.println(mensaje). System.

5. 2. } } 3. 15. 3.8. u Entrada y salida. o Esto equivale a encontrar los n´meros que se pueden formar por 2a 3b 5c .1.. Muestra los primeros 11 n´u meros feos. Ejercicios A continuaci´n se presentan varios problemas que est´n asociados a la o a tem´tica presentada. 8.. La salida debe consistir de una l´ ınea reemplazando n´mero con el n´mero calculado. Por convenci´n se incluye el 1.3. 4. u Escriba un programa que encuentre e imprima el n´mero 1500. Estos problemas se pueden ver en su versi´n original en a o ingl´s en el sitio de la Universidad de Valladolid http://online-judge.. 9.modPow(e. e El n´mero de problema especificado es el n´mero de problema publicado en u u la UVA. 6.8. u ..8. Problema 136 .No existe entrada en este problema.modPow(d. u u ´ La secuencia 1.es/. . 3. n). 10.uva. Esto se utilizar´ tambi´n en cap´ a e ıtulos posteriores. 3. u u Ejemplo de salida The 1500’th ugly number is n´mero. EJERCICIOS 57 public BigInteger cifrar(BigInteger mensaje) { return mensaje. o 5. 12. } public BigInteger decifrar(BigInteger mensaje) { return mensaje. n).N´ meros Feos u Los n´meros feos son n´meros cuyos unicos factores primos son 2.

un matem´tiıa ıa e a co de la universidad de Lehigh. TEOR´ DE NUMEROS IA 3. not´ que el n´mero de tel´fono de su cu˜ado o u e n H. Fue capaz de presentar una colecci´n de diversos n´meros de Smith: Sin embargo. e o o Problema. n u n u 22. Albert Wilansky. 58. encontrar los n´meros de Smith que son m´s n u a grandes que 4937775. Wilansky no pod´ o u ıa dar un n´mero de Smith que sea m´s grande que el n´mero de tel´fono de u a u e su cu˜ado. u a n Salida. 202. 85. Cada caso de prueba consiste de una l´ u ınea que 9 contiene un solo n´mero entero positivo m´s peque˜o que 10 .Wilansky public´ un art´ o ıculo acerca de los n´meros de Smith u en ”Two Year College Mathematics Journal”. 265.El n´mero que se introduce en la primera l´ u ınea de entrada es el n´mero de casos de prueba.Para cada valor de n. N´meros de Smith. u Ejemplo de entrada 1 4937774 Ejemplo de salida 4937775 . Una lista peque˜a de n´meros de Smith es 4.2. Este n´mero se pueu u e u de escribir como el producto de sus factores primos de la siguiente manera: 4937775 = 3 ∗ 5 ∗ 5 ∗ 65837. Entrada.N´ meros De Smith u Mientras le´ su gu´ de tel´fonos en 1982. Pues esta observaci´n es tambi´n verdad para cada n´mero primo. 121.58 ´ 3. Problema 10042 .. Asumir que existe tal n´mero. se tiene que calcular el n´mero de Smith u m´s peque˜o. y la suma de los d´ ıgitos de los factores primos es igualmente 3 + 5 + 5 + 6 + 5 + 8 + 3 + 7 = 42.. Smith ten´ la siguiente caracter´ ıa ıstica peculiar: La suma de los d´ ıgitos de ese n´mero era igual a la suma de los d´ u ıgitos de los factores primos de ese n´mero. 166. con el nombre de su o u cu˜ado. Wilansky fue as´ que sorprendido por ı su descubrimiento que nombr´ a este tipo de n´meros.8.. Esta es su tarea. que sea mayor a n (o que est´ por encima de n) e imprimir a n e cada n´mero en una sola l´ u ınea. El n´mero de tel´fono de Smith era 493-7775. La suma de todos los d´ ıgitos del n´mero de tel´fono es 4 + 9 + 3 + 7 + u e 7 + 7 + 5 = 42. 94. Wio e u lansky decidi´ m´s adelante que el n´mero primo no es igual que el n´mero o a u u de Smith y ´l los excluy´ de la definici´n. 27.

Ejemplo de entrada 69 6 27 20 10000 20 100000 1000 1009 Ejemplo de salida 9 divides 6! 27 does not divide 6! 10000 divides 20! 100000 does not divide 20! 1009 does not divide 1000! . Y y D.El problema de Euclides Desde la ´poca de Euclides se conoce que para cualquier entero positivo e A y B existen enteros X y Y que AX + BY = D.Si hay m´ltiples X y Y . Entrada. menores a 2 . donde D es el m´ximo a com´n divisor de A y B.La entrada consiste de un conjunto de l´ ıneas con n´meros enu teros A y B. Cada una conte31 niendo dos enteros no negativos.3. B < 1000000001). Cada l´ ınea de salida consiste de una l´ ınea indicando si m divide a n!..8. separados por un espacio (A. Problema 10104 . Salida. en el formato que se muestra. EJERCICIOS 59 3. n! est´ definida para todos los enteros no negativos o a como sigue: 0! = 1n! = n ∗ (n − 1)! (n > 0) La entrada para el programa consiste de varias l´ ıneas. Problema 10139 . El problema es encontrar los correspondientes X. n y m.Para cada l´ ınea de entrada la salida debe consistir de tres enteros X. Ejemplo de entrada 46 17 17 Ejemplo de salida -1 1 2 0 1 17 3.8. debes imprimir u el par para el cual |X| + |Y | es m´ ınimo (primordialmente).8.4.. separados por un espacio. Y u y D.Factovisors La funci´n factorial.3.

000. Esfuerzos corrientes en verificaci´n han tenido ´xito en verificar la traducci´n de c´digo o e o o de alto nivel a nivel del chip.. y. Debe haber una l´ ınea de salida por cada l´ ınea de entrada.La entrada consiste de una secuencia de enteros positivos.Para cada entero N en el archivo de entrada imprime dos enteros separados por un espacio. Ejemplo de entrada 10 25 100 Ejemplo de salida 14 49 16 27 . Tambi´n tiene u e que calcular el n´mero de valores tal que p no es parte de alg´n triple. Este problema trata de calcular cifras relacionadas a una parte del ultimo ´ teorema de Fermat: que explica que no existen soluciones enteras para an + bn = cn con n > 2.8. TEOR´ DE NUMEROS IA 3. y z son valores enteros positivos menores o iguales N .. y. u u Entrada. Problema Dado un entero positivo N . 000. Salida.5. Problema 106 . tal que u x < y < z. z) que sean primos relativos.60 ´ 3. Pit´goras a Las pruebas asistidas por computadora ocupan un verdadero nicho en las ciencias de la computaci´n. Cada entero en el archivo de entrada es menor o igual a 1. La entrada termina con fin de archivo. es decir no tienen un com´n divisor mayor que 1. El segundo n´mero u es el n´mero de enteros positivos que no son parte de alg´n triple cuyos u u componentes son ≤ N . La primera prueba de muchos problemas o fue completado con la ayuda de un programa de computadora. escriba un programa que calcule dos valores respecto la soluci´n de o x2 + y 2 = z 2 donde x. El primer entero es el n´mero de primos relativos u triples (tal que cada componente del triple es ≤ N . Se tiene que computar el n´mero de triples (x.Fermat vs. uno por l´ ınea.

1. Existen programas en diferentes industrias que. Durante muchos a˜os se han o o n prometido programas que podr´ verificar a otros. Desde la d´cada de los ıan e 60 seguimos esperando. podemos mencionar los programas que controlan el vuelo de los aviones. e Tradicionalmente la prueba del software ha sido presentada como un detalle de pruebas denominadas de caja negra y caja blanca. Estos o o planes de prueba han dado como resultado que durante la explotaci´n del o software siguen apareciendo errores no detectados en la prueba. Las pruebas de caja negra son aquellas que se enfocan en el exterior del m´dulo sin importar o el c´digo. Como ejemplo.Cap´ ıtulo 4 Codificaci´n con miras a la o prueba 4. u Hoy en d´ se hace mucho m´s importante la verificaci´n de los prograıa a o mas. A´n no existe esta posibilidad. Introducci´n o La prueba de programas de software ha sido siempre un campo muy ´rido a y no se ha tomado en cuenta en el momento del desarrollo del c´digo. servomecanismos asistidos por computadora e inclusive muchos de los electrodom´sticos que existen en su hogar. Las pruebas de caja blanca son m´s amplias y tratan de verificar o a el c´digo probando partes indicando la cobertura del c´digo probado. en caso de fallas pueden causar inclusive la muerte de personas y otros que no permiten pruebas experimentales. Para o desarrollar programas m´s fiables se hace necesario planificar la verificaci´n a o del c´digo al momento de su construcci´n. 61 .

..2. Por este motivo quiero presentar este tema. CODIFICACION CON MIRAS A LA PRUEBA Hoy en d´ se tiene un conocimiento m´s profundo de la programaci´n y ıa a o se pueden realizar muchas m´s verificaciones que. Por ejemplo salirse del tama˜o de un n vector incrementando el tama˜o del ´ n ındice fuera de los l´ ımites del mismo. Veamos un ejemplo: void copia(char[] b) { char[] datos = new char(100). for (int i=1. En el presente cap´ ıtulo presentaremos una serie de t´cnicas que ayudan e a la prueba y mantenimiento del c´digo. .62 ´ 4. n . La codificaci´n es una de las habilidades requeridas o para esto. solo las de la caja negra a que pueden indicarnos bien o mal. . las aserciones y la programaci´n por contrato.i< b.. } return En el segmento de c´digo expuesto se puede apreciar que se copia el vector o b a datos pudiendo causarse un desborde en datos si es que b es de mayor tama˜o que datos. sin embargo. i++) datos[i]=b[i] . Algunos errores de programaci´n o Cuando revisaba las revistas Comunicati´n of the ACM [KBO+ 05] eno contr´ una serie de preguntas sobre errores existentes en diferentes c´digos. No se trata de ninguna manera o de entrar en el campo de la verificaci´n formal de programas. o 4. El control de calidad y la verificaci´n de programas nos permite encontrar o errores de los programas. e o Estos errores normalmente no son vistos por los programadores proveen una puerta por donde se producen fallos mal intencionados durante la explotaci´n o del programa. Se presenta la especificaci´n o o formal. El desborde de la memoria se produce cuando se accede fuera de las dimensiones de la variable definida. o espero que sirva de una buena introducci´n.length.

durante la ejecuci´n. y la ejecuci´n del mismo se ve as´ o ı: >desp 12 12 Que pasa si en la invocaci´n al mismo colocamos m´s de dos d´ o a ıgitos? >desp 12345 12345 Cuando llegamos a 6 d´ ıgitos obtenemos una lista interminable de .´ 4. printf("%s\n".h> #include <stdlib. Como.2. copia). o Estos errores se producen al reescribir parte del c´digo con datos. error de bus. //programa para desplegar el primer // argumento de la l´nea de comando ı // desp.argv[1]). se obtendr´ un error de ´ndice fuera o a ı de rango. En estos casos al no producirse este error se obtienen mensajes tales como error de segmentaci´n. Cuando colocamos un programa en producci´n generalmente se o recompilan los c´digos con argumentos de optimizaci´n y el control de ´ o o ındices fuera de rango queda eliminado. un o intruso puede enviar una serie de c´digos que quiere ejecutar. ALGUNOS ERRORES DE PROGRAMACION 63 Normalmente.c // Autor Jorge Teran #include <stdio.h> int main(int argc. return 0. se va ha reescribir parte del c´digo. char *argv[]) { char copia[2]. } Como se ve este programa despliega en pantalla el argumento introducido en la l´ ınea de comando. al salirse o del rango del vector datos.h> #include <string. strcpy(copia. o Veamos un ejemplo escrito en lenguaje C.

e class Nombre { String nombre. Estas acciones hacen el tiempo de proceso m´s lento. Esto o o hace que este tipo de problemas no se presenten en algunos lenguajes como el Java. Cuanto m´s controles o a se tengan se demorar´ m´s tiempo de proceso. Con respecto al lenguaje de programaci´n podemos preguntarnos cual o lenguaje ofrece mejores condiciones en el tiempo de proceso durante la ejecuci´n del programa. ´sto puede ser un mecanismo para introducir c´digos e o a un programa y hacer que realice algo para lo que no ha sido dise˜ado. n Es posible que se cambie el c´digo para realizar un chequeo de ´ndice o ı fuera de rango durante la copia pero. Para ejemplificar supongamos o o la clase N ombre que tiene un m´todo para devolver el nombre. Y en caso contrario se tienen a a algunas inseguridades a cambio de una mejora en la ejecuci´n. Existen algunas soluciones que se pueden adoptar para resolver este tipo de problemas por ejemplo. Tal es el caso de la rutina strcpy mostrada. o En el caso del lenguaje Java al ejecutarse en un entorno cerrado provee control sobre la ejecuci´n del c´digo que es inexistente en el lenguaje C. proteger la memoria donde se encuentra la direcci´n de retorno a solo o lectura. a Lo que queremos expresar con este ejemplo es que a´n cuando un prou grama haya sido probado y se supone que funciona correctamente puede presentar fallas.. CODIFICACION CON MIRAS A LA PRUEBA >desp 123456 123456 123456 123456 . a La programaci´n Java no est´ exenta de fallas que se producen en la ejeo a cuci´n del c´digo.. La respuesta es bastante obvia. Como se dijo. por situaciones no previstas. Claramente hemos invadido el ´rea de c´digo y eliminado parte de la instruca o ci´n return de la rutina printf. introducir un control de sub´ ındices durante la copia.64 ´ 4.. Nombre(String n) { nombre=n. } . consume m´s tiempo de proceso. Si introducimos m´s valores se obtienen otros o a errores.

devuelveNombre(). cuando da el error identifica claramente el problema. int largo=persona.´ 4. Analizando vemos que se trata de calcular la longitud del nombre.length(). String dato = persona. } } Suponga que quiere utilizar la clase N ombre como sigue: Nombre persona = new Nombre(nombrePersona). El mensaje del sistema no dice cual es la causa del error. ALGUNOS ERRORES DE PROGRAMACION 65 String devuelveNombre() { return (nombre).trim().err. ahora que est´ sea guro que el programa no falla se pone el programa en ejecuci´n en un sistema o distribu´ ıdo. ¿Qu´ pasa cuando nombreP ersona es un valor nulo? e Claramente obtendremos un error de ejecuci´n indicando la l´ o ınea donde se produjo el error. Para solucionar este problema en medio de la ejecuci´n de un sistema o se tiene que corregir el programa para tomar en cuenta este posible error modificando el c´digo como sigue: o Nombre persona = new Nombre(nombrePersona). puede ocurrir que no se encuentre la clase persona y el sistema falle. } Ahora estamos seguros que el programa funciona y que. Bien supongamos que. Para esto hay que volver a corregir el c´digo adicionando un control: o .devuelveNombre().length(). } else { largo=dato.2. if { (dato == null) System.println("Error grave: Falta la propiedad ’nombre’ ").trim(). int largo=0.

length().err.trim(). CODIFICACION CON MIRAS A LA PRUEBA Nombre persona = new Nombre(nombrePersona). e . if { (persona == null) System.devuelveNombre(). a Cuando se especifica un programa hay que considerar que no solo puede tener errores. } Estas consideraciones hacen necesario especificar el c´digo de una forma que. Por esta raz´n tambi´n deben verificarse las especificaciones de los o e mismos.err.3. String dato = persona. Tambi´n o o e puede ver un excelente trabajo que describe esta axiom´tica en [CK79]. o 4. Aunque no es parte del texto un tratamiento riguroso de la verificaci´n y prueba de programas. if { (dato == null) System.66 ´ 4. } else { largo=dato.println( "Error grave: Falta la propiedad ’nombre’ ").println( "Error grave: clase Persona no disponible"). } int largo=0. tambi´n puede ser que est´ equivocada la especificaci´n del e e o mismo. es necesario introducir este tema que se estudia o en los cursos de m´todos formales. Especificaci´n de programas o La especificaci´n de programas tienen su origen en Hoare [Hoa83] quien o desarroll´ las bases para la especificaci´n formal de programas. o se pueda determinar una serie de problemas con mucha anticipaci´n.

la existencia de una clase. Post condici´n Son los valores finales que toman las variables del programa o Todo programa consiste de tres partes: 1. que los datos esten ordenados. Las letras min´sculas se utilizan para especificar u u valores. La notaci´n que se o utiliza para esto es: [P ]C[Q] . o Llamemos a {P } precondici´n. o Ejemplo: {X = 1}X = X + 1{X = 2} Este peque˜o c´digo especifica que si X es inicialmente 1 una vez corrido el n o programa X toma el valor de 2 que es claramente verdadero. etc. Una expresi´n del tipo {P }C{Q} es una especificaci´n de correctitud o o parcial porque para verificar que es correcta. no es necesario que el programa C termine. Esta notaci´n se debe a Hoare [Hoa83]. Normalmente en esta notaci´n las precondiciones y las variables se escrio ben en letras may´sculas. Por ejemplo para indicar que la variable X toma una valor arbitrario x se escribe X = x. ESPECIFICACION DE PROGRAMAS 67 Precondici´n Son lo valores iniciales que toman las variables del programa. Terminaci´n o La preservaci´n de propiedades se denomina invariante y es lo que nos permite o verificar el c´digo. o o La notaci´n o {P }C{Q} significa que si partimos de un estado P despu´s de que el programa termine e llegaremos al estado Q.´ 4. e Por ejemplo puede ser que una variable no sea nula. Inicializaci´n o 2. Una especificaci´n m´s fuerte es la especificaci´n de correctitud total en o a o la que se pide la prueba de que el programa termine.3. Preservaci´n de propiedades o 3. o o tambi´n los pre requisitos necesarios para su correcto funcionamiento. a {Q} post condici´n y C un programa.

W HILE Y ≤ R R = R − Y . desea una descripo ci´n m´s abstracta o porque desea realizar un an´lisis del mismo. El valor de Q y R est´n especificados solo en la post condici´n. o a a Lo que uno debe preguntarse es porque especificar formalmente y las respuestas que se pueden conseguir de desarrolladores profesionales son: 1.Q = Q + 1 {R < y ∧ X = R + (Y xQ)} Este ejemplo es menos intuitivo para la verificaci´n pero nos indica clarao mente que el resultado depende de los valores de X y Y . ¿Por qu´ especificar? e La primera pregunta que uno se hace es por qu´ especificar?. o Se quiere mostrar que la propiedad es realmente una invariante. n . o o 4. CODIFICACION CON MIRAS A LA PRUEBA la relaci´n que existe entre ambas definiciones es: o correctitud total = terminacion + correctitud parcial Por ejemplo si queremos especificar la correctitud total de que los valores de X. Y = R [X = y ∧ Y = x] No todas las variables deben especificarse en una precondici´n. Q = 0.1. a o Como no se especificaron en la precondici´n no se puede decir nada de o ellos antes de la ejecuci´n del c´digo. Mostrar que una propiedad se mantiene globalmente en un programa Se quiere caracterizar la condici´n de correctitud. X = Y .68 ´ 4. Se quiere mostrar que mi sistema cumple alg´n criterio de alto u nivel en el dise˜o. Y se intercambian podemos escribir: [X = x ∧ Y = y] R = X. veamos o como ejemplo una divisi´n por restas sucesivas: o {Y = y ∧ X = y} R = X. Uno puede e especificar para tener mayor documentaci´n del sistema.3.

3. Se quiere saber si el programa que he dise˜ado es computacionaln mente completo.2. 3. ESPECIFICACION DE PROGRAMAS 69 2. a n Cumplir los requisitos legales de algunos pa´ ıses. ¿Puede o debe? Una vez que uno tiene claro lo que hay que especificar uno puede determinar que puede formalizarse. o a 5. Se quiere estar seguro que no exista este error. Especificar interfases Se quiere definir una jerarqu´ de clases.3. Solo se pueden especificar algunos aspectos tales como funcionalidad y comportamiento de un sistema de tiempo real. Manejar la complejidad El dise˜o est´ muy complicado para manejar todo en la cabeza y n a necesitamos una forma de pensar en pedazos m´s peque˜os. Se quiere especificar que las cosas correctas ocurren cuando se produce un error. ıa Se quiere una descripci´n m´s formal de la interfase del usuario. Cambiar el control Cada vez que cambio un pedazo de c´digo quisiera conocer que o otras partes son afectadas sin mirar todos los m´dulos y sin mirar o el c´digo fuente. Completitud Se quiere estar seguro que se ha cubierto todos los casos. ¿Qu´ especificar? e Los m´todos formales no est´n desarrollados de tal forma que un sistema e a entero y muy grande pueda ser especificado completamente. o 4. incluyendo los casos de error. Al escribir una especificaci´n uno debe decidir si la descripci´n es requeo o rida y permitida. 4.´ 4. . Manejo de errores Se quiere especificar que ocurre cuando se produce un error. 6.

para entidades estructuradas podemos ver otras propiedades de las que. Formalizar las transiciones le permite probar que se mantienen durante la ejecuci´n del programa. ¿Los elementos est´n ordenados? a Duplicados. ¿Se Permiten? Rangos. etc? a 4.3. jer´rquica. ¿Pueden acotarse los elementos de alguna manera? Acceso asociativo. Las invariantes son una buena forma de caracterizar las propiedades deseadas de un sistema. La correspondencia entre este tipo de propiedades se verifica por el compilador. u Propiedades de entidades Las propiedades m´s importantes de las entidades se expresan comunmena te por el tipo. o Comportamiento observable Se denomina cuando se especifica el comportamiento del sistema cuando interact´a con su ambiente. ¿C´mo especificar? o Dado que entiende lo que desea especificar y lo que desea obtener puede empezar a especificar. e o o Para ´sto damos algunas ideas: e . Sin embargo. ¿Los elementos se recuperan por ´ ındices o llaves? Forma ¿El objeto tiene una estructura lineal. arbitraria. CODIFICACION CON MIRAS A LA PRUEBA Esto implica la noci´n de una condici´n global de correctitud que el siso o tema debe mantener.70 Condiciones de correctitud ´ 4.3. Invariantes La forma de caracterizar algunas condiciones que no cambian de un estado a otro se denominan invariantes. La t´cnica principal es la descomposici´n y abstracci´n. podemos anotar por ejemplo: Orden. a gr´fica.

Las invariantes explican las estructuras de datos y algoritmos. codificaci´n. Verificar las suposiciones. Una invariante es una proa piedad que es verdadera y no cambia durante le ejecuci´n del programa. El uso de invariantes informalmente o tambi´n ayuda a los programadores.Teniendo las invariantes las podemos utilizar en la verificaci´n del progrma observando que no cambian a medida que o se procesa. Las invariantes son utilies en todos los aspectos de la programaci´n: di´ o se˜o..Las invariantes caracterizan ciertos aspectos de la ejecuci´n del programa y proveen una documentaci´n valiosa o o sobre el algoritmo. Piense en funci´n de la definici´n. e Documentar el programa. estructura de datos y los conocimientos a un nivel necesario para modificar el programa. Las propiedades de las invariantes deben mantenerse cuando se modifica el programa.. No piense como programador. prueba.3. no de la funcionalidad o o Trate de construir teor´ no solo modelos ıas..3. Presentamos una n o o lista de usos a fin de motivar a la utilizaci´n de las mismas por los prograo madores. Esta o propiedad engloba a la mayor parte de los elementos o variables del programa. Evitar errores. No piense en forma computacional 4. Invariantes Definamos con m´s claridad una invariante. Escribir mejores programas. La invariante obtenida se utiliza en un proceso est´tico para a verificar la correctitud del programa.Muchos autores coinciden que se pueden construir mejores programas cuando se utilizan especificaciones en el dise˜o de los programas.4. mantenimiento y optimizaci´n.Las invariantes pueden prevenir que el programa realice cambios que accidentalmente cambien las suposiciones bajo las cuales su funcionamiento es correcto. ESPECIFICACION DE PROGRAMAS 71 Abstraer. Las invariantes formalizan en forma precisa n el contrato de un trozo de c´digo.´ 4. .. Cada ciclo tiene una propiedad invariante.

Pruebas.. ı o o Veamos varios detalles del programa: Tiene tres variables P. o .Prueba de teoremas. precondici´n.Condiciones inusuales o excepcionales deben llamar la atenci´n a los programadores porque pueden ser causa o de posibles errores. IF not (x=0) while not (N=0) IF IMPAR(N) P=PxX N=N /2 X=X x X ELSE P=0 aqu´ la precondici´n es {X = x∧N = n} y la post condici´n {P = xn }. Algunas de ´stas son el n´mero de o e u l´ ıneas ejecutadas por el prgrama.. La otra es de mantener las invariantes para caracterizar el uso correcto del programa. Los valores iniciales son un valor x. CODIFICACION CON MIRAS A LA PRUEBA Formar un espectro. o La post condici´n indica que el resultado es xn .Las invariantes pueden ayudar en la generaci´n o de datos de prueba de dos maneras. Crear datos de prueba. Ubicar condiciones inusuales..72 ´ 4.El espectro de un programa son propiedades medibles en el programa o su ejecuci´n. el tama˜o de la salida o propiedades n est´ticas como la complejidad. n cualesquiera. o Ejemplos 1. N. X. La diferencia entre varios aspectos nos a muestran cambios en los datos o el programa. Mostrar que la invariante es P X N = xn ∧ x = 0 P:=1. chequeo del a modelo y otros mecanismos automatizados o semi automatizados pueden verificar la correctitud del programa con respecto a su especificaci´n. an´lisis de flujo de datos.. Pueden infringir intencionalmente las invariantes ampliando los datos de prueba.

N .´ 4.1: Valores que toman la variables durante la ejecuci´n o Para mostrar que P X n es una invariante tomamos dos valores X. N<M. Esto indica que la invariante es: N −1 X= i=0 i . Con estos valores contruimos el cuadro 4. Comprobamos que es correcta porque sus valores no cambian.1 que muestra los valores que toman las variables durante la ejecuci´n. M++) X=X+M post condici´n {X = (M (M − 1))/2} o En este ejemplo vemos que efectivamente X en cualquier momento representa el resultado de la sumatoria hasta el n´mero de iteraci´n en u o que se encuentra. 2. o Como ve hemos anotado todos los valores que toman las variables involucradas y anotado los valores que toman al final de cada iteraci´n o calculando la supuesta invariante . for (N=1. Las invariantes pueden tomar diferentes formas. ESPECIFICACION DE PROGRAMAS 73 Iteraci´n o 1 2 3 4 - N 9 9 4 2 2 1 1 1 0 0 P X P XN 1 2 512 2 2 – 2 4 512 2 4 – 2 16 512 2 16 – 2 256 512 512 256 512 512 256 – 512 65536 – Cuadro 4.3. Supongamos que X = 2 y N = 9. consideremos por ejemplo el siguiente programa precondici´n {M ≥ 1 ∧ N = n} o X=0.

} 2. while (X < 20){ X=X+5. a Mcd(a. al principio del ciclo ı toma el valor de 1 y al terminar el mismo toma en valor de N +1.b) if (b==0) return (a) else Mcd(b.. Determinar la invariante del ciclo siguiente: X=0. a %b) por lo tanto esta expresi´n es la invariante que se cumple durante la o ejecuci´n de todo el programa. Ejercicios propuestos 1. Indicar cuales son las precondiciones y post condiciones de un ciclo f or. o −1 cuando no existe. } Aqu´ vemos que I debe ser una variable definida. dados dos n´meros a.74 ´ 4. Considere un programa de b´squeda secuencial que devuelve la posici´n u o del elemento buscado. b se cumple u M cd(a. CODIFICACION CON MIRAS A LA PRUEBA 3. o 4... b) = M cd(b. No se ha caracterizado una invariante dado que no se ha escrito un programa al interior del ciclo.. I<=N. a%b) Recordando el teorema de Euclides.. .5.. Considere el algoritmo de Euclides para hallar el m´ximo com´n divisor a u y caracterice cu´l es la invariante del problema. for (I=1. 4. N++{ . Cu´l es la invariante a apropiada? .3.

Considere una clase que coloca y saca elementos en una estructura de pila. while ((i<v. el de verificar que las o propiedades se cumplen durante la ejecuci´n. Durante el proceso. Aplicaciones de las invariantes Las aplicaciones de las invariantes se orientan basicamente en el desarrollo y verificaci´n de los programas. APLICACIONES DE LAS INVARIANTES 75 int buscar(int [] v. post a condiciones e invariantes de la clase? 4. Escriba un programa e indique cu´les son las precondiciones. Probar que la invariante del procedimiento de divisi´n por restas suceo civas es X = R + (Y xQ) {Y = y ∧ X = y} R = X. a .length()&&(v[i]!=t){ i++. W HILE Y ≤ R R = R − Y . Q = 0.Q = Q + 1 {R < y ∧ X = R + (Y xQ)} 4. int t){ // precondici´n el vector v no esta ordenado o // precondici´n t es el valor a buscar o int i=0. } if (i<n) return (i) else return (-1) } //post condici´n devuelve -1 cuando no existe y o // devuelve la posici´n i cuando existe o 3. En la verificaci´n est´n los o o a m´todos formales que vienen de la l´gica formal y de aquellos procedentes e o del c´lculo de predicados [Red90].4.4.4.

posteriormente introducirnos a la tem´tica de verficar o a el funcionamiento del programa en tiempo de ejecuci´n. Codificar el ciclo. Comenzamos escribiendo las pre y post condiciones /* * * * * */ Programa que realiza una divisi´n por restas sucesivas o Precondici´n: x toma un valor y la variable y es > 0 o Post condici´n: x=y*q +r o Donde q es el cociente y r es el resto El proceso contin´a identificando las variables del programa que. utilizando restas sucesivas.. Escribir las pre y post condiciones . Y hallar Q denomiu nado cociente y R denominado residuo tal que Q sea el cociente de la divisi´n o y R sea el residuo. manteniendo la invariante en cada instante.Dados dos n´mero X. el proceso de dividir un n´mero por otro u hallando el residuo. Planteamiento del problema. Prueba del programa. CODIFICACION CON MIRAS A LA PRUEBA Lo que se presenta es el desarrollo de programas utilizando los principios de verificaci´n para. 6. 2. 5.76 ´ 4. las codiu ficamos directamente: /* * * * * * */ Programa que realiza una divisi´n por restas sucesivas o Precondici´n: x toma un valor entero o y la variable entera y es > 0 Post condici´n: x=y*q +r o Donde q es el cociente y r es el resto . 3. o El m´todo que se sigue consiste de los siguientes pasos: e 1. Especificar el problema. Desarrollemos como ejemplo. Encontrar la invariante . 4. Identificar las variables del problema.

... } En este momento identificamos las caracter´ ısticas y las invariantes del problema utilizando las variables definidas en la pre y post condici´n .. APLICACIONES DE LAS INVARIANTES 77 divide(int x. Los valores iniciales de las variables q. } La invariante del ciclo debe mantenerse durante toda el ciclo. } ..int y) { int q.4. En nuestro caso es obvio que la invariante es x = q · y + r /* Programa que realiza una divisi´n por restas sucesivas o * Precondici´n: x toma un valor entero o * y la variable entera y es > 0 . . Segundo observamos que el resto debe ser menor que el dividendo caso contrario se puede seguir restando.4....int y) { int q=0. ... y r = y respectivamente.. while (r > = x) { .. a Codificando estas consideraciones /* Programa que realiza una divisi´n por restas sucesivas o * Precondici´n: x toma un valor entero o * y la variable entera y es > 0 * Post condici´n: x=y*q +r o * Donde q es el cociente y * r es el resto */ divide(int x........ ... Prio mero el algoritmo consiste en restar sucecivamente el valor del divisor hasta hallar el cociente y el resto... int r=y.. r ser´n q = 0.r. .

q++. Vemos por ejemplo 9/2 : . q++. while (r > = x) { //invariante x=y*q +r r=r-y. int r=y. o /* Programa que realiza una divisi´n por restas sucesivas o * Precondici´n: x toma un valor entero o * y la variable entera y es > 0 */ divide(int x.78 ´ 4.int y) { int q=0. } /* Post condici´n: x=y*q +r o * Donde q es el cociente y * r es el resto */ } La invariante se verifica que es matem´ticamente correcta. Tomando un a ejemplo de ejecuci´n para un caso particular se puede ver que la invariante o no cambia. } } reacomodando los comentarios tenemos la versi´n final. while (r > = x) { //invariante x=y*q +r r=r-y.int y) { int q=0. CODIFICACION CON MIRAS A LA PRUEBA * Post condici´n: x=y*q +r o * Donde q es el cociente y * r es el resto */ divide(int x. int r=y.

Los que no son u u u e m´ltiplos son n´meros primos y no est´n marcados. . o o ı o import java.4.000 * utilizando la Criba de Eratostenes * Precondici´n: o * Un vector de bits con todos sus valores en cero */ public class Criba { public static void main(String[] s) { int n = 100000000. post condici´n as´ como. Especifiquemos el programa para construir la criba de Eratostenes.. 5. APLICACIONES DE LAS INVARIANTES 79 Iteraci´n o 0 1 2 3 4 x y q r x=y*q +r 9 2 0 9 9 9 2 1 7 9 9 2 2 5 9 9 2 3 3 9 9 2 4 1 9 Como se observa en cada iteraci´n se ha mantenido la invariante. } } /** * Post condici´n: o * Un vector de bits con los numeros primos en cero. BitSet a = new BitSet(n + 1)..*. o Veamos un ejemplo que utiliza dos bucles.util. u Al tener solo dos estados se puede utilizar un vector de bits. 4.. u u a De aqu´ se ve que. Escribimos la precondici´n. Lo que se quiere es un vector donde los todos los m´ltiplos de alg´n n´mero est´n marcados. Recordemos que lo que se hace en el algoritmo es marcar todos los m´ltiplos de 2. Los marcados son los n´meros no primos.4. los elementos requeridos en el c´digo. la precondici´n del problema es un vector que tiene dos ı o estados: marcado y no marcado. */ Ahora debemos construir las invariantes del ciclo.000. 3. hasta la u . /** * Programa para construir los numeros primos * hasta = 100.

El resultado obtenido es: import java. BitSet a = new BitSet(n + 1). CODIFICACION CON MIRAS A LA PRUEBA ra´ cuadrada del n´mero m´ximo. */ Ahora completemos con las pre y post condiciones de cada ciclo. j=j+i. i * i <= n. i++) { //Invariante hasta i-1 se han marcado todos los //multiplos de i .get(i)) { for (j = i + i.) { //Invariante j es multiplo de i a. Las corres- . j <= n.80 ´ 4. // construcci´n de la criba o for (i = 2. Las correspondientes al primer ciclo son las mismas del programa. j = 0. /** * Programa para construir los numeros primos * hasta = 100.set(j). Como se requieren dos ciclos tambi´n se ız u a e requieren dos invariantes.util.000. int i = 2.000 * utilizando la Criba de Eratostenes * Precondici´n: o * Un vector de bits con todos sus valores en cero */ public class Criba { public static void main(String[] s) { int n = 100000000. } } } } } /** * Post condici´n: o * Un vector de bits con los numeros primos en cero.*.1 para i > 2 if (!a.

j=j+i.000 * utilizando la Criba de Eratostenes * Precondici´n: o * Un vector de bits con todos sus valores en cero */ public class Criba { public static void main(String[] s) { int n = 100000000. o import java. i++) { //Invariante hasta i-1 se han marcado todos los //multiplos de i .*. i * i <= n. APLICACIONES DE LAS INVARIANTES 81 pondientes al segundo ciclo son: Precondici´n: Los m´ltiplos de i no han sido o u marcados.4. j = 0. j <= n.000. BitSet a = new BitSet(n + 1). int i = 2.4.1 para i > 2 if (!a.get(i)) { //Precondici´n: o // los multiplos de i no han sido marcados for (j = i + i. /** * Programa para construir los numeros primos * hasta = 100. } //Post condici´n: o //los multiplos de i han sido marcados } } } } /** * Post condici´n: o //Un vector de bits con los numeros primos en cero. Introduo u ciendo las mismas tenemos la versi´n final. // construcci´n de la criba o for (i = 2.set(j).) { //Invariante j es multiplo de i a.util. */ . Post condici´n: Los m´ltiplos de i han sido marcados.

Un programa para evaluar esta secuencia de n´meros ser´ el siguiente: u ıa //Precondicion: N>=0 y=1. y=x+y. De aqu´ se puede ver que la invariante del ciclo es: ı x y = 0 1 1 1 n 0 1 (4. while(n!=N){ x=y.4.2) Si reemplazamos 4.4. CODIFICACION CON MIRAS A LA PRUEBA Una de las aplicaciones de las invariantes es caracterizar el desarrollo de un programa. } donde A y B son matrices. B tenemos A= x y B= 0 1 1 1 (4.4. Analizando vemos que lo que se est´ calculando a n es A = B A. n=0. n++.4. reescribimos las siguientes l´ ıneas de c´digo: x = y y y = x + y como una ecuaci´n matricial: o o x y = 0 1 1 1 x y (4.82 ´ 4. como ver´ es dif´ de comprender si no se u a ıcil sigue el desarrollo. x=0.3) .1) Denominando estas matrices A. La serie de Fibonacci es formada por la ecuaci´n t(n)+t(n−1) con t(0) = o 1. El siguiente ejemplo muestra el desarrollo de un programa que eval´a la serie de Fibonacci que.2 en el programa la parte del ciclo se convierte en: while(n!=N){ A=B*A n++. } //Post condicion x=Fibonacci(N) Para mejorar el tiempo de proceso de este algoritmo.

4.5) Esto nos lleva al hecho que.4.4. APLICACIONES DE LAS INVARIANTES 83 Se ve que lo que tenemos es una potencia de una matriz. Con esta idea podemos aplicar el m´todo que mostramos para hallar una potencia en tiempo e logar´ ıtmico.4. de que todas las potencias pares tienen la forma: a b (4.6) b a+b Calculando B · B se tiene que: a = a · a + b · by b = b · a + a · b + b · b. Calculando A · B se tiene que: x = a · x + b · yy y = b · x + a · y + b · y. no demostraremos. Inicialmente hallemos las siguientes potencias: 0 1 1 1 1 1 1 2 2 = 4 0 1 1 1 1 1 1 2 0 1 1 1 1 1 1 2 = 1 1 1 2 2 3 3 5 (4. Recordando que el algoritmo mejorado a O(log(n)) para hallar las potencias trabaja bajo el siguiente m´todo: e while(n!=N){ si par(n) B=B*B n=n/2 si impar(n) A=A*B n=n-1 } Llevando ´sto al c´digo se tiene el programa final: e o .4) = = (4.4.

b = b*a + a*b + b*b.y=1.println("y= "+y).4.1. System. } } System. y = b*x + a*y + b*y. } else { temp = a*x + b*y.out.out.println("x= "+x). a=temp. while(n!=0){ if(n%2==0){ temp = a*a + b*b. 4. En este programa se ve claramente que la especificaci´n de o la invariante es esencial para entender el programa final. } } Como se ve en la ejecuci´n del programa x = F ibonacci(n − 1) y y = o F ibonacci(n). x=temp.n=8 * @author Jorge Teran * @param args * none */ public static void main(String[] args) { int n=8.84 ´ 4.a=0. n=n/2. n=n-1. CODIFICACION CON MIRAS A LA PRUEBA public class Fibonacci { /** * Programa para hallar el Fibonacci 8.x=0. Principio de correctitud El principio de correctitud se define como: .b=1.temp=0.

o o . o o 4. El dise˜o por contratos es un m´todo de la ingenier´ de o o n e ıa software para la fiabilidad y aplicable a la programaci´n orientada a objetos.000 l´ ıneas de c´digo y le preguntan si es correcto o no. Puede realizarse. son la programaci´n defensiva y programaci´n por contratos. Consiste en establecer o relaciones cuyo fundamento est´n en la l´gica formal entre las diferentes a o clases del programa. Dise˜ o por contratos n El dise˜o por contratos tiene sus or´ n ıgenes en 1990 con los trabajos de Bertrand Meyer y el lenguaje de programaci´n Eifel.5. codigo). en forma est´tica (l´gica formal) y en forma din´mica a o a durante la realizaci´n del c´digo. terminaci´n El programa termina y produce los resultados esperados. DISENO POR CONTRATOS 85 inicializaci´n La invariante es verdadera cuando se ejecuta el programa o por primera vez. lo que se requiere es una especificaci´n detallada para verificar o que el producto satisface la especificaci´n. supongamos que le traen 100.5. La robustez es la facilidad que tiene un programa para reaccionar en forma razonable a condiciones que no est´n en la especificaci´n. al final de cada uno o de los ciclos del programa y cuando este termina. Claramente no se puede decir mucho o al respecto. o Definimos la correctidud como una tupla de pares de elementos: correctitud = (especif icacion. preservaci´n la invariante se preserva al principio. o La fiabilidad del software se puede ver como dos aspectos: primero la correctitud y segundo la robustez. o Un elemento de software no es correcto o incorrecto por s´ mismo.˜ 4. Es ı correcto o incorrecto con respecto a su especificaci´n. a o En la construcci´n de programas existen dos metodolog´ principales o ıas que. o Esto puede probarse utilizando los hechos que hacen la invariante. El proceso de prueba moderno consiste en verificar el principio de correctitud. Para describir la correctitud. La motivaci´n principal para desarrollar el dise˜o por contratos es la reuo n tilizaci´n del c´digo.

Esto se realiza incluyendo precondiciones. Se puede ver como un contrato entre personas donde cada una de las partes tiene una obligaci´n que cumplir. } Como se ve el concepto de una simple divisi´n ha sido complicada con una o serie de operaciones que ocultan el pr´posito de la rutina Divide. En este tipo de o programaci´n se tiene cada vez m´s c´digo.. int Divide (int a. o La programaci´n por contratos toma los conceptos de la l´gica formal o o y la especificaci´n de programas.. return a/b... La obligaci´n del programa que llama a Divide es o el de pasar los datos correctos... int b){ return a/b. int b){ if (!(b>0)){ System.... En el ejemplo que vimos no es o obligaci´n de Divide que..86 ´ 4. . haciendo que el c´digo nuevo o a o o requiera introducir nuevos controles.. post condiciones e invariantes. la respuesta sea adecuada. m´s bien el o a de dividir correctamente. Sup´ngase que se tiene una rutina que devuelve el resultado de dividir o a/b el c´digo podr´ ser o ıa int divide (int a.. los valores que recibe sean correctos.. Esta metodolog´ de dise˜o establece una o ıa n relaci´n contractual entre clases especificando los requerimientos y los resulo tados esperados. . ... } Aplicando la programaci´n defensiva se tendr´ que codificar los posibles o ıa errores. CODIFICACION CON MIRAS A LA PRUEBA La programaci´n defensiva se basa en ir agregando controles a fin de o verificar posibles errores durante la ejecuci´n del programa.out. por ejemplo b > 0 o si a puede estar en un rango de valores y as´ sucecivamente todas las posibles situaciones que puedan ocurrir a fin de ı que.println("error b=0") } .

Un fallo es un evento incorrecto que. DISENO POR CONTRATOS 87 Normalmente utilizamos la palabra bug para referirnos a cualquier tipo de problema de software. o En el enfoque tradicional se presentan varios problemas: El cliente no entiende en que situaciones puede utilizar una clase. e Cuando se cambia un c´digo.5. Un defecto es una propiedad que hace que no se adecue a su especificaci´n. Un producto de software puede tener tres tipos de problemas: errores. en su comportamiento o esperado. Esta palabra es un poco ambigua por lo que hay que definir los problemas que existen.˜ 4. la mantiene y publica una interfaz. construye la documentaci´n. ocurre en alguna de sus ejecuciones. Cliente Es un programa que hace uso de un objeto (programa) conoce la interfaz de la clase y no sabe nada de la implementaci´n o Proveedor Es un programa (objeto) que es utilizado por un cliente. defectos y fallos. ¿C´mo se consigue que la interfaz se o o mantenga? . El cliente no entiende las consecuencias de utilizar un m´todo. o El siguiente cuadro muestra los beneficios y obligaciones de clientes y proveedores: Obligaciones Cliente Satisfacer la precondici´n o Beneficios Obtener los resultados de la post condici´n o Un proceso m´s simple a gracias a que se presume que se satisface la precondici´n o Proveedor Satisfacer la post condici´n o En nuestro caso el programa que llama a la rutina de dividir debe garantizar que los datos enviados son correctos y el programa que realiza la divisi´n garantiza que la respuesta es correcta. Error es una mala decisi´n realizada durante el desarrollo o del software. La programaci´n por contratos divide en obligaciones y beneficios entre o proveedor y cliente.

o puede que. a ı 4. se hace el software m´s complicado. Con este m´todo e se puede simplificar el hallar el tiempo transcurrido a restar dos variables enteras. Especificaci´n de contratos o Los contratos se especifican a trav´s de cla´sulas que definen las pre y e u post condiciones. ¿C´mo se entera el cliente? o Con esta metodolog´ es muy f´cil determinar la causa de un fallo en un ıa a programa: Una falla en la precondici´n es una manifestaci´n de una falla en el o o cliente Una falla en la post condici´n es una manifestaci´n de una falla en el o o proveedor. En un contrato entre cliente y proveedor se pueden dar dos situaciones.5. e Una posible implementaci´n puede ser crear tres variables hora. al agregar c´digo redundante en la prograo maci´n defensiva. En el dise˜o bajo contratos se debe colocar estos controles n en las precondiciones. . u Supongamos que se quiere especificar una clase Tiempo que tiene los m´todos ponerHora. tiempoTranscurrido. De esta forma es n posible almacenar el tiempo en una sola variable entera. el contrato se rompa en cuyo caso se puede utilizar una clase especializada para manejar el error o simplemente terminar el proceso indicando la causa de la falla. la primera es que el contrato se cumpla con lo cual no hay que hacer absolutamente nada. En todo el proceso de dise˜o por contratos se debe evitar la redundancia. No est´ por dem´s o a a realizar controles en el c´digo.88 ´ 4. e Otra implementaci´n puede ser hallar el tiempo transcurrido desde un o momento determinado. el principio del a˜o. Las precondiciones se especifican con la cla´sula requires y u las post condiciones con la cla´sula ensures. minutos. CODIFICACION CON MIRAS A LA PRUEBA Si la interfaz cambia. ponerMinutos. ponerSegundos.1. El objetivo es la simplicidad. pueden hacer el c´digo muy o o poco entendible. Al agregar m´s c´digo o a a o hay que agregar m´s controles y as´ sucesivamente. sin embargo. o segundos y a trav´s de un algoritmo hallar el tiempo transcurrido. por ejemplo. n Esta regla es el opuesto de la programaci´n defensiva.

es que la variable hora tome el valor h.5. parece que la post condici´n es una o o redundancia del c´digo.˜ 4. Hay que hacer notar que la post condici´n hora=h o o indica que lo que se espera. o Es posible justificar la precondici´n en base de la especificaci´n solao o mente. se tendr´ un ıa c´digo m´s complejo y la misma especificaci´n. fao cilitando la reusabilidad y mantenimiento al haber mantenido los contratos entre clientes y proveedores. Cada pre y post condici´n debe satisfacer los siguientes requerimientos: o Las pre y post condici´n aparece en la documentaci´n oficial distribuida o o a autores de m´dulos cliente. DISENO POR CONTRATOS 89 Con el sistema de dise˜o por contrato solo se debe especificar el contrato n que las clases deben cumplir y no la implementaci´n. Una implementaci´n de esta especificaci´n podr´ ser o o ıa void ponerHora(int h) /* requieres 0 <= h <= 23 * ensures hora=h * ensures minutos = minutos * ensures segundos = segundos */ hora=h. } Si analizamos el c´digo propuesto. Si se hubiera escogido la segunda forma de implementar. . que o a los minutos y segundos no cambian y que la variable h toma el valor de hora. Esto permite que podamos o a o cambiar el c´digo sin tener que avisar este cambio a todos los clientes. La clase ponerHora se o puede especificar como sigue: void ponerHora(int h) /* requieres 0 <= h <= 23 * ensures hora=h * ensures old minutos = minutos * ensures old segundos = segundos */ Esta especificaci´n garantiza que la hora est´ en un rango permitido. El c´digo o indica como se hace esto.

cuando se aplica a los argumentos o que satisfacen la precondici´n.2. a Una especificaci´n de la clase tiempo puede ser como sigue: o public clase Tiempo Invariant 0 < = Invariant 0 < = Invariant 0 < = ponerHora(int h){ } (){ hora < =24 minutos < =59 segundos < =59 . satisface la invariante I. CODIFICACION CON MIRAS A LA PRUEBA Cada caracter´ ıstica que aparece en la pre y post condici´n debe eso tar disponible a cada cliente cuya ejecuci´n est´ disponible (regla de o e disponibilidad). Invariantes El el dise˜o por contratos se tienen dos tipos de invariantes. En cambio las invariantes de bucle describen las propiedades que deben preservarse entre las variables de un bucle.90 ´ 4. tambi´n satisface la invariante. Tero e mina en uno estado que satisface la invariante En la clase Tiempo la invariante quedar´ especificada como: ıa Tiempo (){ Invariant 0 < = hora < =24 Invariant 0 < = minutos < =59 Invariant 0 < = segundos < =59 } El estado global de la clase especificada indica que cuando cambiamos la hora. Las invariantes de clase describen propiedades globales que deben preservarse entre todas las rutinas. minutos y segundos est´n en el rango correcto. o Cuando termina una rutina exporta sus resultados. los valores hora. Una invariante es correcta si y solo si cumple: La creaci´n de un procedimiento p. cuando satisface la precondici´n dando un estado I. las invariantes n de clase y las invariantes de bucles o ciclos. 4.5.

Eso o tas pruebas se realizan aplicando una serie de reglas de la l´gica formal. se muestran en la siguiente secci´n.. con un c´digo o o C se llega a la post condici´n {Q}. o 4... o a A fin de ejemplificar el proceso que se sigue veamos un ejemplo muy sencillo: La regla de bloques indica que dada una precondici´n {P }. El texto de la Dra Tanja Vos [Vos01].6. En Java se puede implementar a trav´s de varios prograa e mas utilitarios que.. o o Como se ve estos conceptos simplifican la construcci´n del programa y lo o hacen m´s legible... .´ 4.6.. Ejemplo: o o {X = x}X = X + 1{X = x + 1} .. Prueba est´tica a Las pruebas est´ticas de c´digo utilizan la l´gica formal para probar que a o o aplicando a la precondici´n la invariante se llega a la post condici´n.. El o prop´sito de presentar estas reglas es mostrar en forma simple como se aplio can en el proceso de prueba. provee la prueba y un extensa explicaci´n de esta tem´tica.. Las variables locales no deben figurar en o la precondici´n y post condici´n.. En cada m´todo se deber´ especificar las invariantes del ciclo apropiadas e a en funci´n de la implementaci´n. PRUEBA ESTATICA 91 /* requieres 0 <= h <= 23 * ensures hora=h * ensures minutos = minutos * ensures segundos = segundos */ } ponerMinutos(int m){ } /* requieres 0 <= h <= 23 * ensures minutos=m * ensures hora = hora * ensures segundos = segundos */ .

para secuencias. ciertas o condiciones que se deben cumplir durante la ejecuci´n del programa. condicionales... En estos desarrollos se encuentra o a iContract. En el ejemplo reo o o emplazamos valor de la variable X obteniendo: {X = x}x = x + 1{X = x + 1} finalmente reemplazamos la x y se obtiene la post condici´n. Esta o opci´n viene en Java despu´s de la versi´n 1.. Estos controles son insertados en el c´digo autom´ticamente con afirmaciones.Cn una precondici´n {P } y la post condici´n {Q}.. y Java Modeling Language (JM L). bucles while. {Q1 }{P2 }C2 .92 ´ 4.. C2 . Afirmaciones Las afirmaciones son una forma de verificar en tiempo de ejecuci´n. Prueba din´mica a La prueba din´mica es la que se realiza en tiempo de ejecuci´n y el lena o guaje de programaci´n brinda el m´todo de afirmaciones a trav´s de la inso e e trucci´n assert. ´sta secuencia de instrucciones o o e puede expresarse como: {P } {P1 }C1 . o En el caso de las secuencias se procede de forma similar Dada una secuencia de instrucciones C1 . 4. {Q2 }. for y todos les elementos utilizados en la programaci´n. La utilizaci´n dentro del o e o o .{Pn }Cn . Con aplicaciones adicionales se pueden verificar las precono diciones. bloques. post condicones e invariantes.7. {Qn } {Q} De este desarrollo se ve que P1 es consecuencia de P y que P2 es consecuencia de Q1 y sucecivamente hasta llegar a Q que es consecuencia de Qn .1..4. o 4.. CODIFICACION CON MIRAS A LA PRUEBA El procedimiento de prueba consiste en reemplazar las variables de la precondici´n en el c´digo para obtener la post condici´n.7. JM SAssert [Fel05]. . Para este proceso existen reglas.

if (dato == null) { System. int largo=0.devuelveNombre(). assert expresion1 : expresion2. cuando est´ en modo de a producci´n se desea eliminar estas instrucciones para mejorar el tiempo de o proceso. esto se hace con la opci´n −esa. Por este motivo al invocar la ejecuci´n del programa se debe incluir o la opci´n −ea para que se ejecuten. PRUEBA DINAMICA 93 lenguaje Java se realiza con la instrucci´n assert que tiene las dos formas o siguientes: assert expresion1.length().println("Error grave: Falta la propiedad ’nombre’ "). a o Cuando uno ejecuta un programa en modo de prueba est´ interesado a en que se procesen las afirmaciones. Por ejemplo se queremos ejecutar el o programa Ejemplo con las afirmaciones habilitadas se coloca java − ea Ejemplo El propio lenguaje Java trae la opci´n que permite habilitar las afirmao ciones propias del lenguaje a fin de diagnosticar posibles errores propios del Java. o En la segunda forma se agrega expresion2 que es un mecanismo para pasar una cadena que ser´ mostrada en caso de fallar la afirmaci´n. } else { largo=dato.trim(). Recordando el ejemplo de la secci´n o o anterior: Nombre persona = new Nombre(nombrePersona). String dato = persona. En la primera forma expresion1 es una expresi´n booleana que el proo gramador afirma ser verdadera durante la ejecuci´n del programa. sin embargo.err.´ 4. } .7.

pudiendo habilitar o desabilitar o el control en tiempo de ejecuci´n. j=j+i. assert dato == null : "Falta la propiedad ’nombre’ " largo=dato.get(i) : "Procesando multiplos " + i +" dos veces" for (j = i + i.devuelveNombre(). i++) { //Invariante hasta i-1 se han marcado todos los //multiplos de i .94 ´ 4. i * i <= n.length(). o Retomando el ejemplo de la criba de Eratostenes en versi´n final. } } . public class Criba { public static void main(String[] s) { int n = 100000000.1 para i > 2 if (!a.get(i)) { //Precondici´n: o // los multiplos de i no han sido marcados assert !a.) { //Invariante j es multiplo de i assert i%j == 0: " J no es multiplo de I" a. Reeso cribimos algunas invariantes y precondiciones en una instrucci´n assert para o obtener: import java. for (i = 2.*. j <= n.set(j). Como puede observar el programa ha quedado en formas m´s comprensia ble y la cantidad de c´digo a revisar es menor. int i = 2. Cuando el sistema est´ completamente depurado es muy probable que no se requiera a realizar este control. int largo=0.trim(). CODIFICACION CON MIRAS A LA PRUEBA Se observa que el control sobre el nombre se hace permanentemente. BitSet a = new BitSet(n + 1).util. Utilizando la instrucci´n assert queda como sigue: o Nombre persona = new Nombre(nombrePersona). j = 0. String dato = persona.

) { //Invariante j es multiplo de i assert i%j == 0: " J no es multiplo de I" Este error que puede pasar desapercibido por la costumbre de escribir el c´digo de esa forma. j <= n. post condiciones e invariantes del programa. En el tiempo de ejecuci´n al habilitar las invariantes se o o obtiene el mensaje de error.´ 4.8. a 4. Como se ve ´stos conceptos simplifican la construcci´n del programa y lo e o hace m´s legible. PROGRAMACION BAJO CONTRATOS CON JML 95 } } } /** * Post condici´n: o //Un vector de bits con los numeros primos en cero. o a o o . al codificar el c´digo se puede haber escrito con un o error: for (j = i + i. La siguiente lista muestra una serie de o herramientas disponibles: Herramienta Descripci´n o Jass Java with Asertions Icontract Java Design by Contract Jcontract Java Design by Contract Jcontractor Java Design by Contract JML Java Modeling Language Esc/java Extended Static Checker De estas herramientas hay que destacar que Esc/java trata de realizar una verificaci´n est´tica del c´digo utilizando principios de la l´gica formal. j++. Esta forma de describir el c´digo requiere que se busquen formas de eso pecificar las pre. Programaci´n bajo contratos con JML o Existen varias herramientas que se pueden utilizar para implementar la programaci´n bajo contratos en Java.8. */ Ahora en una ejecuci´n normal del programa se ve que no hay ning´n proo u blema. Sin embargo.

pre y post condiciones. int b){ return (a/b).. Las anotaciones se escriben en l´ ıneas de comentarios con la forma / ∗ @. Para ejecutar el programa se procede de la siguiente manera: jmlrac Divide Ahora supongamos que el programa de la divisi´n produce un resultado o err´neo en el programa hemos colocado o return (a*b).. o o Para compilar el c´digo con JML se procede como sigue: o jmlc Divide. @ ensures \result * b <= a .. } } En este caso probamos la clase desde la entrada principal y la clase Divide tiene la obligaci´n de verificar la precondici´n y la post condici´n. CODIFICACION CON MIRAS A LA PRUEBA El JML aprovecha los mecanismos de la especificaci´n de programas y de o la documentaci´n para incluir los elementos del contrato incorporados en un o programa Java y herramientas para compilar y ejecutar el c´digo.@ ∗ /. En el o o o ejemplo la precondici´n es que b > 0 para evitar la divisi´n por cero y la post o o condici´n para garantizar que el resultado de la divisi´n no sea incorrecto. en lugar de return (a/b). En el ejemplo el c´digo completo queda como sigue: o public class Divide { /*@ requires b > 0 . .java Este proceso incluye todas las afirmaciones necesarias para verificar las invariantes. @*/ public static int Div (int a. o La precondici´n se incluye con la instrucci´n requires y la post condici´n o o o con ensures.96 ´ 4.

8.Div regarding specifications at File "Divide.runtime. i<n. line 4.main(Divide. La forma de especificar las invariantes es a trav´s de la cl´usula e a invariant.Div(Divide. Las o invariantes de ciclo que son las que se cumplen durante la ejecuci´n del ciclo y o las invariantes de clase que deben ser v´lidas antes y despu´s de la ejecuci´n a e o de la clase. //@ loop_invariant suma %5 == for (int i=0.java:446) at Divide. .8. Las invariantes de clase se especifican al principo de la clase con la cl´usula a invariant Veamos un ejemplo: 0. i=i+5) { suma+=i.java:14) at Divide.JMLInternalNormal PostconditionError: by method Divide.java". Especificaci´n de invariantes o En la programaci´n por contratos se tienen dos tipos de invariantes. Para ejemplificar las invariantes de ciclo se utiliza la instrucci´n o loop invariant delante de la instrucci´n que especifica el ciclo.java:548) 4. PROGRAMACION BAJO CONTRATOS CON JML 97 obtendremos un error explicando la causa de la falla Exception in thread "main" org. } En el c´digo se ve que la invariante especifica que suma es m´ltiplo de 5 en o u cada instante durante el ciclo for. Por ejemplo: o static int Suma (int n) { int suma=0. character 23 when ’b’ is 3 ’a’ is 10 ’\result’ is 30 at Divide.internal$main(Divide.´ 4.1.jmlspecs. } return suma.jmlrac.

Invariant() { vector = new boolean[7].2: Cuantificadores cuantificadores es como sigue: {\cuantif icador int V ariable. o o Como ejemplo veamos una funci´n que suma los elementos de un veco tor. } } Esta especificaci´n indica que el vector no es nulo. Cuantificadores Los cuantificadores son los descritos en el cuadro 4.2. Esto queda especificado como sigue: . o 4. rango. en la post condici´n hay que verificar que el vector no ha o o cambiado y que el resultado es realmente la suma.length == 7. codigo} Adicionalmente se incluye la \old(variable) para obtener el valor anterior a la ejecuci´n del c´digo.98 ´ 4. CODIFICACION CON MIRAS A LA PRUEBA public abstract class Inv1 { boolean[] vector.8.2: La sintaxis de los Cuantificador \forall \exists \sum \product \num of \max \min Descripci´n o para todo existe suma producto n´mero de u m´ximo a m´ ınimo Cuadro 4. Antes de la ejecuci´n del c´digo es necesario que el vector no sea nulo o o (precondici´n). tiene una longitud de 7 y o estos valores no se modifican en la ejecuci´n de la clase. //@ invariant vector != null && vector.

@ 0 <= i && i< a. @ ensures \result == @ (\sum int i. o . Ejercicios Instalar JML en su equipo. verMinutos. A o la hora de escribir el texto no funcionaba adecuadamente con la versi´n 1.3. i<a. 2. i++) { suma+=a[i]. algunas versiones de JML solo funcionan con la versi´n 1.5 o de Java. } } JML es un lenguaje mucho m´s completo. @*/ static int Suma (int[] a) { int suma=0.length.´ 4. } return suma. 1.4 de Java.8. Especificar en JML una clase hora que tenga los m´todos siguientes: e ponerHora.length. 4. Realizar dos implementaciones diferentes de la clase hora en base a la especificaci´n anterior. tiempoTranscurrido. o pre y post condiciones utilizando JML. 3.length. a[i] ) @ && a == \old(a) @ && (\forall int i. Se puede obtener el manual de a + referencia de [LPC 02].8. Para ´sto es necesario que tome en cuenta e que. ponerMinutos. ponerSegundos.5 y comprobar las invariantes. Tiempo transcurrido es la resta del tiempo entre dos horas. verHora. 0 <= i && i < a. verSegundos. PROGRAMACION BAJO CONTRATOS CON JML 99 public class Vector { /*@ requires a != null. Programar los ejercicios de la secci´n 4. for (int i=0.3. a[i] == \old(a[i])).

Crear un programa para utilizar la clase hora y verificar que ambas implementaciones funcionan. .100 ´ 4. CODIFICACION CON MIRAS A LA PRUEBA 4.

Este algoritmo. pre y post condiciones sin entrar en la demostraci´n de ´stas.1. bases de datos.Cap´ ıtulo 5 Aplicaciones de b´ squeda y u clasificaci´n o 5. ıas 5. La b´squeda en forma gen´rica se presenta como. denominado b´squeda secuencial.2. El proceso de especificaci´n se realiza como se mostr´ en el cap´ o o ıtulo anterior especificando las invariantes. texto plano y otros. el mecaniso u e mo de hallar un elemento en un vector del cual solo conocemos. Cada algoritmo de b´squeda da u como resultado una eficiencia diferente en funci´n de como se ha organizado o la informaci´n. Algoritmos de b´ squeda u La b´squeda de elementos ha sido analizada en diferentes entornos. Introducci´n o La b´squeda y la clasificaci´n tienen una serie de aplicaciones que ser´n u o a descritas en las siguientes secciones. Se proceder´. el n´mero u de elementos que contiene. de m´todos generales a a e casos particulares que reducen el tiempo de proceso. meu moria. u viene especificado como sigue: public class Sec { /* Programa de busqueda secuencial 101 . o e Los libros de Horstman [CSH05] proporcionan una buena descripci´n de las o librer´ de Java.

Estos o u n´meros corresponden al c´digo de producto en un almac´n.length && hallo >=0). Este concepto hace que se puedan realizar u b´squedas espec´ u ıficas para cada conjunto de datos a fin de mejorar el tiempo de proceso. @ requires t != null . o n armar un vector de bits en memoria. i < v. Se puede colocar la informaci´n en un vector y u o proceder con el esquema de b´squeda anterior obteniento un tiempo O(n) = u n. Se quiere cambiar la b´squeda secuencial aprovechando algunas caracu ter´ ısticas particulares al problema.102 ´ ´ 5. } return (hallo). a La respuesta es s´ Consideremos un c´digo n peque˜o entonces podemos ı. suponiendo que los datos est´n previaa mente ordenados. . APLICACIONES DE BUSQUEDA Y CLASIFICACION *@ author Jorge Teran */ static int buscar(int[] v. Sup´ngase que se tiene una lista de n´meros enteros entre 0 y n. ¿Ser´ posible obtener un tiempo O(n) = 1 ?. int t) { /*@ requires v != null . Para esto podemos organizar e los n´meros de varia formas. i++) if (v[i] == t) { hallo = i. for (int i = 0. @*/ int hallo = -1.length && hallo = -1. Dado un n´mero u o e u se quiere conocer si este pertenece al almac´n. @ ensures (hallo = -1) @ || (hallo < v.length. } Aplicando la teor´ vista se determina que el tiempo de ejecuci´n del algoıa o ritmo es proporcional n 1=n i=0 Esto significa que es necesario conocer m´s sobre el conjunto de datos para a mejorar el tiempo de b´squeda. // @ loop_invariant i < v. break. qu´ indique que n´meros existen y e u cuales no.

2. resuelve el problema reu u cordando permanentemente el rango en el cual el arreglo almacena t..´ 5. Primero buscaremos una representaci´n del rango digamos l. Inicialmente el rango es todo el arreglo y luego es reducido comparando t con el valor del medio y descartando una mitad.. Esta b´squeda denominada b´squeda binaria. la elecci´n obvia es l = o 0. Se utiliza la descripci´n para construir el programa. ALGORITMOS DE BUSQUEDA 103 Esta soluci´n debe funcionar tanto para enteros. realiza log2 n comparaciones. cadenas y reales siempre o y cuando todos los elementos sean del mismo tipo.u..u entonces la o invariante es el rango debe estar entre l.n-1$ loop {invariante: el valor a buscar debe estar en el rango} si el rango es vacio terminar y avisar que t no esta en el arreglo calcular m que es el medio del rango use m con una prueba para reducir el rango si se encuentra t en el proceso de reducci´n o terminar y comunicar su posici´n o La parte esencial del programa es la invariante que al principio y final de cada iteraci´n nos permite tener el estado del programa y formalizar la noci´n o o intuitiva que ten´ ıamos. o precondici´n el vector esta ordenado o inicializar el rango entre $0. El proceso termina cuando se halla el valor de t o el rango es vac´ En una tabla de n elementos en el peor caso ıo. El pr´ximo paso es la inicializaci´n o o y debemos estar seguros que respeten la invariante. u = n − 1. La idea principal es que t debe estar en el rango del vector. Se construye el programa utilizando refinamiento sucesivo haciendo que todos los pasos respeten la invariante del mismo. −1 indica que el elemento buscado no existe en el arreglo. Codificando un programa con los conceptos detallados previamente tenemos: precondici´n x debe estar ordenado o post condici´n p especifica la posici´n o o . La respuesta se almacena en un entero p que representa la posici´n en el arreglo donde se encuentra o el elemento t que estamos buscando.

u} if l > u p=-1. Con lo que el programa queda como sigue: precondici´n x debe estar ordenado o post condici´n p especifica la posici´n o o o p es -1 cuando no existe l=0. u=n-1 loop {invariante: debe estar en el rango l. Las siguientes l´ ıneas implican el comparar t con x[m] en la que hay tres posibilidades.104 ´ ´ 5. u=n-1 loop {invariante: debe estar en el rango l. Llevando esto al programa o tenemos: precondici´n x debe estar ordenado o post condici´n p especifica la posici´n o o o p es -1 cuando no existe l=0.u} . por igual. menor y mayor. break.u} si el rango es vacio terminar y avisar que t no esta en el arreglo calcular m que es el medio del rango use m con una prueba para reducir el rango si se encuentra t en el proceso de reducci´n o terminar y comunicar su posici´n o Continuando con el programa vemos que el rango es vac´ cuando l > u. APLICACIONES DE BUSQUEDA Y CLASIFICACION o p es -1 cuando no existe l=0. u=n-1 loop {invariante: debe estar en el rango l. en ıo esta situaci´n terminamos y devolvemos p = −1. calcular m que es el medio del rango use m con una prueba para reducir el rango si se encuentra t en el proceso de reducci´n o terminar y comunicar su posici´n o Ahora calculamos m con m = (l + u)/2 donde / implementa la divisi´n o entera.

1.´ 5. while (l <= u) { m = (l + u) / 2. Consideremos el siguiente pseudo c´digo y realicemos una prueba de eso critorio: public class b´squeda { u public static int BusquedaBinaria(int[] x. ALGORITMOS DE BUSQUEDA 105 if l > u p=-1. x[m]> t : u=m-1 Se deja como ejercicio para el lector comprobar que el tiempo de ejecuci´n o de este algoritmo es proporcional a log(n). 5. else if (x[m] == t) { p = m.2.length . int u = x. Para resolver esto f´cilmente se a puede reescribir en forma recursiva y aplicar el teorema master. esto no garantiza que el programa funcione correctamente para todos los casos. x[m]= t : p=m: break. pre y post condiciones con afirmaciones o utilizando el lenguaje JML. break. } else u = m. } return p.1. int p = -1. . case x[m]< t : l=m+1. int t) { int l = 0.2. m=(l+u)/2. Prueba exhaustiva Ahora es necesario probar la b´squeda binaria. break. Sin embargo. El primer paso es el de u convertir la invariante. if (x[m] < t) l= m . int m = 0.

i++) { if (b´squeda. utilizamos el siguiente c´digo: o int[] x = new int[MAXIMO]. Decimos que esta probado cuando funciona correctamente con los datos de prueba utilizados.BusquedaBinaria(x. for (int i = 0.out. i++) { x[i] = i * 5. i++) { if (b´squeda. u ıa Un programa puede estar probado o certificado. para lo cual. Por esto es conveniente construir un conjunto de datos de prueba.BusquedaBinaria(x. i < MAXIMO. } . vale decir que. i * 5) != i) { u System. Por ejemplo.println("Error al buscar " + i*5). i < MAXIMO. } En este conjunto de datos conocemos perfectamente el contenido del vector. El c´digo es el siguiente: o for (int i = 0. pero una prueba de escritorio extensiva es larga y aburrida. } Ahora sabemos que se prueba la b´squeda de todos los valores existentes en u el vector y no produce errores. Los valores que no existen en el vector pueden pertenecer a cualquier rango de datos. Por esto se hace necesario buscar un elemento no existente entre cada uno de los valores introducidos obteniendo el sigiente c´digo: o for (int i = 0. con el vector de datos construidos podemos probar con algunos valores y ver que funciona adecuadamente. i * 5 + 1) != -1) { u System.106 ´ ´ 5. ¿Podremos decir lo mismo para todo los valores? Para realizar esta prueba vamos a buscar todos los elementos introducidos al vector y verificar que los encuentra y devuelve el resultado correcto. APLICACIONES DE BUSQUEDA Y CLASIFICACION } Aparentemente es correcto. si buscamos un m´ltiplo de 5 deber´ encontrarlo.out. i < MAXIMO. Decimos que el programa est´ certificado cuando funciona correctamente a con todos los posibles casos que pueden ocurrir.println("Error al buscar " + i*5+1).

El a c´digo completo es: o public static final int MAXIMO = 1000. for (int i = 0.out. Representaci´n gr´fica de la b´ squeda o a u Una representaci´n gr´fica puede ser adecuada para mostrar como funo a ciona un programa.out. Generalmente se deben colocar las invariantes.println("Fin de la prueba"). } } System. } System. i * 5) != i) { u System. for (int i = 0. ALGORITMOS DE BUSQUEDA 107 Este c´digo nos certifica que el programa es correcto en un determinado o conjunto de datos. Sin embargo es util tambi´n ´ e afirmar o especificar el O(n) para verificar el funcionamiento del programa en los tiempos previstos o detectar bucles infinitos.2. pre y post condiciones.BusquedaBinaria(x. i < MAXIMO. public static void main(String[] args) { System. i < MAXIMO. i * 5 + 1) != -1) { u System. i++) { if (b´squeda.2.println("Buscando elementos existentes"). for (int i = 0. no est´ certificado. aparentemente sin errores. .BusquedaBinaria(x.´ 5.out.out.2. Esto hace que de un golpe de vista se determine que el programa funcione.println("Buscando elementos no existentes"). int[] x = new int[MAXIMO]. Que podemos decir si ampliamos el tama˜o del vector? n Solo que se ha probado y puede que funcione pero.println("Error al buscar " + i*5+1).out. } } System. i++) { if (b´squeda.println("Error al buscar " + i*5). i++) { x[i] = i * 5. i < MAXIMO. } Nos preguntamos que es lo que se debe especificar. 5.println("Creando el vector").out.

frame.EXIT_ON_CLOSE). javax. // agregar un panel con el texto a buscar JPanel panel = new JPanel(). 5).event. u DocumentListener listener = new TextoFieldListener().addDocumentListener(listener).awt.swing. javax.*. Luego permite buscar un valor mostrando u el proceso seguido en la b´squeda. queBuscaField. Para ejemplificar ´sto se muestra un programa que construye un vector e con los n´meros pares entre 0 y 60.*. public class Busbin { public static void main(String[] args) { TextFrame frame = new TextFrame().*.setDefaultCloseOperation(JFrame. java.add(new JLabel("Buscar:")).event.swing. java. frame.*.awt. u import import import import import java.add(queBuscaField).getDocument(). panel. frame.setSize(640. .awt.480).108 ´ ´ 5. El programa debe u ser capaz de mostrar como se reduce el rango y contar el n´mero de iteraciones u del mismo.*. APLICACIONES DE BUSQUEDA Y CLASIFICACION Para realizar una representaci´n gr´fica del programa de b´squeda binaria o a u construimos una l´ ınea para mostrar el rango de b´squeda. panel. queBuscaField = new JTextField("30". } } class TextFrame extends JFrame { public TextFrame(){ setTitle("b´squeda Binaria").setVisible(true).geom.

pack(). private JTextField queBuscaField.} public void removeUpdate(DocumentEvent event) {setTexto(). BorderLayout.maximo=30.muestra(queBuscas).CENTER). . BorderLayout. incrementos=20. add(muestra. private DrawPanel muestra. muestra. } // recuperar el valor a buscar public void setTexto(){ try { int queBuscas = Integer.2. public static final int DEFAULT_HEIGHT = 480.NORTH).´ 5. ALGORITMOS DE BUSQUEDA 109 add(panel. } catch (NumberFormatException e) {} //no se reliza nada si no se puede interpretar los datos } public static final int DEFAULT_WIDTH = 640. private class TextoFieldListener implements DocumentListener { public void insertUpdate(DocumentEvent event) {setTexto().getText().} public void changedUpdate(DocumentEvent event) {} } } class DrawPanel extends JPanel { int t=30.parseInt( queBuscaField. medio=0. // agregar el grafico muestra = new DrawPanel().trim()).

topY=100. g2. hasta=600. while (l <= u) { topY += incrementos. g.setPaint(Color. hasta. } } public void muestra(int x){ t=x.m=0.Double(desde.l=0. topY).110 ´ ´ 5.u=maximo. topY). desde.setColor(Color. . topY)). topY). g2. medio = (hasta + desde) / 2. g.BLACK).paintComponent(g).contador=0. topY). g2. // dibujar String explica="Las lineas representan el "+ "rango en el cual se busca". desde = medio + 1.draw(new Line2D.fillRect(0. } else if (v[m] == t) { topY += incrementos.length()*3).0. i <= maximo.WHITE). } public void paintComponent(Graphics g) { super. m = (l + u) / 2. APLICACIONES DE BUSQUEDA Y CLASIFICACION int[] v = new int[maximo + 1]. repaint(). Graphics2D g2 = (Graphics2D) g. if (v[m] < t) { l = m + 1. g. int desde=20. g. g2. int hallo=-1. i++) { v[i] = i * 2.drawString("" + contador++. topY.drawString("" + v[m]. medio.640.drawString("" + v[u]. 5. g.(explica.drawString("" + v[l].480). hasta. ((desde+hasta)/2 ) . public DrawPanel(){ for (int i = 0.drawString(explica. topY).

u o 5.drawString("" + contador++. A continuaci´n se detallan una serie de o o aplicaciones sin pretender que sean todas. . CLASIFICACION 111 Figura 5. A la izquierda se ve un u contador con el n´mero de iteraci´n.1: Representaci´n gr´fica de la b´squeda binaria o a u g.1.1 que. } } } } La salida del programa se ve en la figura 5. hallo = m. muestra como se va reduciendo el rango de b´squeda hasta encontrar el valor. 5. topY).drawString("" + v[m]. } else { u = m .3. Clasificaci´n o La clasificaci´n o procedimiento de ordenar es uno de los problemas m´s o a importantes en la computaci´n y existen un sin n´mero de problemas de o u programaci´n que requieren de ella.topY). hasta = medio .3. break.1.(hasta + desde)/ 2. g.´ 5.

Esto se denomina un corte de control. . Se incrementa el valor de i y j en cada iteraci´n. Pueden existir varios cortes de control. Para realizar uni´n de conjuntos se pueden ordenar los conjuntos. Si deseamos hallar la mediana de un conjunto de datos podemos indicar que la mediana est´ en el medio. Supongamos que tenemos una lista de trabajos que tenemos que realizar con una prioridad espec´ ıfica. En el caso de la intersecci´n intercalamos los dos conjuntos ordenados o y dejamos uno solo de los que existan en ambos conjuntos. Cuando hay dos elementos iguales solo o insertamos uno eliminando los duplicados. por ejemplo secci´n. ordenando y aplicando el concepto de control. ordenamos los datos por el deo partamento que. Para esto ordenamos los trabajos seg´n la prioridad y luego se u los procesa en este orden. se convierte en el elemento de control y luego cada vez que cambia imprimimos un total. Por supuesto que hay que tomar recaudos al agregar nuevos elementos y mantener la lista ordenada. C´mo podemos eliminar los duplicados? Ordenamos el conjunto de dao tos y luego utilizamos dos ´ ındices haciendo x[j] = x[i].112 ´ ´ 5. con un solo barrido podemos listar todos las frecuencias. Una t´cnica muy utilizada para agrupar ´ e ıtems es la denominada cortes de control. Por ejemplo para hallar el elemento a k ´simo mayor bastar´ en acceder a x[k]. APLICACIONES DE BUSQUEDA Y CLASIFICACION C´mo podemos probar que en un grupo de elementos no existen elemeno tos duplicados? Bien para esto ordenamos el conjunto y posteriormente verificamos que no existen valores tales que x[i] = x[i + 1] recorriendo el conjunto para todos los valores de i permitidos. Puede ser por ejemplo una cola de impresi´n donde se ordenan los trabajos en funci´n de alguna priorio o dad. Por ejemplo. o departamento. Cuando se halla un duplicado solo o incrementa i. e ıa Cuando queremos contar frecuencias y desconocemos el n´mero de eleu mentos existentes o este es muy grande. Al finalizar ajustamos el tama˜o del conjunto al valor de n j. si se desea obtener los totales de sueldo por departamento en una organizaci´n. realio zar un proceso de intercalaci´n. etc.

short.util. CLASIFICACION 113 Para reconstruir el orden original es necessario crear un campo adicional que mantenga el original para realizar una nueva ordenaci´n para. i < 10. //Ordenar en forma ascendente Arrays. Como vimos tambi´n se pueden ordenar los datos para realizar b´squee u das r´pidas. float o double es suficiente utilizar la clase Arrays con el m´todo sort. long. Clasificaci´n en Java o Los m´todos propios del Java proveen rutinas para ordenar objetos que e facilitan el desarrollo de aplicaciones. el e siguiente ejemplo genera 10 n´meros al azar y los ordena. byte.1.nextInt(100). i < 10. char. Para ordenar vectores que pueden ser de tipos int. i++) System. o reconstruir el orden original. /** * Programa ordenar enteros * utilizando el metodo de java * @author Jorge Teran */ public class SortVect { public static void main(String[] args) { int[] x = new int[10].out.sort(x).3. u import java. //Generar 10 n´meros enteros entre 0 y 100 u for (int i = 0.3. } } .*.println(x[i]). //mostrar los n´meros ordenados u for (int i = 0. i++) x[i] = gen. Random gen = new Random().´ 5. a 5.

} } Para crear diferentes instancias de P ersona se procede como sigue: Persona[] alumnos = new Persona[3].55). a e . 85). } public String getNombre() { return nombre. private int nota. apellido = ap. } public int getNota() { return nota."Choque". import java. private String apellido. nota = n. class Persona { private String nombre.util. alumnos[2] = new Persona("Laura".sort(alumnos) dado que el m´todo de clasificaci´n no conoce e o cu´les y qu´ campos comparar para realizar el ordenamiento. APLICACIONES DE BUSQUEDA Y CLASIFICACION Cuando se requiere ordenar un objeto se hace necesario crear un mecanismo para comparar los elementos del objeto. String ap. apellido y nota. public Persona(String no.*. 70). Construyamos una clase P ersona que almacene nombre.114 ´ ´ 5."Laura". alumnos[1] = new Persona("Maria"."Meriles". } public String getApellido() { return apellido. alumnos[0] = new Persona("Jose". Si se requiere ordenar ´stos alumnos por nota no es posible utilizar direce tamente Arrays. int n) { nombre = no.

"Meriles". 0 cuando es igual y 1 cuando es mayor. 70). /** * Programa ordenar objetos * utilizando el metodo de java * @author Jorge Teran */ public class OrdObjeto { public static void main(String[] args) { Persona[] alumnos = new Persona[3].nota) return 1. alumnos[0] = new Persona("Jose". "Choque". "Laura". Esta rutina queda como sigue: public int compareTo(Persona otro){ if (nota < otro.util. 85).´ 5. En nuestro ejemplo creamos el m´todo compareTo. CLASIFICACION 115 Por esto es necesario primeramente escribir un m´todo que resuelva el e problema. Este nombre e es un nombre reservado de Java y lo que realiza es una sobrecarga de m´todo e reemplazando el m´todo de Java con el nuestro.*. alumnos[1] = new Persona("Maria". 55).3. for (Persona e : alumnos) . e Los valores que debe devolver son −1 cuando es menor.sort(alumnos). alumnos[2] = new Persona("Laura". } Ademas es necesario especificar que la clase persona incluye el m´todo e Comparable y se especifica as´ ı: class Persona implements Comparable<Persona> El programa final queda implementado en el siguiente c´digo: o import java.nota) return -1. Lo que hace este m´todo es comparar el valor presente e con otro pasado a la rutina. if (nota > otro. Arrays. return 0. Esta rutina utiliza el m´todo qsort para ordenar e los valores.

getApellido() + ". . } public int compareTo(Persona otro) { if (nota < otro. nota=" + e. } public String getApellido() { return apellido. int n) { nombre = no. APLICACIONES DE BUSQUEDA Y CLASIFICACION System.nota) return -1. private String apellido.getNota()). public Persona(String no. } public int getNota() { return nota. private int nota. return 0. String ap. if (nota > otro. } public String getNombre() { return nombre.nota) return 1.out. nota = n.println("Nombre=" + e. } } class Persona implements Comparable<Persona> { private String nombre.getNombre() + ". Apellido= " + e. apellido = ap.116 ´ ´ 5.

´ 5. x[j] = temp. for (i = (n .3. j. o En la realidad existen problemas que pueden ser resueltos m´s eficientemente a con un algoritmo espec´ ıfico. Este proceso se repite hasta que todos los elementos est´n e ordenados. CLASIFICACION 117 } } 5. i >= 0. en cambio los algoritmos particulares son aplicables a casos especiales para obtener un mejor tiempo de proceso. Vale decir que. Los algoritmos generales se pueden aplicar sin importarnos como son los datos.3. ordenaci´n por selecci´n y el de burbuja. el qsort. x[j-1] = x[j]. u El c´digo para este algoritmo es el siguiente: o void Burbuja (int[] x) { int i. Algoritmos de clasificaci´n o Dado que el lenguaje ya incluye un soporte para realizar clasificaciones con un algoritmo parece que no es necesario revisar algorimos de clasificaci´n. Si se requiere se realiza un intercambio para que est´n en e el orden previsto.length.1).1] > x[j]) { temp = x[j-1]. e a El m´todo consiste en comparar todos los elementos de la lista con el e elemento de su lado. temp. i--) { for (j = 1.2. Esto se logra conociendo como est´n los datos a que pretendemos procesar. j++) { if (x[j . int n=x. Los algoritmos para ordenar se clasifican en algoritmos generales y particulares. o o o M´todo de la burbuja e El m´todo de la burbuja es el m´s simple y el m´s antiguo. } } } . Tambien hay e a a que mencionar que es el m´todo m´s lento para ordenar. en alguna pasada no se realiza ning´n intercambio. Entre los algoritmos generales se explica el m´todo de clasificaci´n por e o inserci´n. j <= i.

} } } Para explicar el funcionamiento del algoritmo supongamos que inicialmente tenemos la siguiente secuencia de n´meros u 62 46 97 0 30 Inicialmente suponemos que el primer valor es el menor y lo insertamos en la primera posici´n que. a Podemos mencionar como una ventaja la simplicidad de la codificaci´n y o como desventaja la ineficiencia del algoritmo. Existen otros m´todos que tambi´n tienen un tiempo similar pero que e e son mucho m´s eficientes que mencionamos a continuaci´n. o void Insercion(int[] x) { int i. es el lugar donde estaba inicialmente. El segundo ciclo se encarga de que el ultimo elemento sea el mayor de todos.118 ´ ´ 5. temp. int n = x. j--) { temp = x[j-1]. x[j] = temp. x[j-1] = x[j]. i++) { for (j = i. j. Para ´sto podemos suponer que el primer elemento est´ en su lugar y e a proceder a colocar los siguientes en funci´n del primer elemento. el tiempo de proceso en el caso general es: 0 j=i 0 = i=n−1 j=1 i=n−1 i=n n−1 2 como se ve. APLICACIONES DE BUSQUEDA Y CLASIFICACION Como se ve en el programa en el primer ciclo se recorren todos los elementos. for (i = 1. j > 0 && x[j . ´ Analizando el programa se puede determinar que.1] > x[j]. i < n. demora un tiempo proporcional a O(n2 ) que lo hace impr´ctico. a o Clasificaci´n por inserci´n o o Cuando se tiene un conjunto de cartas en la mano lo que hacemos es tomar una carta y buscar su ubicaci´n e insertarla en su sitio hasta ordenar o todas.length. luego se toma o .

el anterior y a´n a u cuando su tiempo de proceso es tambi´n proporcional a n2 es m´s eficiente e a y puede afinarse para ser m´s eficiente. El c´digo siguiente muestra el ala o goritmo mejorado para ser m´s eficiente. for (i = 1. CLASIFICACION 119 el siguinte valor y se ve si le corresponde estar antes o despu´s. j. Luego se realiza lo u mismo con el siguiente elemento recorriendo todo el vector e insertando el elemento en el lugar apropiado.´ 5. j > 0 && x[j .length. El tiempo de proceso sigue siendo a proporcional a O(n2 ) void Insercion2(int[] x) { int i. temp. for (j = i. Realizando el an´lisis del algoritmo se ve que el tiempo de ejecuci´n es a o proporcional a n−1 j=1 n−1 = i=1 j=i i=1 i=n n−1 2 La ventaja de este algoritmo es que es m´s simple que. i++) { temp=x[i].3. j--) { x[j] = x[j-1]. i < n. } x[j] = temp. en el ejemplo e se produce un intercambio 46 62 97 0 30 En la siguiente iteraci´n tomamos el 97 y se ve que. obteniendo 0 46 62 97 30 esto se repite hasta obtener el vector ordenado. u . int n = x.1] > temp. } } Como se observa se ha mejorado la parte que corresponde a constuir el espacio para introducir el elemento siguiente reduciendo el n´mero de intercambios. no debe recorrerse o hacia adelante por lo que no se hace ning´n intercambio.

o a y se basa en dividir el vector en dos mitades utilizando un elemento denominado pivote de tal forma que todos los elementos mayores al pivote est´n en e un vector y los restantes en el segundo vector. j < n. Hoare en 1962. El resultado es el ı siguiente programa void Seleccion(int[] x) { int i. j++) { if (x[j] < x[min]) min = j.R.120 ´ ´ 5. j. } temp = x[i]. i++) { min = i.u){ if (u >= l) { . APLICACIONES DE BUSQUEDA Y CLASIFICACION Ordenaci´n por selecci´n o o Una alternativa al problema de ordenaci´n es el concepto de escoger el o elemento m´s peque˜o y reemplazarlo por el primer elemento. Como inicial pivote se puede tomar el primer elemento o uno al azar. temp. A partir de este enfoque podemos realizar una primera aproximaci´n a lo o que viene ser el algoritmo: Ordenar (l. tercero y as´ sucesivamente. int min. } } Como se observa este algoritmo es similar al algoritmo de inserci´n con tiemo 2 po similar y proporcional a O(n ) Algoritmo de clasificaci´n r´pida o a El qsort cuyo nombre en ingl´s es QuickSort o tambi´n denominado ale e goritmo de clasificaci´n r´pida ya fue publicada por C. x[min] = temp.length. for (j = i + 1. for (i = 0.1. int n = x. i < n .A. Este proceso se repite en forma recursiva hasta tener el vector ordenado. x[i] = x[min]. luego repetir a n el proceso para el segundo.

Utilizando el concepto que la invariante es que los valores entre x[m] y x[i] son menores al pivote x[l] podemos contruir el siguiente c´digo o para hallar el pivote. i <= u. //invariante los valores entre x[m] y x[i] //son menores al pivote x[l] for (int i = l + 1. Supongamos que tenemos los siguientes datos: 27 2 81 81 11 87 80 7 Iniciamos un contador m en el primer valor y tomando x[l] = 27 como pivote y se recorre el vector comparando cada uno de los valores con el pivote haciendo un intercambio entre (m+1) y la posici´n del vector.3. x[m] = temp. x[i] = temp. } } temp = x[l]. int m = l.u) } Aqu´ como digimos el problema es encontrar el punto de partici´n denomiı o nado pivote. obteniendo: u o 27 2 81 81 11 87 80 7 .´ 5. x[m] = x[i]. x[l] = x[m]. CLASIFICACION 121 hay como maximo un elemento por lo tanto no hacer nada } hallar un pivote p para dividir en vector en dos Ordenar (l. i++) { if (x[i] < x[l]) { temp = x[++m].p-1) Ordenar (p+1. obteniendo o en el primer intercambio entre el n´mero 2 que es menor que el pivote y el u n´mero de la posici´n m que es casualmente el 2.

1). x[l] = x[m]. temp. //invariante los valores entre x[m] y x[i] // son menores al pivote x[l] for (int i = l + 1. m + 1. 2T (n/2) + n en otros casos. a 7 2 11 27 81 87 80 81 Este proceso se puede repetir recursivamente para el vector a la izquierda del pivote y para el que est´ a la derecha obteniento finalmente: a private void qsort(int[] x. int l. . } Analizando el c´digo anterior podemos ver que el tiempo de proceso se puede o calcular. x[m] = x[i]. } } temp = x[l]. x[i] = temp. int u) { if (l >= u) return. u). utilizando los m´todos vistos en los cap´ e ıtulos anteriores T (n) = 1 si n = 1. APLICACIONES DE BUSQUEDA Y CLASIFICACION El segundo intercambio es entre el 11 que es menor que el pivote y el 81 obteniento: 27 2 11 81 81 87 80 7 El tercer intercambio se produce con el 7 y el 81 obteniendo 27 2 11 7 81 87 80 81 Para finalizar intercambiamos el pivote con la posici´n del ultimo n´mero o ´ u menor al pivote Obteniendo un vector donde todos los elementos menores al pivote est´n a la izquierda y los mayores a la derecha. int m = l. x[m] = temp. qsort(x. m .122 ´ ´ 5. i <= u. qsort(x. i++) { if (x[i] < x[l]) { temp = x[++m]. l.

j=0. se dispone de memoria. for(int i =0. i++){ if (x[i] > max) . Para ordenar estos u a n´meros se puede utilizar cualquiera de los algoritmos descritos para ordenar. Aplicando el teorema master obtenemos que el tiempo de proceso es proporcional a n log(n). los datos son enteros positivos sin repetici´n en el o rango de 0 a N. En la realidad se puede mejorar en funci´n de como est´ el conjunto de datos y como se elige al pivote. Aunque no se divide exactamente a la mitad se ha tomado este valor para mostrar como mejora la eficiencia . u Recorriendo el vector se pueden imprimir los n´meros a los que corresponden u los bits encendidos en forma ordenada. El resultado proporciona el siguiente algoritmo. donde N es el n´mero m´ximo existente. public void bitSort(int[] x) { int max=0.´ 5. CLASIFICACION 123 En la ecuaci´n anterior n corresponde al ciclo f or que recorre todo los eleo mentos del vector reordenando el vector seg´n el pivote. o a En el caso de que el vector est´ previamente ordenado el tiempo de proe ceso ser´ mayor. El proceso de elegir un pivote aleatoriamente produce un a algoritmo m´s estable. Es posible optimizar el m´todo de ordenaci´n r´pida a e o a pero no se tratar´ en el texto. Una demostraci´n se o puede leer en el texto de [GB96] Algoritmos de una pasada Considere las siguientes condiciones para los datos de entrada. ıas Se pueden mejorar a´n m´s los algoritmos de clasificaci´n? En casos paru a o ticulares se puede obtener algoritmos proporcionales a O(n) en el caso m´s a general. En este caso es u posible leer los n´meros de entrada y encender el bit que le corresponde.3. Si cada posici´n del vector representa a uno de los n´meros del vector se o u utiliza un bit para almacenar cada uno de los n´meros. u Para mejorar el proceso de ordenar consideremos la siguiente estructura BitSet a = new BitSet(max + 1). Cuando uno requiere un algoritmo de estas a caracter´ ısticas normalmente recurre a las rutinas ya implementadas en las librer´ del lenguaje.length. suficiente. i< x. el mejor algoritmo es proporcional a n log(n). Las siguientes dos u llamadas al programa hacen que 2T (n/2).

i<= max. i++) x[i]=i. } BitSet a = new BitSet(max + 1). public static void main(String[] args) { //generar MAXIMO n´meros sin repetidos u int[] x = new int[MAXIMO]. // Hasta aqui todos los valores de // a estan en cero for(int i =0. Para esto realizamos el siguiente programa: /**Programa para probar los diferentes * algoritmos de ordenaci´n o * @author Jorge Teran * */ import java. i++){ if (a. public class pruebaMetodos { public static int MAXIMO = 10000.get(i)) x[j++]=i . . } } Analizando el algoritmo se ve que se tienen tres ciclos que recorren todos los datos dando un tiempo de ejecuci´n proporcional a O(n).*.util. i++) a. for(int i =0. APLICACIONES DE BUSQUEDA Y CLASIFICACION max=x[i]. for (int i = 0.length.set(x[i]).i< x. i < MAXIMO. o Comparaci´n pr´ctica de la eficiencia de los algoritmos o a A fin de comparar los algoritmos de clasificaci´n es necesario hacer una o corrida de los mismos sobre el mismo conjunto de datos. int[] y = new int[MAXIMO].124 ´ ´ 5.

Insercion2(y).y. temp = x[i].arraycopy(x.currentTimeMillis().tiempoInicio. System.tiempoInicio. i < MAXIMO. x[i] = x[j]. tiempoTotal. CLASIFICACION 125 Random gen = new Random(). sort. for (int i = 0.tiempoInicio.currentTimeMillis(). //obtener una copia de x para ordenar //para siempre utilizar el mismo conjunto de datos System. tiempoTotal = tiempoFin . tiempoInicio = System. System. tiempoTotal = tiempoFin .MAXIMO). } System. . int temp. sort. i++){ j = gen. System.currentTimeMillis(). Metodos sort =new Metodos().nextInt(MAXIMO). tiempoInicio = System. j.0. tiempoFin.y.y.Insercion(y). tiempoFin = System. x[j]=temp.println(" M´todo Burbuja " e + " Tiempo de proceso " + tiempoTotal).out.3.out. tiempoInicio = System.currentTimeMillis().0.MAXIMO).out.arraycopy(x. System.0.currentTimeMillis().println("Tama~o de la instancia"+MAXIMO).´ 5.Burbuja(y).out. System. sort.currentTimeMillis(). tiempoFin = System.arraycopy(x. n long tiempoInicio.println(" M´todo Insercion2 " e + " Tiempo de proceso " + tiempoTotal).0.0.MAXIMO).0. tiempoFin = System.println(" M´todo Insercion " e + " Tiempo de proceso " + tiempoTotal). tiempoTotal = tiempoFin .

0.out. } } obteniendo los siguientes resultados para el proceso de 100.out.println(" M´todo bitSort " e + " Tiempo de proceso " + tiempoTotal).000 n´meros geu nerados aleatoriamente. sort.0.0.currentTimeMillis(). tiempoFin = System. M´todo e Tiempo de proceso en miliseg Burbuja 265.y.arraycopy(x. tiempoInicio = System.arraycopy(x.println(" M´todo Seleccion " e + " Tiempo de proceso " + tiempoTotal).tiempoInicio.0. tiempoInicio = System.251 Inserci´n o 114.out.arraycopy(x. tiempoInicio = System. tiempoFin = System.println(" M´todo quickSort " e + " Tiempo de proceso " + tiempoTotal).0.tiempoInicio.currentTimeMillis(). sort. System.MAXIMO).currentTimeMillis().364 Inserci´n2 o 86.currentTimeMillis().currentTimeMillis().795 Selecci´n o 155.y.126 ´ ´ 5. System. System. tiempoTotal = tiempoFin . System. tiempoTotal = tiempoFin .0. APLICACIONES DE BUSQUEDA Y CLASIFICACION System.y.MAXIMO). System.Seleccion(y). tiempoTotal = tiempoFin .tiempoInicio.MAXIMO).quickSort(y). sort.854 quickSort 110 bitSort 30 Hay que observar que antes de cada proceso hemos realizado una copia del vector original para que la comparaci´n sea adecuada al mismo conjunto de o .bitSort(y).currentTimeMillis(). tiempoFin = System.

3. 2. Describir las invariantes de ciclo para el algoritmo de Inserci´n.3.5. En funci´n del tama˜o del conjunto el comportamiento de los algorito n mos ser´ diferente y es posible comprobarlo experimentalmente. a a . El tama˜o a n a a n est´ dado por el di´metro. se pide es que realice una implementaci´n de los algoritmos exo plicados y encuentre experimentalmente el n´mero de elementos para los que u un algoritmo sea mejor que otro. Pero sabemos que una ime plementaci´n particular est´ afectada por una constante que var´ seg´n el o a ıa u grado de eficiencia con el que fue programado. Describir las invariantes de ciclo para el algoritmo de Selecci´n. Ejercicios 1.3.3. CLASIFICACION 127 datos. Para la a a presentaci´n de la pila usted los puede ordenar por tama˜o de tal manera o n que cada panqueque es m´s peque˜o que los que est´n m´s abajo. Laboratorio Para probar que el sort de burbuja toma un tiempo menor al qsort solo se requiere hallar un n que cumpla la relaci´n o n n−1 < n log(n) 2 Algebraicamente podemos hallar ´stos valores. Describir las invariantes de ciclo para el algoritmo de Burbuja. 5. Ejemplo de aplicaci´n o Se presenta el problema 120 publicado en el Juez de Valladolid Espa˜a y n que es un t´ ıpico problema de ordenaci´n. Este proceso debe realizarse tanto para un vector ordenado de manera aleatorea.´ 5. o 5. o 3. el lenguaje o las caracter´ ısticas del conjunto de datos. El tiempo a que demor´ el m´todo de Java para 100. o Cocinar panqueques en una sart´n es bastante complicado porque sin e importar cuanto se esmere todos tendr´n un di´metro diferente.3. Lo que.4. ascendente y descendente.000 n´meros aleatorios 60 miliseo e u gundos. 5.

Un volteo se especifica a indicando la posici´n del panqueque en la base de la subpila a ser volteado. Entrada La entrada consiste en secuencias de pilas de panqueques. Cada pila consiste de 1 a 20 panqueques y cada panqueque tendr´ un di´metro entero a a entre 1 y 100. a Ejemplo entrada 1 2 3 4 5 5 4 3 2 1 5 1 2 3 4 Ejemplo Salida 1 2 3 4 5 0 5 4 3 2 1 1 0 . APLICACIONES DE BUSQUEDA Y CLASIFICACION La pila se ordena por una secuencia de volteos. la entrada se termina con un fin de archivo. Por ejemplo considere las tres pilas de panqueques en el cual 8 es el panqueque encima de la pila de la izquierda 8 7 2 4 6 5 6 4 8 7 8 4 5 5 6 2 2 7 La pila de la izquierda puede ser transformada a la pila del medio por volteo(3). Cuando la pila est´ ordenada no se deben realizar a a m´s volteos. la secuencia de volteos debe terminar con un 0 indicando que n no se requieren m´s volteos. Todos ellos separados por un espacio. o La pila se especifica dando el di´metro de cada panqueque en orden en a que aparecen. La del medio puede transformarse en la de la derecha con volteo(1). Cada pila est´ dada a en una fila con el panqueque de arriba primero y el de la base al final. o El panqueque de la base tiene la posici´n 1 y el de encima n. Un volteo consiste en insertar una esp´tula entre dos panqueques y volteando todos los panqueques a en la esp´tula (colocando en orden reverso la subpila). Salida Para cada pila de panqueques su programa debe imprimir la pila original en una l´ ınea seguido de una secuencia de volteos que ordena la pila de panqueques de tal forma que el panqueque m´s grande este abajo y el m´s a a peque˜o arriba.128 ´ ´ 5.

int l) { int temporal = 0. j--. c = 0.1. void reverso(int[] pan. conocido de clasificaci´n. j >= 0. // listar el orden original for (int i = l. e Primero un m´todo para invertir la pila de panqueques que denominaree mos reverso. Como se ve es muy parecido al m´todo de inserci´n por lo que codificae o remos ´ste y agregaremos los requerimientos del problema. En segundo lugar codificamos el m´todo buscando el lugar apropiado para e realizar la inserci´n que se consigue llamando a reverso o void inicio() { .. i--) { max = i. for (int j = i . El segundo paso u o es el de determinar si el algoritmo provisto por el lenguaje de programaci´n o resuelve el problema. CLASIFICACION 129 5 1 2 3 4 1 2 0 Soluci´n Para resolver el ejercicio en cuesti´n lo primero que se debe evaluar o o es si se parece a alg´n algoritmo. int j = l.. ver(pan. j--) if (pan[j] > pan[max]) . while (i < j) { temporal = pan[i]. pues no vamos a contruir un algoritmo existiendo uno que resuelve el problema. pan[j] = temporal. pan[i] = pan[j].´ 5..3.. } return. l).1. i++. i > 0. . l = l . int i = 0.

out. } } void ver(int[] pan. i < l.out. i).130 ´ ´ 5. APLICACIONES DE BUSQUEDA Y CLASIFICACION max = j. else System.print((l+1-max) + " " + (l+1-i) + " "). i++) System.out.print(pan[l] + "\n"). max). System. int l) { //lista los datos instroducidos for (int i = 0.print(pan[i] + " ").print((l + 1 .out.out. reverso(pan.println("0"). if (max != i) { if (max == 0) System. } } System. reverso(pan. o o . } } Intencionalmente hemos omitido la parte de la lectura de datos porque es irrelevante en la explicaci´n del procedimiento de resoluci´n.i) + " ").

tenemos cinco n´meros {1. as´ nosotros cono ı sideramos el promedio de la mitad de estos valores {3.4. Los n´meros u u pueden tener espacios blancos. Como resultado. De esa manera. {1. 3 es la u mediana como tiene exactamente dos n´meros en cada lateral.4. 7. Ejercicios Problema 10107 . 6}. En este caso. 5. Entrada. e Salida.Hallar la mediana La mediana juega un importante rol en el mundo de las estad´ ısticas. Supongamos que. 7}..4.000. Ejemplo de entrada 1 3 4 60 70 50 2 Ejemplo de salida 1 2 3 3 4 27 4 . u Si fueran un n´mero par de valores como {1. antes o despu´s. 2} y {6. 6. Por definici´n. 8}.5. la mediana ser´ (3 + 6)/2 = 4. esta es un valor que divide una colecci´n en dos partes iguales. En o o este problema tiene que determinar el flujo medio de algunos enteros largos.Para cada entrada imprime el valor de la mediana con los valores introducidos hasta el momento.1. no los decimales. 6. acordado en este problema. En este problema tu tienes que imprimir a solamente la parte entera. la mediana debe ser 4. 7}.5. solamente un u valor n puede dividir esta colecci´n en dos partes iguales. 3. 3. 2. EJERCICIOS 131 5.. 2.El archivo de entrada consiste de una serie de enteros X (0 <= X < 231 ) y el n´mero total de enteros N es menor que 10.

Dado a un diccionario de palabras y un n´mero de descripciones de trabajos debe u calcular el salario de cada persona.132 ´ ´ 5.2. El proceso consiste en juzgar al empleado en base de una serie de frases buscando las palabras que implican responsabilidad. Para cada descripci´n del texto debe imprimir el salario calculado que es o la suma de los puntos asignados en las palabras de la descripci´n que figuran o en el diccionario. que describe las responsabilidades del mismo.C´lculo de salario a Cada empleado en un trabajo burocr´tico tiene una descripci´n de su a o trabajo en un peque˜o p´rrafo. n a La descripci´n del trabajo est´ combinado con aspectos tales como expeo a riencia para definir su salario. Seguidamente vienen las descripciones de u los puestos de trabajos que consisten en una o varias l´ ıneas de texto que terminan en un punto.4. El sistema libera al personal de recursos humanos de tener que juzgar en forma inteligente como valorar a un empleado.. u Cada palabra del diccionario contiene una palabra y un valor que es un n´mero real entre 0 y 1. Problema 10295 . this individual must have the skill to perform a heart transplant and expertise in rocket science .000.7 2 administer 100000 spending 200000 manage 50000 responsibility 25000 expertise 100 skill 50 money 75000 the incumbent will administer the spending of kindergarden milk money and exercise responsibility for making change he or she will share responsibility for the task of managing the money with the assistant whose skill and expertise shall ensure the successful spending exercise . Entrada. Debe implementar un sistema simplificado de c´lculo de salarios. APLICACIONES DE BUSQUEDA Y CLASIFICACION 5. La primera entrada contiene dos n´meros enteros positivos m <= 1000 u que corresponden al n´mero de palabras en el diccionario y un n´mero n <= u u 100 que indica el n´mero de descripciones de trabajo.000.

5. EJERCICIOS 133 . Ejemplo de salida.4.700150 150 .

un arreglo se cuente el n´mero de mapas de intercambio u diferentes que existen. La pree a gunta se refiere a encontrar los mapas de intercambio existentes.4. que en ning´n caso pasar´ de 5.Contando los intercambios La clasificaci´n como se vi´ puede realizarse intercambiando valores ado o yacentes utilizando el m´todo de la burbuja e Si realizamos un listado de los pares de n´meros a ser intercambiados se u obtiene un mapa de intercambios y la secuencia en que se deben realizar. tambi´n puede ser ordenado intercambiando A1 y A2. Entrada La entrada es un conjunto de casos arbitrarios seguidos de un 0. . Se pide que para. Problema 331 . y finalmente e A2 con A3. El vector anteriormente descripto que. Salida Para cada caso de entrada imprima un mensaje como los mostrados indicando el n´mero de mapas existentes. a Es util hacer notar que pueden existir muchas formas de intercambiar ´ objetos adyacentes para ordenar un vector. Cada caso de entrada comienza con un n´mero n que indica el tama˜o del u n arreglo. 1 se puede ordenar intercambiando los valores A2 y A3. Por ejemplo. el proceso anterior se caracterizar´ como 2 1 2. Pensando un poco podemos llegar a la conclusi´n de o que existen infinitos mapas de intercambio. El mapa de intercambios en esta secuencia es 1 2 1. APLICACIONES DE BUSQUEDA Y CLASIFICACION 5. e luego A2 y A3 y finalmente A1 y A2.3. Si el par identificado en el mapa de intercambios por el ´ ındice del vector del primer elemento a ser intercambiado. Con el ejemplo anterior podemos escribir 1 1 1 2 1 que tambi´n dejar´ el vector en forma ascendente. contiene 3 2 1. que tengan el m´ ınimo de intercambios. despu´s A1 y A2. si se quiere ordenar un vector cuyos elementos son 3. 2. u u a Ejemplo de entrada 2 2 3 3 0 9 7 12 50 3 2 1 9 1 5 Ejemplo de salida There are 1 swap maps for input data set 1.134 ´ ´ 5.

Problema 499 . La salida contiene la lista de letras que incurrieron con la m´xima frea cuencia seguido de la frecuencia. There are 2 swap maps for input data set 3. 5.4. There are 1 swap maps for input data set 4.5. La lista de letras debe estar en min´sculas y en forma ordenada.Hallar la frecuencia El problema consiste en hallar las letras que ocurren con mayor frecuencia en una l´ ınea de texto. EJERCICIOS 135 There are 0 swap maps for input data set 2. u Ejemplo de entrada When riding your bicycle backwards down a one-way street. if the wheel falls of a canoe.4.how many ball bearings does it take to fill up a water buffalo? Hello Howard. Ejemplo de salida e6 al 7 a3 Hlo 2 .4.

136

´ ´ 5. APLICACIONES DE BUSQUEDA Y CLASIFICACION

Cap´ ıtulo 6 Combinatoria b´sica a
6.1. Introducci´n o

La combinatoria es la disciplina de las matem´ticas que se refiere a las a t´cnicas de contar. En realidad lo que trata de responder es a la pregunta e ¿cu´ntos son? sin tener que contarlos. a En general las t´cnicas de contar proveen una serie de alternativas al e momento de tener que escribir programas complicados que cuenten todos los valores y permiten tener expresiones, que solucionen el problema aplicando f´rmulas simples. o

6.2.

T´cnicas b´sicas para contar e a

En esta parte recordaremos una serie de f´rmulas de la combinatoria y o mostraremos como son aplicadas en la programaci´n. No desarrollaremos los o conceptos matem´ticos porque no corresponde a lo que el texto pretende, a que es mostrar la forma de resolver problemas. Regla del Producto Si un conjunto A tiene |A| posibilidades y el B tiene |B| posibilidades entonces existen |A| x |B| formas de combinar ´stos. e Por ejemplo si tengo 4 tipos de autom´viles y 3 colores se tienen 12 o combinaciones. Estas combinaciones pueden representarse en una matriz cuadrada almacenando en cada celda una combinaci´n. En el caso o de tres conjuntos con una matriz de tres dimensiones, vea que el espacio ocupado o el recorrido de los elementos se hace cada vez m´s grande a 137

138

´ 6. COMBINATORIA BASICA

Regla de la suma Si un conjunto A tiene |A| posibilidades y el B tiene |B| posibilidades entonces existen |A| + |B| posibles formas en las que A o B pueden ocurrir. En el ejemplo anterior si uno de los autom´viles, o o de los colores es errado, existen 4 + 3 = 7 posibles ´ ıtems fallados. Regla inclusi´n y exclusi´n Esta es una regla generalizada de la suma. o o Supongamos que tenemos autom´viles de 5 colores y minibuses de 6 o colores y queremos conocer cu´ntos colores diferentes existen. En este a caso tenemos dos conjuntos que se superponen. Esto significa sumar la cantidad de colores de ambos y restar los que sean comunes a ambos que se expresa como: |A| ∪ |B| = |A| + |B| − |A| ∩ |B| Permutaciones Una permutaci´n es un arreglo de n ´ o ıtems donde cada ´ ıtem aparece solo una vez. Existen 3! permutaciones para un conjunto de tres elementos. Si los elementos son 123 las permutaciones vienen a ser 123 132 231 213 312 321. Para un n arbitrario son n!. hay que observar que a medida que aumenta n el n´mero de permutaciones aumenta muy u r´pidamente. a Subconjuntos Un subconjunto es la selecci´n de algunos elementos de n o posibles ´ ıtems. Para un conjunto arbitrario existen 2n posibles subconjuntos, por ejemplo para 3 elementos existen 23 subconjuntos, ´sto es: e 1,2,3,12,13,23,123 y el conjunto vac´ A medida que crece n, r´pidaıo. a mente se llega a tiempos de proceso muy grandes. Cadenas Cuando tratamos con cadenas o sea una secuencia de ´ ıtems con n repetici´n, se tienen m distintas secuencias. Para 3 elementos con reo petici´n se tienen 27 casos que son 111, 112, 113, 121, 122, 123, 131, o 132, 133, 211, 212, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321, 322, 323, 331, 332, 333. El n´mero crece m´s r´pidamente a medida u a a que crece m. En muchos casos podemos encontrar que lo que tenemos es una funci´n o biyectiva o sea un asociaci´n uno a uno con otro conjunto. En este caso o podemos resolver el problema de contar cualquiera de los dos conjuntos. Por ejemplo si decimos que cada planta est´ en una maceta da lo mismo contar a las plantas o las macetas. Si una maceta pudiera tener m´s de una planta a esto ya no es cierto.

6.3. COEFICIENTES BINOMIALES

139

6.3.

Coeficientes binomiales

Los coeficientes binomiales se refieren a calcular n k que es el n´mero de formas posibles de escoger k elementos de n posibilidades. u Que elementos se cuentan m´s comunmente? a Comit´s Cuantas maneras hay de formar un comit´ de k miembros con n e e personas. La respuesta se halla por la definici´n. o Caminos en un matriz C´antas maneras hay de viajar desde la esquina u superior hasta la esquina inferior derecha en una matriz de m x n caminando solamente hacia abajo o hacia la izquierda? Cada camino debe consistir de m + n pasos n hacia abajo y m a la derecha, por lo que existen: n+m n Coeficientes de (a + b)n Cu´l es el coeficiente de ak bn−k claramente a n k porque cuenta el n´mero de formas que podemos utilizar para escoger u k elementos de n.

Tri´ngulo de Pascal Para calcular los coeficientes binomiales de puede a realizar utilizando directamente la f´rmula o n! n = k k!(n − k)! Sin embargo los c´lculos intermedios pueden hacer que el trabajo con a n´meros grandes sea inadecuado o de tiempo muy largo, una alternativa u es utilizar el tri´ngulo de Pascal. a n 1 2 3 4 5 6 7 p(n) 1 1 1 1 1 1 1 p(n,1) p(n,2) p(n,3) p(n,4) p(n,5) p(n,6) 1 2 3 4 5 6

1 3 6 10 15

1 4 10 20

1 5 15

1 6

1

COMBINATORIA BASICA Lo interesante de ´ste tri´ngulo es que calcula los coeficientes binomiae a les sin tener que realizar factoriales. int k) { return x[n][k]. Y en segundo lugar en cada l´ ınea la suma de sus valores da 2i .i++) x[i][i]=1.i<MAXIMO. Esto es k=i k=0 i k = 2i . Para calcular n tomados de k en tiempo constante podemos construir el tri´ngulo de Pascal a /**Programa para constuir el * triangulo de Pascal * @author Jorge Teran * */ public static void tri´ngulo(int[][] x) { a // Invariante cada linea debe comenzar con uno for (int i=0.j<=i.j++) x[i][j]=x[i-1][j-1]+x[i-1][j].i<MAXIMO.i++) x[i][0]=1. } } luego es posible hallar n tomados de k public static int nTomadosDek( int [][] x. for (int i=1.int n.i++) // Invariante cada linea debe sumar 2**i for (int j=1.140 ´ 6.i<MAXIMO. } Ahora explicamos cu´les son las invariantes del tri´ngulo de Pascal. // Invariante cada linea debe terminar con uno for (int i=0. a a Primero cada l´ ınea debe comenzar y terminar con 1.

6.4. ALGUNAS SECUENCIAS CONOCIDAS

141

F´ ıjese que en ´sta implementaci´n se utiliza solo la mitad del arreglo e o bidimensional creado. Una propiedad interesante es que la suma de las diagonales del tri´ngulo a da los n´meros de Fibonacci, que se presentan en la siguiente secci´n, u o veamos esto con los datos del ejemplo: Diagonal 1 2 3 4 5 6 Suma 1=1 1=1 1+1=2 2+1=3 1+3+1=5 3+4+1=8

Otras propiedades del tri´ngulo de Pascal pueden verse en a http://mathworld.wolfram.com/

6.4.
6.4.1.

Algunas secuencias conocidas
N´ meros de Fibonacci u

Los n´meros de Fibonacci son la secuencia de n´meros definidos por la u u ecuaci´n: o T (n) = T (n − 1) + T (n − 2) Teniendo definido que T (0) = 0 y T (1) = 1, se genera la siguiente secuencia 1, 1, 2, 3, 5, 8, 13, 21, ... Los n´meros Fibonacci aparecen en diferentes ´mbitos, desde la criptou a graf´ como menciona Dan Brown en su novela C´digo DaVinci, en la naıa, o turaleza existen ejemplos, en cristalograf´ y en la descripci´n de la posici´n ıa o o de las semillas en las plantas de girasol. Para hallar el t´rmino en´simo de la secuencia podemos utilizar los m´toe e e dos de resoluci´n de recurrencias obteniendo: o √ √ n 1− 5 1 1+ 5 n T (n) = √ (( ) −( ) 2 2 5 Una explicaci´n detallada se halla en el texto de Matem´tica Discreta de o a Grimaldi [Gri77].

142

´ 6. COMBINATORIA BASICA

Los n´meros de Fibonacci satisfacen tambi´n la siguinte relaci´n del m´xiu e o a mo com´n divisor u M CD(Fn , Fm ) = FM CD(n,m) Tambi´n se puede ver que los n´meros de Fibonacci tienen la carater´ e u ıstica de que al dividirse m´dulo m, producen una secuencia c´ o ıclica. Fibonacci 1 1 2 3 5 8 13 21 34 55 mod 2 mod 3 mod 4 1 1 1 1 1 1 0 2 2 1 0 3 1 2 1 0 2 0 1 1 1 10 0 1 00 1 2 00 1 3

6.4.2.

N´ meros Catalanes u

Los n´meros Catalanes son los n´meros que est´n asociados a la f´rmula u u a o
n−1

Cn =
k=0

Ck Cn−1−k =

1 n+1

2n n

Los primeros n´meros Catalanes son: 1,1,2,5,14,42,132,429 y se pueden obu tener como sigue: n´mero Catalan Valor u C0 1 C1 1 C2 C0 C1 + C1 C0 = 2 C3 C0 C2 + C1 C1 + C2 C0 = 5 C4 C0 C3 + C1 C2 + C2 C1 + C3 C0 = 14 Estos n´meros se presentan en diferentes problemas, veamos por ejemplo u la siguiente secuencia {−1, −1, −1, 1, 1, 1}. ¿De cu´ntas maneras se pueden a ordenar para que las sumas parciales de los elementos sea positiva?

6.4. ALGUNAS SECUENCIAS CONOCIDAS

143

Estos elementos son {1, 1, 1, −1, −1, −1}, {1, 1, −1, 1, −1, −1}, {1, 1, −1, −1, 1, −1}, {1, −1, 1, 1, −1, 1} y {1, −1, 1, −1, 1, −1}. Esta secuencia corresponde al n´mero Catal´n 3 que es 5, que tambi´n u a e podemos calcular de la combinatoria 1 3+1 6 3

=5

Algunos otros ejemplos de aplicaci´n de los n´meros Catalanes son los o u siguientes. ¿De cu´ntas formas se pueden colocar 3 par´ntesis de tal manera que a e cada par´ntesis de apertura tenga su respectivo de cierre? La respuesta e es el n´mero Catal´n 3, veamos ((())), ()(()), (())(), (()()) y ()()() u a Dado un pol´ ıgono regular de n v´rtices, de cu´ntas formas se puede e a dividir en n − 2 tri´ngulos, si las diferentes orientaciones se cuentan en a forma diferente?. Un cuadrado se puede dividir en dos tri´ngulos con a una l´ ınea entre sus v´rtices las posibilidades son 2. En un pent´gono se e a hace con, dos l´ ıneas y se obtienen 3 tri´ngulos y el n´mero de casos es a u n´mero Catal´n 3 o sea 5. u a Dados dos candidatos A y B que en una elecci´n, cada uno obtiene o n votos (empate). De cuantas maneras se puede contar los votos de tal forma que al realizar el recuento, el candidato A siempre est´ por e delante del candidato B. Este tambi´n el n´mero Catal´n n. e u a

6.4.3.

N´ mero Eulerianos u

Sea p = {a1 , a2 , ...an }, deseamos conocer todas las permutaciones que cumplen la relaci´n ai < ai+1 . Por ejemplo si p = {1, 2, 3, 4} se construyen o todas las permutaciones de p y contamos los casos en los que se cumple la relaci´n de orden: o

144 Permutaci´n o 1234 1243 1324 1342 1423 1432 3124 3142 3214 3241 3412 3421

´ 6. COMBINATORIA BASICA

Cu´ntos cumplen Permutaci´n a o 3 2134 2 2143 2 2314 2 2341 2 2413 1 2431 2 4123 1 4132 1 4213 1 4231 2 4312 1 4321

Cu´ntos cumplen a 2 1 2 2 2 1 2 1 1 1 1 0

por ejemplo la permutaci´n 2341 tiene 2 < 3 y 3 < 4 que son dos casos que o cumplen la relaci´n de orden. Cu´ntas permutaciones de 4 elementos tienen o a dos casos que cumplen la relaci´n de orden?. Este valor est´ representado o a por n´mero Euleriano u n k
k+1

=
j=0

(−1)j

n+1 j

(k − j + 1)n

si contamos los valores del ejemplo vemos que son 11. Si organizamos estos n´meros en un tri´ngulo se obtiene el tri´ngulo u a a Euleriano n 1 2 3 4 5 6 1 1 1 1 1 1 n 0 1 4 11 26 57 n 1 n 2 n 3 n 4 n 5

1 11 66 302

1 26 302

1 57

1

Analizando la tabla de permutaciones realizada vemos que 4 0 =1 4 1 = 11 4 2 = 11 4 3 =1

j<=i.i++) for (int j=2. for (int i=1.i<MAXIMO.out.i++) x[i][i]=1. } } } .4.1) k k k−1 Una propiedad interesante de los n´meros Eulerianos que. for (int j=1.j++) System.i++) x[i][1]=1.out.4.i<MAXIMO.1 /**Programa para construir el * triangulo Euleriano * @author Jorge Teran * */ public class Eulerian { public final static int MAXIMO=6. for (int i=0.j<=i. for (int i=2.println(" "). ALGUNAS SECUENCIAS CONOCIDAS 145 corresponden al tri´ngulo presentado.i<MAXIMO. a Este tri´ngulo puede generarse de la siguiente relaci´n de recurrencia: a o n n−1 n−1 =k + (n − k + 1) (6. puede utilizarse u como invariante es que: n n = n! k k=0 El presente programa genera dicho tri´ngulo utilizando la recurrencia a 6.i<MAXIMO. public static void main(String[] args) { int [][] x = new int [MAXIMO][MAXIMO]. for (int i=0.j++) x[i][j]=(i-j+1)*x[i-1][j-1] +j*x[i-1][j].print(x[i][j]+" ").6.i++){ System.4.

y S(n.1. Pau u ra calcular S(n.3). ¯ son 2n − 2. al igual que los ejemplos anteriores la siguiente recurrencia: S(n.4)} {(1. esto es: 2n − 2 = 2n − 1 2 En el caso de dividir en dos subconjuntos es relativamente simple de hallar el resultado. Nos preguntamos cu´ntos conjuntos de k a subconjuntos podemos formar que excluyan el elemento vac´ y la uni´n de ıo o ellos. A} y {A. 3. COMBINATORIA BASICA 6. a Estos n´meros se denominan n´meros de Stirling de segundo orden.146 ´ 6. 4} todos los conjuntos de 2 elementos son: 1 2 3 4 5 6 7 {(1). el n´mero total de subconu n juntos que podemos formar es 2 .(2.3. Como no nos importa el orden.(3.1)} {(1. 1) = 1.(2.3. k) = S(n − 1.(2.4)} {(2).4. nos da el conjunto original? Para comprender el problema considere el conjunto p = {1.4)} {(4).(2. A} Como tenemos dos conjuntos existen dos conjuntos vac´ entonces el total de subıos.(1. 6.4)} {(3).5. k) se puede utilizar. Primeramente veamos que un conjunto ¯ ¯ de n elementos se puede dividir en dos conjuntos {A. conjuntos que puede tener A y A vale decir que el complemento est´ antes o despu´s hay que tomar la mitad e e de los elementos. n) = 1.2). k) + kS(n − 1. En cambio cuando tenemos un n´mero mayor se hace u m´s complicado. Particiones enteras Se quiere contar de cu´ntas formas se puede escribir un n´mero entero a u positivo como la suma de enteros positivos.4.4.4)} {(1. Ahora el orden de los sumandos .3)} Como podemos calcular este valor?.(2. 2.3.4). k) Hay que tomar en cuenta que los l´ ımites son: S(n. N´ meros de Stirling u Consideremos un conjunto con n elementos.

k) el n´mero total de elementos de u una partici´n de k elementos entonces el n´mero de particiones o u k=n p(n) = k=1 p(n. Cada una de estas formas se denomina partici´n y cada uno o de los sumandos parte. Sea p(n. k) = p(n − 1. El siguiente programa produce el resultado deseado. 2 de 2 y 1 de 1. Este problema no o lo desarrollaremos y mencionaremos la recurrencia As´ analizamos este ejemplo veremos que hay 1 partici´n de 5 elementos. /**Programa para hallar las * particiones enteras * @author Jorge Teran * */ public class ParticionEntera { public final static int MAXIMO = 8. i < MAXIMO. Por ejemplo: 1 2 3 4 5 6 7 5=1+1+1+1+1 5=1+1+1+2 5=1+2+2 5=1+1+3 5=2+3 5=1+4 5=5 En este caso la partici´n de 5 tiene 7 posibles particiones. k) Estos valores tambi´n nos proporcionan un tri´ngulo que puede armarse con e a la siguiente recurrencia: p(n. k) Considerando que p(1. public static void main(String[] args) { int[][] x = new int[MAXIMO][MAXIMO].6. 2 de 3. ALGUNAS SECUENCIAS CONOCIDAS 147 es irrelevante. k) = siendo k > n. ı o 1 de 4. i++) . for (int i = 1. k − 1) + p(n − k.4. 1) = 1 y que p(n.

else x[i][j] = x[i .1) 1 1 1 1 1 1 1 ´ 6.out. i++) { System. for (int j = 1.2) p(n. Para hallar el n´mero total de particiones solo hay que sumar los elementos de una fila.k) esta representado por la fila y la columna. u Estos est´n sumarizados en la columna p(n). j <= i.1][j .3) p(n.4) p(n. a . i < MAXIMO. COMBINATORIA BASICA p(n.5) p(n. j++) { if (j == 1 || j == i) x[i][j] = 1. j++) System.148 n 1 2 3 4 5 6 7 p(n) 1 2 3 5 7 11 15 p(n. } } } El resultado del proceso produce el tri´ngulo que mostramos en el cuadro a 6.6) p(n.out.1 donde la p(n.print(x[i][j] + " "). } for (int i = 1.1]. j <= i.j][j] + x[i .7) 1 1 2 2 3 3 1 1 2 3 4 1 1 2 3 1 1 2 1 1 1 Cuadro 6.println(" ").1: Tri´ngulo para hallar las particiones a for (int j = 1.

10c. There is only 1 way to produce 4 cents change. 5c. There are $m$ ways to produce n cents change.5.6.La entrada consiste de una serie de n´meros entre 1 y 30. en dos monedas de 5 centavos y 7 de un centavo.5.5. en diferentes combinaciones de monedas? Despu´s de pensar e obtuvo la respuesta. EJERCICIOS 149 6. que es 6. Ejercicios Problema 357 . . El recibi´ una moneda de 10 centavos una de 5 centavos o y dos de dos centavos.. Considere el problema general. 6. Luego se pregunt´ ¿en cuantas tiendas puedo comprar y recibir cambio de o 17 centavos. Ejemplo de entrada. realice un programa para determinar el n´mero de combinaciones de monedas de 1c.Formas de combinar monedas Despu´s de realizar la compra en una tienda de departamentos. D´ despues realizando compras recibi´ otra vez ıas o 17 centavos de cambio. 25c. Entrada.There are 6 ways to produce 17 cents change.La salida consiste en una frase que indica el n´mero de formas que u existen de dar cambio.1. y 50c que se pueden u utilizar para dar esa cantidad de cambio..17 11 4 Ejemplo de salida. There is only 1 way to produce n cents change.000 inu clusive. Salida. una por l´ ınea de entrada. There are 4 ways to produce 11 cents change. el cambio e fue de 17 centavos.

963.381. uno ´ m´s espacios y un o a o a valor para M . 20 things taken 5 at a time is 15504 exactly.000 Entrada y salida La entrada de este programa puede ser una o m´s l´ a ıneas que contienen 0 ´ m´s espacios.000.443.000.518.608. 941.976. un valor para N.286.5.185. ıo Por consiguiente hay que hacer un programa que calcule los siguientes: datos: 5 ≤ n ≤ 100 y 5 ≤ m ≤ 100 y m ≤ n Calcule el valor exacto de: c= n! (n − m)!m! Se puede asumir que el valor final de C no sobrepasa un entero de 32 bits.856.599. Como antecendente.621.150 ´ 6. el valor exacto de 100! es: 93.326.156.944. .827.920.238.916.000.217.681.592. La ultima l´ ´ ınea de la entrada dos ceros. 210. El programa debe terminar cuando lee esta l´ ınea.715.697.223.266. en un tiempo u dado pueden ser un gran desaf´ cuando N y/o M llegan a ser muy grandes.468. Problema 369 . COMBINATORIA BASICA 6. 18 things taken 6 at a time is 18564 exactly.264. La salida para el programa debe estar en la forma: N things taken M at a time is C exactly.490.251.215.993.253.000.758. Ejemplo de entrada 100 20 18 0 6 5 6 0 Ejemplo de salida 100 things taken 6 at a time is 1192052400 exactly.463.152.915.000.700.864.229. 968.2.000.895.699.000.Combinaciones Calcular el n´mero de formas que N objetos tomados de M.

Durante el evento algunos estudiantes decidieron cambiar el orden de las letras. escriba el n´mero de formas diferentes.001.Mal educados Se coloc´ un letrero en un panel consistente en casillas individuales para o cada letra.3. Cada palabra tiene un m´ximo de 20 letras y no incluye caracteres de a puntuaci´n. Para cau da palabra. De cu´ntas formas unicas y sin repetici´n se pueden organizar a ´ o las letras? Entrada y salida En la primera l´ ınea viene un entero que indica el n´mero u de conjuntos de datos de prueba. Cada entrada consiste de letras escritas todas en may´sculas. Ejemplo de entrada 3 HAPPY WEDDING ADAM Ejemplo de salida Data set 1: 60 Data set 2: 2520 Data set 3: 12 .5. Problema 10338 .6. o El n´mero de arreglos siempre podr´ almacenarse en un entero de tipo u a long. en las que se pueden u reorganizar las letras contando el arreglo original. EJERCICIOS 151 6. Tome en cuenta que el n´mero m´s grande que se puede almacenar en u a una variable entera es 12!.5. Este valor es inferior a 30.

COMBINATORIA BASICA 6. Cada caso de prueba consiste en dos n´meros a.4. b ≤ 10100 . El proceso termina u cuando a. Ejemplo de entrada 10 100 1234567890 9876543210 0 0 Ejemplo de salida 5 4 . Entrada y salida La entrada consiste en varios casos de prueba.b estan en 0.b con a.152 ´ 6. Problema 10183 .5.Secuencia de Fibonacci Utilizando la secuencia de Fibonaci se quiere calcular cu´ntos n´meros a u caben en un determinado rango.

de reutilizar las herramientas provistas.Cap´ ıtulo 7 Estructuras de datos elementales 7. sino m´s bien. extraer el ultimo objeto o mirar el ultimo. Esto significa que e el ultimo valor introducido es el primero en salir. No se trata de o introducir los conceptos que corresponden a los cursos de estructura de datos. La intenci´n de ´ste cap´ a o e ıtulo es orientar en el uso de estructuras que vienen implementadas en el lenguaje de programaci´n Java. o public class Alumno { String nombre. La estructura de pila es una a lista en la que solo se pueden ingresar y sacar valores por un solo lugar. En Java ´sto equivale a los m´todos push.2. 153 . que almacena nombre y c´digo. Introducci´n o En el presente cap´ ıtulo se hace una introducci´n a las estructuras de datos o b´sicas. ´ En esta estructura solo se pueden insertar objetos al final. a 7. Pilas Una de las estructuras m´s simples es la pila.1. Estas pilas se denominan tambi´n listas LIFO (last in first out). ´ ´ e e pop y peek. Para mostrar como se realiza esta implementaci´n utilizaremos la clase o Alumno.

a import java. 11). pila.push(alm1). import java. // almacenar los alumnos Alumno alm1 = new Alumno("Juan".println(pila. this. pila.nombre=nombre.154 7. o } } El siguiente c´digo implementa la clase pila.peek().util.verNombre()). alm1 = new Alumno("Jose". o o } public String verNombre() { return nombre. pila. 17). El siguiente programa realiza lo indicado. } public int verCodigo() { return c´digo.c´digo=c´digo. ESTRUCTURAS DE DATOS ELEMENTALES int c´digo.push(alm1). // Recuperar el elemento de encima System. /** * Ejemplo de manejo de pilas * @author Jorge Teran * @param args * none */ public class pila { public static void main(String[] args) { // definir una pila de alumnos Stack<Alumno> pila = new Stack(). o public Alumno(String nombre.*. 25).io.*. alm1 = new Alumno("Maria". int c´digo) { o this.push(alm1).out. ingresando objetos de tipo o Alumno y luego list´ndolos. // Imprimir la pila .

caso contrario. /** * Ejemplo de manejo de pilas * Comprobaci´n de parentisis bien anidados o * @author Jorge Teran * @param args * parentesis y corchetes * EjemploPila ()()(((()[) */ public class EjemploPila { public static void main(String[] args) { //String cadena="(([]))(".util. quiere decir que hay m´s llaves de apertura que de cierre en a la expresi´n a ser analizada.println(pila. La secuencia (([)]) es una secuencia mal anidada.2. Cuando se quiere recuperar un elemento de la pila y est´ vac´ indica que a ıa.isEmpty()) System. Cuando se termina el proceso la pila debe estar vac´ ıa. o Esto nos lleva al siguiente c´digo: o import java.io. Consideree a mos algunos casos La secuencia (([])) es una secuencia bien anidada. un corchete no puede cerrarse con un par´ntesis. sobran llaves de cierre. import java. a e Para resolver este tipo de problemas una pila es un m´todo apropiado.7.pop().*. . porque le falta un par´ntesis de cierrre.verNombre()). e La secuencia ((()) est´ mal. La e estrategia de soluci´n es el almacenar en la pila todas las llaves de apertura y o cada vez que aparece una de cierre obtenemos un elemento de la pila y debe ser una llave de apertura correspondiente a la de cierre. PILAS 155 while (!pila. } } Para ejemplificar la utilizaci´n de pilas supongamos que queremos verifio car si una secuencia de par´ntesis y corchetes est´ bien anidada.out.*.

println("Sobran llaves de apertura"). for (int i=0.push("]"). ESTRUCTURAS DE DATOS ELEMENTALES String cadena=args[0].compareTo("[")==0) pila.isEmpty()){ System.exit(0).i+1). } } Los m´todos disponibles para pilas son: e M´todo e push(E elemento) pop() peek() isEmpty() Descripci´n o Agrega un elemento a la pila.println("Bien anidada").println("Mal anidada"). else System. if (caracter.util. String caracter.pop().Stack(). ´ Lee el ultimo elemento introducido.println("Sobran llaves de cierre"). System. else if (caracter. else { if (pila.isEmpty()) System.length().out. i< cadena.out.compareTo(caracter)==1){ System.out.i++){ caracter=cadena.push(")"). // definir una pila de cadena Stack<String> pila = new java.compareTo("(")==0) pila. ´ Devuelve true si la pila est´ vac´ a ıa. if (delapila. } delapila=pila. Extrae el ultimo elemento introducido.out.delapila. . System.substring(i.156 7.exit(0). } } } if (!pila.

Cuando insertamos elementos consecutivos se introducen en el orden que se env´ ıan. supongamos la lista que tiene los elementos abc existen cuatro lugares donde se pueden insertar los nuevos valores. Listas enlazadas Las listas enlazadas tienen la ventaja de que permiten ingresar elementos en cualquier lugar de la lista sin necesidad de tener que hacer un espacio como en los vectores. El lenguaje Java provee una clase denominada iterador que permite recorrer la clase. u Hay que hacer notar que las listas no son una estructura de datos adecuadas para el acceso aleatoreo. . es el que indica donde se puede introducir el ´ elemento.3. add(int i. si est´ apuntando al final de la lista se introducen despu´s del a e ultimo elemento. En una lista enlazada existen varias posiciones en las que se puede introducir un elemento. clear() Borra la lista. removeLast() Quita y devuelve el ultimo elemento. Cuando el iterador apunta al principio se introducen al principio. Los m´todos de Java para listas enlazadas son los siguientes: e M´todo e Descripci´n o add(E elemento) Agrega un elemento a la lista. ´ set(int i. E elemento) Agrega un elemento en la posici´n i. contains(E elemento) Devuelve true si la lista contiene el elemento.3.7. o addFirst(E elemento) Agrega un elemento al principio. addLast(E elemento) Agrega un elemento al final. addAll(int i.coleccion) Agrega toda una colecci´n en la o posici´n i. a bc. ab c y abc . o isEmpty() Devuelve true si la lista esta vac´ ıa. El interador. E elemento) Cambia el elemento de la posici´n i. LISTAS ENLAZADAS 157 7. o removeFirst() Quita y devuelve el primer elemento. estos son: abc. Cada vez que se busca un elemento o recorre la lista siempre comienza desde el principio. o remove(int i) Quita y devuelve el elemento de la posici´n i. size() Devuelve el n´mero de elementos.

ESTRUCTURAS DE DATOS ELEMENTALES La colecci´n para listas enlazadas provee una clase para recorrer la lista o llamada iterador que tiene los siguientes m´todos: e M´todo e Descripci´n o ListIterator(E) Crea un iterador para visitar elementos de la lista. Luego se utiliza el iterador para recorrer la lista.158 7. while (aIter. 11)). set(E elemento) Cambia el ultimo elemento visitado.out.next().out. uno. } .verNombre()). 17)). o o En el siguiente ejemplo se crean dos listas y se introducen elementos de la clase Alumno.println("Listar la lista UNO"). previous() Devuelve el elemento anterior.add(new Alumno("Juan". uno. LinkedList<Alumno> uno = new LinkedList<Alumno>(). nextIndex() Devuelve el ´ ındice que ser´ llamado en la ıa pr´xima iteraci´n. ´ hasPrevious() Devuelve true si tiene un elemento anterior.add(new Alumno("Maria". Finalmente se muestra el m´todo removeAll que permite remover todos los elementos e de una lista que est´n en la otra.println(alm. a public class ListaEnlazada { /** * Ejemplo de lista enlazada * @author Jorge Teran * @param args * none */ public static void main(String[] args) { Alumno alm.hasNext()) { alm = aIter. // desplegar la lista uno System.listIterator(). ListIterator<Alumno> aIter = uno. System.

next().removeAll(dos).out.7.out.3. // Reiniciar el iterador y listar la lista uno aIter = uno. } System.out.listIterator().add(bIter. while (aIter. dos.out.println( "Despues de agregar la lista DOS").verNombre()).hasNext()) { System. ListIterator<Alumno> bIter = dos.hasNext()) { alm = aIter.hasNext()) { uno. System. dos.println( "Listar despues de quitar la lista DOS").listIterator(). System.println(alm. 25)). // Reiniciar el iterador y listar la lista uno aIter = uno. // agregar los alumnos de lista dos // a la lista uno while (bIter. 8)). } } } Para realizar listas doblemente enlazadas es suficiente crear una lista con una clase de tipo lista.listIterator().next()).verNombre()). while (aIter. LISTAS ENLAZADAS 159 List<Alumno> dos = new LinkedList<Alumno>().add(new Alumno("Laura". } // quitar los elementos de la lista dos de uno en uno uno. .println(aIter. De esta forma se pueden crear listas con cualquier nivel de anidamiento.next().add(new Alumno("Jose".

160

7. ESTRUCTURAS DE DATOS ELEMENTALES

7.4.

Conjuntos

El manejo de conjuntos es similar, al de las listas con la condici´n que, o no se permiten elementos repetidos y el orden no es relevante. La implementaci´n de un conjunto se hace como una estructura de tio po Set y esta estructura viene implementada en HashSet. Para definir un conjuto conjA hay que escribir lo siguiente: Set<String> conjA = new HashSet<String>(); Los m´todos disponibles para la clase set son los siguientes: e M´todo e add(E elemento) clear() addAll(coleccion) removeAll(coleccion) Descripci´n o Agrega un elemento al conjunto. Borra el conjunto. Agrega toda una colecci´n. o Elimina todos los elementos de la colecci´n que existan en el conjunto. o remove(Object objeto) Elimina el objeto del conjunto. Devuelve true si ha sido eliminado. isEmpty() Devuelve true si el conjunto esta vac´ ıo. contains(E elemento) Devuelve true si el conjunto contiene el elemento. size() Devuelve el n´mero de elementos del u conjunto.

Los m´todos para recorrer los conjuntos se realizan con la clase Iterator e que tiene los siguientes m´todos: e M´todo e Descripci´n o Iterator(E) Crea un iterador para visitar elementos del conjunto. hasNext() Si existe un pr´ximo elemento devuelve true. o next() Avanza al pr´ximo elemento. o Para utilizar la clase Iterator se procede como sigue: Primero creamos el iterador sobre el conjunto

7.4. CONJUNTOS

161

Iterator<String> iter = conjA.iterator();

Para recorrer el conjunto while (iter.hasNext()) Finalmente para acceder a elementos individuales podemos utilizar iter.next(). Por ejemplo para desplegar el elemento: System.out.println(iter.next()); En el siguiente ejemplo se muestra como introducir elementos, recorrer el conjunto y como hallar la intersecci´n de dos conjuntos. o import java.util.*; /** * Ejemplo manejo de conjuntos * @author Jorge Teran * @param args * none */ public class Conjuntos { public static void main(String[] args) { Set<String> conjA = new HashSet<String>(); conjA.add("aaa"); conjA.add("bbb"); conjA.add("aaa"); conjA.add("ccc"); conjA.add("ddd"); Set<String> conjB = new HashSet<String>(); conjB.add("aaa"); conjB.add("bbb"); conjB.add("bbb"); conjB.add("xxx");

162

7. ESTRUCTURAS DE DATOS ELEMENTALES

conjB.add("yyy"); //hallar conjB interseccion conjA Set<String> conjC = new HashSet<String>(); conjC.addAll(conjA); // para intersectar A y B // hacemos C=A-B y luego A-C conjC.removeAll(conjB); conjA.removeAll(conjC); //listar Iterator<String> iter = conjA.iterator(); while (iter.hasNext()) System.out.println(iter.next()); } }

7.5.

Clases map

Las clases donde se almacenan los valores como clave y valor se denomina clase Map por ejemplo, si se quiere almacenar color=rojo donde color es la clave y rojo es el valor se puede almacenar y recuperar por la clave. Los m´todos de la clase Map est´n descriptos en el cuadro 7.1. e a El recorrido de la clase Map se puede realizar por clave, valor o por ambos. Para definir un recorrido de una clase Map por clave se procede como sigue: Iterator<String> iter = preferencias.keySet().iterator(); Para definir un recorrido por valor: Iterator<String> iter = preferencias.values().iterator(); Para recorrer por ambos hay que tomar en cuenta que Iterator no permite definir dos cadenas como es la definici´n de Map. Por esto es necesario o cambiar el recorrido como sigue: Map.Entry<String, String> datos : preferencias.entrySet() Luego podemos acceder a la clave con datos.getKey() y a los valores a trav´s de datos.getValue(). e En el siguiente ejemplo, se introducen pares de elementos y luego se recorre el conjunto Map listando clave y valor.

7.5. CLASES MAP

163

M´todo e put(Clave, Valor) get(Clave)

Descripci´n o Agrega un elemento Map. Devuelve el elemento Map con la clave especificada. clear() Borra el conjunto Map. remove(Object objeto) Elimina el objeto del conjunto con la clave especificada. Devuelve true si es eliminado. isEmpty() Devuelve true si el conjunto Map esta vac´ ıo. containsValue(Object elemento) Devuelve true si el conjunto contiene el valor. containsKey(Object elemento) Devuelve true si el conjunto contiene la clave. size() Devuelve el n´mero de elementos u del conjunto Map. Cuadro 7.1: M´todos de la clase map e import java.util.*; /** * Ejemplo de la estructura map * @author Jorge Teran * @param args * none */ public class PruebaMap { public static void main(String[] args) { Map<String, String> preferencias = new HashMap<String, String>(); preferencias.put("color", "rojo"); preferencias.put("ancho", "640"); preferencias.put("alto", "480"); //listar todo System.out.println(preferencias); // Quitar color

164

7. ESTRUCTURAS DE DATOS ELEMENTALES

preferencias.remove("color"); // cambiar una entrada preferencias.put("ancho", " 1024"); // recuperar un valor System.out.println("Alto= " + preferencias.get("alto")); // iterar por todos los elementos for (Map.Entry<String, String> datos : preferencias.entrySet()) { String clave = datos.getKey(); String valor = datos.getValue(); System.out.println( "clave=" + clave + ", valor=" + valor); } } }

7.6.

Clases para ´rboles a

En el Java tenemos la clase de ´rboles que permite mantener ordenados a los elementos de un conjunto a medida que, se introducen los elementos. Para poder implementar ´sto es necesario tener una clase de comparaci´n e o que permita decidir en que rama del ´rbol corresponde insertar un elemento, a para esto agregamos a la clase Alumno el siguiente m´todo. e public int compareTo(Alumno other) { return c´digo - other.c´digo; o o } que superpone el m´todo de comparaci´n que solo se utiliza con los tipos e o de datos b´sicos; vea que, lo que se est´ comparando es el c´digo y la resa a o

´ 7.6. CLASES PARA ARBOLES

165

puesta puede ser 0,1 o -1. En la definici´n de la clase es necesario agregar o implements Comparable<Alumno> quedando como sigue: public class Alumno implements Comparable<Alumno> { Luego el siguiente c´digo ingresa Alumnos a un ´rbol organizado por c´digo o a o import java.util.*; /** * Ejemplo de la estructura de Arboles * @author Jorge Teran * @param args * none */ public class Arbol { public static void main(String[] args) { TreeSet<Alumno> alm = new TreeSet<Alumno>(); alm.add(new Alumno("Juan", 11)); alm.add(new Alumno("Maria", 17)); alm.add(new Alumno("Jose", 25)); alm.add(new Alumno("Laura", 8)); System.out.println(alm); } No siempre es el unico orden que deseamos tener, por ejemplo si se desea ´ ordenar por nombre, no es posible especificar dos clases de comparaci´n. Por o este motivo podemos crear otro ´rbol especificando su clase de comparaci´n. a o TreeSet<Alumno> ordenarPorNombre = new TreeSet<Alumno>( new Comparator<Alumno>() { public int compare(Alumno a, Alumno b) { String nombreA = a.verNombre(); String nombreB = b.verNombre(); return nombreA.compareTo(nombreB); } }); ordenarPorNombre.addAll(alm); System.out.println(ordenarPorNombre); } }

166

7. ESTRUCTURAS DE DATOS ELEMENTALES

La instrucci´n ordenarPorNombre.addAll(alm) permite insertar todo el o a ´rbol alm en el ´rbol ordenarPorNombre. Los m´todos de la clase TreeSet a e son los siguientes: M´todo e add(E elemento) clear() addAll(coleccion) remove(Object objeto) isEmpty() contains(E elemento) size() Descripci´n o Agrega un elemento al ´rbol. a Borra el ´rbol. a Agrega toda una colecci´n. o Elimina el objeto del ´rbol. a Devuelve true si ha sido eliminado Devuelve true si el ´rbol est´ vac´ a a ıo. Devuelve true si el conjunto contiene el elemento. Devuelve el n´mero de elementos del ´rbol. u a

Los m´todos para recorrer el ´rbol elemento por elemento se realiza con e a la clase Iterator especificando que el iterador es alumno y se procede como sigue: Iterator<Alumno> iter = alm.iterator(); while (iter.hasNext()) System.out.println(iter.next());

7.7.

Clases para colas de prioridad

Las colas de prioridad tienen la caracter´ ıstica de estar basadas en la estructura de datos denominada mont´ ıculo. La caracter´ ıstica principal es que cada elemento introducido est´ asociado a una prioridad. A medidad que a se van introduciendo valores se van organizando para que al recuperar uno, siempre se recupere primero, el que tiene menos prioridad. La aplicaci´n t´ o ıpica de ´sta cola es por ejemplo el organizar una lista e de impresi´n por prioridad a medida que se introducen y procesan trabajos, o siempre se procesa primero el de menor prioridad. Para ejemplificar el uso en Java presentamos el siguiente ejemplo que muestra como se introducen y obtienen uno a uno lo elementos comenzando del valor m´ ınimo.

while (!cp.verCodigo() + " = " + datos. cp. System.add(new Alumno("Laura". 11.out. a Los m´todos disponibles para las colas de prioridad est´n descriptos en e a el cuadro 7.isEmpty()) { datos = cp. 17)).add(new Alumno("Maria". ..println("Sacando elementos. 8)). 25. cp. En este ejemplo. cp. System. 18. dado o que a la clase Alumno se ha adicionado el m´todo comparTo del ejemplo e anterior que utiliza el campo c´digo en la comparaci´n.remove().add(new Alumno("Juan".2. CLASES PARA COLAS DE PRIORIDAD 167 import java. } } } Analizando el c´digo vemos que los datos ingresados ser´n extra´ o a ıdos seg´n u la prioridad.*. Alumno datos.println( datos.add(new Alumno("Jose". la salida o o del programa est´ en el orden 8. /** * Ejemplo de Cola de prioridad * @author Jorge Teran * @param args * none */ public class ColaPrioridad { public static void main(String[] args) { PriorityQueue<Alumno> cp = new PriorityQueue<Alumno>(). Por esto. 11)). 25)).verNombre()).."). hemos tomado como prioridad el c´digo.out. cp.7.util.7.

a a Para esto se deben tomar los tiempos de ejecuci´n de cada estructura de o datos.8.000 n´meros aleatorios a cada una de las estructuras esu tructuras presentadas en el cap´ ıtulo y encontrar cual es m´s eficiente a para hallar los 100 m´s peque˜os.2: M´todos de las colas de prioridad e 7. .000 datos a una pila. size() Devuelve el n´mero de elementos. ESTRUCTURAS DE DATOS ELEMENTALES Descripci´n o Agrega un elemento a la cola de prioridad. a n 3. construir la siguiente tabla y analizar los resultados. addAll(coleccion) Agrega toda una colecci´n.000 valores y analice tres estructuras de datos. Ejercicios para laboratorio Los siguientes ejercicios de laboratorio tienen el objetivo de determinar en la pr´ctica las estructuras m´s eficientes para resolver diferentes problemas. Hallar el tiempo de insertar 10. Realice un ejercicio con 10. a n isEmpty() Devuelve true si est´ vac´ a ıa. a ´rbol.168 M´todo e add(E elemento) 7. En una combinaci´n de operaciones: 10 % recorrer ordenado. contains(E elemento) Devuelve true si el conjunto contiene el elemento. lista enlazada. u Cuadro 7. 30 % buso car. cola de prioridad. Estructura Tiempo de ejecuci´n o Pila Lista enlazada Arbol Cola de prioridad Conjuntos Map 1. Insertar 10. Explicar la ventaja de cada una de ellas. Escoja las m´s a adecuada. 40 % insertar y 20 % remover un valor arbirario. clear() Borra la cola de prioridad. 2. o remove() Elimina el elemento m´s peque˜o.

Repetir el ejercicio tres para 10.8. EJERCICIOS PARA LABORATORIO 169 4.000 y 100. 10.100. Indicar en qu´ casos es m´s conveniente cada estructura.7.000. e a . 1.000 valores.

ESTRUCTURAS DE DATOS ELEMENTALES .170 7.

con el prop´sito. de realizar un proceso m´s inteligente.1. a El proceso comienza en nodo A. Para este tipo de problemas se desarrolla una implementaci´n b´sica que o a consiste de tres partes: una que determina si hemos hallado una soluci´n. La segunda es empezar a recorrer el grafo retrocediendo un lugar cada vez que se llegue a un nodo del que no podamos avanzar m´s. Una de ellas es hacer todas las combinaciones ıas posibles partiendo del origen. Posteriormente se trabaja construyendo subconjuntos y permutaciones. y se va al primer nodo que encontramos el nodo B. 171 . Introducci´n o Backtracking significa ir atr´s. no examina todas las come u binaciones posibles. Este tema es introducido mostrando el recorrido de un grafo que muestra el concepto de volver a un estado anterior. Recorrido de grafos Un ejemplo t´ ıpico de algoritmo de retroceso es el hallar un camino desde un origen hasta un destino en grafo.2.1: Si partimos del nodo A y queremos llegar al nodo G tenemos dos estrateg´ para hallar un camino. Ver figura 8. Aunque o a este m´todo aparenta una b´squeda exhaustiva. Consideremos el grafo de la figura 8.Cap´ ıtulo 8 Backtracking 8. Esto implica llevar un registro de los evena tos pasados. o 8.2. la o segunda que procesa la soluci´n y la tercera que realiza el proceso.

por lo que. Para el grafo de ejemplo la matriz que constuimos es: . es necesario regresar al nodo anterior C y vemos que no hay ning´n otro u nodo para visitar. Cuando llegamos al nodo D ya no se puede seguir (figura 8.j) o indica que existe un camino cuando tiene un 1 y un 0 cuando no existe un camino.3. No hay forma en ´ste momento de elegir el nodo F porque no sabemos e si nos lleva al destino.4).1: Ejemplo de un grafo Figura 8.2: Muestra el recorrido del nodo A a B Del nodo B se procede hasta el nodo E que es el primer nodo que encontramos. retrocedemos una vez m´s llegando a E y continuamos. Para programar hemos construido una matriz para representar el grafo. De esta forma llegamos al nodo C y posteriormente a D. Cuando el algoritmo llega al inicio y no hay nodos que no hayamos visitado termina sin encontrar un camino. Ver figura 8. a Cuando llegamos al punto final imprimimos el recorrido.172 8. BACKTRACKING Figura 8. En esta matriz la filas y columnas representan los nodos y la posici´n (i.

Cuando se llega a un nodo que no va a ning´n u lado regresamos (bactrack) al nodo anterior para buscar una nueva ruta.3: Muestra el recorrido hasta el nodo C Figura 8. El nodo anterior se ha guardado en una estructura de pila. Esto es para evitar ciclos y volver a realizar un recorrido anterior. RECORRIDO DE GRAFOS 173 Figura 8.2.8. .4: Muestra el proceso de retorceso A B C 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 D E 0 1 0 1 1 0 0 0 0 0 1 0 0 0 F G 0 0 1 0 0 0 0 0 1 0 0 1 0 0 A B C D E F G Para el proceso se comienza con la posici´n 0. El programa recorre el grafo mostrado y produce la ruta en orden inverso listando: 6 5 4 1 0. Cada vez que pasamos por o un nodo lo marcamos como visitado.

print(" " + i). BACKTRACKING /**Programa para mostrar el * recorrido de un grafo * @author Jorge Teran */ import java.out. int[] v.length . while (!pila. int fila) { int hallo = -1. import java.Stack.174 8. System. // visitados int[] v = new int[g[0].pop(). i = (int) pila.empty()) { System.Vector. Stack<Integer> pila = new Stack().pop().out. v.exit(0). i = Buscar(g. if ((i == -1) && (v[v. i = 0.length].length .1] == 0)) { if (pila.println("No Hay Ruta "). i).println("Ruta en Orden Inverso "). while (v[v. System. i.1] == 0) { pila.push(i). } } static int Buscar(int[][] g. } } } System.util.empty()) { i = (int) pila. public class Grafo2 { static void Camino(int[][] g) { int i = 0.pop(). } else { //bactracking al anterior i = (int) pila.util. .out. v[i] = 1.

return hallo.B=1.out.G=6 g[0][1] = 1.3} los 7 posibles subconjuntos son: {1 2 3 }. break. {2 } y {3 }.out. Para construir un programa que construya ´stos subconjuntos inicialmene . g[5][3] = 1. {1 2 }.8. g[4][5] = 1. i < g[0]. {2 3 }. // Nodos A=0. Constuir todos los subconjuntos Consideremos el problema de construir todos los subconjuntos de un conjunto de tama˜o n. CONSTUIR TODOS LOS SUBCONJUNTOS 175 for (i = 0. {1 }.println("Hallo ="+hallo). Camino(g). g[1][4] = 1. g[0][4] = 1. g[2][3] = 1. Consideremos el conjunto {1.2. El n´mero total de subconjuntos es 2n − 1 sin contar el n u conjunto vac´ Por ejemplo si n = 3 existen 7 subconjuntos.E=4.C=2.D=3.println("busca ="+g[fila][i]). g[5][6] = 1. {1 3 }. i++) { // System. } public static void main(String[] args) { int[][] g = new int[7][7].F=5. } } // System. g[6][0] = 0. } } 8.3. if ((g[fila][i] == 1) && (v[i] == 0)) { hallo = i. g[3][0] = 0. g[1][5] = 1.length. g[4][2] = 1.3. ıo.

length. En este problema hemos considerado una o soluci´n cuando llegamos al ultimo elemento del conjunto. int posicionActual) { // cuando se llego al final del vector // no se puede seguir iterando return (conjuntos. o Cuando hallamos una soluci´n se retorna al estado anterior y marcamos o el ultimo elemento como procesado. Luego se procesa recursivamente o una nueva soluci´n. Al inicio de cada recursi´n preguntamos si hemos hallado una soluci´n o o para procesar. se usa para indicar que o o este elemento puede ser parte de la soluci´n. BACKTRACKING te se construye un vector de unos y ceros para representar las posibles soluciones. i++) if (conjuntos[i]) System.print("{"). o ´ Luego regresamos a un estado anterior y comenzamos la b´squeda de una u nueva soluci´n.out. Si no se hall´ una soluci´n guardamos el vector de soluciones o o y probamos una nueva soluci´n.length == posicionActual).out. // conjuntos indica cuales imprimir System. } public static boolean esSolucion( boolean[] conjuntos. for (int i = 0. } . La instrucci´n subset[cur] = true.println("}"). EL c´digo que halla esta soluci´n es el ´ o o siguiente: /**Programa para hallar todos los * subconjuntos * @author Jorge Teran */ public class Subconjuntos { private static void procesarSolucion( boolean[] conjuntos) { // imprimir la solucion.out.print((i + 1) + " ").176 8. System. i < conjuntos.

} } Al analizar el proceso se observa que se procede a marcar las posibles soluciones cambiando el arreglo que hemos denominado conjuntos cambiando el estado de 000 a 100. Ahora se produce un retroceso. CONSTUIR TODOS LOS SUBCONJUNTOS 177 public static void imprimeSubconjuntos( boolean[] conjuntos.1. En el proceso recursivo la pila es la que guarda los resultados previos. // Inicialmente conjuntos esta todo en false imprimeSubconjuntos(conjuntos. Cuando se llega a marcar tres elementos se imprime la primera soluci´n {1. posicionActual + 1). 110 e o y 111. 2 o }. Se procede a marcar el 101 el bit 2 y se contin´a el proceso. // procesar una nueva solucion imprimeSubconjuntos(conjuntos. 0).8. Al terminar sale este valor de la pila y regresa al valor almacenado 100. posicionActual)) { procesarSolucion(conjuntos). El proceso del u programa se muestra en el cuadro 8. o En ´ste momento la pila de la recurci´n contiene los valore 000. 100. } } public static void main(String[] args) { boolean[] conjuntos = new boolean[3]. posicionActual + 1).3. Luego se cambia el estado del ultimo bit ´ a 0 para indicar que ya fue procesado y volvemos a llamar recursivamente al programa almacenando en la pila el 110. imprimeSubconjuntos(conjuntos.int posicionActual) { if (esSolucion(conjuntos. 110 y 111. . } else { conjuntos[posicionActual] = true. 3 }. 2. que produce la soluci´n {1. // retornar (bactrack) al caso anterior conjuntos[posicionActual] = false. el arreglo que almacena los estados contiene 111 que se recupera de la pila.

1: Proceso realizado para construir todos los subconjuntos . BACKTRACKING Bits de Estado Posici´n Actual o 100 0 110 1 111 2 2 111 110 2 110 100 1 101 2 100 2 100 2 b 100 2 100 1 000 0 010 1 011 2 010 2 010 2 2 010 000 1 001 2 Retroceso Soluci´n o {1. 3 } Fin Recursi´n 1 o {1. 3 } Fin Recursi´n 1 o {1 } Fin Recursi´n 2 o Fin Recursi´n 2 o Fin Recursi´n 1 o {2. 2 } Fin Recursi´n 2 o Fin Recursi´n 1 o {1.178 8.3} Fin Recursi´n 1 o {2} Fin Recursi´n 2 o Fin Recursi´n 1 o {3} Fin Recursi´n 2 o Cuadro 8. 2.

out. en un ciclo.println(" ").print(a[i]). Comienza intercambiando el primer elemento con el ultimo. i++) { swap(a. i < n. Construir todas las permutaciones Para construir todas las permutaciones de un conjunto tambi´n se utiliza e la t´cnica de backtrackig. } private static void permutar( String[] a. } for (int i = 0. o /**Programa para hallar todas * las permutaciones * @author Jorge Teran */ public class Permutaciones { // imprimir las n! permutaciones en desorden private static void procesarSolucion(String[] a) { for (int i = 0.out. CONSTRUIR TODAS LAS PERMUTACIONES 179 8. } System. n-1). i < 3. i++) { System.4. Recursivamente ´ retornando al estado anterior cuando se halla una permutaci´n. } public static boolean esSolucion(int posicionActual) { // cuando se llego al final del vector // no se puede seguir iterando return (posicionActual == 1).4. . i. En este ejemplo se ha constru´ un programa e ıdo similar al anterior con una clase que procesa la soluci´n y otra que determina o si ha llegado la soluci´n. o El programa intercambia valores empezando del primer valor en forma recursiva al igual que el programa de hallar todos los subconjuntos. int n) { if (esSolucion(n)) { procesarSolucion(a). return.8.

cba. En a orden significa que los resultados deben estar en la siguiente secuencia: abc. i.println(a). a[0]="a". } } private static void swap(String[] a. } . a[j] = c.out. uno para almacenar las combinaciones que se van formando y otro que mantiene el vector original. } } El resultado que se obtiene del programa es: bca. permutar(a. int j) { String c. El siguiente c´digo permite realizar estas permutaciones. bac. Se crearon dos vectores. ı Para realizar ´sto hemos utilizado una estructura de vector que. c = a[i]. acb. n-1). a[2]="c". a[i] = a[j]. abc. } public static void main(String[] args) { String[] a = new String[3]. cab.Vector. bac. permite e insertar y extraer objetos. o /**Programa para hallar todas * las permutaciones en orden * @author Jorge Teran */ import java. a[1]="b".util. cba. public class PermutacionesEnOrden { private static void procesarSolucion(Vector a) { System. int i. acb.180 8. luego llevar el segundo elemento al principio y as´ sucesivamente. Como se ve en el ejemplo anterior los resultados no est´n en orden. cab. n-1). BACKTRACKING permutar(a.3). Esto significa realizar todos los intercambios manteniendo el primer elemento. swap(a. bca.

original). v. } else { for (int i = 0. CONSTRUIR TODAS LAS PERMUTACIONES 181 public static boolean esSolucion(int posicionActual) { // cuando se llego al final del vector // no se puede seguir iterando return (posicionActual == 0). String[] a = new String[3]. i < N.4. } } public static void main(String[] args) { Vector v = new Vector().add(proximo).add(s).8. a[1] = "b". i++) { String proximo = (String) original. original.size(). a[2] = "c".remove(proximo). permutar(auxiliar.length. i < a. auxiliar. v). a[0] = "a". proximo). } } . } permutar(new Vector(). i++) { String s = a[i]. for (int i = 0. } private static void permutar( Vector auxiliar. Vector original) { int N = original. auxiliar.add(i.remove(i). if (esSolucion(N)) { procesarSolucion(auxiliar).

cab and cba. algunas pueden aparecer repetidas. u Ejemplo de entrada 2 aAb acba Ejemplo de salida Aab aabc Aba aacb aAb abac abA abca bAa acab baA acba baac baca bcaa caab caba cbaa . Las letras may´sculas van adelante de las letras e u min´sculas.5. bac. u u Cada l´ ınea siguiente contiene una palabra. Las letras may´sculas y min´sculas u u u u se consideran diferentes.1. Las palabras generadas de una palabra de entrada deben imprimirse en orden alfab´tico. 8. bca. La primera l´ ınea contiene un n´mero que indica el n´mero de palabras del archivo. Para una palabra de entrada su programa no debe producir palabras repetidas. e Entrada El archivo de entrada consiste de varias palabras.5. Ejercicios Prolema 195 .Anagramas Se pide que escriba un programa que genere todas las posibles palabras de un conjunto de letras. Una palabra consiste de letras min´sculas y may´sculas de la A a la Z. Salida Para cada palabra del archivo de entrada el archivo debe contener todas las palabras diferentes que pueden ser generadas con las letras de una palabra. por ejemplo: dada la palabra abc su programa debe explorar las diferentes combinaciones de tres letras y escribir estas palabras abc.182 8. y las palabras deben escribirse en orden alfab´tico. acb. En las palabras le´ ıdas de la entrada. BACKTRACKING 8.

En otros casos t es un entero positivo t ≤ 1000. 2+2. El tama˜o n de la lista es de 1 a 12. EJERCICIOS 183 8.Sum It Up Dado un total n y una lista n de enteros. una por l´ ınea. Todas las sumas deben ser diferentes y no pueden aparecer ı m´s de dos veces. existen 4 sumas diferentes que suman 4. 2. 1. Un solo n´mero puede u utilizarse como una suma. En otras palabras las sumas con el mismo primer n´mero deben ordenarse por el u segundo. Estas son: 4. Las sumas deben ordenarse en orden descendente. Los n´meros en cada suma deben aparecer en orden u descendente. 1]. a Ejemplo de entrada 4 6 4 3 2 2 1 1 5 3 2 1 1 400 12 50 50 50 50 50 50 25 25 25 25 25 25 0 0 Ejemplo de salida Sums of 4: 4 3+1 2+2 2+1+1 Sums of 5: NONE Sums of 400: . seguido de n que es el n´mero de enteros de la lista. Luego escriba cada suma.5. 3. n = 6 y la lista es [4.8.2. hallar todas las distintas sumas que suman t. Si n = 0 se termina el u archivo de entrada. Entrada EL archivo de entrada contiene uno o m´s casos de prueba. 3+1.5. y 2+1+1. Los enteros positivos son menores a 100. 2. Por ejemplo si t = 4. Uno a por l´ ınea. 1 ≤ n ≤ 12. seguidos de n enteros. Prolema 574 . Los n´meros est´n separados por un espacio. Un n´mero u puede utilizarse tantas veces como ocurre en la lista. Cada caso de prueba contiene el total t. Si los dos primeros n´meros igualan debe ordenarse por el tercero y u as´ sucesivamente. Los n´meros de la lista est´n u a u a en orden descendente y existen n´meros repetidos u Salida Para cada caso de prueba primero escriba la l´ ınea Sums of el total y dos puntos. Si no hay sumas escriba la l´ ınea NONE.

184 8. BACKTRACKING 50+50+50+50+50+50+25+25+25+25 50+50+50+50+50+25+25+25+25+25+25 .

(0 < n <= 16) Salida En la salida cada l´ ınea representa una serie de n´meros del c´ u ırculo.3. Se pide que el n´mero del primer c´ u ırculo debe ser siempre 1.5. EJERCICIOS 185 8. Ejemplo de Entrada 6 8 Ejemplo de salida Case 1: 1 4 3 2 5 6 1 6 5 2 3 4 Case 2: 1 2 3 8 1 2 5 8 1 4 7 6 1 6 7 4 5 3 5 3 6 4 8 8 7 7 3 5 4 6 2 2 .8. Problema 524 . Se pide colocar un n´mero natural en cada uno de los c´ u ırculos. Entrada n. Comenzando con el n´mero 1 los n´meros deben satisfacer la condici´n tanto u u o en el sentido del reloj y como en el sentido contrario.5.Anillos de primos Un anillo est´ compuesto de n c´ a ırculos como se muestra en el diagrama. la condici´n es o que la suma de los n´meros de dos c´ u ırculos adyacentes deben ser un n´mero u primo.

excepto a las computadoras a de los extremos.4. o La figura muestra la forma ´ptima de conectar las computadoras y la o distancia total de cable requerida para ´sta configuraci´n es (4 + 16) + (5 + e o 16) + (5. La imagen muestra las computadoras como puntos negros y sus ubicaciones en la red est´n identificadas como coordenadas en el plano. Debe construir un programa que determine como debe establecerse dicha cadena a fin de minimizar el total del cable requerido. el cable se instalar´ por el piso.186 8. BACKTRACKING 8. Entrada El archivo de entrada consiste de una serie de conjuntos de datos. es necesario minimizar la distancia del cable.Hacer la l´ ınea Una red de computadoras requiere que las computadoras de una red est´n e interconectadas. a Las distancias entre las computadores est´n puestas en pies. Cada conjunto comienza con el n´mero que indica el n´mero de computadou u . La distancia total a a ser´ igual a la distancia entre las computadoras adyacentes m´s 16 pies adia a cionales para conectar del piso a las computadoreas y facilitar la instalaci´n. El problema considera una red lineal de tipo bus. En la instalaci´n o que se est´ construyendo.83 + 16) + (11.18 + 16) = 90.5. en la que las computadoras est´n conectadas exactamente a otras dos.01 pies. Por varias a razones. Problema 216 .

y cada una est´ listada una sola vez. Al final se incluir´ una oraci´n indicando la cantidad de a o cable utilizado. determinada por su posici´n en los datos de entrada. Cada red tiene al menos 2 computadoras y un m´ximo de 8. Utilice un formato similiar a la provista. En el listado las longitudes de cable a recortar que. No existen dos computadoras en el mismo lugar. Luego una l´ o ınea que especifica la longitud del cable que ser´ cortado para conectar dos compua tadoras adyacentes. a Un n´mero cero en el n´mero de computadoras indica el final de la entrada. Separe los datos de una red imprimiento una l´ ınea de asteriscos e imprima las distancias con dos decimales. Ejemplo de Entrada 6 5 19 55 28 38 101 28 62 111 84 43 116 5 11 27 84 99 142 81 88 30 95 38 3 132 73 49 86 72 111 0 Ejemplo de Salida .5. Estas coordenadas a son enteros en el rango de 0 a 150.8. a Salida La salida para cada red debe tener una l´ ınea que incluya el n´mero de la u red. u u Despu´s de especificar el n´mero de computadoras en la red. van de un extremo al otro de la red. cada l´ e u ınea adicional le dar´ las coordenadas de cada computadora. EJERCICIOS 187 ras en la red.

28) to (28.02 feet.84) is 91.98 feet.45.27) to (88.99.19) to (55.97 feet.40.81) is 76. Number of feet of cable required is 274.63 feet.28) is 66.62) to (38. Cable requirement to connect (43. Cable requirement to connect (55.15 feet.101) to (43.38) to (84.101) is 56.26 feet.30) is 93. Cable requirement to connect (95.73) to (72. Cable requirement to connect (28.111) to (49.81 feet.30) to (95. ********************************************************** Network #3 Cable requirement to connect (132.188 8.80 feet. Cable requirement to connect (88.86) is 49.73 feet. Cable requirement to connect (84.42 feet. Number of feet of cable required is 136.116) to (111. Number of feet of cable required is 305.111) is 87.99) is 77.38) is 26.62) is 59.116) is 31. . BACKTRACKING ********************************************************** Network #1 Cable requirement to connect (5.06 feet.99) to (142. ********************************************************** Network #2 Cable requirement to connect (11. Cable requirement to connect (38. Cable requirement to connect (72.

usualmente con la restricci´n de que a o cada lado del tri´ngulo sea compartido por dos tri´ngulos adyacentes. e o Cerco convexo o convex hull Un cerco convexo crea un subconjunto de un plano denominado plano convexo. Lo que trata normalmente es de particionar el pol´ ıgono en objetos convexos m´s peque˜os.Cap´ ıtulo 9 Geometr´ computacional ıa 9. visibilidad para conocer las ´reas visibles al iluminar con un rayo de luz y las b´squedas a u en un subconjunto espec´ ıfico. Introducci´n o La geometr´ computacional trata de una serie conceptos que se definen ıa a continuaci´n: o Triangulaci´n de pol´ o ıgonos Triangulaci´n es la divisi´n de un pol´ o o ıgono plano en un conjunto de tri´ngulos. n Problemas de intersecci´n En el plano los problemas de intersecci´n eso o t´n relacionados con encontrar los puntos de intersecci´n de todos los a o segmentos que se forman con los puntos especificados. 189 . a B´ squeda geom´trica La b´squeda geom´trica se refiere a tres problemas u e u e principales: ubicaci´n de un punto en un pol´ o ıgono. a a Problemas de partici´n La triangulaci´n es un caso especial de la paro o tici´n de un pol´ o ıgono. En dimensiones superiores se analizan tambi´n la intersecci´n de poliedros.1. s´ y solo s´ cualquier segmento de ı ı recta de los puntos especificado est´ en este subconjunto. porque es m´s f´cil trabaa n a a jar con objetos peque˜os.

Una descripci´n de las tem´ticas que trata el campo de la geometr´ compuo a ıa tacional se puede encontrar en [Cha94]. Una buena bibliograf´ para temas de ıa geometr´ se puede leer en [Leh88].x = x. GEOMETR´ COMPUTACIONAL IA Areas de pol´ ıgonos Comprende los m´todos para calcular el ´rea de un e a pol´ ıgono. por ıa a ejemplo puntos. ıa Bien para definir un punto crearemos la clase P unto con dos par´metros a el valor del eje x y el valor del eje y. En ambos casos se mostrar´n a ıa a algunos algoritmos y la implementaci´n de las librer´ de Java. a un tri´ngulo que est´ formada por tres puntos. this. dada una lista de puntos. Geometr´ ıa La geometr´ es el estudio matem´tico de elementos en el espacio.2. A´n cuando esta geometr´ ha u u ıa sido estudiada ampliamente se quiere mostrar como se implementa computacionalmente y c´mo un conjunto b´sico de m´todos nos ayuda a resolver o a e una variedad de problemas si tener que resolver cada uno. o ıas 9. reduciendo significativamente el tiempo de desarrollo. l´ ıneas. El c´digo para definir este objeto es: o /* Clase para definir un punto * @author Jorge Teran */ public Punto(double x. a a El resultado da la siguiente clase: . Tomando los conceptos de la geometr´ se presenta la distancia a otro punto y el ´rea de ıa.190 9. planos y vol´menes. e u a En el desarrollo de ´sta clase se han definido una serie de m´todos gee e nerales que nos permiten resolver una variedad de problemas. this.y = y. Iniciaremos el desarrollo de ´ste cap´ e ıtulo con concepto de geometr´ y ıa luego se describir´ la geometr´ computacional. } Los valores se han definido como double para permitir la implementaci´n de o los m´todos que efect´an c´lculos cuyos resultados no son enteros. double y) { super().

p.sqrt(d). return d. GEOMETR´ IA 191 /* Clase para definir un punto * @author Jorge Teran */ public class Punto { double x.X()) + (y . this.X() .X() .p.Y() -c. . } double areaTriangulo(Punto b. double y) { super().y * b. } double Distancia(Punto p) { double d = 0.9. } double X() { return (x). d = (x .Y()). public Punto(double x. d = Math.2.x = x.X() + y * c." + y + ")").x * c. y.p. d = x * b. Punto c) { double d = 0. this.X()) * (x . } double Y() { return (y). } public String toString() { return ("(" + x + ".X() * b.y = y.Y().X() * c.Y() + b.Y()) * (y .p.

this. b.X() * p2. this.X().Y() * p2.b = -p1. public Linea(double a. b. Existe una representaci´n m´s apropiada que es ax + by + c = 0 que es la o a que se construy´ en este ejemplo.b = b.a = a.c = c. Punto p2) { this. c.192 9. La clase completa queda como sigue: public class Linea { /* Clase para definir una linea * @author Jorge Teran */ double a.p1. double c) { this.X() + p2. GEOMETR´ COMPUTACIONAL IA d = Math.Y() . return d. Los m´todos implementados son: punto de intersecci´n.abs(d / 2). double b. En la clase que se ha construido se ha tomado las dos anteriores y la que se define por un punto m´s una pendiente. this. l´ ınea perpendicular que pasa por un punto. c desde ´sta especificaci´n. Tambi´n puede definirse la recta con dos o e puntos. } . se puede utilizar la expresi´n y = ax + b sin embargo tiene el problema que cuando la recta o es paralela al eje y dado que la pendiente es infinita haciendo que haya que tomar algunos recaudos. this.Y() . } public Linea(Punto p1. prueba de l´ e o ıneas paralelas. Cuando se dan los dos puntos a constru´ ımos los valores a. } } Para definir una recta en el plano existen varias alternativas.a = p1.c = p1.X(). e o A fin de poder comparar dos n´meros no enteros hemos construido una u variable que la hemos llamado ERROR. pendiente.p2. Esto se hace porque las operaciones de punto flotante no dan un valor exacto.Y().

a = m.A() * b . // System.B() * c .9. double m) { double a.Y()). else y = -(l.B()). b = 1.X() + b * p.out. } x = (l.2.a * l. } double B() { return b.B(). . if (Paralelas(l)) { System.A() * x + l.C()) / l. } Punto Interseccion(Linea l) { double x. y. c = -(a * p.0001.abs(b) > ERROR) y = -(a * x + c) / b. GEOMETR´ IA 193 public Linea(Punto p.exit(0). if (Math. double A() { return a. b.C()) / (l.b * l. } double C() { return c.println("Error: Lineas parelas"). } public static final double ERROR = 0.

} } Se pueden construir una variedad de clases para manejar diferentes figuras geom´tricas que incluyan funciones b´sicas que. a a . else return (a / b).abs(b . a.Y()))). } Boolean Paralelas(Linea l) { return ((Math.l.X() .l. } Linea lineaPerpendicularPunto(Punto l) { return (new Linea(-b.A()) <= ERROR) && ((Math. Como ejemplo. combinadas permiten resole a ver algunos problemas utilizando sus funciones.194 9.B()) <= ERROR))).a * l. GEOMETR´ COMPUTACIONAL IA return (new Punto(x. } public String toString() { return (a + "x+" + b + "y+" + c + "=0"). } double Pendiente() { if (b == 0) // pendiente infinita return (0). (b * l. y)). consideremos una lista de puntos de la cu´l queremos a hallar cu´les son los dos puntos m´s cercanos.abs(a .

System.2. if (d < minimo) { minimo = d. double minimo = 999999.out. 16). p[0] = new Punto(8. d = 0. } } Para mostrar la utilizaci´n de los m´todos construidos hallaremos la distancia o e de un punto al punto con el cual una recta tiene la distancia m´s corta. esto a es: . p[3] = new Punto(24. 11). p[4] = new Punto(13. a System.println("Los puntos m´s cercanos son :"). for (int i = 0. j < 5.println("Con distancia :" + minimo). punto2 = j. p[1] = new Punto(8. i < 5. GEOMETR´ IA 195 Para resolver ´sto definimos un vector de puntos y con dos ciclos comparae mos exaustivamente todas las posibilidas hallando la distancia m´ ınima. j++) { d = p[i]. p[2] = new Punto(12.out. 10). 16). int punto1 = 0.println(p[punto1] + " y " + p[punto2]). punto1 = i. punto2 = 0. } } } System. Este 2 c´digo con tiempo de ejecuci´n proporcional a O(n ) es el siguiente: o o public class minimoPuntos { /* * @author Jorge Teran */ public static void main(String[] args) { Punto[] p = new Punto[5].9.out. i++) { for (int j = i + 1.Distancia(p[j]). 8).

y pol´ a a ıgonos. y finalmente la distancia entre ´stos o e dos puntos. } } 9.-4. Se presentan las principales en el cuadro 9.out. Linea l5 = l4.196 9. Existen clases para puntos.-1). Luego hallamos la intersecci´n de las dos rectas. e e . Como ve no es necesario resolver matem´ticamente este problema a a fin de codificarlo. a la recta que pase por el punto especificado. lo que se hace es utilizar las funciones disponibles. Algunos de ´stos m´todos se muestran en el cuadro 9. El resultado es el siguiente: public class PruebaGeo { /* * @author Jorge Teran */ public static void main(String[] args) { Punto p4 = new Punto(4. Punto p5 = l5.geom que provee una serie de e clases que facilitan el desarrollo de programas que tratan con problemas geom´tricos.3.Distancia(p4)).Interseccion(l4).2. ´reas.println("Distancia = "+p5. Librer´ de Java ıas En el lenguaje Java se cuentan con funciones trigonom´tricas en la clase e Math. rect´ngulos.lineaPerpendicularPunto(p4).12).awt. GEOMETR´ COMPUTACIONAL IA Como se ve en el dibujo lo que se quiere hallar es el punto con el cual una l´ ınea trazada desde el punto forman un ´ngulo recto. l´ e ıneas . Para ´sto primero hallamos a e una recta perpendicular.1 Tambi´n se dispone del paquete java. System. Linea l4 = new Linea(3.

sinh(double x) Math.cos(double a) Math. LIBRER´ IAS DE JAVA 197 Constante PI Arco coseno Arco seno Arco tangente Seno Coseno Tangente Coseno hiperb´lico o Seno hiperb´lico o Valor de la hipotenusa Convertir a grados Convertir a radianes Math.acos(double a) Math.3.atan(double a) Math.1: Funciones trigonom´tricas del Java e Construir un punto Distancia a otro punto Construir una l´ ınea Point2D.Double(double x.9. Point2D p2) Contiene el punto p contains(Point2D p) Intersecta con el rect´ngulo intersects(Rectangle2D r) a intersectsLine(Line2D l) Intersecta la l´ ınea Distancia al punto p ptLineDist(Point2D p) Cuadro 9.tan(double a) Math.asin(double a) Math.Double(Point2D p1.PI Math.hypot(double x. double y) distance(Point2D p) Line2D.cosh(double x) Math.sin(double a) Math. double y) toDegrees(double anguloRadianes) toRadians(double anguloGrados) Cuadro 9.2: Funciones para puntos y l´ ıneas .

35).ptLineDist(p3)).Double(p3.distance(p2)).println("Distancia al punto P3= " + l.out.*. } } 9.out. System.Double(p1.out. 5). /* * @author Jorge Teran */ public class ClasesJava { public static void main(String[] args) { Point2D. System.out.198 9.println("Distancia de p1 a p2= " + p1. System.Double l2 = new Line2D.Double(3. Line2D.geom. p2).0) es el extremo superior izquierdo de la pantalla.Double l = new Line2D.Double(7.out.out. 5).4.println("l contiene a p2= " + l. System. System.Double(3. Point2D.awt. Cercos convexos Dado un conjunto de puntos S se define un el cerco convexo.println("p2= " + p2). Consideremos los siguientes puntos: .contains(p2)). p2).intersectsLine(l2)). el conjunto convexo m´s peque˜o que contenga a todos los puntos de S. e import java. System. GEOMETR´ COMPUTACIONAL IA El siguiente programa muestra el uso de ´ste paquete de Java.println("l intersecta a l2= " + l. Line2D.Double p2 = new Point2D.Double p3 = new Point2D.Double p1 = new Point2D.println("p1= " + p1). a n Cuando graficamos en la pantalla los puntos (x.y) hay que tomar en cuenta que el (0. Point2D.

Esto genera un algorimo proporcional a O(n3 ). .34). (41. Consideremos inicialmente que comparemos un punto con cada uno de los segmentos de recta que se pueden formar y decidir si est´ al interior del cerco. La a figura siguiente muestra el cerco y se puede observar que todos los puntos est´n contenidos por el cerco.4. a Este proceso claramente involucra tres ciclos.85). (110. a Para hallar cercos convexos existen varios algoritmos desarrollados. CERCOS CONVEXOS 199 El cerco convexo se forma con los puntos (86.39). uno para cada punto y dos para armar los segmentos de recta a probar. (57.98). Una propiedad del cerco convexo es que todos los segmentos de recta conformada por los puntos del conjunto est´n en el interior del cerco convexo.9.

x) return true.x < p2.x < p1. o sea paralelas al eje y. La figura 9. GEOMETR´ COMPUTACIONAL IA Figura 9. Cuando el segmento de recta no es perpendicular al eje y se presentan varios casos de los que solo mostramos algunos en la figura 9.x = p2. if (this.3.y) && (p.y > p1.1 lo esquematiza. else { if (p.2 muestra el caso cuando el punto se encuentra en el segmento de recta. Para hallar la posici´n de un punto con relaci´n a un segmento de recta se ha o o agregado un m´todo de la clase L´nea que da true si el punto esta m´s a la e ı a izquierda del segmento de recta.1: Alternativas para comparar un punto con una l´ ınea A fin de implementar la comparaci´n de un punto con respecto a una o l´ ınea es necesario tomar en cuenta diferentes alternativas.x. Supongamos que el segmento de recta entre los puntos p1 y p2 donde el p1.y > p2. Esto significa que el punto est´ m´s a a a la izquierda de p1. La figura 9.y)) || ((p.y < p2. El c´digo es el siguiente: o public boolean aIzquierda(Punto p) { double pendiente=Pendiente().200 9.x == p1.y))) .y) && (p.x. En este caso con referencia al primer punto obtendremos la respuesta verdadera cuando p1.sinPendiente) { if (p.y < p1.x) { if (((p.

CERCOS CONVEXOS 201 Figura 9.9.2: Punto en el segmento de la recta Figura 9.3: Caso en que el segmento de recta no es perpendicular al eje Y .4.

p1.y)).x .p1. } else return false. if (pendiente == (double) 0) { if ((p. else return false.y + p.202 9. double y3 = ((pendiente * (x3 / 1 . } else { if ((p.x )) return true. } else { if (pendiente > (double) 0) { if (x3 > (p. else return false. GEOMETR´ COMPUTACIONAL IA return true.x + pendiente * (pendiente * p1. que es el siguiente: .y ) > y3) return true.x * 1) > x3) return true.y)) / (1 + pendiente * pendiente)) ). } } } } Para construir el c´digo que halle el cerco convexo se ha realizado un proo grama de ejemplo. } } else { double x3 = (((p.x) + p1. else return false. else return false.

71)). j++) { masIzquierdo = true. 98)). CERCOS CONVEXOS 203 import java. k < puntos. for (k = 0.elementAt(j)). masDerecho = true. Punto(60. int i. 85)).elementAt(k)).size(). for (i = 0. Vector cerco = new Vector().elementAt(i). (Punto) puntos. 39)).out. masDerecho. Linea temp = new Linea( (Punto) puntos. k < puntos.awt.out.addElement(new puntos. puntos.Vector.4.aIzquierda( (Punto)puntos. i < puntos.println("Punto"). for (k = 0.size(). import java.addElement(new puntos. System. i++) { for (j = (i + 1). /* Programa oara hallar un * cerco convexo * @author Jorge Teran */ public class Convexo { public static void main(String[] args) { Vector puntos = new Vector().addElement(new Punto(57.addElement(new puntos. 34)). 75)).Graphics. Punto(87. j < puntos.size().addElement(new puntos. k++) { if ((k != i) && (k != j)) { if (temp. Punto(86. Punto(110. k++) { System.9. k.elementAt(k))) .size().addElement(new puntos. Punto(41. } boolean masIzquierdo. 59)). j. Punto(64.println((Punto) puntos.util.addElement(new puntos.

elementAt(i).size().addElement(new Linea((Punto) puntos.p2). k < cerco.out.elementAt(k)). Se escoge el punto con una coordenada a y m´s grande.princeton.html El m´todo de Graham de basa en e Encontrar el punto m´s extremo.Jarvis Quick hull.out. Luego se construye el cerco recorriendo el contorno del pol´ ıgono. terminamos con un pol´ ıgono con forma de estrella. k++) { System.elementAt(j))).println(((Linea) cerco. Se ordenan los puntos en forma ascendente en funci´n del ´ngulo que o a forman con el pivote. . } } } Existen varios algoritmos m´s eficientes para hallar el cerco convexo de a los que se mencionan Graham. o Se pueden ver en su p´gina web: a http://www. else masDerecho = false.p1 + ".cs.edu/¬ah/alg anim/version1/ConvexHull.elementAt(k)). (Punto) puntos. Se denomina pivote y se garantiza que est´ en el cerco a a convexo. } } } System. for (k = 0. Alejo Hausner del departamento del ciencias de la computaci´n de la o universidad de Princeton ha desarrollado unas animaciones que.println("Cerco Convexo"). } } if (masIzquierdo || masDerecho) { cerco.204 9. GEOMETR´ COMPUTACIONAL IA masIzquierdo = false." + ((Linea) cerco. muestran la ejecuci´n de estos algoritmos.

5.Point.9. ese esa a tar´ en el cerco.awt. se garantiza pertenece al cerco u Se recorren los puntos buscando cual est´ m´s a la izquierda. int y) contains(Point p) getBounds() intersects(Rectangle2D r) Cuando construimos un pol´ ıgono la forma de la figura est´ dada por el orden a en el que ingresamos los puntos.awt. Con los puntos que est´n afuera del segmento AB se crea un a conjunto y con los que est´n fuera del segmento BC otro. import java. /* . Clase Java para pol´ ıgonos Las clases de Java para el manejo de pol´ ıgonos es la clase Polygon() que crea un pol´ ıgono vac´ Los m´todos de esta clase son: ıo. El siguiente c´digo ejemplifica el uso de la o clase Polygon().5. Los puntos que est´n en el interior del tri´ngulo no pueden ser del arco a a convexo. CLASE JAVA PARA POL´ IGONOS 205 El m´todo de Jarvis de basa en: e Se inicializa en alg´n punto que. Con estos a dos conjuntos se repite el proceso recursivamente. e Agregar un punto Verifica si el punto est´ al interior a del pol´ ıgono Obtiene las coordenadas de un rect´ngulo que contiene al pol´ a ıgono Verifica si el pol´ ıgono intersecta con el rect´ngulo a addPoint(int x.Polygon. Se halla el punto m´s alejado a este segmento formando un tri´ngulo a a ABC. a El m´todo de Quick hull de basa en: e Dado un segmento de l´ ınea AB cuyos dos puntos que conocemos est´n a en el cerco convexo. 9. import java.

puntos.contains(p)).out.Rectangle[x=41. 71).addPoint(87. GEOMETR´ COMPUTACIONAL IA * @author Jorge Teran */ public class pol´gono { ı public static void main(String[] args) { Polygon puntos = new Polygon(). 85). } } Este c´digo inserta los puntos del ejemplo de cerco convexo. puntos. System. puntos.addPoint(86. puntos. Point p= new Point (60.addPoint(64. puntos.addPoint(110. produciendo un o rect´ngulo que incluye todos los puntos.75).println(puntos. 75). (86. 34) obtendremos true dado que el punto est´ en el interior del pol´ a ıgono. (41. 34).println(puntos.out.println(puntos.out. . (110.height=64] Si realizamos la prueba Point p= new Point (60. 39).width=69.75).awt.getBounds()). 85). System. 98). 59). j.println(p). a java.y=34. En cambio si creamos un pol´ ıgono con los puntos (57. 98). k. System. y este punto no es interior al pol´ ıgono. puntos.out.addPoint(60. 39). puntos.206 9.addPoint(57.addPoint(41. Veremos que las respuesta es f alse debido a que la clase pol´ ıgono no halla un cerco convexo. System. int i.contains(p)).

Consideremos el siguiente pol´ ıgono Para poder determinar el ´rea de ´ste se requiere triangulizar el mismo. CALCULO DEL PER´ IMETRO Y AREA DEL POL´ IGO-NO.6. De esta forma se divide el pol´ ıgono en tres partes. Luego tomamos la l´ ınea entre los puntos 0 y n − 1 como base y buscamos un punto con el cual producen un tri´ngulo que no contenga puntos a interiores. Cuando se quiere hallar el ´rea a no es tan simple. Si un subpol´ ıgono . Esto a e es dividir en tri´ngulos y sumar. Para hallar el per´ ımetro de un pol´ ıgono.6.´ ´ 9. 207 9. a El proceso de triangular se inicia numerando los v´rtices del pol´ e ıgono de 0 a n − 1. C´lculo del per´ a ımetro y ´rea del pol´ a ıgono. Un tri´ngulo y a dos subpol´ ıgonos uno a la izquierda y otro a la derecha. es suficiente con hallar la distancia entre dos puntos consecutivos y sumar.

59)). i=0.awt. 75)).addElement(new puntos. puntos. Punto(64. Proceso(puntos. 98)). if (j<2) return.Graphics.t2. if (j==2){ t1=(Punto) puntos. t2=(Punto) puntos. GEOMETR´ COMPUTACIONAL IA tiene tres lados es un tri´ngulo y no requiere m´s subdivisiones.addElement(new Punto(57.t3.addElement(new puntos.addElement(new puntos.addElement(new puntos.size()-1. Punto(110. import java. 71)). Vector triangulo = new Vector(). 39)).Vector.util.208 9. Luego este a a proceso se repite hasta terminar todos los subpol´ ıgonos.addElement(new puntos. Punto(86. Punto(60.addElement(new puntos. Vector dPuntos = new Vector().triangulo). j. k. return. Punto t1. Cada triangulizaci´n de un pol´ o ıgono de n v´rtices tiene n − 2 tri´ngulos e a y n − 3 diagonales. 34)). j= puntos. Punto(41. Punto(87. Vector triangulo){ Vector iPuntos = new Vector(). /* Programa para triangular el poligono * @author Jorge Teran */ public class T { public static void main(String[] args) { Vector puntos = new Vector(). . 85)).elementAt(1). El c´digo para triangular el pol´ o ıgono de ejemplo es el siguiente: import java.elementAt(0). int i. } static void Proceso(Vector puntos.

elementAt(ult). return pi. Proceso(iPuntos.t3.size().triangulo). t2 = (Punto)puntos. Proceso(dPuntos.add((Punto)puntos.´ ´ 9. Linea l1 = new Linea(t1.elementAt(k). for (i = 1. return.t2. for (i=k. CALCULO DEL PER´ IMETRO Y AREA DEL POL´ IGO-NO.int ult){ Punto t1.addElement(new Linea(t1.t3). iPuntos=new Vector(). Linea l2 = new Linea(t1. triangulo). } static int buscaTriangulo(Vector puntos){ int i.elementAt(i)).t3)). .elementAt(2).i++) iPuntos.elementAt(0)). } static int tienePuntoInterior (Vector puntos.size()-1.i<puntos.addElement(new Linea(t2.addElement(new Linea(t1.pi.t3).i++){ pi=tienePuntoInterior(puntos.i<=k. trangulo.ult). triangulo. new DibujarPuntos(dPuntos.add((Punto)puntos. 209 t3=(Punto) puntos. iPuntos.t2)).size()-1. triangulo. new DibujarPuntos(iPuntos.elementAt(0).i++) dPuntos. dPuntos=new Vector().ult. } k=buscaTriangulo(puntos). t3 = (Punto)puntos.t4. for (i=0. triangulo). t1 = (Punto)puntos. } return 0.elementAt(i)).i.t3)).add((Punto)puntos. ult=puntos.i<puntos.t2).6.int k. Linea l3 = new Linea(t2.triangulo).

De los que hay que mencionar el algoritmo de Chazelles que puede triangular pol´ ıgonos simples en tiempo lineal.210 9.i++){ if ((i!=k)&&(i!=ult)){ t4 = (Punto)puntos. for (i = 1. .aIzquierda(t4)) return i.i<puntos. if (l1.elementAt(i).aIzquierda(t4)) return i.size()-1. if (l3. } } En el libro [Mis97] se muestran diversos algoritmos para triangular pol´ ıgonos. } } return i. if (l2.aIzquierda(t4)) return i. GEOMETR´ COMPUTACIONAL IA int i=-1.

9. x2 y2 . Salida.1. 2) intersectan en una l´ o ınea cuando est´n a sobrepuestas y 3) intersectan en un punto. Un par de l´ ıneas en el plano pueden intersectarse de tres maneras 1) no hay intersecci´n porque son paralelas.20 END OF OUTPUT . a) NONE cuando no intersectan b) LINE cuando se sobreponen y c) POINT seguido de las coordenadas x.7.x3 y3 . El programa lee repetidamente una serie de cuatro puntos que definen dos l´ ıneas x y y y determina como intersectan las l´ ıneas.00 5. La primera l´ ınea de salida es decir INTERSECTING LINES OUTPUT.5 0 5 5 2 0 0 0 0 0 3 4 7 7 2 4 4 0 4 4 0 6 1 0 2 3 6 3 -6 4 -3 27 1 5 18 5 0 1 2 2 5 Ejemplo de Salida. De la misma forma los puntos x3 y3 y x4 y4 . Las siguientes N l´ a ıneas contienen los ocho puntos que representan las coordenadas de las l´ ıneas en el formato x1 y1 . Ejemplo de Entrada. y al final como ultima l´ ´ ınea END OF OUTPUT.x4 y4 .L´ ıneas que intersectan Se sabe que todo par de puntos distintos en el plano definen una l´ ınea..La primera l´ ınea contiene un n´mero N entre 1 y 10 indicando u el n´mero de pares de l´ u ıneas que est´n representadas. El punto x1 y1 es distinto del punto x2 y2 .y del punto de intersecci´n cuando se o intersectan.00 POINT 1.9.7. EJERCICIOS 211 9..La salida debe ser N + 2 l´ ıneas. Ejercicios Problema 378 .7. Todos los n´meros u de este problema estaran entre −1000 y 1000 Entrada. Las siguientes l´ ıneas corresponden a una l´ ınea de entrada describiendo la forma en la que se intersectan las l´ ıneas.INTERSECTING LINES OUTPUT POINT 2.07 2.00 NONE LINE POINT 2.00 2.

Juego de Palos En este juego un n´mero de palos pl´sticos se esparcen en una mesa y los u a jugadores tratan de removerlos sin mover los otros. No existen palos de longitud 0.212 9. La primera l´ ınea ser´ un n´mero entero n > 1 dando el n´mero de palos en la mesa. Problema 273 . Todas las coordenadas son menos de 100. Dos palos pueden estar conectados indirectamente por otros a palos. Un palo se considera conectado a s´ mismo. La o salida de dos casos consecutivos se separaran por una l´ ınea en blanco. El primer palo se denominara #1. si no pueden conectarse. Dada una lista de puntos terminales para algunos palos se pregunta si varios pares de palos est´n conectados o si ninguno a est´ conectado.2. el segundo #2 y as´ sucesivamente.7. Esta l´ u ınea est´ seguida por una l´ a ınea en blanco. Debe determinar a si el palo a puede conectarse con el palo b. o ”NOT CONNEC¸ TED”. Los palos son de longitud variable. GEOMETR´ COMPUTACIONAL IA 9. Cuando a = 0 y b = 0 termina la entrada. ı Las siguientes l´ ıneas contendr´n dos enteros positivos a y b. Salida Para cada caso de prueba la salida debe seguir la descripci´n. a u u Las siguientes n l´ ıneas contienen las coordenadas x. Entrada La entrada comienza con un n´mero entero positivo en una l´ u ınea el n´mero de casos que siguen.y de los dos puntos que definen las coordenadas de inicio y fin de los palos. Un caso de prueba consiste en m´ltiples l´ u ıneas de entrada. ı Ejemplo de Entrada 1 7 1 4 4 1 3 5 5 1 6 6 5 4 5 2 4 4 3 4 6 3 5 6 7 3 9 7 5 5 3 2 . Tambi´n existe una l´ e ınea en blanco entre dos entradas consecutivas. b = 0 debe generar una l´ ınea que diga CONNECTED”si el palo a se puede conectar al palo b. Excepto si la ultima l´ ´ ınea donde a. En este problema solo se quiere conocer si varios pares de palos est´n conectados por un camino a de palos que se tocan.

7. EJERCICIOS 213 1 3 6 2 1 0 6 3 7 3 3 0 Ejemplo de salida CONNECTED NOT CONNECTED CONNECTED CONNECTED NOT CONNECTED CONNECTED .9.

y la tercera la longitud del mismo. el pol´ ıgono asociado ser´ el siguiente: ıa Lo que se debe hacer es un programa que. Ejemplo de entrada 3 1 2 4 10 5 12. La primera l´ ınea contiene el n´mero de trampas de una regi´n. Los datos en un registro no son duplicados y el fin de los datos de una regi´n se indica con 0.Erradicaci´n de moscas o Los entimologistas en el noreste han colocado trampas para determinar la influencia de una variedad de moscas en el ´rea. Por ejemplo.214 9.7. o El estudios deben organizar las trampas en las que se agarraron moscas en regiones compactas que luego ser´n utilizadas para probar los programas a de erradicacci´n. Se planea estudiar programas a de erradicaci´n que tienen posibilidades de controlar el crecimiento de la o poblaci´n. tome como entrada la ubicaci´n o de las trampas en cada regi´n e imprimir las ubicaciones de las trampas que o figuran en el per´ ımetro de la regi´n y la longitud total del per´ o ımetro. las trampas de una regi´n particular son representadas por o puntos.y de las trampas.3 .3. Los siguientes u o registros contienen dos n´meros reales que son las coordenadas de ubicaci´n u o x. Problema 218 . Una regi´n se define como un pol´ o o ıgono con el per´ ımetro m´ ınimo que puede encerrar a todas las trampas. Una l´ ınea en blanco debe separar las diferentes regiones. Entrada El archivo de entrada contiene los datos de varias regiones. GEOMETR´ COMPUTACIONAL IA 9. o Salida La salida para una regi´n son tres l´ o ıneas: La primera l´ ınea es el n´mero de la regi´n. la segunda lista los puntos del per´ u o ımetro.

2 7 1 0.2.5.0.0.5 0 0 2 2 0 Ejemplo de salida Region \#1: (1.0.3 3 4.-3.2.5)-(0.-1.5)-(6.2.0.0.0) Perimeter length = 22.0.4.0.0)-(2.1)-(2.0)-(3.0.2.5 3 -0.5 6 2.0.0)-(2.0.66 Region \#3: (0.0.5)-(5.0)-(4.0) Perimeter length = 12.0.0.3)-(1.0)-(5.1 1.0) Perimeter length = 19.0.10 Region \#2: (0.12.0.0.0.2)-(0.0.5 -1.1.0)-(4.1 2 -3.0. EJERCICIOS 215 6 0 0 1 1 3.7.52 .9.10.2 2.5 5 0 4 1.

Cada rect´ngulo esta descripto por dos puntos especificados a por sus coordenadas en n´meros reales.5 12.6 3.y de los puntos.9 9999.9.9.4. GEOMETR´ COMPUTACIONAL IA 9. a Las siguientes l´ ıneas contienen las coordenadas x.9 11. a a Entrada La entrada est´ formada for n < 10 rect´ngulos descriptos uno a a en cada l´ ınea.9 Ejemplo de salida Point Point Point Point Point Point Point 1 2 2 3 4 5 6 is is is is is is is contained in figure 2 contained in figure 2 contained in figure 3 contained in figure 3 not contained in any figure contained in figure 1 not contained in any figure .5 12.0 20.0 17.5 r 0. El final de la lista ser´ indicada por un punto con coordenadas 9999..7.0 10.5 -8.2 20. se consideran interiores al cuadrado.0 4.216 9. Estos puntos representan la esquina u superior izquierda y la esquina inferior derecha.2 -5. Ejemplo de entrada r 8. a 9999.2 -7. Problema 476 .3 6. que no se incluyen en la salida.0 25.0 r 2.0 2.5 * 2.5 2. El final de la lista ser´ indicada por un asterisco en la columna uno.8 9999.7 5.5 17.3 5. una por l´ ınea.Puntos en rect´ngulos a Dado una lista de rect´ngulos y puntos en el plano determinar cu´les a a puntos est´n en que rect´ngulos.5 0. Los puntos que coinciden con el borde del cuadrado.

Hoare. 1994. Resour. 1977. 48(11):50–56. ˜ T. ACM. ACM Press. USA. Printice Hall. Detection and prevention of stack buffer overflow attacks. Horstman. 1996. Paul Bratley Gilles Brassard. Educ. Computational geometry: a retrospective. Hilmi Ozdoganoglu. Core Java 2 J2SE 5. 1996. J. Communicating sequential processes. [CK79] [CSH05] [EH96] [Fel05] [GB96] [Gri77] [Hoa83] [KBO+ 05] Benjamin A. Sun Microsystems Press. 5(1):1–16. Feldman. Vijaykumar. Addison Wessley. Cherniavsky and SamuelN. NY. 1983. 26(1):100–106. 2005. Comput. ˜ John C. 1979. 217 . Sartaj Sahni Ellis Horowits. Brodley.. R. Ralph P. Commun. Computer Science Press. 26(1):119–128. In STOC ’94: Proceedings of the twenty-sixth annual ACM symposium on Theory of computing. Kuperman. 2005.Bibliograf´ ıa [Cha94] Bernard Chazelle. Grimaldi. A complete and consistent hoare axiomatics for a simple programming language. 2005. Kamin. and Ankit Jalote. C. Commun. Fundamentals of Algoritms. Matematica Discreta. Yishai A. ACM. ACM. Fundamentals of Algoritms. Teaching quality object-oriented programming. J. A.0 Volume 1. Carla E.N. New York. pages 75–94. Gary Cornell Cay S.

In Jacob E. [LPC+ 02] G. Graham. Rivest. Poll. [McC01] [Mis97] Jeffrey J. Reddy. [Red90] [RLG94] [THCR90] Charles E. E. Revilla. Addison Wessley. Cheon. Ruby. Clifton. Leavens. . 1997. M´todos Formales Especificaci´n y Verificaci´n. McConnell. 1994. Knuth. Leiserson Thomas H. pages 104–114. 2001. ACM Press. Donald E. editors.218 [Leh88] BIBLIOGRAF´ IA Charles H. C. NY. Editorial Limusa. Jones and Bartlett Pub. Y. Goodman and Joseph O’Rourke. In Conference proceedings on Formal methods in software development. Formal methods in transformational derivation of programs. ı ı 1988. 1997. Mishra. USA. 2003. Programming Challenges. Uday S. Lehmann. CRC Press. 1990. 1990. 2002. Cormen and Ronald L. Oren Patashnik Ronald L. Analysis of Algorithms: An Active Learning Approach. Computational real algebraic geometry. [Vos01] Tanja Vos. Introduction to Algorithms. and C. Handbook of Discrete and Computational Geometry. Jml reference manual. Concrete Mathematics. [MAR03] Steven S. 2001. Geometr´a Anal´tica. Massachusetts Institute of Technology. Springer. Ume o o sa. Skiena Miguel A. New York.

2. log(ab) = log(a) + log(b) 3. log(a/b) = log(a) − log(b) 4. Se presentan las f´rmulas y m´todos que se a o e requieren en una forma simple sin ahondar en desarrollos te´ricos y demoso traciones. en el estudio que nos interesa normalmente trabajamos con logaritmos en base 2. ab = c significa que loga c = b donde a se denomina la base de los logaritmos. pero como se explic´ en cap´ o ıtulos anteriores simplemente se utiliza log sin importarnos la base. u 1. Algunas referencias a a a ´stos textos est´n en la bibliograf´ e a ıa.1. logb (x) = loga (x)/ loga (b) 6. A.Ap´ndice A e Fundamentos matem´ticos a Para el correcto an´lisis de los programas se requiere recordar algunos a conceptos de las matem´ticas. Recordatorio de logaritmos Es necesario recordar los siguientes conceptos de logaritmos que son de uso com´n. introducimos las ecuaciones m´s utilizadas y cuyos desarroa llos rigurosos los encontrar´ en los libros de matem´ticas. alog b = blog a 219 . En el mismo. log(ab ) = b log(a) 5.

+ un .. entre dos elementos contiguos. ar2 .2.. Si sumamos o estos valores obtenemos: s(n) = u(1) + u(2) + u(3).. Recordatorio de series Series simples Supongamos que u(n) es una funci´n definida para n valores. llamada raz´n. .. La o notaci´n matem´tica para describirla es como sigue: o a sn = a.....3.2. FUNDAMENTOS MATEMATICOS A. A. Serie geom´trica e Una serie geom´trica es una secuencia de t´rminos donde los t´rminos e e e tiene la forma a. a + 2d. Serie aritm´tica e Una serie aritm´tica puede expresarse como una secuencia en la que existe e una diferencia constante. ar. Es muy com´n el cambiar la notaci´n a la siguiente forma u o sn = u1 + u2 + u3 . + u(n).220 ´ A...2.. a + d.1........ La suma de los primeros n t´rminos de una serie aritm´tica puede expresarse e e como n n(a1 + an ) d ai = sn = = an + n(n − 1) 2 2 i=1 donde d es la raz´n ´ sea la diferencia entre dos t´rminos. o simplemente n sn = i=1 ui . o o e A.. ar3 ... A..2. arn la suma de ´sta serie podemos expresarla como sigue: e n sn = i=0 ari = a(1 − rn ) (1 − r) . a + (n − 1)d....2..

Propiedades de la sumatorias n n Propiedad distributiva ci = c i=1 i=1 i (A.8) ´sta serie se denomina serie arm´nica serie arm´nica y log(n + 1) < Hn ≤ e o o 1 + log n .5. De esto podemos decir que una serie geom´trica e es convergente s´ y solo s´ −1 < r < 1.5) (A.2.2.2. n Hn = i=1 1 i (A.1) Propieadad asociativa n n n (ai + bi ) = i=1 i=1 ai + i=1 bi (A.A. RECORDATORIO DE SERIES 221 en general la suma de una serie geom´trica tiende a un l´ e ımite solo si rn tambi´n tiende a un l´ e ımite.7) sn = i=1 n i = n(n + 1)/2 sn = i=1 n i2 = n(n + 1)(2n + 1)/6 ir = nr+1 /r + 1 + pr (n) i=1 sn = donde r es un entero positivo y pr (n) es un polinomio de grado r.2.2.4.2.2) Propiedad conmutativa ai = i∈K p(i)∈K ap (i) (A.2.2.2.6) (A.2.3) A.4) (A. ı ı A.2. Series importantes n sn = i=1 n 1=n (A.

luego el segundo de n − 1 maneras.i par i=0.3.3..1.3.2) i=0 n n i n i = 2n n (A. F´rmulas importantes o n r = n−1 r−1 n n + n i n−1 r xi (A. Combinatoria b´sica a Una permutaci´n de n objetos es un arreglo ordenado de los objetos. b.222 ´ A.2.1 = n! Una combinaci´n de r objetos de n objetos es una selecci´n de r objetos sin o o importar el orden y se escribe: n r = n! r!(n − r)! A.3.1) (1 + x) = 1 + i=1 n (A. c los podemos ordenar de 6 maneras: abc acb bac bca cab cba El primer elemento se puede escoger de n formas...3. Por o ejemplo si tenemos 3 objetos a. y as´ sucesivamente por lo que ı n(n − 1)(n − 2).4) .i impar n i (A.3.3) = i=0. FUNDAMENTOS MATEMATICOS A.

4. Para cada evento de A ≥ 0 2. Se dice que un evento ocurre cuando al realizar un experimento aleatorio obtenemos un elemento de un conjunto. 4. Se dice que es discreto cuando el n´mero de puntos de la u u muestra es finito o si pueden ser etiquetados como 1.3. Por ejemplo si lanzamos un dado el resultado obtenido es parte del conjunto de n´meros impares.2. 6}. 5. 3. El espacio muestral puede ser finito o infinito.A. los fen´menos cuyo futuro no es predecible con exactitud. o Todas las posibles salidas de un experimento al azar se denomina espacio muestral. P r[A|B] = P r[A∩B] P r[B] entonces 7.4 y as´ sucesivamente. Para indicar la suma de los eventos de S utilizamos la notaci´n: o P r[X = x] = P r[Ax ] = ∀sεS P r[s] . PROBABILIDAD ELEMENTAL 223 A. Denominamos al conjunto u el evento imposible y a todo el conjunto muestral al evento universal. 1. Probabilidad elemental La teor´ de la probabilidad est´ asociada a los fen´menos aleatorios. La probabilidad es una medida que asigna a cada evento A del espacio muestral un valor num´rico un valor P r[A] que da la medida de que A pueda e ocurrir. P r[A ∪ B] = P r[A] + P r[B] − P r[A ∩ B] 6. Para este experimento el espacio u muestral es S = {1. Si A y B son mutuamente excluyentes vale decir A ∩ B = P r[A ∪ B] = P r[A] + P r[B] ¯ 4. Dos eventos son independientes si P r[A ∩ B] = P r[A]P r[B] 8. contin´o o discreto. ı Un evento es una colecci´n de puntos de una muestra que a su vez un o subconjunto del espacio muestral. Por ejemplo cuando lanzamos un dado com´n existen seis posibles u salidas que son los n´meros del 1 al 6. P r[A] = 1 − P r[A] 5. 2. P r[S] = 1 3. esto ıa a o significa.4.

Ejemplo: Demostrar que existe un n´mero infinito de n´meros primos. Demostraci´n por inducci´n o o Existen dos t´cnicas que normalmente se utilizan que son la deducci´n y la e o inducci´n. u A. La desviaci´n standard se define como la ra´ cuadrada de la varianza o ız y se representa por el s´ ımbolo σx A.. .5. FUNDAMENTOS MATEMATICOS 9. p2 . por lo tanto se demuestra que el conjunto de n´meros u u primos no es finito y queda demostrada nuestra hip´tesis original el conjunto o de n´meros primos es infinito.224 ´ A.5. o o . T´cnicas de demostraci´n e o Demostraci´n por contradicci´n o o La prueba por contradicci´n es conocida como prueba indirecta y consiste o en demostrar que la negaci´n de una aseveraci´n nos lleva a una contradico o ci´n. u u Para resolver esto se ve que S est´ dada por la frase existe un n´mero a u infinito de n´meros primos y la negaci´n de ´sta seria existe un n´mero finito u o e u de n´meros primos.. La varianza escribimos como σx y la definimos como E[X] = x x(p(x) − E[X])2 11. La esperanza matem´tica la representamos como a E[X] = x xp(x) = ∀sεS X(s)P r[s] 2 10... La deducci´n consiste en ir de un caso general a un caso particular.1. o Por ejemplo si deseamos probar que la proposici´n S es correcta debemos o primeramente negar S y luego demostrar que ¬S es falso... Sea Pn+1 = p1 ∗ p2 . A.5. pn entonces si encontramos un n´mero primo Pn+1 habr´ u ıamos demostrado que el conjunto no contiene a todos los primos por lo cual ¬S es falso.pn + 1 claramente se ve que el resultado es un n´mero primo.2. si demostramos que esto es una contradicci´n entonces u o la aseveraci´n inicial S es verdadera.. o Demostraci´n: Supongamos que existe un n´mero finito de n´meros prio u u mos P = p1 .

nos hacemos alguna idea de como se comporta suponemos que. El principio de inducci´n matem´tica se basa. Sin embargo la deducci´n siempre o o lleva a resultados correctos. primeramente demostrar o a la validez de nuestras suposiciones para valores de 0. 2. En base de ´sta suposici´n demostramos que para e o n − 1 es correcto con lo cual se demuestra nuestra suposici´n original. y luego de que. para un valor arbitrario n es correcto. 1. TECNICAS DE DEMOSTRACION 225 En cambio la inducci´n matem´tica trata de establecer una ley general en o a base a instancias particulares.. Este razonamiento puede llevar a resultados err´neos si no se plantea adecuadamente.5. o .´ ´ A. .

117 eficiencia. 46 inverso. 221 afirmaciones. 45 reflexiva. 139 cola prioridad. 102 Backtracking. 113 pivote. 1 an´lisis amortizado. 179 226 . 105 eficiencia. 45 propiedades. 198 ejemplo. 123 eficiencia. 45 ecuaciones. 124 coeficientes binomiales. 120 a eficiencia. 137 complejidad. 137 contar. 122 selecci´n. 11 congruencias. 113 una pasada. 3 b´squeda. 93 Java. 45 e suma. 138 Carmichael. 45 transitiva. 161 Construir permutaciones. 52 Cercos convexos. 166 ejemplo. 165 . 124 o compareTo. 160 ejemplo. 120 o eficiencia. 101. 45 potencias. 179 en desorden. 92 assert. 101 secuencial. 45. 120 sort. 139 aplicaciones.´ Indice alfab´tico e a ´rbol. 164 ejemplo. 113 burbuja. 204 e clasificaci´n. 1 Algoritmo. 118 comparaci´n. 171 cadenas. 118 o Java. 101 u binaria. 93 algor´ ıtmica elemental. 115 inserci´n. 166 combinatoria. 101. 202 m´todos. 102 eficiencia. 103. 121 r´pida. 17 a apriori. 45 sim´trica. 45 conjuntos. 111 o arrays.

7. 97 espacio muestral. 40 m´ximo com´n divisor. 97 ejemplo C. 3 e o factores primos.Rabin. 85 aplicaciones. 11. 144 a grafo. 40 a u Euclides extendido. 171 ineficiencia. 158 estructuras recursivas. 118 instancia. 94 ejecutar. 38 divisor com´n. 15 m´todos. 49 m´ ınimo com´n m´ltiplo. 124. 41 m´todo iterativo. 101.´ ´ INDICE ALFABETICO en orden. 20 e m´todo te´rico. 38 u recorrido. 123. 224 o divide y vencer´s. 68. 96 JML. 24. 1–3. 97 especificaci´n. 143 u l´ ınea. 38. 142 u ejemplo. 82. 52 geometr´ 189. 219 Euclides. 96 emp´ ırico. 162 Fermat. 43 u u factorizaci´n. 157 estructuras de datos. 6. 224 o o demostraci´n por Inducci´n. 190 ıa. 146 u grafos n´meros Catalanes. 37. anotaciones. 153 ejemplo. 180 demostraci´n por contradicci´n. 96 ejemplo. 172 . 98 Eratostenes. 2. 221 e Miller . 67. 44 Java. 96 errores de programaci´n. 96 especificar. 62 o ensures. 75 227 Java Modeling Language. 49 o map. 9–11 invariante. 64 invariante. 12. 223 invariante clase. 62. 96 127 compilar. 107 listas enlazadas. 3. 22 geom´trica. 2 cuantificadores. 74 Euclides complejidad. 157 e estructuras secuenciales. 224 o o desviaci´n standard. 39. 162 Fibonacci. 190 tri´ngulo. 196 n´mero Euleriano. 141 master. 145 punto. 43. 22 a divisibilidad. modular. 171 n´mero Stirling. 70–80. 51 ejemplo. 96 eficiencia. 47. 40. 63 invariante ciclo. 7. 192 invariante. 66 o requires. 14 logaritmos.

13 o o notaci´n omega. 3 tri´ngulo de Pascal. 67. 189 o pol´ ıgonos Java. 205 Post condici´n. 91 a proceso. 138 regla del producto. 47. 18 o sumatoria propiedades. 12 l´ ımites. 96 o precondici´n. 51 prueba de programas. 153 pol´ ıgono. 23 regla de la suma. 54 programa certificado. 53 u n´meros primos. 61 ´ ´ INDICE ALFABETICO caja blanca. 91. 3 o teor´ de n´meros. 190 b´squeda. 106 prueba de primalidad. 35 ıa u tiempo proceso operaciones. 75. 35 . 74. 105 recurrencias. 223 probable primo. 6 orden de. 106. 176 subconjuntos. 220 e Series Simples. 189 o partici´n. 175 ejemplo. 13 o O grande igualdad logaritmos. 72. 221 te´rica. 92 a prueba est´tica. 67. 91 prueba exaustiva. 220 Subconjuntos. 140 triangulaci´n. 66. 220 e Serie geom´trica. 79– o 81 post condici´n. 138. 74–77. 61 verificaci´n. 108 o a RSA. 207 variables Java. 189 a ´rea. 3. 61 caja negra. 11 permutaci´n. 12 operaciones elementales. 47 o notaci´n asint´tica. 96 o probabilidad. 13 o notaci´n teta. 139 a invariante. 143 n´meros grandes. 12 propiedades. 138 substituci´n. 107 programa probado. 138 o regla inclusi´n. 138 o representaci´n gr´fica. 153 lista LIFO. 189 intersecci´n. 68. 222 o pila. 12 transitiva. 35 tipos de algoritmos. 61 o prueba din´mica. 189 u convexo. 18 recurrencias lineales. 153 ejemplo Java. 91.228 aplicaciones. 55 Serie aritm´tica. 49 u generaci´n. 189 o triangular. 137 regla exclusi´n.

Sign up to vote on this title
UsefulNot useful