CONTENIDO DE LA LECCIÓN 18
CONTENIDO DE LA LECCIÓN 18 CONTENIDO DE LA LECCIÓN 18
MIGUEL Á. TOLEDO MARTÍNEZ mitad = (primero + ultimo) / 2 [primero] [ultimo] [primero] [mitad – 1] [mitad + 1] [ultimo] Figura 18.4. La búsqueda binaria recursiva requiere que un arreglo sea dividido en mitades con cada llamada recursiva. Cualquiera de estas condiciones primitivas hará que termine la llamada recursiva. Ahora, vamos a considerar la primera condición primitiva más de cerca. ¿Cómo saber si el arreglo que se busca tiene solamente un elemento? Bueno, conforme continúan las llamadas recursivas sin encontrar el elemento, finalmente el arreglo se reducirá a un elemento sencillo. Si éste es el que se está buscando, la verificación si A[mitad] == elemento será verdadera, y las llamadas recursivas se detendrán. Si no lo es, el valor de primero se hará más grande que el valor de ultimo en la siguiente división. ¿Por qué? Porque si piensa en la acción de división del algoritmo, se dará cuenta que cada llamada recursiva hace que primero se incremento y ultimo se decremente. De esta manera, si el elemento no está en el arreglo, el valor de primero se hace finalmente más grande que el valor de ultimo. Por lo tanto se puede usar esta idea para verificar que el elemento no está en el arreglo, también para usarlo como una condición primitiva. De esta manera, se reemplazará la condición primitiva original con el siguiente enunciado: si (primero > ultimo) entonces regresar – 1 Si ocurre esta condición, se regresa el valor -1, indicando que no se encontró el elemento y terminan las llamadas recursivas. Ahora, vamos a aplicar este conocimiento a un segundo nivel del algoritmo. Como sigue: Algoritmo busquedaBin(): Segundo nivel busquedaBin(A, elemento, primero, ultimo) INICIO si(primero > ultimo) entonces regresar -1. sino Establecer mitad = (primero + ultimo) / 2. si (A[mitad] == elemento) entonces regresar mitad. sino si (el elemento está en la primera mitad) entonces busquedaBin(A, elemento, primero, mitad - l) sino busquedaBin(A, elemento, mitad + 1, ultimo) FIN. Es evidente ahora que el algoritmo realiza la recursividad, porque se puede ver la función llamándose a sí misma en uno o dos lugares, dependiendo de en qué mitad del arreglo dividido es probable que se encuentre el elemento. También, observe en dónde se verifican los dos casos primitivos. Si, al inicio de una llamada recursiva, primero > ultimo, el elemento no está en el arreglo y las llamadas recursivas terminan. Además, si después de calcular mitad, se encuentra el elemento en A[mitad], terminará la llamada recursiva. En ambos casos, la función ha terminado su ejecución y regresa un valor al programa llamador. Lo último que ARREGLOS, APUNTADORES Y ESTRUCTURAS – LECCIÓN 18 18-54
MIGUEL Á. TOLEDO MARTÍNEZ necesita el algoritmo es una forma para determinar si el elemento que se busca es muy probable que se encuentre en la primera mitad o en la segunda mitad del arreglo dividido. Aquí es donde viene el requerimiento para un arreglo ordenado. Si el arreglo está ordenado, es muy probable que el elemento se encuentre en la primera mitad del arreglo cuando elemento < A[mitad]; de otra manera, es muy probable que el elemento se encuentre en la segunda mitad del arreglo. Observe que usamos el término es muy probable. Nosotros no podemos garantizar que el elemento se encuentre en cualquier mitad, ¡ya que, inclusive, podría no estar en el arreglo! Todo lo que se puede hacer es dirigir la búsqueda a la mitad donde es muy probable que se encuentre el elemento, dependiendo del orden de clasificación de los elementos. Por lo tanto, se puede completar el algoritmo usando esta idea. Aquí está el algoritmo final: Algoritmo busquedaBin() busquedaBin(A, elemento, primero, ultimo) INICIO si(primero > ultimo) entonces regresar -1. sino Establecer mitad = (primero + ultimo) / 2. si (A[mitad] == elemento) entonces regresar mitad. sino si (elemento < A[mitad]) entonces busquedaBin(A, elemento, mitad - l). sino busquedaBin(A, elemento, mitad + 1, ultimo) FIN. Observe qué elegante es el algoritmo. Por elegante se debe entender que más que un proceso complicado de búsqueda binaria, se trata de sólo unos cuantos enunciados. Se sabe que hay mucho por recorrer todavía, pero la recursividad permite expresar todo este procedimiento en sólo unos cuantos enunciados. Como puede ver, a menudo los algoritmos recursivos proporcionan soluciones simples a problemas de gran complejidad, en donde una solución iterativa equivalente puede ser compleja. Éste no es siempre el caso, porque algunas soluciones recursivas son relativamente poco prácticas para la eficiencia de velocidad y de memoria. Recuerde la siguiente regla cuando considere la recursividad: considere una solución recursiva para un problema sólo cuando no sea posible una solución iterativa sencilla. Tome en cuenta que la búsqueda binaria tiene una solución iterativa relativamente sencilla. Se codificará esta solución para uno de los problemas al final de esta lección. CODIFICACIÓN DEL PROGRAMA La función que requiere C++ ahora se puede codificar con facilidad a partir del algoritmo final. Como sigue: int busquedaBin(int[A], int elemento, int primero, int ultimo) { int mitad; // PUNTO MEDIO DEL ARREGLO if (primero > ultimo) // SI EL ELEMENTO NO ESTÁ EN EL ARREGLO return -l; // REGRESA -1, SI NO CONTINÚA LA BÚSQUEDA else { mitad = (primero + ultimo) / 2; // ENCUENTRA EL PUNTO // MEDIO DEL ARREGLO if (elemento == A[mitad]) // Si EL ELEMENTO ESTÁ EN // A[mitad] return mitad; // REGRESA mitad else // Si NO, BUSCA LA MITAD APROPIADA if (elemento < A[mitad]) return busquedaBin(A, elemento, primero, mitad - l); else ARREGLOS, APUNTADORES Y ESTRUCTURAS – LECCIÓN 18 18-55
- Page 3 and 4: MIGUEL Á. TOLEDO MARTÍNEZ LECCIÓ
- Page 5 and 6: MIGUEL Á. TOLEDO MARTÍNEZ ELEMENT
- Page 7 and 8: MIGUEL Á. TOLEDO MARTÍNEZ Con las
- Page 9 and 10: MIGUEL Á. TOLEDO MARTÍNEZ del arr
- Page 11 and 12: MIGUEL Á. TOLEDO MARTÍNEZ // MUES
- Page 13 and 14: MIGUEL Á. TOLEDO MARTÍNEZ que exp
- Page 15 and 16: MIGUEL Á. TOLEDO MARTÍNEZ Ejemplo
- Page 17 and 18: MIGUEL Á. TOLEDO MARTÍNEZ Ejemplo
- Page 19 and 20: MIGUEL Á. TOLEDO MARTÍNEZ void ma
- Page 21 and 22: MIGUEL Á. TOLEDO MARTÍNEZ PASO DE
- Page 23 and 24: MIGUEL Á. TOLEDO MARTÍNEZ void pa
- Page 25 and 26: MIGUEL Á. TOLEDO MARTÍNEZ Ejemplo
- Page 27 and 28: MIGUEL Á. TOLEDO MARTÍNEZ int bus
- Page 29 and 30: MIGUEL Á. TOLEDO MARTÍNEZ El cuer
- Page 31 and 32: MIGUEL Á. TOLEDO MARTÍNEZ /******
- Page 33 and 34: MIGUEL Á. TOLEDO MARTÍNEZ Ejemplo
- Page 35 and 36: MIGUEL Á. TOLEDO MARTÍNEZ Ejemplo
- Page 37 and 38: MIGUEL Á. TOLEDO MARTÍNEZ /* El s
- Page 39 and 40: MIGUEL Á. TOLEDO MARTÍNEZ escribi
- Page 41 and 42: MIGUEL Á. TOLEDO MARTÍNEZ /* El s
- Page 43 and 44: MIGUEL Á. TOLEDO MARTÍNEZ Ejemplo
- Page 45 and 46: MIGUEL Á. TOLEDO MARTÍNEZ SOLUCI
- Page 47 and 48: MIGUEL Á. TOLEDO MARTÍNEZ // Busc
- Page 49 and 50: MIGUEL Á. TOLEDO MARTÍNEZ Paso 1
- Page 51 and 52: MIGUEL Á. TOLEDO MARTÍNEZ { j = i
- Page 53: MIGUEL Á. TOLEDO MARTÍNEZ un tama
- Page 57 and 58: MIGUEL Á. TOLEDO MARTÍNEZ { for (
- Page 59 and 60: MIGUEL Á. TOLEDO MARTÍNEZ // Comp
- Page 61 and 62: MIGUEL Á. TOLEDO MARTÍNEZ INICIAC
- Page 63 and 64: MIGUEL Á. TOLEDO MARTÍNEZ Esta ve
- Page 65 and 66: MIGUEL Á. TOLEDO MARTÍNEZ • Los
- Page 67 and 68: MIGUEL Á. TOLEDO MARTÍNEZ Es posi
- Page 69 and 70: MIGUEL Á. TOLEDO MARTÍNEZ p[100];
- Page 71 and 72: MIGUEL Á. TOLEDO MARTÍNEZ a) Cree
- Page 73 and 74: MIGUEL Á. TOLEDO MARTÍNEZ d) ¿cu
- Page 75 and 76: MIGUEL Á. TOLEDO MARTÍNEZ medio d
- Page 77 and 78: MIGUEL Á. TOLEDO MARTÍNEZ EXAMEN
MIGUEL Á. TOLEDO MARTÍNEZ<br />
mitad = (primero + ultimo) / 2<br />
[primero] [ultimo]<br />
[primero] [mitad – 1] [mitad + 1] [ultimo]<br />
Figura <strong>18</strong>.4. La búsqueda binaria recursiva requiere que un arreglo sea dividido en mitades con cada llamada recursiva.<br />
Cualquiera de estas condiciones primitivas hará que termine la llamada recursiva. Ahora, vamos a<br />
considerar la primera condición primitiva más de cerca. ¿Cómo saber si el arreglo que se busca tiene<br />
solamente un elemento? Bueno, conforme continúan las llamadas recursivas sin encontrar el elemento,<br />
finalmente el arreglo se reducirá a un elemento sencillo. Si éste es el que se está buscando, la verificación si<br />
A[mitad] == elemento será verdadera, y las llamadas recursivas se detendrán. Si no lo es, el valor de<br />
primero se hará más grande que el valor de ultimo en la siguiente división. ¿Por qué? Porque si piensa en<br />
la acción de división del algoritmo, se dará cuenta que cada llamada recursiva hace que primero se<br />
incremento y ultimo se decremente. De esta manera, si el elemento no está en el arreglo, el valor de<br />
primero se hace finalmente más grande que el valor de ultimo. Por lo tanto se puede usar esta idea para<br />
verificar que el elemento no está en el arreglo, también para usarlo como una condición primitiva. De esta<br />
manera, se reemplazará la condición primitiva original con el siguiente enunciado:<br />
si (primero > ultimo) entonces<br />
regresar – 1<br />
Si ocurre esta condición, se regresa el valor -1, indicando que no se encontró el elemento y terminan las<br />
llamadas recursivas.<br />
Ahora, vamos a aplicar este conocimiento a un segundo nivel del algoritmo. Como sigue:<br />
Algoritmo busquedaBin(): Segundo nivel<br />
busquedaBin(A, elemento, primero, ultimo)<br />
INICIO<br />
si(primero > ultimo) entonces<br />
regresar -1.<br />
sino<br />
Establecer mitad = (primero + ultimo) / 2.<br />
si (A[mitad] == elemento) entonces<br />
regresar mitad.<br />
sino<br />
si (el elemento está en la primera mitad) entonces<br />
busquedaBin(A, elemento, primero, mitad - l)<br />
sino<br />
busquedaBin(A, elemento, mitad + 1, ultimo)<br />
FIN.<br />
Es evidente ahora que el algoritmo realiza la recursividad, porque se puede ver la función llamándose a sí<br />
misma en uno o dos lugares, dependiendo de en qué mitad del arreglo dividido es probable que se encuentre<br />
el elemento. También, observe en dónde se verifican los dos casos primitivos. Si, al inicio de una llamada<br />
recursiva, primero > ultimo, el elemento no está en el arreglo y las llamadas recursivas terminan. Además,<br />
si después de calcular mitad, se encuentra el elemento en A[mitad], terminará la llamada recursiva. En<br />
ambos casos, la función ha terminado su ejecución y regresa un valor al programa llamador. Lo último que<br />
ARREGLOS, APUNTADORES Y ESTRUCTURAS – <strong>LECCIÓN</strong> <strong>18</strong> <strong>18</strong>-54