Listas, búsqueda binaria y procedimientos
Imagina que tu escuela tiene una lista con los nombres de 1,000,000 de estudiantes de todo el distrito, y necesitas encontrar a uno solo. ¿Tienes que mirar nombre por nombre? Con la idea correcta, bastan unos 20 pasos. En esta página verás cómo guardar datos en listas, cómo buscar de forma muy rápida y cómo empaquetar tu código en procedimientos reutilizables.
Listas: muchos datos bajo un solo nombre
Una lista es una colección ordenada de elementos guardada bajo un solo nombre. En lugar de crear score1, score2, score3… usas una sola variable scores. Esto es abstracción de datos: tratas muchos valores como una sola cosa.
Aquí nums[1] es 4 y nums[3] es 1. Si pides una posición que no existe, como nums[5] o nums[0], el programa da error (índice fuera de rango).
Operaciones con listas
| Operación | Qué hace |
|---|---|
aList[i] |
Valor en la posición i |
aList[i] ← v |
Reemplaza el valor en la posición i |
LENGTH(aList) |
Cantidad de elementos |
APPEND(aList, v) |
Agrega v al final |
INSERT(aList, i, v) |
Pone v en la posición i; los demás se corren a la derecha |
REMOVE(aList, i) |
Quita el elemento de la posición i; los demás se corren a la izquierda |
FOR EACH item IN aList { … } |
Recorre la lista, un elemento por vuelta |
Sea nums ← [4, 9, 1, 7]. Recuerda que las posiciones de las listas en AP empiezan en 1. a) ¿Cuál es nums[2]? b) ¿Cuál es LENGTH(nums)? c) ¿Cuál es LENGTH(nums) después…
Sea nums ← [4, 9, 1, 7]. Recuerda que las posiciones de las listas en AP empiezan en 1.
- a) ¿Cuál es
nums[2]?
- b) ¿Cuál es
LENGTH(nums)?
- c) ¿Cuál es
LENGTH(nums)después deAPPEND(nums, 5)?
¿Cuál es el contenido final de list? Muestra la lista después de cada paso.
list ← [10, 20, 30]
INSERT(list, 2, 15)
REMOVE(list, 1)
¿Cuál es el contenido final de list? Muestra la lista después de cada paso.
Búsqueda secuencial y búsqueda binaria
Buscar un valor en una lista es una tarea muy común. Hay dos métodos.
Búsqueda secuencial (lineal): revisas el primer elemento, luego el segundo, y así hasta encontrar el valor o llegar al final. Funciona con cualquier lista. En el peor caso revisas los $n$ elementos.
Búsqueda binaria: como buscar una palabra en un diccionario: abres por la mitad y descartas la mitad que no sirve. Pero tiene una condición:
El procedimiento es:
-
Define
low ← 1yhigh ← LENGTH(lista). -
Revisa el elemento del medio: posición $\lfloor (low + high)/2 \rfloor$.
-
Si es el valor buscado, terminaste.
-
Si el valor buscado es menor, descarta la mitad derecha (
highpasa a sermedio − 1). Si es mayor, descarta la mitad izquierda (lowpasa a sermedio + 1). -
Repite hasta encontrarlo o hasta que no queden elementos.
¿Qué tan rápida es?
Cada revisión descarta la mitad de los elementos. Entonces el número de pasos en el peor caso es aproximadamente $\log_2 n$: la cantidad de veces que puedes partir $n$ por la mitad.
| Elementos $n$ | Secuencial (peor caso) | Binaria (peor caso, aprox.) |
|---|---|---|
| 8 | 8 | 3 |
| 1,024 | 1,024 | 10 |
| 1,000,000 | 1,000,000 | 20 |
Por eso el gancho del inicio se resuelve en unos 20 pasos: $2^{20} = 1{,}048{,}576$, que es un poco más de un millón.
La búsqueda binaria requiere algo de los datos. ¿Cuáles de estas listas se podrían buscar directamente con búsqueda binaria? Explica. i) [2, 5, 8, 11] ii) [9, 3, 7, 1]…
La búsqueda binaria requiere algo de los datos. ¿Cuáles de estas listas se podrían buscar directamente con búsqueda binaria? Explica.
- i)
[2, 5, 8, 11]
ii) [9, 3, 7, 1]
iii) ["ant", "bee", "cat"]
Usa búsqueda binaria para buscar 26 en esta lista ordenada. En cada paso, revisa el elemento de la posición ⌊(low + high) / 2⌋, donde las posiciones empiezan en 1. [3,…
Usa búsqueda binaria para buscar 26 en esta lista ordenada. En cada paso, revisa el elemento de la posición ⌊(low + high) / 2⌋, donde las posiciones empiezan en 1.
[3, 8, 12, 17, 21, 26, 30, 35, 41]
- a) Escribe, en orden, los valores que se revisan.
- b) ¿Cuántos elementos se revisaron en total? ¿Cómo se compara esto con una búsqueda secuencial del mismo valor?
La lista ordenada de una escuela tiene 1,000,000 de nombres de estudiantes. a) En el peor caso, ¿aproximadamente cuántos elementos revisa una búsqueda secuencial? ¿Y la…
La lista ordenada de una escuela tiene 1,000,000 de nombres de estudiantes.
- a) En el peor caso, ¿aproximadamente cuántos elementos revisa una búsqueda secuencial? ¿Y la búsqueda binaria? (Pista: $2^{20} = 1{,}048{,}576$.)
- b) Supón que la lista no está ordenada y solo necesitas buscar una vez. ¿Es mejor ordenarla primero y usar búsqueda binaria, o usar búsqueda secuencial? Justifica tu respuesta.
- c) Supón ahora que la lista se buscará miles de veces al día. ¿Qué enfoque es mejor y por qué?
Procedimientos: abstracción procedimental
Un procedimiento es un grupo de instrucciones con nombre que puedes usar una y otra vez. Así no repites código y puedes usarlo sin pensar en cómo funciona por dentro. Eso es abstracción procedimental.
PROCEDURE nombre(parametro1, parametro2) {
instrucciones
RETURN(valor)
}
-
Los parámetros son las entradas (variables que reciben datos).
-
Los argumentos son los valores concretos que das al llamarlo.
-
RETURN(valor)termina el procedimiento y devuelve un valor a quien lo llamó.
Los procedimientos también pueden llamarse unos dentro de otros: mystery(mystery(3, 8), 5) primero evalúa lo de adentro y usa ese resultado como argumento.
Cuidado con las listas vacías
Un procedimiento debe funcionar también con casos límite (edge cases). Si average divide entre LENGTH(list) y la lista está vacía, divide entre 0 y da error. Se arregla con un IF:
PROCEDURE average(list) {
IF (LENGTH(list) = 0) {
RETURN(0)
}
total ← 0
FOR EACH x IN list {
total ← total + x
}
RETURN(total / LENGTH(list))
}
a) ¿Qué devuelve countAbove([72, 85, 90, 64, 88], 80)? b) ¿Qué devuelve countAbove([72, 85, 90, 64, 88], 90)? c) Describe en una oración qué hace el procedimiento.
PROCEDURE countAbove(list, limit)
{
count ← 0
FOR EACH item IN list
{
IF (item > limit)
{
count ← count + 1
}
}
RETURN(count)
}
- a) ¿Qué devuelve
countAbove([72, 85, 90, 64, 88], 80)?
- b) ¿Qué devuelve
countAbove([72, 85, 90, 64, 88], 90)?
- c) Describe en una oración qué hace el procedimiento.
a) Evalúa mystery(4, 9). b) Evalúa mystery(mystery(3, 8), 5). c) ¿Qué hace el procedimiento? Identifica los parámetros y el valor que devuelve.
PROCEDURE mystery(a, b)
{
IF (a > b)
{
RETURN(a)
}
ELSE
{
RETURN(b)
}
}
- a) Evalúa
mystery(4, 9).
- b) Evalúa
mystery(mystery(3, 8), 5).
- c) ¿Qué hace el procedimiento? Identifica los parámetros y el valor que devuelve.
a) Sigue paso a paso average([80, 90, 70, 100]). ¿Qué devuelve? b) ¿Qué sale mal si la lista está vacía? Reescribe el procedimiento para que devuelva 0 cuando la lista…
PROCEDURE average(list)
{
total ← 0
FOR EACH x IN list
{
total ← total + x
}
RETURN(total / LENGTH(list))
}
- a) Sigue paso a paso
average([80, 90, 70, 100]). ¿Qué devuelve?
- b) ¿Qué sale mal si la lista está vacía? Reescribe el procedimiento para que devuelva
0cuando la lista esté vacía.
- c) Explica cómo ayuda la abstracción procedimental a un maestro que usa este procedimiento en muchas partes de un programa de calificaciones.
Vuelve al principio: con una lista ordenada de 1,000,000 de nombres, la búsqueda binaria encuentra a cualquier estudiante en unos 20 pasos, en lugar de hasta un millón.
Resumen
-
Una lista guarda varios elementos bajo un nombre; en AP las posiciones empiezan en 1, y un índice fuera de rango causa error.
-
APPEND,INSERT,REMOVE,LENGTHyFOR EACHson las operaciones básicas;INSERTyREMOVEmueven los demás elementos. -
La búsqueda secuencial sirve con cualquier lista; la binaria exige una lista ordenada y necesita unos $\log_2 n$ pasos.
-
Un procedimiento tiene parámetros (entradas) y puede devolver un valor con
RETURN. -
La abstracción procedimental evita repetir código y permite arreglar o mejorar algo en un solo lugar.
-
Prueba siempre los casos límite, como una lista vacía.