CONTENIDO DE LA LECCIÓN 18

CONTENIDO DE LA LECCIÓN 18 CONTENIDO DE LA LECCIÓN 18

azul2.bnct.ipn.mx
from azul2.bnct.ipn.mx More from this publisher
06.05.2013 Views

MIGUEL Á. TOLEDO MARTÍNEZ PLANEACIÓN DE LA SOLUCIÓN La búsqueda binaria representa una operación recursiva natural. Recuerde que la idea detrás de la recursividad es dividir un problema en subproblemas. Dividir un problema en subproblemas más simples de exactamente el mismo tipo hasta que ocurra una condición primitiva. Esto no es lo mismo que el diseño de software descendente, que divide los problemas en subproblemas más simples. La diferencia con la recursividad es que los subproblemas son exactamente del mismo tipo de problema que el problema original. Por ejemplo, suponga que está buscando un nombre en un directorio. Imagine que empieza al principio del directorio y ve cada nombre hasta que encuentra el correcto. Esto es exactamente lo que hace la búsqueda secuencial. ¿No sería más rápido, en promedio, abrir el directorio a la mitad? Después, determinar qué mitad del directorio contiene el nombre que está buscando, dividir esta sección del directorio a la mitad y así sucesivamente, hasta que obtiene la página en la cual aparece el nombre deseado. Aquí está un algoritmo que describe la búsqueda en el directorio como se describió. UN ALGORITMO DE BÚSQUEDA RECURSIVA EN UN DIRECTORIO buscaTel() INICIO si(el directorio telefónico sólo tiene una página) entonces Busca el nombre en la página. sino Abre el libro a la mitad. si(el nombre está en la primera mitad) entonces buscaTel(primera mitad del directorio para el nombre) sino buscaTel(segunda mitad del directorio para el nombre) FIN. ¿Observa cómo esta búsqueda es recursiva? Se mantiene realizando las mismas operaciones básicas hasta que llega a la página que contiene el nombre que está buscando. En otras palabras, la función buscaTel() se mantiene llamándose a sí misma en el enunciado anidado si/sino hasta que se encuentra la página correcta. La razón por la que se llama al proceso de búsqueda binaria es que deberá dividir el directorio entre 2 (bi) cada vez que se llama a sí mismo el algoritmo. Ahora, vamos a ver cómo se puede aplicar este proceso a la búsqueda en un arreglo de enteros. Se llamará a la función de búsqueda binaria recursiva busquedaBin() y se desarrollará el algoritmo en varios pasos. Aquí esta el primer nivel del algoritmo. Algoritmo busquedaBin(): Primer nivel busquedaBin() INICIO si(el arreglo tiene sólo un elemento) entonces Determine si este elemento es el elemento buscado. sino Encuentre el punto medio del arreglo. si(el elemento está en la primera mitad) entonces busquedaBin(primera mitad) sino busquedaBin(segunda mitad) FIN. Observe cómo este algoritmo es casi idéntico al algoritmo buscaTel() Aquí el proceso de búsqueda se continúa hasta que el arreglo se reduce a un elemento que se verifica contra el elemento que se está buscando. ¿Observa cómo la búsqueda se mantiene llamándose a sí misma hasta que ocurre la condición primitiva? Aunque este algoritmo proporciona una idea general de búsqueda binaria, se necesita mayor detalle para codificar el algoritmo. Para hacerlo, debemos preguntarnos que datos necesita busquedaBin() para realizar esta tarea. Bueno, al igual que la búsqueda secuencial, ésta necesita un arreglo en dónde buscar y el elemento que se va a buscar ¿correcto? Sin embargo, la búsqueda secuencial trata con ARREGLOS, APUNTADORES Y ESTRUCTURAS – LECCIÓN 18 18-52

MIGUEL Á. TOLEDO MARTÍNEZ un tamaño de arreglo dado, mientras que la búsqueda binaria necesita tratar con arreglos de tamaños diferentes conforme sigue dividiendo al arreglo original a la mitad. No solamente son estos arreglos de diferente tamaño, sino el primero y el último índices de cada mitad son diferentes. Como resultado, debemos proporcionar a busquedaBin() los límites del arreglo que está tratando en cualquier momento dado. Esto se puede hacer pasando el primero y último índices del arreglo dado a la función. Llamemos a estos índices primero y ultimo. Estamos listos para escribir la descripción de la interfaz de la función: Función busquedaBin(): Busca en un arreglo de enteros ordenado un valor determinado. Acepta: Un arreglo de enteros, un elemento de búsqueda, el primero y el último índices del arreglo en el cual se busca. Regresa: El índice del elemento, si se encuentra, o el valor -1 si el elemento no se encuentra. Esta descripción da suficiente información para escribir la interfaz de la función C++, como sigue: int busquedaBin(int A[], int elemento, int primero, int ultimo) Aquí, busquedaBin() regresará un valor entero que representa el índice del elemento que se busca. De nuevo, verá que regresará el valor -1 si el elemento no se encuentra en el arreglo. La función recibe el arreglo de enteros que se busca (A[]), el elemento que se busca (elemento), el primer índice del arreglo (primero) y el último índice del arreglo (ultimo) Observe que ningún tamaño se proporciona para el arreglo en que se busca porque la función buscará en forma recursiva en arreglos de diferentes tamaños. El siguiente problema es determinar qué valor de primero y ultimo se utilizarán para cualquier arreglo durante la búsqueda. Bueno, recuerde que se deberá dividir cualquier arreglo dado a la mitad para producir dos nuevos arreglos cada vez que se hace una llamada recursiva busquedaBin() Dado cualquier arreglo donde el primer índice es primero y el último índice es ultimo, se puede determinar el índice medio, como sigue: mitad = (primero + ultimo) / 2 Con este cálculo, la primera mitad del arreglo empieza en primero y finaliza en mitad - 1, y la segunda mitad del arreglo empieza en mitad + 1 y finaliza en ultimo. Esta idea se muestra en la figura 18.4. Pero, observe que ninguna mitad del arreglo contiene el elemento medio. Por me- dio de la utilización de esta técnica, las dos mitades no hacen un todo, ¿correcto? Por lo tanto, antes que se haga la división, suponga que verificamos el elemento medio para ver si es el elemento que se está buscando. La siguiente verificación realiza el trabajo. si (A[mitad] == elemento) entonces regresar mitad. Si esta verificación es verdadera antes de la división, se habrá encontrado el elemento que se está buscando y es posible terminar las llamadas recursivas. De otra manera, el elemento almacenado en A[mitad] no es el elemento que se está buscando, y esta posición del arreglo se puede ignorar durante el resto de la búsqueda. Si éste es el caso, se dividirá el arreglo y continuará el proceso recursivo. Sin embargo, se tiene que adicionar una segunda condición primitiva para el algoritmo recursivo. Aquí están las dos condiciones primitivas que se han hecho: 1. El arreglo que se busca tiene sólo un elemento. 2. A [mitad] == elemento. ARREGLOS, APUNTADORES Y ESTRUCTURAS – LECCIÓN 18 18-53

MIGUEL Á. TOLEDO MARTÍNEZ<br />

un tamaño de arreglo dado, mientras que la búsqueda binaria necesita tratar con arreglos de tamaños<br />

diferentes conforme sigue dividiendo al arreglo original a la mitad. No solamente son estos arreglos de<br />

diferente tamaño, sino el primero y el último índices de cada mitad son diferentes. Como resultado,<br />

debemos proporcionar a busquedaBin() los límites del arreglo que está tratando en cualquier momento<br />

dado. Esto se puede hacer pasando el primero y último índices del arreglo dado a la función. Llamemos a<br />

estos índices primero y ultimo.<br />

Estamos listos para escribir la descripción de la interfaz de la función:<br />

Función busquedaBin(): Busca en un arreglo de enteros ordenado un valor<br />

determinado.<br />

Acepta: Un arreglo de enteros, un elemento de búsqueda, el primero<br />

y el último índices del arreglo en el cual se busca.<br />

Regresa: El índice del elemento, si se encuentra, o el valor -1 si el<br />

elemento no se encuentra.<br />

Esta descripción da suficiente información para escribir la interfaz de la función C++, como sigue:<br />

int busquedaBin(int A[], int elemento, int primero, int ultimo)<br />

Aquí, busquedaBin() regresará un valor entero que representa el índice del elemento que se busca. De<br />

nuevo, verá que regresará el valor -1 si el elemento no se encuentra en el arreglo. La función recibe el<br />

arreglo de enteros que se busca (A[]), el elemento que se busca (elemento), el primer índice del arreglo<br />

(primero) y el último índice del arreglo (ultimo) Observe que ningún tamaño se proporciona para el arreglo<br />

en que se busca porque la función buscará en forma recursiva en arreglos de diferentes tamaños.<br />

El siguiente problema es determinar qué valor de primero y ultimo se utilizarán para cualquier arreglo<br />

durante la búsqueda. Bueno, recuerde que se deberá dividir cualquier arreglo dado a la mitad para producir<br />

dos nuevos arreglos cada vez que se hace una llamada recursiva busquedaBin() Dado cualquier arreglo<br />

donde el primer índice es primero y el último índice es ultimo, se puede determinar el índice medio, como<br />

sigue:<br />

mitad = (primero + ultimo) / 2<br />

Con este cálculo, la primera mitad del arreglo empieza en primero y finaliza en mitad - 1, y la segunda<br />

mitad del arreglo empieza en mitad + 1 y finaliza en ultimo. Esta idea se muestra en la figura <strong>18</strong>.4.<br />

Pero, observe que ninguna mitad del arreglo contiene el elemento medio. Por me- dio de la utilización de<br />

esta técnica, las dos mitades no hacen un todo, ¿correcto? Por lo tanto, antes que se haga la división,<br />

suponga que verificamos el elemento medio para ver si es el elemento que se está buscando. La siguiente<br />

verificación realiza el trabajo.<br />

si (A[mitad] == elemento) entonces<br />

regresar mitad.<br />

Si esta verificación es verdadera antes de la división, se habrá encontrado el elemento que se está buscando<br />

y es posible terminar las llamadas recursivas. De otra manera, el elemento almacenado en A[mitad] no es el<br />

elemento que se está buscando, y esta posición del arreglo se puede ignorar durante el resto de la búsqueda.<br />

Si éste es el caso, se dividirá el arreglo y continuará el proceso recursivo. Sin embargo, se tiene que<br />

adicionar una segunda condición primitiva para el algoritmo recursivo. Aquí están las dos condiciones<br />

primitivas que se han hecho:<br />

1. El arreglo que se busca tiene sólo un elemento.<br />

2. A [mitad] == elemento.<br />

ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-53

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!