Complejidad computacional. Algoritmos y Estructuras de Datos I. Complejidad computacional. Notación O grande

Documentos relacionados
Complejidad computacional. Algoritmos y Estructuras de Datos I. Complejidad computacional. Notación O grande

Arreglos. Algoritmos y Estructuras de Datos I. Arreglos en C++ Arreglos y listas

Ordenamiento de un arreglo. Algoritmos y Estructuras de Datos I. Demostración. Cota inferior de complejidad tiempo para sorting

Algoritmos de Búsqueda

Programación imperativa. Algoritmos y Estructuras de Datos I. Ciclos

Especificación de programas. Algoritmos y Estructuras de Datos I. Correctitud de ciclos

Esquema. Condicionales. Ejemplo de condicional. Demostración. P { if (B) uno else dos } Q. P { while (B) cuerpo } Q

Demostrando cotas inferiores: Arboles de decisión

Ordenamiento de un arreglo. Algoritmos y Estructuras de Datos I. Algoritmo downsort. Upsort vs downsort

Algoritmos en teoría de números

Multiplicación de matrices simétricas

Búsqueda Binaria. Universidad de Buenos Aires. Universidad Nacional del Comahue. Training Camp 2017

Análisis de Algoritmos

Análisis de Algoritmos

Análisis de algoritmos

Introducción al Análisis del Coste de Algoritmos

Notación Asintótica 2

Verificación de programas. Algoritmos y Estructuras de Datos I. Semánticas formales: Primer cuatrimestre de 2016

Estructuras de Datos y Algoritmos

Ordenamiento (Sorting)

Análisis y Diseño de Algoritmos. Complejidad Computacional

Algoritmo de Euclides

Estructuras de Datos y Algoritmos

Complejidad de los Algoritmos

Programación Análisis de Algoritmos: Tiempo de Ejecución (Introducción)

Algoritmos para determinar Caminos Mínimos en Grafos

ELO320 Estructuras de Datos y Algoritmos. Complejidad. Tomás Arredondo Vidal

Tema 01: Fundamentos del Análisis Asintótico de Algoritmos

Algoritmos Iterativos de Búsqueda y Ordenación y sus tiempos

Introducción a la Computación

Un tercer ejemplo: verificación de primalidad

Carlos Delgado Kloos Ingeniería Telemática Univ. Carlos III de Madrid. Java: Complejidad / 1

1/16. Coste de Algoritmos. 8 de abril de 2018

dit UPM Tema 1: Algoritmos /complejidad /java Análisis y diseño de software José A. Mañas

Algoritmos y Estructuras de Datos Tema 2: Diseño de Algoritmos

NOTACIÓN O GRANDE. El análisis de algoritmos estima el consumo de recursos de un algoritmo.

Lenguajes de programación. Algoritmos y Estructuras de Datos I. Lenguajes compilados. Lenguajes compilados

Complejidad computacional y asintótica

Introducción a la computación. Carlos Lopez Pombo

Pasaje de argumentos en lenguajes de programación. Algoritmos y Estructuras de Datos I

Programación 2. Lección 8. Caracterización asintótica de la eficiencia de un algoritmo

Introducción al análisis de algoritmos

Programación II Arboles Binarios(AB)

Análisis y Diseño de Algoritmos

Algoritmos y Complejidad

Tema 10: Árbol binario de búsqueda

Análisis de algoritmos

Introducción a la computación. Charlie

Diseño y Análisis de Algoritmos

Árboles balanceados (AVL) Tablas de dispersión (Hash) Colas de prioridad (Heap)

Algoritmos Geométricos. Héctor Navarro. UCV

Programación II. Mario Aldea Rivas Programación II 04/04/11 1. Mario Aldea Rivas Programación II 04/04/11 2

Introducción. Algoritmos y Complejidad. Algoritmos y Algoritmia. Introducción. Problemas e instancias. Pablo R. Fillottrani

Algoritmos y Estructuras de Datos Tema 2: Diseño de Algoritmos

Semana 14 [1/19] Polinomios. 8 de junio de Polinomios

Departamento de Informática Primer semestre de 2009 Ejercicios resueltos de temas del Certamen n o 3

EDA. Tema 8 Colas de Prioridad: Heaps

Estructura de Datos. Complejidad de Algoritmos. Algoritmo. Algoritmo. Mauricio Solar Lorna Figueroa

Notación Asintótica. Temas. Introducción Notación O Notación Omega Notación Theta. Análisis de Algoritmos

Tipos algebraicos y abstractos. Algoritmos y Estructuras de Datos I. Tipos algebraicos

Recurrencias y cómo resolverlas

Programación Lógica. Programación Lógica

Solución de Problemas Mediante Búsqueda (2) Carlos Hurtado Depto de Ciencias de la Computación, Universidad de Chile

Tema 3. Análisis de costes

Programación 2. Lección 11. Análisis de la corrección de un algoritmo: primera parte

IN34A - Optimización

Programación 2 Práctico 9 - TADs Árbol Binario de Búsqueda, Árbol Finitario y Árbol n-ario

Ordenamiento en Tiempo Lineal - Medianas y Ordenes sticas

Complejidad Computacional

Tema 5- Diseño Recursivo y Eficiente. Tema 5- Diseño Recursivo y. Descomposición recursiva ascendente de un vector. Etapas del diseño recursivo

Tema: Métodos de Ordenamiento. Parte 3.

Especificación Clase 2

Muchas de las ecuaciones de recurrencia que vamos a usar en este curso tienen la siguiente forma: ( c n =0 T (n) = a T (b n b.

Geometría. Facultad de Ciencias Exactas y Naturales Universidad de Buenos Aires. Training Camp 2012

Ejercicio 2 Considere la representación para Lista de Naturales y Árbol Binario de Naturales de la Figura 1.

Programación. Curso 2005/2006. Tema 3: Complejidad computacional

Grafos. Leopoldo Taravilse. Facultad de Ciencias Exactas y Naturales Universidad de Buenos Aires. Training Camp 2012

Programación II Árboles binarios de búsqueda (ABB)

Decrementa y vencerás II

Solución - práctico 10

Análisis de algoritmos

1. Recuerdo del algoritmo de KRUSKAL

PROGRAMA EDUCATIVO INFORMATICA ADMINISTRATIVA

Pruebas de Validez (Correctness) de Algorithmos.

Tema 06: Recursividad

2. Con una lista ordenada, aunque la localización y eliminación es rápida el problema es en la inserción de datos pues puede ser del orden de O(n).

ESTRUCTURA DE DATOS Y ALGORITMOS Titulación: Ingeniero Técnico en Informática de Gestión Curso: 2º Nombre y apellidos: Nota:

Tipos de datos en S. Lógica y Computabilidad. Codificación de variables y etiquetas de S. Codificación de programas en S

Algoritmos y problemas

Árboles. Árboles. Árboles binarios de búsqueda. Árboles. Inserción en un árbol. Árbol binario de búsqueda

Introducción y Comportamiento Asintótico

Complejidad computacional (Análisis de Algoritmos)

Sucesiones. Una sucesión de números reales es una tira, o una lista, de nḿeros reales que generalmente denotamos como

Algoritmos y Estructuras de Datos III

Problemas fáciles, difíciles e imposibles

Conceptos básicos de paralelismo

Estructuras de datos y algoritmos

Algoritmos y programas. Algoritmos y Estructuras de Datos I

Máquinas de Turing IIC3242. IIC3242 Máquinas de Turing 1 / 45

Algoritmos y Complejidad

Transcripción:

Complejidad computacional Algoritmos y Estructuras de Datos I Segundo cuatrimestre de 2015 Departamento de Computación - FCEyN - UBA Algoritmos - clase 10 Introducción a la complejidad computacional y algoritmo de búsqueda binaria Definición. La función de complejidad de un algoritmo es una función f : N N tal que f (n) es la cantidad de operaciones que realiza el algoritmo en el peor caso cuando toma una entrada de tamaño n. Algunas observaciones: 1. Medimos la cantidad de operaciones en lugar del tiempo total. 2. Nos interesa el peor caso del algoritmo. 3. La complejidad se mide en función del tamaño de la entrada y no de la entrada particular. 1 2 Notación O grande Complejidad computacional Definición. Si f y g son dos funciones, decimos que f O(g) si existen α R y n 0 N tales que f (n) α g(n) para todo n n 0. Intuitivamente, f O(g) si g(n) le gana a f (n) para valores grandes de n. Ejemplos: Si f (n) = n y g(n) = n 2, entonces f O(g). Si f (n) = n 2 y g(n) = n, entonces f O(g). Si f (n) = 100n y g(n) = n 2, entonces f O(g). Si f (n) = 4n 2 y g(n) = 2n 2, entonces f O(g) (y a la inversa). Utilizamos la notación O grande para especificar la función de complejidad f de los algoritmos. Si f O(n), decimos que el algoritmo es lineal. Si f O(n 2 ), decimos que el algoritmo es cuadrático. Si f O(n 3 ), decimos que el algoritmo es cúbico. En general, si f O(n k ), decimos que el algoritmo es polinomial. Si f O(2 n ) o similar, decimos que el algoritmo es exponencial. El algoritmo de búsqueda lineal tiene complejidad O(n). Decimos también el algoritmo es O(n). Se puede dar un algoritmos de búesuqeda más eficiente? 3 4

Búsqueda binaria Especificación del ciclo Problema: Determinar si un arreglo contiene un elemento dado. 1. Conocemos el algoritmo de búsqueda lineal, que tiene una complejidad de... O(n). 2. Se puede hacer mejor? Suponemos que el arreglo está ordenado, y que el elemento a buscar está dentro del rango dado por el primer y el último elemento. problema buscarbin (a : [Int], x : Int, n : Int) = res : Bool{ requiere a == n n > 1; requiere ( j [0..n 1)) a[j] a[j + 1]; requiere a[0] x a[n 1]; asegura res == (x a); Pc : low == 0 high == n 1 Qc : x a (a[low] == x a[high] == x) I : (0 low < high < n) (a[low] x a[high]) B : low + 1 < high v : high low 1, cota 0 5 6 Código del programa Código del programa y especificación del ciclo bool buscarbin(int a[], int x, int n) { int low = 0, high = n - 1; bool buscarbin(int a[], int x, int n) { int low = 0, high = n - 1; while ( low+1 < high ) { int mid = (low + high) / 2; if ( a[mid] <= x ) low = mid; else high = mid; return (a[low] == x a[high] == x); // vale Pc : low == 0 high == n 1 while ( low+1 < high ) { // invariante I : 0 low < high < n a[low] x a[high] // variante v : high low 1 int mid = (low + high) / 2; if ( a[mid] <= x ) low = mid; else high = mid; // vale Qc : x a (a[low] == x a[high] == x) return (a[low] == x a[high] == x); 7 8

Teorema del Invariante 1. La precondición del ciclo implica el invariante Si 1. La precondición implica el invariante 2. El cuerpo del ciclo preserva el invariante 3. La postcondición vale al final 4. La función variante decrece 5. Si la función variante pasa la cota, el ciclo termina Entonces el ciclo es correcto y termina. Pc : low == 0 high == n 1 a[0] x a[n 1] n > 1 implica I : 0 low < high < n a[low] x a[high] 9 10 2. El cuerpo del ciclo preserva el invariante // estado E (invariante + guarda del ciclo) // vale 0 low low + 1 < high < n a[low] x a[high] mid = (low + high) / 2; // estado F // vale mid = (low + high)@e div 2 low = low@e high = high@e // implica 0 low < mid < high < n if ( a[mid] <= x ) low = mid; else high = mid; // vale mid == mid@f // vale (x < a[mid@f ] high == mid@f low == low@f ) (x a[m@f ] low == mid@f high == high@f ) Falta ver que esto último implica el invariante 0 low < high < n: sale del estado F a[low] x a[high]: caso x < a[mid]: tenemos a[low] x < a[mid] == a[high] caso x a[mid]: tenemos a[low] == a[mid] x a[high] 11 3. La poscondición vale al final Sabiendo que el arreglo está ordenado queremos probar que 1 {{ 0 low < high < n I B implica Qc 2 {{ a[low] x a[high] implica 4 5 {{{{ x a (a[low] == x a[high] == x) Por 1 y 3, resulta (low == high 1 low == high) 3 {{ high low + 1 Supongamos 4. Usando 2 y (low == high 1 low == high), implica 5. Supongamos 5. Directamente implica 4. Entonces la postcondición vale al terminar la ejecución del ciclo. 12

4. La función variante decrece 5. Si la función variante pasa la cota, el ciclo termina // estado E (invariante junto con guarda del ciclo) // vale 0 low low + 1 < high < n a[low] x a[high] // implica high low 1 > 0 mid = (low + high) / 2; // estado F // vale mid == (low + high) div 2 low == low@e high == high@e // implica 0 low < mid < high < n if ( a[mid] <= x ) low = mid; else high = mid; // vale mid == mid@f // vale (x < a[mid@f ] high == mid@f low == low@f ) (x a[mid@f ] low == mid@f high == high@f ) high low 1 0 implica high low + 1 Cuánto vale v = high low 1? caso x < a[mid]: high decrece pero low queda igual caso x a[mid]: low crece pero high queda igual 13 14 Complejidad del algoritmo de búsqueda binaria Búsqueda binaria Cuántas comparaciones hacemos como máximo? En cada iteración nos quedamos con la mitad del espacio de búsqueda. Paramos cuando el segmento de búsqueda tiene longitud 1 o 2 número de iteración longitud del espacio de búsqueda 1 n 2 n/2 3 (n/2)/2 = n/2 2 4 (n/2 2 )/2 = n/2 3. t. n/2 t 1 Para llegar al espacio de búsqueda de longitud 1 hacemos t iteraciones 1 = n/2 t 1 entonces 2 t 1 = n entonces t = 1 + log 2 n. Luego, la complejidad de la bú squeda binaria es O(log 2 n). Es bueno un algoritmo con complejidad logarítmica? Búsqueda Búsqueda n Lineal Binaria 10 10 4 10 2 100 7 10 6 1, 000, 000 21 2,3 10 7 23, 000, 000 25 7 10 9 7, 000, 000, 000 33 Sí! Un algoritmo con este orden es muy eficiente. 15 16

Búsqueda lineal versus búsqueda binaria Búsqueda lineal versus búsqueda binaria Vimos dos algoritmos de búsqueda para problemas relacionados problema buscar (a : [Int], x : Int, n : Int) = res : Bool requiere a == n > 0; asegura res == (x a); problema buscarbin (a : [Int], x : Int, n : Int) = res : Bool requiere a == n > 1; requiere ( j [0..n 1)) a[j] a[j + 1]; requiere a[0] x a[n 1]; asegura res == (x a); La búsqueda binaria es mejor que la búsqueda lineal porque la complejidad tiempo para el peor caso O(log 2 n) es menor que O(n). En general, más propiedades en los datos de entrada permiten dar algoritmos más eficientes. Consideremos la variante del problema de búsqueda que retorna la posición en la secuencia donde se encuentra el elemento x, y retorna un valor negativo en caso de que x no esté en la secuencia. Búsqueda lineal retorna la primera posición donde está el elemento x buscado. En general la busqueda binaria retorna alguna de las posiciones donde está x, pero no necesariamente la primera. La versión del algoritmo de búsqueda binaria que dimos encuentra la primera posición del elemento buscado (si es que existe). Simplemente hay que adaptar el algoritmo para que retorne un número entero. Y demostrar que el algoritmo encuentra la menor posición, si es que existe. 17 18 http://goo.gl/ww0cx6 Nearly All Binary Searches are Broken! En 2006 comenzaron a reportarse acceso a un arreglo fuera de rango en el binarysearch implementado en las liberías de Java. En la implementación en Java, los enteros tienen precisión finita ([2 31..(2 31 1)]). Si low y high son valores muy grandes, al calcular mid se produce overflow. Por ejemplo: 1. Sean high=2 31 y low=1 2. Entonces mid=(low+high)/2= 1073741824! (negativo) 3. Al leer a[mid] esto produce un error en Java La falla estuvo dormida muchos años y se manifestó sólo cuando el tamaño de los arreglos creció a la par de la capacidad de memoria de las computadoras. Bugfix: Computar mid evitando el overflow: int mid = low + (high-low)/2; 19 20

Moraleja Búsqueda binaria retornando la menor posición El binarysearch implementado en Java estaba formalmente demostrado Pero la demostración suponía enteros de precisión infinita (en Java son de precisión finita) En AED1 no nos preocupan los problemas de aritmética de precisión finita (+Info: Orga1) En la vida real, hay que validar las hipótesis sobre las que se realizó la demostración valgan en la implementación (aritmética finita, existencia de acceso concurrente, multi-threading, etc.) problema buscarbinmp (a : [Int], x : Int, n : Int) = pos : Int requiere a == n > 1; requiere ( j [0..n 1)) a[j] a[j + 1]; requiere a[0] x a[n 1]; asegura ( x a (pos == cabeza([j j [0.. a ), a[j] == x]) ) ( x a (pos == 1) ) ; 21 22 Búsqueda binaria retornando la menor posición Búsqueda binaria retornando la menor posición int buscarbinmp(int a[], int n, int x) { int low = 0, high = n - 1; while (low+1 < high) { int mid = low + (high -low) / 2; if (x <= a[m]) high=mid; else low=mid; if (x == a[low]) return low; else if (x == a[high]) return high; else return -1; P : a == n ( j [0..n 1)) a[j] a[j + 1] ( ) Q : ( x a pos == cabeza([j j ) [0.. a ), a[j] == x] x a pos == 1 Especificación del ciclo P c : low == 0 high == n 1 a[low] x a[high] I : (0 low < high < n) (a[low] x a[high]) (low > 0 a[low 1] x) Q c : (x a low == cabeza([j j [0.. a ), a[j] == x]) (x a high == cabeza([j j [0.. a ), a[j] == x]) (x a) v = high low 1, cota 0 23 24

Búsqueda ternaria Búsqueda ternaria Resuelve exactamente el mismo problema que la búsqueda binaria problema buscart (a : [Int], x : Int, n : Int) = res : Bool requiere a == n > 1; requiere ( j [0..n 1)) a[j] a[j + 1]; requiere a[0] x a[n 1]; asegura res == (x a); bool buscartern(int a[], int n, int x) { int low = 0, high = n - 1; while (low+2 < high) { int m1 = low + (high - low) / 3; int m2 = low + (high - low) * 2 / 3; if(x <= a[m1]) { high = m1; else if (x>=a[m2]) { low = m2; else { low = m1; high = m2; bool res = (a[low]==x) (a[high]==x) (a[low+(high-low)/2]==x); return res; 25 26 Búsqueda ternaria La búsqueda binaria es óptima El invariante del ciclo es: // invariante I: (0 low < high < n) (a[low] x a[high]) // variante high low 2 cota 0. La complejidad del algoritmo de búsqueda ternaria es O(log 3 a ). Es el mismo orden de complejidad que la búsqueda binaria, ya que log 3 n = (log 2 n)/log 2 (3), y log 2 (3) es una constante (no depende de n). De mismo modo que extendimos la búsqueda binaria a ternaria s puede extender para cualquier número de segmentos. Así obtenemos la búsqueda n-aria. Cosideremos los algoritmos de búsqueda sobre arreglos ordenados, que operan evaluando condiciones booleanas exclusivamente. Teorema: cualquier algoritmo de búsqueda (inventado o por inventarse) sobre una secuencia ordenada de longitud n toma para el peor caso al menos log n pasos. 27 28

La búsqueda binaria es óptima Demostración. La entrada es una secuencia a ordenada de n elementos, y un elemento x a ser buscado. Hay (n + 1) posibilidades para x: que sea menor al a[0] o que x esté entre a[i] y a[i + 1] para i = 0, 1.., n 2 o que x sea mayor al a[n 1]. Visualicemos todas las ejecuciones como un árbol de ejecuciones. Cada nodo es la evaluación de una expresión booleana, donde el árbol se ramifica en dos. Cada camino desde la raíz hasta una hoja es una ejecución del programa. La altura del árbol da el peor caso de cantidad de instrucciones ejecutadas por el programa. Para cada una de las (n + 1) posibilidades que tiene x respecto de la secuencia a, la ejecución bebe alcanzar una hoja diferente. El árbol debe tener al menos n + 1 hojas. Sabemos que un árbol binario con L hojas tiene altura al menos log 2 L. Por lo tanto nuestro árbol tiene altura mayor o igual que log 2 (n + 1). Concluímos que la búsqueda, en el peor caso, requiere al menos log 2 (n + 1) pasos. 29