Diapositiva 1 - PowerPoint PPT Presentation

1 / 18
About This Presentation
Title:

Diapositiva 1

Description:

Complejidad de Algoritmos ... Una medida de eficiencia es el tiempo que requiere un ... Las expresiones Big-O no tienen constantes o t rminos de orden bajo. ... – PowerPoint PPT presentation

Number of Views:140
Avg rating:3.0/5.0
Slides: 19
Provided by: LuisFern
Category:

less

Transcript and Presenter's Notes

Title: Diapositiva 1


1
Complejidad de Algoritmos Cuándo proporciona un
algoritmo una solución SATISFACTORIA a un
problema? Primero, debe producir siempre la
respuesta correcta. Segundo, deberá ser
eficiente. Cómo se puede analizar la
eficiencia de los algoritmos? Una medida de
eficiencia es el tiempo que requiere un ordenador
para resolver un problema utilizando un algoritmo
para valores de entrada de un tamaño específico.
Una segunda medida es la cantidad de memoria que
se necesita de nuevo para valores de entrada de
un tamaño dado. Una tercera medida sería
estabilidad un ordenamiento estable mantiene el
orden relativo que tenían originalmente los
elementos con claves iguales. Un análisis del
tiempo requerido para resolver un problema de un
tamaño particular está relacionado con la
complejidad en tiempo del algoritmo y un análisis
de la memoria de ordenador requerida involucra la
complejidad en espacio del algoritmo.
Obviamente, es importante saber si un algoritmo
producirá su respuesta en un milisegundo, en un
minuto o en un millón de años y de manera similar
debemos tener suficiente memoria disponible para
poder resolver el problema.
2
Las consideraciones sobre complejidad en
espacio están ligadas a las estructuras de datos
usadas en la implementación del algoritmo. La
complejidad en el tiempo de un algoritmo se puede
expresar en términos del número de operaciones
que realiza el algoritmo cuando los datos de
entrada tienen un tamaño particular. (comparación
de enteros, sumas, multiplicaciones, etc.) La
complejidad se describe en términos del número de
operaciones requeridas en lugar del tiempo de
cálculo real, debido a que distintos ordenadores
necesitan tiempos diferentes para realizar las
mismas operaciones básicas. Cada algoritmo se
comporta de modo diferente de acuerdo a cómo se
le entregue la información por eso es
conveniente estudiar su comportamiento en casos
extremos, como cuando los datos están
prácticamente ordenados o muy desordenados. Compl
ejidad del peor caso.- Por comportamiento de un
algoritmo en el peor caso entendemos el mayor
número de operaciones que hace falta para
resolver el problema dad utilizando el algoritmo
para unos datos de entrada de un determinado
tamaño. Los análisis del peor caso nos dicen
cuántas operaciones tienen que realizar los
algoritmos para garantizar que producirán una
solución. Complejidad del caso promedio.- En
este tipo de análisis de complejidad se busca el
número promedio de operaciones realizadas para
solucionar un problema considerando todas las
posibles entradas de un tamaño determinado. El
análisis de la complejidad del caso promedio es
generalmente mucho más complicado que el análisis
del peor caso.
3
La complejidad del algoritmo se denota según la
notación Big-O. Las expresiones Big-O no tienen
constantes o términos de orden bajo. Esto se debe
a que cuando N es muy grande, las constantes y
los términos mas bajos no existen (un método
constante será más rápido que uno lineal y este
será más rápido que uno cuadrático). Por
ejemplo, O(n) significa que el algoritmo tiene
una complejidad lineal. En otras palabras, toma
10 veces más tiempo en operar un set de 100 datos
que en hacerlo con un set de 10 items. Si la
complejidad fuera O(n2) entonces tomaría 100
veces más tiempo en operar 100 items que en
hacerlo con 10. Complejidad
Terminología O(1)
Complejidad constante O(log n)
Complejidad logarítmica O(n)
Complejidad lineal O(n log n)
Complejidad n log n O(nb)
Complejidad polinómica O(bn)
Complejidad exponencial O(n!)
Complejidad factorial
4
Problemas Tratables, Intratables y
NP-completos Clase P.- Los algoritmos de
complejidad polinómica se dice que son tratables
en el sentido de que suelen ser abordables en la
práctica. Los problemas para los que se conocen
algoritmos con esta complejidad se dice que
forman la clase P. Aquellos problemas para los
que la mejor solución que se conoce es de
complejidad superior a la polinómica, se dice que
son problemas intratables. Clase NP.- Algunos
de estos problemas intratables pueden
caracterizarse por el curioso hecho de que puede
aplicarse un algoritmo polinómico para comprobar
si una posible solución es válida o no. Esta
característica lleva a un método de resolución no
determinista consistente en aplicar heurísticos
para obtener soluciones hipotéticas que se van
desestimando (o aceptando) a ritmo polinómico.
Los problemas de esta clase se denominan NP (la N
de no-deterministas y la P de polinómicos).
Clase NP-completos.- Se conoce una amplia
variedad de problemas de tipo NP, de los cuales
destacan algunos de ellos de extrema complejidad.
Gráficamente podemos decir que algunos problemas
se hayan en la "frontera externa" de la clase NP.
Son problemas NP, y son los peores problemas
posibles de clase NP. Estos problemas se
caracterizan por ser todos "iguales" en el
sentido de que si se descubriera una solución P
para alguno de ellos, esta solución sería
fácilmente aplicable a todos ellos. Actualmente
hay un premio de prestigio equivalente al Nobel
reservado para el que descubra semejante
solución.
5
Como Determinar las Complejidades Cómo
determinar el tiempo de ejecución de un código?
Depende del tipo de instrucciones
utilizadas. 1. Secuencia de instrucciones instru
cción 1 instrucción 2 ... instrucción k (Este
código es una secuencia de exactamente k
instrucciones) El tiempo total es la suma de
los tiempos de cada instrucción Tiempo total
tiempo (instrucción 1) tiempo (instrucción 2)
... tiempo (instrucción k) Si cada
instrucción es "simple" (solo involucra
operaciones básicas) entonces el tiempo de cada
instrucción es constante y el tiempo total
también es constante O(1). En los siguientes
ejemplos se asume que las instrucciones son
simples, a menos que se exprese lo contrario.
6
2. Instrucciones condicionales (if-then-else)
if (condición) secuencia de instrucciones
1 else secuencia de instrucciones
2 Aquí, se ejecutara la secuencia 1 o la
secuencia 2. Entonces, el peor caso es el mas
lento de los dos max(tiempo(secuencia 1),
tiempo(secuencia 2)). Por ejemplo, si la
secuencia 1 es O(N) y la secuencia 2 es O(1) el
peor caso para todo el código condicional debe
ser O(N). 3. Ciclos for (i 0 i lt N i)
secuencia de instrucciones El ciclo se
ejecuta N veces, entonces la secuencia de
instrucciones también se ejecuta N veces. Como
asumimos que las instrucciones son O(1), El
tiempo total para el ciclo es N O(1), lo cual
seria O(N).
7
4. Ciclos anidados for (i 0 i lt N i)
for (j 0 j lt M j) secuencia de
instrucciones El ciclo exterior se
ejecuta N veces. Por cada una de esas
ejecuciones, el ciclo interno se ejecuta M veces.
Como resultado, las instrucciones en el ciclo
interno se ejecutan un total de N M veces. En
este caso, la complejidad es de O(N M). En el
común de los casos, donde la condición de fin del
ciclo interior es que j lt N, igual al ciclo
exterior, la complejidad total para los dos
ciclos es de O(N2).
8
  • Ordenamiento por Selección
  • Este algoritmo también es sencillo. Consiste en
    lo siguiente
  • Buscas el elemento más pequeño de la lista.
  • Lo intercambias con el elemento ubicado en la
    primera posición de la lista.
  • Buscas el segundo elemento más pequeño de la
    lista.
  • Lo intercambias con el elemento que ocupa la
    segunda posición en la lista.
  • Repites este proceso hasta que hayas ordenado
    toda la lista.
  • De esta manera se puede escribir el siguiente
    seudocódigo para ordenar una lista de n elementos
    indexados desde el 1
  • iterar i desde 1 hasta n-1
  • minimo i
  • iterar j desde i1 hasta n
  • si listaj lt listaminimo entonces
    minimo j
  • intercambiar(listai, listaminimo)

9
Implementación en C int minimo0 for(i0
iltn-1 i) minimoi for(ji1 jltn
j) if (xminimo gt xj) minimoj
tempxminimo xminimoxi xitemp

10
Análisis del Algoritmo Tiempo de Ejecución
El ciclo externo se ejecuta n veces para una
lista de n elementos. Cada búsqueda requiere
comparar todos los elementos no clasificados. Por
lo tanto la complejidad es O(n2). Este algoritmo
presenta un comportamiento constante
independiente del orden de los datos. Luego la
complejidad promedio es también O(n2).
Ventajas Fácil implementación. No requiere
memoria adicional. Realiza pocos intercambios.
Rendimiento constante poca diferencia entre el
peor y el mejor caso. Desventajas Lento.
Realiza numerosas comparaciones.
11
Ordenamiento por Inserción Para ordenar una
lista con n elementos, la ordenación por
inserción comienza con el segundo elemento. Se
compara este segundo elemento con el primero y se
coloca antes del primero si no es mayor que el
primer elemento y tras el primer elemento si es
mayor que éste. En este punto, los dos primeros
elementos están en el orden correcto. El tercer
elemento se compara con el primero y si es mayor
que él se compara con el segundo. Se coloca en
la posición correcta entre los tres primeros
elementos. Para simular esto en un programa
necesitamos tener en cuenta algo no podemos
desplazar los elementos así como así o se perderá
un elemento. Lo que hacemos es guardar una copia
del elemento actual y desplazar todos los
elementos mayores hacia la derecha. Luego
copiamos el elemento guardado en la posición del
último elemento que se desplazó. Pseudo-código fo
r (i1 iltTAM i) temp listai j i -
1 while ( (listaj gt temp) (j gt 0)
) listaj1 listaj j-- listaj1 temp
12
Análisis del Algoritmo Tiempo de Ejecución
Para una lista de n elementos el ciclo externo
se ejecuta n-1 veces. El ciclo interno se ejecuta
como máximo una vez en la primera iteración, 2
veces en la segunda, 3 veces en la tercera, etc.
Esto produce una complejidad O(n2). Ventajas
Fácil implementación. Requerimientos mínimos
de memoria. Desventajas Lento. Realiza
numerosas comparaciones. Este también es un
algoritmo lento, pero puede ser de utilidad para
listas que están ordenadas o semiordenadas,
porque en ese caso realiza muy pocos
desplazamientos.
13
Merge sort El merge sort divide la lista a ser
ordenada en dos mitades iguales y las pone en
arrays separadas. Cada array es ordenado
recursivamente, y luego se juntan en el array
final. Este algoritmo tiene un comportamiento de
O(n log n). - Primera parte Cómo intercalar
dos listas ordenadas en una sola lista ordenada
de forma eficiente? - Segunda parte divide y
vencerás. Se separa la lista original en dos
trozos mismo tamaño (salvo listas de longitud
impar) que se ordenan recursivamente, una vez
ordenados se fusionan obteniendo una lista
ordenada. Como todo basado en divide y vencerás
tiene un caso base y un caso recursivo. Caso
base cuando la lista tiene 1 ó 0 elementos (0 se
da si se trata de una lista vacía). Se devuelve
la lista tal cual está. Caso recursivo cuando
la longitud de la lista es de al menos 2
elementos. Se divide la lista en dos trozos del
mismo tamaño que se ordenan recursivamente. Una
vez ordenado cada trozo, se fusionan y se
devuelve la lista resultante.
14
El esquema es el siguiente Ordenar(lista L)
inicio si tamaño de L es 1 o 0 entonces
devolver L si tamaño de L es gt 2 entonces
separar L en dos trozos L1 y L2. L1
Ordenar(L1) L2 Ordenar(L2) L Fusionar(L1,
L2) devolver L fin El algoritmo funciona y
termina porque llega un momento en el que se
obtienen listas de 2 ó 3 elementos que se dividen
en dos listas de un elemento (112) y endos
listas de uno y dos elementos (123, la lista de
2 elementos se volverá adividir),
respectivamente. Por tanto se vuelve siempre de
la recursión con listas ordenadas (pues tienen a
lo sumo un elemento) que hacen que el algoritmo
de fusión reciba siempre listas ordenadas.
15
(defun mergesort (lista) (if (vacia lista)
lista (combina (mergesort (divideizq lista))
(mergesort(divideder lista)) ) ) ) (defun
combina ( lista1 lista2 ) ( if (and lista1
lista2) (if ( lt (first lista1) (first
lista2) ) (cons (first lista1) (combina
(rest lista1) lista2)) (cons (first
lista2) (combina lista1 (rest lista2))))
(or lista1 lista2) ) ) (defun divideder
(lista) ( last lista (ceiling (/ (length
lista) 2 ) ) ) ) (defun divideizq (lista)
(ldiff lista (divideder lista) ) ) (defun vacia
(lista) (or (eq (length lista) 1) (eq
(length lista) 0) ) )
16
Análisis del Algoritmo Tiempo de Ejecución
Caso promedio. La complejidad para dividir una
lista de n es O(n). Cada sublista genera en
promedio dos sublistas más de largo n/2. Por lo
tanto la complejidad se define en forma
recurrente como f(1) 1 f(n) n 2 f(n/2)
La forma cerrada de esta expresión es f(n) n
log2n Es decir, la complejidad es O(n log2n).
Ventajas Rápido No memoria
adicional Desventajas Implementación un poco
más complicada. Recursividad (utiliza muchos
recursos).
17
Shell sort Inventado en 1959, éste algoritmo es
el más eficiente de los del tipo O(n2). Pero el
Shell es también el más complicado de los
algoritmos de este tipo. Como funciona Es una
mejora del método de inserción directa, utilizado
cuando el array tiene un gran número de
elementos. En este método no se compara a cada
elemento con el de su izquierda, como en el de
inserción, sino con el que está a un cierto
número de lugares (llamado salto) a su
izquierda. Shell sort mejora al método de
inserción comparando los elementos separados por
una distancia de varias posiciones, esto permite
que un elemento tome pasos mas grandes hacia su
posición esperada. Se realizan varias pasadas
sobre los datos con pasos cada vez menores. El
último paso del Shell sort es plenamente un
ordenamiento por inserción pero para entonces se
garantiza que el arreglo esté prácticamente
ordenado Tal vez la propiedad mas crucial del
Shell sort es que los elementos se mantienen
k-ordenados incluso mientras el salto se
disminuye. Por ejemplo, si una lista ya fue
5-ordenada y luego 3-ordenada, la lista ahora no
solamente está 3-ordenada sino 5 y 3-ordenada.
Si esto no fuera cierto, el algoritmo desharía
trabajo que había hecho previamente y no
obtendría tiempos de ejecución tan bajos.
18
El algoritmo requiere menos de O(n²)
comparaciones y cambios en el pero caso. Aunque
es fácil desarrollar intuitivamente el sentido de
cómo funciona el algoritmo, es bastante difícil
analizar su tiempo de ejecución pero los
estimados difieren entre O(nlog2n) a O(n1.5)
dependiendo de los detalles de implementación
Dependiendo en la elección de la secuencia de
saltos, Shell sort a probado tener un tiempo de
ejecución en el peor caso igual a O(n2), O(n3/2),
O(n4/3) o O(nlog2n) o posiblemente mejores
tiempos de ejecución aún no probados. La
existencia de una implementación que tenga una
complejidad O(nlogn) en el peor caso para el
Shell sort aún se mantiene como una pregunta
abierta a la investigación. El tamaño del set
de datos usado tiene un impacto significativo en
la eficiencia del algoritmo. Algunas
implementaciones de este algoritmo tienen una
función que permite calcular el tamaño óptimo del
set de datos para un array determinado. La
secuencia de salto que fue sugerida inicialmente
por Donald Shell fue comenzar con N/2 y
posteriormente disminuir a la mitad el salto
hasta que llegue a 1. Esta secuencia provee una
mejora de desempeño sobre los algoritmos
cuadráticos como el método por inserción pero
puede ser cambiada levemente para disminuir aún
mas el tiempo de ejecución en el peor y el caso
promedio.
Write a Comment
User Comments (0)
About PowerShow.com