Anda di halaman 1dari 27

Anlisis y diseo de

algoritmos Clase 2
Contenido

Eficiencia algortmica
Notacin Big Oh
Ejercicios del curso
Tips & tricks

Material elaborado por: Julin Moreno


Facultad de Minas, Departamento de Ciencias de la Computacin y la Decisin

Qu es un algoritmo?
Un algoritmo es un conjunto ordenado de instrucciones
bien definidas, inambiguas y finitas que permite resolver
un determinado problema computacional.
Un corolario de esta definicin es que un determinado
problema computacional puede ser resuelto por diversos
(infinitos) algoritmos.
Veamos una demostracin de esto

Nota
Para este y todos los ejercicios que veremos en clase:
paciencia para los que ya saben y mucha concentracin
para los que se sientan perdidos.

Ejemplo: ACM138 Street Numbers*


A computer programmer lives in a street with houses numbered
consecutively (from 1) down one side of the street. Every
evening she walks her dog by leaving her house and randomly
turning left or right and walking to the end of the street and
back. One night she adds up the street numbers of the houses
she passes (excluding her own). The next time she walks the
other way she repeats this and finds, to her astonishment, that
the two sums are the same. Although this is determined in part
by her house number and in part by the number of houses in
the street, she nevertheless feels that this is a desirable
property for her house to have and decides that all her
subsequent houses should exhibit it.
Write a program that, given the quantity of houses in a street,
prints the number of the house that satisfy this condition; print -1
if none. (exs: if n=5 it should print -1, if n=8 it should print 6)

Qu es un algoritmo?
Esta caracterstica (mltiples alternativas para resolver
un mismo problema) es la motivacin de este curso:
disear buenos (si no los mejores) algoritmos para
solucionar determinados problemas.
Quiz el principio ms importante para el buen diseador de
algoritmos es negarse a estar satisfecho
Aho et al. (1974) The design and analysis of computer algorithms

Si deseas ser un buen diseador de algoritmos debes preguntarte


siempre a manera de mantra: se puede hacer mejor?
Roughgarden, T. (2012) Algorithms design and analysis part 1

La primera solucin que se nos ocurre o la solucin ms obvia


generalmente no es la mejor
Yo :D

Cmo se mide un algoritmo?


Una manera objetiva de determinar que tan bueno es
un algoritmo es por medio del nmero de operaciones
bsicas que este debe realizar para resolver un problema
cuya entrada tiene un tamao n. Es decir, calcular un f(n)
Ejemplo: cuantas comparaciones debe realizar el
selectSort dado un arreglo n de nmeros enteros
diferentes. f(n)=?
f(n)= n*(n-1)/2 - 1

Notacin Big Oh
Definicin formal:
T(n) = O(f(n)), si y solo si existen dos constantes c, n0 > 0
de forma que T(n) c*f(n) para todo n>n0
En trminos prcticos:
Considerar el peor escenario
Realizar un anlisis asinttico (enfocarse en
valores grandes de n)
No prestar atencin a trminos constantes o de
orden menor
En el ejemplo del selectSort podemos decir entonces que
T(n) = 2 , o lo que es lo mismo, que es O(2 )

Utilidad de la notacin Big Oh


Aunque esta notacin no es rigurosa, y no se debe usar
como un predictor exacto del tiempo de ejecucin de un
algoritmo, si da cuenta de su tasa de crecimiento cuando
varia el tamao de la entrada. Por ejemplo, si un
algoritmo es O(n2) podemos decir que su tasa de
crecimiento es proporcional a una funcin cuadrtica.
Decimos entonces que un algoritmo es mejor (ms
eficiente) que otro si su O es menor. En otras palabras
si su tiempo de ejecucin (determinado por la cantidad
de operaciones bsicas) considerando el peor escenario
crece ms lentamente a medida que se aumenta el
tamao de la entrada.

Comparacin de eficiencias
Habiendo comprendido el concepto de la notacin Big O,
cul es el orden de complejidad o eficiencia del
bubbleSort?, por qu?
function bubbleSort(X[], n){
for i=n-1:1 {
ordenado = true;
for j=0:i-1 {
if (X[j] > X[j+1]){
switch(X[j], X[j+1])
ordenado = false;
}
}
if ordenado = true: break
}
}

O(2 ) al igual que selectSort


es cuadrtica (lo mismo
sucede con el insertSort)

Comparacin de eficiencias
Volviendo al ejercicio de street numbers, determinemos
cul de los siguientes algoritmos es mejor.
function sn1(n){
if n<3: return -1
for i=2:n-1{
s1 = 0
for j=1:i-1{
s1 += j
}
s2 = 0
for k=i+1:n{
s2 += k
}
if s1=s2: return i
}
return -1
}
O(2 ) cuadrtica

function sn2(n){
if n<3: return -1
for i=2:n-1{
s1 = i*(i-1)/2
s2 = (n*(n+1)-i*(i+1))/2
if s1=s2: return i
}
return -1
}

function sn3(n){
if n<3: return -1
i = sqrt((n^2+n)/2)
if i = INT(i): return i
return -1
}
O(1) constante

O(n) lineal

Considerando que
(+1)

=
=1
2

Cambiando el condicional
por una igualdad y luego
despejando

Comparacin de eficiencias
Ejercicio: Considerando la notacin Big O, determinemos
cul de los dos siguientes algoritmos es mejor.
function fib1(n){
if n <= 1: return n
else return fib1(n-1) + fib1(n-2)
}

function fib2(n){
f[0] = 0, f[1] = 1
for i = 2:n{
f[i] = f[i-1] + f[i-2]
}
return f[n]
}

O(2 )

O(n)

en realidad

O( )

siendo =

1+ 5
2

Comparacin de eficiencias
Supongamos que estamos trabajando en un computador con procesador de un solo
ncleo a 3,2Ghz lo que nos da un aproximado de 1,000,000,000 operaciones por
segundo. En la siguiente tabla vamos a relacionar el tamao de un problema
determinado con lo que demoraran en resolverlo una serie de algoritmos con
eficiencias diferentes.
log(n)
10
100
1000
10.000
100.000
1'000.000
1E+9 (mil millones)
1E+12 (un billn)
1E+15 (mil billones)
1E+18 (un trilln)
1E+21 (mil trillones)
1E+24 (un cuatrilln)
1E+27 (mil cuatrillones)

n.log(n)

n^2

n^3

2^n

3 nanosegs

10 nanosegs

33 nanosegs

100 nanosegs

1 microseg

1 microseg

7 nanosegs

100 nanosegs

664 nanosegs

10 microsegs

1 miliseg

4E+10 milenios

10 nanosegs

1 microseg

10 microsegs

1 miliseg

1 seg

13 nanosegs

10 microsegs

133 microsegs

100 milisegs

17 minutos

17 nanosegs

100 microsegs

2 milisegs

10 segs

12 dias

20 nanosegs

1 miliseg

20 milisegs

17 minutos

32 aos

30 nanosegs

1 seg

30 segs

32 aos

40 nanosegs

17 minutos

11 horas

50 nanosegs

12 dias

1 ao y medio

60 nanosegs

31 aos

19 siglos

70 nanosegs

317 siglos

80 nanosegs
90 nanosegs

Notaciones Big Omega y Big Theta


Definiciones formales:

T(n) = (f(n)), si y solo si existen dos constantes c, n0 > 0


de forma que T(n) c*f(n) para todo n>n0
T(n) = (f(n)), si y solo si existen tres constantes c1, c2,
n0 > 0 de forma que c2*f(n) T(n) c2*f(n) para todo
n>n0
As como la notacin Big O puede considerarse como un
lmite superior, la notacin Big Omega puede
considerarse como un lmite inferior.
La notacin Big Theta implica que T(n) es al mismo
tiempo O(f(n)) y (f(n))

Ejercicios de programacin tipo ACM-ICPC


Todo ejercicio ACM cuenta con los siguientes 7 elementos
Un ttulo
Un tiempo lmite, que determina cunto es lo mximo que
debe demorarse la ejecucin del cdigo solucin
Un enunciado que contextualiza el problema y que es
presentado generalmente a manera de historia (a veces
descabellada)
Una descripcin explcita de cmo es la entrada del problema:
cuntos parmetros son, de qu tipo y en qu rango. Si el
ejercicio dice que un determinado dato es de cierta forma no
es necesario verificarlo (su rango por ejemplo)
Una descripcin explcita de cmo debe ser la salida: qu
incluye y en qu formato. Tanto la entrada como la salida de
datos deben ser por consola
Un ejemplo de entrada
Un ejemplo de salida

Ejercicios de programacin tipo ACM-ICPC


Recomendaciones para la solucin de problemas
1. Aunque suene tonto, leer cuidadosamente el enunciado.
Comenzar entendiendo mal no tiene sentido
2. No comenzar a codificar sin antes tener clara la solucin.
Preferiblemente disear primero el algoritmo en papel y lpiz.
3. Los ejemplos de entrada y salida son precisamente eso:
ejemplos. Que un cdigo cumpla con ellos no significa
necesariamente que est bueno. De hecho los ejemplos
suelen ser los casos ms triviales, por ello parte del diseo
del algoritmo debe ser probarlo ante casos extremos (segn
indique el rango de las entradas) o truculentos (que sean
extraos pero que no violen las restricciones dadas).
4. Una vez cumplidos con los pasos 1 a 3 analizar si la solucin
encontrada satisface o no el tiempo lmite

Envo de ejercicios a la plataforma


Una vez cumplidos los cuatro pasos anteriormente mencionados
se puede enviar el cdigo teniendo en cuenta que:

1. La clase o archivo principal se debe llamar Main y no debe


estar en ningn paquete
2. Se deben incluir las libreras requeridas siempre que sean
estndar
3. No se puede incluir paquetes ni archivos externos

Envo de ejercicios a la plataforma


Ejemplo:

Envo de ejercicios a la plataforma


Ejemplo:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
StringBuilder sb = new StringBuilder();
int N;
N = entrada.nextInt();
for(int i=0; i<N; i++){
sb.append("Hello world!\n");
}
System.out.println(sb.toString());
}
}

Envo de ejercicios a la plataforma:


Posibles resultados de un envo
Error de compilacin: El cdigo no compila. Esto suele
deberse a no cumplir con las consideraciones 3 a 5
anteriormente mencionadas. A veces ocurre por usar s en el
cdigo
Error de ejecucin: El cdigo compila pero no corre, o no
termina de correr debido a un error. Un caso tpico es un
indexOutOfBounds
Tiempo lmite excedido: El cdigo corre pero se demora
ms del tiempo lmite, cuando esto ocurre la plataforma
detiene su ejecucin en ese momento
Respuesta incorrecta: El cdigo corre y se ejecuta antes del
tiempo lmite pero la salida no coincide con la que tiene
almacenada el juez para la entrada correspondiente. Muchas
veces se debe a cuestiones de formato (maysculas o
minsculas, espacios en blanco, saltos de lnea, etc.)
Aceptado: El cdigo corre, se ejecuta antes del tiempo lmite
y la salida es la adecuada

Entrada de datos
Scanner vs. InputStreamReader
Scanner sirve para leer dato por dato especificndole el tipo de
cada uno
Scanner entrada = new Scanner(System.in);
int a = entrada.nextInt();
float b = entrada.nextFloat();

InputStreamReader sirve para leer lnea por lnea, cada una


como un nico string
BufferedReader entrada =
new BufferedReader(new InputStreamReader(System.in));
String linea = entrada.readLine();

Entrada de datos
StringTokenizer vs. Split
StringTokenizer sirve para partir un string en tokens, es decir,
elementos individuales separados entre s por un delimitador.
Los delimitadores por defecto son: " \t\n\r\f, es decir, espacio en
blanco, caracter de tabulacin, caracter de nueva lnea, caracter
de retorno, y caracter de salto de pgina
StringTokenizer st = new StringTokenizer(linea);
while( st.hasMoreTokens() ){
String dato = st.nextToken();
//procesar dato, por ejemplo convertirlo a algn tipo
}

Tiene adems otras dos formas de usarse:


StringTokenizer(String str, String delim) //especifica los
delimitadores
StringTokenizer(String str, String delim, boolean
returnDelims) //especifica los delimitadores y estos se
retornan junto a los tokens

Entrada de datos
StringTokenizer vs. Split
Split hace lo mismo que StringTokenizer solo que adems
de permitir definir delimitadores especficos, tambin
permite usar expresiones regulares lo cual puede ser til si
se desea remover datos intiles de la entrada
String arr1[] = linea.split("-");
String arr2[] = linea.split("\\s+|,\\s*|.\\s+");

Entrada de datos: Anlisis


Generalmente InputStreamReader es ms rpido que Scanner,
mientras que StringTokenizer es ms rpido que Split.

Tomado de: http://goo.gl/qO2RFM

Qu usar depender entonces de la entrada:


Pocos datos: Scanner
Muchos datos: InputStreamReader
Datos relativamente uniformes: StringTokenizer
Datos que requieran limpieza o una extraccin especial: Split

Salida de datos: impresin


No se debe abusar de System.out.println() pues hace lento el cdigo.
Cuando se necesite imprimir por pantalla muchos datos es preferible
acumularlos y luego imprimirlos de una sola vez.

Para concatenar sin embargo no es recomendable usar String pues


esta tiene una eficiencia O(n), es preferible usar StringBuffer o
StringBuilder, ambos con concatenacin O(1) pero siendo ms rpida
la segunda por no ser sincronizada.
StringBuilder sb = new StringBuilder();
sb.append("Hola ");
sb.append("mundo");
System.out.println(sb.toString());

Salida de datos: formatacin


Cuando se requiere imprimir un valor numrico con una cantidad de
cifras decimales y/o con un ancho de campo determinado se puede
usar System.out.printf().
System.out.printf("%.2f", 123.458); //mostrara 123.46
//%f es para real, %d para entero, %e notacin cientfica
System.out.printf("%+d", 26); //mostrara +26

System.out.printf("%10.1f", 123.458); //mostrara

123.46

Datos de alta magnitud o precisin


BigInteger: Entero de precisin arbitraria (Para operaciones con enteros
muy grandes, si deben manejar valores mayores a , cuidado, se debe
usar solo como ltimo recurso pues es menos eficiente). BigInteger
provides analogues to all of Java's primitive integer operators, and all
relevant methods from java.lang.Math. Additionally, BigInteger provides
operations for modular arithmetic, GCD calculation, primality testing,
prime generation, bit manipulation, and a few other miscellaneous
operations.

BigDecimal (Para operaciones con nmeros reales, cuando la precisin


de double no basta). Immutable, arbitrary-precision signed decimal
numbers. A BigDecimal consists of an arbitrary precision integer
unscaled value and a 32-bit integer scale. If zero or positive, the scale is
the number of digits to the right of the decimal point. If negative, the
unscaled value of the number is multiplied by ten to the power of the
negation of the scale. The value of the number represented by the
BigDecimal is therefore (unscaledValue 10-scale).
The BigDecimal class provides operations for arithmetic, scale
manipulation, rounding, comparison, hashing, and format conversion.

Estructuras de datos tpicas


Estructura

Java

Insercin

Indexacin

Bsqueda

Borrado

Arreglo
dinmico

ArrayList

O(n)

O(1)

O(log(n)) si
est
ordenado,
O(n) si no

O(1)

ListaEnlazada

LinkedList

O(1) si es al
inicio o al
final, O(n) si
no

O(1) para el
inicio o el
final, O(n) si
no

O(n)

O(1) para el
inicio o el
final, O(n) si
no

Pila

Queue

O(1) para el
push

O(1) para el
peek

O(n)

O(1) para el
pop

Cola

Deque

O(1) para el
push

O(1) para el
peek

O(n)

O(1) para el
pop

rbol binario
de bsqueda
balanceado

TreeSet

O(log(n))

No aplica

O(log(n))

O(log(n))

Montculo
binario

PriorityQueue

O(log(n))

No aplica

O(1) si es
para la cima,
O(n) si no

O(log(n)) si
es la cima,
O(n) si no

Tabla hash

HashMap

O(1)*

No aplica

O(1)*

O(1)*

Tareas
1. Para calentar motores en lo que a programar se
refiere, codificar los tres algoritmos de ordenamiento
mencionados (selectSort, insertSort, bubbleSort) en el
lenguaje que deseen. Luego probarlos con diferentes
tamaos de arreglos (100, 1.000, 10.000, 100.000,
1000.000). Hacer un grfico tamao vs tiempo de
ejecucin. Comprobar si tienen la forma n^2.
2. Hacer lo mismo con las funciones fib1 y fib2 pero para
los valores de n entre 5 y 20.
3. Realizar todos los ejercicios de calentamiento en la
plataforma.

Anda mungkin juga menyukai