Este documento presenta información sobre algoritmos de búsqueda y ordenación. Explica los conceptos básicos de búsqueda lineal y binaria, y diferentes algoritmos de ordenación como selección, inserción, burbuja y quicksort. Describe las complejidades computacionales de cada algoritmo y cuando es más adecuado utilizar cada uno. El objetivo es entender estos algoritmos fundamentales y cómo se pueden implementar y analizar.
1. Análisis y Diseño
de Software
Tema 2. Búsqueda y
Ordenación
Carlos A. Iglesias <cif@gsi.dit.upm.es>
Departamento de Ingeniería de Sistemas Telemáticos
http://moodle.dit.upm.es
G21
2. Legenda
Teoría
Ejercicio práctico en el ordenador
Ampliación de conocimientos
Lectura / Vídeo / Podcast
Práctica libre / Experimentación
Búsqueda y Ordenación 2
3. Bibliografía
● Data Structures &
Algorithms in Java,
Robert Lafore, 2nd
Edition, SAMS,
2002
● Capítulos 3, 7
●http://www.informit.com/store/product.aspx?isbn=0672324539
Búsqueda y Ordenación 3
4. Biblografía
● The Art of
Computer
Programming:
Sorting and
Searching, v.3,
Donald E. Knuth,
3rd edition, 1998
Búsqueda y Ordenación 4
5. Bibliografía
● Applets de visualización
http://www.informit.com/store/product.aspx?isbn=0672324539
● http://www.sorting-algorithms.com/
● http://math.hws.edu/eck/jsdemo/sortlab.html
Búsqueda y Ordenación 5
7. Objetivos
● Entender qué son los algoritmos, por qué
son importantes, y cómo se pueden
comparar
● Entender los problemas de ordenación y
búsqueda
● Entender algunos algoritmos de
ordenación y búsqueda, sus propiedades, y
cómo se implementan
Búsqueda y Ordenación 7
9. Búsqueda
“La búsqueda es una
herramienta básica que
cada programador
debería conocer para
utilizar en un gran
número de ocasiones”
Donald Knuth, “El Arte
de Programación de
Ordenadores”, Vol. 3,
1973.
Búsqueda y Ordenación 9
10. Búsqueda
●int busca(int val, int [] tabla)
– Devuelve i tal que x== tabla[i]
– -1 si no lo encuentra
●Búsqueda lineal
– Sobre cualquier array
– Recorremos el array hasta que lo encontramos
●Búsqueda binaria
– Sobre arrays ordenados
10
11. Pruebas funcionales
● Comprobamos que un método /
clase / … funciona como es
esperado
● Probamos casos de diferentes
clases de equivalencia:
representantes de casos diferentes
(válidos, inválidos, ...)
● Probar casos límite de cada clase
de equivalencia: 0, 1, n, n+1
● Usamos JUnit para hacer pruebas
funcionales unitarias
11
12. Pruebas de prestaciones
● Medimos recursos que
consume nuestra
implementación
● Nos permite comparar qué
implementación (que funciona)
es mejor, y en qué condiciones
es razonable usarla
● Medimos (p.ej. tiempo o
memoria o …) antes y
después de ejecutar la función
12
13. Ejercicio
● Programa SearchTest
● P.ej.
– Pruebas sobre un
array [1, 2, 3, 4, 5]
13
14. Búsqueda lineal
● Buscamos hasta encontrarlo
● Ejercicio. Implementar
● int buscaLineal (int val, int [] tabla)
– Devuelve i tal que x== tabla[i]
– -1 si no lo encuentra
● ¿Cuántas comparaciones haremos en
media?
● Se dice que tiene complejidad O(n)
14
15. Vamos a medir...
● Test de prestaciones
– Método para crear un array de tamaño n de longs
aleatorios
• private long [] fillRandomArray(long n)
– Método que mida tiempos, buscando un valor
aleatorio en un array de tamaño n, y que lo busque
muchas veces (1M)
• private long calculateTimes(Search s, int n)
– Método que imprima los tiempos, probando para
diferentes tamaños de array (100, 500, 1000, ...)
• private void showTimes(Search s)
15
17. Búsqueda binaria –
Arrays.binarySearch()
●Si sabemos que está ordenado,
– Dividimos el array por su elemento medio.
– Comparamos con el elemento del centro. Si
coincide, terminamos. Si el elemento es menor,
debe estar en el subarray de la izda, y si es mayor
en el de la derecha. Seguimos haciendo esto hasta
encontrarlo
• Ej. [1,2,3,4,5,6,7,8,9] y busco el 3
• [1,2,3,4]-5-[6,7,8,9] como 3 es menor que 5
• [1]-2-[3 ,4] como 3 es menor que 2 → []-3-[4] →
Encontrado
17
18. Búsqueda binaria - Ejercicios
● Programar versión iterativa
● Programar versión recursiva
18
19. Prestaciones...
● Comparar tiempos de las tres
implementaciones:
– Búsqueda lineal
– Búsqueda binaria iterativa
– Búsqueda binaria recursiva
19
20. Ordenación
“Pero no puedes
comprobar a tiempo todos
los carnets de conducir” -
objetó Drake. “No lo
necesitamos, Paul.
Simplemente los
ordenamos y buscamos
los duplicados”
– Perry Mason, El caso de
la Amiga Histérica, 1951
Búsqueda y Ordenación 20
21. Ordenación (Sorting)
● En cualquier problema
con una pequeña base de
datos, nos enfrentamos a
la ordenación: alfabética,
alumnos por curso,
pedidos, …
● La ordenación puede ser
un paso previo a la
búsqueda
Búsqueda y Ordenación 21
22. ¿Por qué estudiamos
algoritmos de ordenación?
● Ordenar es muy habitual y puede requerir
mucho tiempo (= ¡consumo en un móvil!)
● Se han diseñado algoritmos que permiten
optimizar esta tarea
● Vamos a ver
– Algoritmos básicos (poco optimizados):
• selección, inserción, burbuja
– Algoritmos más avanzados
• Quicksort, búsqueda binaria
Búsqueda y Ordenación 22
24. Algoritmos de ordenación
sencillos
● sort(int [] tabla)
● Burbuja
– Voy permutando hasta que no hay cambios
● Selección
– Voy seleccionando el menor
● Inserción
– Voy insertando en su lugar
Búsqueda y Ordenación 24
26. Algoritmos básicos:
estrategia
● En muchas
pasadas
– Comparo dos
elementos
– Los intercambio si
no están en orden, o
copio uno
Búsqueda y Ordenación 26
27. Ordenación por Burbuja
(Bubble Sort)
● Es muuuuuuuuuuuuy lento, pero muy
sencillo de entender
– Comparamos de dos en 2, e intercambiamos si
no están ordenados
– Cuando en una iteración no hay cambios,
hemos terminado
– Los más pequeños flotan a la izda
http://en.wikipedia.org/wiki/Bubble_sort
Búsqueda y Ordenación 27
28. Ordenación: burbuja
●Comparamos un elemento con el siguiente,
y si es mayor los intercambiamos
●Seguimos comparando con el siguiente, e
intercambiando, hasta que en la primera
pasada habrá quedado el mayor a la
derecha.
●Seguimos haciendo esto hasta que no hay
cambios
28
29. Invariantes
● Para analizar un algoritmo, podemos
fijarnos en los invariantes
● Invariante: condición que se cumple
siempre a medida que procede el algoritmo
– Facilitan depurar el algoritmo
● Burbuja: en cada pasada, el elemento que
queda a la derecha, está ordenado
Búsqueda y Ordenación 29
31. Análisis complejidad –
notación O
● Si analizamos cuántas comparaciones
hacemos
● P. ej para n = 10
– 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 = 45
● En general, para N:
– (N – 1) + (N – 2) + … + 1 = N * (N-1)/2
● Si N es grande, el número será N2
● La notación O : O(N2)
Búsqueda y Ordenación 31
32. Complejidad intercambios
● Si analizamos intercambios, si suponemos
que el conjunto es aleatorio, podemos
suponer que sólo estarán desordenados la
mitad
– Si había N2/2 comparaciones, habría N2/4
intercambios
● Tanto comparaciones como intercambios
son O(N2)
Búsqueda y Ordenación 32
33. Burbuja...
“El algoritmo de
ordenación de la
burbuja sólo tiene
de bonito el
nombre”, Donald
Knuth, El Arte de la
Programación de
Ordenadores, vol.
3., 1973.
Búsqueda y Ordenación 33
35. Danzas húngaras
●Puedes aprender los algoritmos mirando
danzas húngaras...
http://www.youtube.com/watch?v=lyZQPjUT5B4
Búsqueda y Ordenación 35
36. Selección (Selection sort)
● Buscamos el mínimo de la lista
– Lo intercambiamos con el primero
● Buscamos el mínimo del resto de la lista
– Lo intercambiamos con el segundo
…
● En general
– Busco el mínimo entre i y la posición final de la
lista
– Intercambio el mínimo con el elemento en la
posición i
Búsqueda y Ordenación 36
38. Análisis
● Invariante: los elementos de la izquierda que ya hemos
intercambiado, están siempre ordenados
● Complejidad:
– Hacemos las mismas comparaciones que en la burbuja: N * (N – 1) /2
→ O(N2)
– Hacemos menos intercambios, menos que N (una pasada) → O(N)
● Para grandes valores de N, pesará más el término de
comparaciones, y la complejidad será O(N 2)
● Para N pequeño, será más rápido que la burbuja
● En general: no es un algoritmo adecuado
● Puede ser bueno si los tiempos de intercambio son altos
38
39. Inserción (insertion sort)
● Como con las barajas
● En cada pasada, cogemos un elemento y
lo dejamos 'colocado', y vamos a por el
siguiente
39
41. Análisis
● Invariante: los elementos que ya hemos
analizado están ordenados entre sí
● Complejidad:
– En la primera pasada, comparamos con 1 carta, en la
segunda con 2, en la tercera con 3, … → 1 + 2 + 3 +
… + N – 1 = N * (N – 1) / 2
– En media, compararemos con la mitad de cartas
ordenadas → N * (N – 1) / 4 → O(N2)
– Número de copias similar al de comparaciones, pero
una copia requiere menos tiempo que un intercambio
– Si los datos ya están ordenados (o casi), sería O(N)
41
42. Estabilidad
● Se dice que dos algoritmos son estables si
mantienen el orden original, y sólo cambian
el orden si hace falta
● P. ej. tenemos alumnos ordenados por
apellidos, y queremos ordenarlos por notas
● Burbuja y selección son estables
● Selección es inestable, aunque se puede
hacer una implementación estable
42
43. Quicksort
(Hoare, 1960)
● Sigue estrategia “divide y vencerás”
● Pasos
– Toma un elemento (pivote de la lista)
– Partición: Reordena → elementos menores a
la izda de pivote, mayores a la derecha, el
pivote queda en su sitio
– Recursión: ordena sublista de menores y de
mayores
43
44. QuickSort
● Divide y vencerás
<= p p > p
<= p p > p <= p p > p
<= p > p <= p > p <= p > p <= p > p
se ordenan los casos triviales, y queda ordenado el conjunto
44
46. Análisis
● Invariante:
– la parte izda < pivote
– la parte dcha > pivote
● Complejidad:
– En la mayor parte de los casos es el más
rápido: O(n * log(n))
46
47. Análisis complejidad
Mejor Medio Peor
Selección O (n2) O (n2) O (n2)
Inserción O (n) O (n2) O (n2)
Burbuja O (n) O (n2) O (n2)
Quick sort O (n log n) O (n log n) O (n2)
47
51. Caso mejor
600
400
inserción
T (ms)
200 burbuja
Quick + Insert
0 Quick + Insert
inserción
QuickSort
100
500
2.000
10.000
L
51
52. Ordenar objetos en Java
● En Java para ordenar, usamos al interfaz Comparable
● int c = a.compareTo(b)
interface Comparable<T> {
● Orden: int compareTo(T o);
– c<0→a<b }
– c == 0 → a == b
– c>0→a>b
● Al implementar Comparable, tenemos que cumplir:
– x.compareTo(y) == 0 ↔ x.equals(y)
– Transitividad. Si x.compareTo(y) > 0 && y.compareTo(z) > 0 →
x.compareTo(z) > 0
– Si x.compareTo(y) == 0 → signo(x.compareTo(z)) ==
signo(y.compareTo(z)), para todo z
52
53. Ejemplo
public class Persiona implements Comparable {
private String nombre;
private String apellido;
int edad;
public int compareTo(Persona otra) {
int c1 = apellido.compareTo(otra.apellido);
if (c1 != 0) { return c1;}
int c2 = nombre.compareTo(otra.nombre);
if (c2 !=0) {return c2;}
return otra.edad – edad;
}
}
53
54. Inserción: búsqueda +
ordenación
● Si vamos a insertar y buscar objetos
comparables, podemos...
● Inserción ordenada + búsqueda binaria
● Inserción (como venga) + búsqueda lineal
● Inserción + ordenación + búsqueda binaria
●¿qué hacemos?
• → según lo que tarde cada operación
54
55. Inserción ordenada
● Si sabemos que el array ya está
ordenado...
●Hay variantes como 'binary insertion sort'
que hace una búsqueda binaria (en vez de
lineal) para determinar dónde insertar
55
56. Ordenación perezosa
(lazy sorting)
● Puede ser interesante ordenar sólo cuando
hace falta (dependerá de cómo sea de
costoso!)
● Insertar sin preocuparnos del orde
dato[pos++] = nuevoDato;
ordenado = false;
●Ordenar al sacar un elemento
if (!ordenado) {
sort(datos, 0, pos);
ordenado = true;
}
return binarySearch(datos, dato);
56
57. Resumen
● Tenemos diferentes algoritmos para
ordenar y buscar
● Las pruebas de prestaciones nos permiten
medirlos
– Es difícil (elementos externos como la máquina
o GC en Java)
● Hemos visto dos algoritmos de búsqueda:
lineal y binaria (para arrays ordenados)
Búsqueda y Ordenación 57
58. Resumen
● Los algoritmos sencillos de ordenación
(burbuja, inserción, selección) tienen
complejidad media O(N2)
● Quicksort tiene complejidad O(nlog(n)) y
puede ser inestable, según la
implementación
Búsqueda y Ordenación 58