Ejemplos 2

Búsqueda binaria

ALGORÍTMICA Y COMPLEJIDAD
Grados en Ing. Informática y Matemáticas
Universidad de Cantabria
Camilo Palazuelos Calderón

Sea $A[0..\ell - 1]$ un array de elementos ordenados de menor a mayor. Definimos la función Buscar, que busca en el subarray $A[i..j]$ la posición del elemento $x$, recibidos $A[0..\ell - 1]$, $i$, $j$ y $x$ como parámetros: si la encuentra, devuelve un entero no negativo $k$ tal que $A[k] = x$; si no, -1.

In [ ]:
def Buscar(A, i, j, x):
    if i > j:
        return -1
    else:
        k = (i + j) // 2
        if A[k] == x:
            return k
        elif A[k] < x:
            return Buscar(A, k + 1, j, x)
        else:
            return Buscar(A, i, k - 1, x)

Probamos la función con el array $A[0..5] = (-20, -19, 3, 10, 18, 22)$ y los elementos $x = 18$ e $y = 19$. Buscar($A[0..5]$,$x$,$0$,$5$) y Buscar($A[0..5]$,$y$,$0$,$5$) deberían devolver 4 y -1, respectivamente.

In [ ]:
A = [-20, -19, 3, 10, 18, 22]
x = 18
y = 19
print(f'Buscar({A}, {0}, {len(A) - 1}, {x}) =  {Buscar(A, 0, len(A) - 1, x)}')
print(f'Buscar({A}, {0}, {len(A) - 1}, {y}) = { Buscar(A, 0, len(A) - 1, y)}')
Buscar([-20, -19, 3, 10, 18, 22], 0, 5, 18) =  4
Buscar([-20, -19, 3, 10, 18, 22], 0, 5, 19) = -1

Para evaluar el coste temporal empírico de Buscar en el peor caso, creamos un array $B[0..m - 1] = (0, \ldots, 0)$ con $m$ suficientemente grande (por ejemplo, $m = 10^7$). Iterativamente, buscaremos el elemento $x = 1$ en las primeras $n$ posiciones de $B[0..m - 1]$ y añadiremos el coste temporal empírico de Buscar($B[0..m - 1]$,$x$,$0$,$n - 1$) a una lista $T$.

In [ ]:
m = 10000000
B = [0 for _ in range(m)]
T = [None]

Modificamos Buscar para añadir una pequeña latencia (por ejemplo, $5$ ms) en cada llamada recursiva.

In [ ]:
import time

def Buscar2(A, i, j, x):
    time.sleep(0.005)
    if i > j:
        return -1
    else:
        k = (i + j) // 2
        if A[k] == x:
            return k
        elif A[k] < x:
            return Buscar2(A, k + 1, j, x)
        else:
            return Buscar2(A, i, k - 1, x)

Evaluamos el coste temporal empírico de Buscar2 con arrays de longitud $n$ desde $1 \cdot 10^5$ hasta $100 \cdot 10^5$ (de $10^5$ en $10^5$).

In [ ]:
for n in range(m // 100, m + 1, m // 100):
    t = time.time()
    Buscar2(B, 0, n - 1, 1)
    T.append(time.time() - t)
    #print(f'Iteración {n // (m // 100)} de 100')

Dibujamos una gráfica con el tiempo de ejecución $T(n)$ de Buscar2 en función de la longitud $n$ del array de entrada.

In [ ]:
import matplotlib.pyplot as plt
import numpy as np

with plt.style.context('ggplot'):
    plt.plot(np.array(T), label = '$T(n) \in \Theta(\log n)$')
    plt.xticks(
        [    x               for x in range(0, 101, 20)],
        [f'${x} \cdot 10^5$' for x in range(0, 101, 20)])
    plt.xlabel(        '$n$', fontsize = 12)
    plt.ylabel('$T(n)$ en s', fontsize = 12)
    plt.title('Complejidad temporal')
    plt.legend()

plt.show()
No description has been provided for this image
In [ ]: