Lo que vas a aprender
- La diferencia entre búsqueda lineal y binaria.
- El algoritmo paso a paso, en versión iterativa y recursiva.
- Por qué su coste es .
- Las variantes para encontrar la primera o la última aparición.
- La búsqueda binaria sobre la respuesta.
- Los errores típicos al programarla.
Fundamentos teóricos
Búsqueda lineal
Recorrer los elementos uno a uno hasta encontrar el buscado. Funciona con cualquier lista, ordenada o no, pero en el peor caso mira todos: .Búsqueda binaria
Con la lista ordenada:- Mira el elemento del medio.
- Si es el buscado, termina.
- Si el buscado es menor, sigue solo con la mitad izquierda; si es mayor, con la derecha.
- Repite hasta encontrarlo o hasta que el intervalo quede vacío.
Por qué es O(log n)
Cada paso divide por 2 el tamaño del intervalo. Tras pasos quedan elementos; se acaba cuando queda 1, es decir, tras pasos. La recurrencia es (ver notación asintótica).Variantes
Con elementos repetidos, a menudo interesa la primera posición dondea[i] >= x (lower bound) o la primera donde a[i] > x (upper bound). Con ellas se cuenta cuántas veces aparece un valor: upper - lower.
bisect.bisect_left y bisect.bisect_right. En C++, std::lower_bound; en Java, Arrays.binarySearch y Collections.binarySearch.
Búsqueda binaria sobre la respuesta
No hace falta un array: sirve para cualquier función monótona. Si se busca el menor valor que cumple una condición y “cumplir” es monótono (a partir de cierto punto siempre se cumple), se puede buscar ese punto por bisección. Es la misma idea que el método de bisección para resolver ecuaciones.Ejemplos resueltos
Ejemplo 1 · Traza de una búsqueda
Ejemplo 1 · Traza de una búsqueda
Buscar 23 en
[2, 5, 8, 12, 16, 23, 38, 56, 72, 91]:Ejemplo 2 · Contar apariciones
Ejemplo 2 · Contar apariciones
En
[1, 2, 2, 2, 3, 5], lower_bound(a, 2) = 1 y bisect_right(a, 2) = 4: el 2 aparece veces, en .Ejemplo 3 · Raíz cuadrada entera
Ejemplo 3 · Raíz cuadrada entera
El mayor entero con :
Ejemplo 4 · Búsqueda sobre la respuesta
Ejemplo 4 · Búsqueda sobre la respuesta
Hay que repartir libros de 100, 200, 300 y 400 páginas, en orden, entre 2 personas, minimizando el máximo que lee una. Se prueba con un máximo : ¿se puede repartir sin superarlo? Si se puede con , también con (monótono). Bisección entre 400 y 1000: la respuesta es 600 (100 + 200 + 300 y 400).
Errores frecuentes
- Aplicarla a datos sin ordenar. El resultado no tiene sentido.
- Bucles infinitos por actualizar mal los límites (
izq = medioen lugar demedio + 1con un intervalo cerrado). - Confundir intervalo cerrado
[izq, der]y semiabierto[izq, der): cambian la condición del bucle y las actualizaciones. - Desbordamiento del punto medio en lenguajes con enteros de tamaño fijo:
(izq + der) / 2puede desbordar con valores enormes. Se usaizq + (der - izq) / 2. Este fallo estuvo años en la biblioteca estándar de Java hasta 2006. - Ordenar para hacer una sola búsqueda. Ordenar cuesta ; para buscar una vez es mejor la lineal.
Preguntas frecuentes
¿Cuándo compensa ordenar para usar búsqueda binaria?
¿Cuándo compensa ordenar para usar búsqueda binaria?
Cuando se van a hacer muchas búsquedas: ordenar una vez cuesta y cada búsqueda . Si además hay que insertar y borrar, mejor un árbol equilibrado; si solo se busca por igualdad, una tabla hash, con de media.
¿Dónde se usa la búsqueda binaria?
¿Dónde se usa la búsqueda binaria?
En los índices de las bases de datos (árboles B, una generalización), en
git bisect para encontrar el commit que introdujo un error (ver Git), en la depuración de cualquier cosa (“¿falla con la mitad de los datos?”) y en muchos problemas de optimización.Temas relacionados
Algoritmos de ordenación
Ordenar antes de buscar.
Notación asintótica
O(log n) frente a O(n).
Ceros de funciones
El método de bisección.