You are on page 1of 23

Algoritmos de ordenación

Análisis y Diseño de Algoritmos

Algoritmos de ordenación
Algoritmos básicos: Θ(n2) Ordenación por inserción Ordenación por selección Ordenación por intercambio directo (burbuja) Algoritmos más eficientes Mergesort Quicksort Heapsort Shellsort Algoritmos para casos especiales Binsort (ordenación por urnas) …

1

Introducción
Supongamos un subconjunto de n elementos X = {e1,…,en} de un conjunto referencial Y, X ⊆Y. Dentro de Y se define una relación de orden total ≤ (con las propiedades reflexiva, simétrica y transitiva). El objetivo de la ordenación es encontrar una secuencia de los elementos de X 〈eσ(1),…,eσ(n)〉 tal que se verifique: eσ(1) ≤ … ≤ eσ(n)

2

Introducción
Observaciones Los datos pueden ser simples o complejos. El orden se establece de acuerdo al campo clave. Los conjuntos de datos pueden tener duplicados. Si se mantiene el orden relativo de los datos con clave repetida en el conjunto de datos original, el algoritmo se dice que es estable.
3

mediana.ej. 5 .ej. binaria). 4 Aplicaciones Aplicaciones evidentes: evidentes: Mostrar los ficheros de un directorio. Encontrar el par más cercano cercano. Detectar duplicados duplicados. p.ej. . p. Identificar “outliers” / anomalías anomalías. Ordenar los resultados de una búsqueda en Internet (p. alfabético). directorio. . . Encontrar la mediana.ej.ej (p. listado alfabético). Google PageRank PageRank). .ej. ). Problemas que resultan más sencillos de resolver con los datos ordenados ordenados: : Realizar una búsqueda (p.Introducción Tipos de algoritmos de ordenación Algoritmos de ordenación interna: En memoria principal (acceso aleatorio) Algoritmos de ordenación externa: En memoria secundaria (restricciones de acceso). búsqueda binaria). Mostrar un listado ordenado del contenido de una base de datos (p.

Biología computacional computacional. Planificación de tareas. paralelo. datos.ej. sistemas de partículas). . p. Balanceado de carga en un ordenador paralelo.Aplicaciones Otras aplicaciones (puede que no tan evidentes) evidentes) : Compresión de datos. Informática gráfica gráfica. Simulación (p.ej. partículas). se selecciona el menor elemento del subvector no ordenado y se intercambia con el primer elemento de este subvector subvector: : 7 . Árbol generador minimal [MST: Minimum Spanning Tree] Gestión de la cadena de suministro [SCM: Supply Chain Management] Recomendaciones de libros en Amazon.com … 6 Ordenación por selección En cada iteración. tareas. .

for (i (i=0. j.length. pos_min pos_min. = } } 9 . int i.. . for (i (i=0. int N = v. j. j<N. i<N<N-1..N-1] pos_min = i. pos_min pos_min. int N = v. ]. i<N<N-1.Ordenación por selección void selectionSort (double v[]) { double tmp tmp. for (j=i+1. v[i v[i] = v[ v[pos_min pos_min]. v[pos_min v[pos_min] ] = tmp tmp. . .Nv[i. . j<N. i++) { // Menor elemento del vector v[i. for (j=i+1. . i++) { // Menor elemento del vector v[i. .length.length v..N-1] pos_min = i. = } } 8 Ordenación por selección void selectionSort (double v[]) { double tmp tmp. int i.. // Coloca el mínimo en v[i] tmp = v[ v[i i]. v[i v[i] = v[ v[pos_min pos_min]. j++) if (v[j]<v[pos_min (v[j]<v[pos_min]) ]) pos_min = j. v[pos_min v[pos_min] ] = tmp tmp. .length v. .Nv[i. ]. // Coloca el mínimo en v[i] tmp = v[ v[i i]. j++) if (v[j]<v[pos_min (v[j]<v[pos_min]) ]) pos_min = j.

11 . 10 Ordenación por inserción En cada iteración.Ordenación por inserción En cada iteración. se inserta un elemento del subvector no ordenado en la posición correcta dentro del subvector ordenado. se inserta un elemento del subvector no ordenado en la posición correcta dentro del subvector ordenado.

length. j j---) ) v[j] = v[jv[j-1]. int i. . i++) { tmp = v[ v[i i]. j. for (i (i=1. . (j>0) && ( (tmp tmp<v[j <v[j-1]).Ordenación por inserción void insertionSort (double v[]) { double tmp tmp. for (j= (j=i i.length v. } } 12 Método de la burbuja Ordenación por intercambio directo IDEA: Los elementos más ligeros ascienden 13 . i<N. v[j] = tmp tmp. int N = v. .

void bubbleSort bubbleSort( (double double[] [] v) { boolean swapped = true. j = 0.length v. for (i = 0. } } } 15 . v[j] = v[jv[j-1]. double tmp tmp. v[i + 1] = tmp tmp. . [j]. for (i = 0. int i. .Método de la burbuja void bubbleSort (double v[]) { double tmp tmp.j.length. } } 14 Método de la burbuja Mejora: Usar un centinela y terminar cuando en una iteración del bucle interno no se produzcan intercambios. i < N – 1. j++.length .j i. while (swapped swapped) ) { swapped = false. swapped = true. i < v. . int N = v. . . . j++ . i++) for (j = N – 1. j j---) ) if (v[j] < v[jv[j-1]) { tmp = v v[j]. j > i. i++) if (v[i] > v[i + 1]) { tmp = v[i].j. v[i] = v[i + 1]. int i. v[jv[j -1] = tmp tmp.

Lineal en su versión mejorada si el vector está ordenado. 2. Ordenación por inserción N2/4 comparaciones y N2/8 intercambios en media El doble en el peor caso. Ordenar recursivamente cada mitad. 17 . 3. Casi lineal para conjuntos casi ordenados. 16 Mergesort Algoritmo de ordenación “divide y vencerás”: 1.Análisis de eficiencia Ordenación por selección N2/2 comparaciones y N intercambios. Combinar las dos mitades ordenadas: O(n). Ordenación por burbuja N2/2 comparaciones y N2/2 intercambios en media (y en el peor caso). Dividir nuestro conjunto en dos mitades.

Repetir hasta que se hayan añadido todos los elementos. Añadir el más pequeño de los dos a un vector auxiliar. 1969) Cantidad constante de almacenamiento extra. A A G L O R H I M S T Optimización: “In“In-place merge” merge” ( (Kronrud Kronrud. .Mergesort A A A A L G L G L G G O O H O R R I R I I H T T I O H H M R M M S S S S T T Dividir O(1) Ordenar 2T(n/2) Mezclar O(n) L M 18 Mergesort ¿Cómo combinar eficientemente dos listas ordenadas? Usando un array auxiliar y un número lineal de comparaciones: Controlar la posición del elemento más pequeño en cada mitad. 19 .

Mergesort A A G L O R H I M S T A A G G L O R H I M S T 20 Mergesort A A G G L H O R H I M S T A A G G L H O I R H I M S T 21 .

Mergesort A A G G L H O I R L H I M S T A A G G L H O I R L M H I M S T 22 Mergesort A A G G L H O I R L M H O I M S T A A G G L H O I R L M H O I R M S T 23 .

. 1969) Cantidad constante de almacenamiento extra. Repetir hasta que se hayan añadido todos los elementos. A A G L O R H I M S T Optimización: “In“In-place merge” merge” ( (Kronrud Kronrud. Añadir el más pequeño de los dos a un vector auxiliar. 25 .Mergesort A A G G L H O I R L M H O I R M S S T A A G G L H O I R L M H O I R M S S T T 24 Mergesort ¿Cómo combinar dos listas ordenadas eficientemente? Usando un array auxiliar y un número lineal de comparaciones: Controlar la posición del elemento más pequeño en cada mitad.

n =1  T ( n) = 2T ( n / 2) + n..Mergesort 26 Mergesort: Mergesort : Eficiencia 1. T(n / 2k) .. n > 1 T(n) n 2(n/2) T(n/2) T(n/2) T(n/4) T(n/4) T(n/4) T(n/4) log2n 4(n/4) . T(2) T(2) T(2) T(2) T(2) T(2) T(2) T(2) n/2 (2) 27 n log2n ...

Mergesort: Mergesort : Eficiencia 1. n =1  T ( n) = 2T ( n / 2) + n. n =1  T ( n) = 2T ( n / 2) + n. n > 1 Usando el método de la ecuación característica: ti = T (2i ) ti = 2ti −1 + 2i ⇒ ti = c1 2i + c2i 2i T (n) = c1 2 log 2 ( n ) + c2 log 2 (n)2log 2 ( n ) = c1n + c2 n log 2 (n) T (n) es O(n log 2 n) 29 . n > 1 Expandiendo la recurrencia: T ( n) n = = = L = = T ( n / n) n/n log 2 n +1+L+1 1 2 3 log 2 n 2T (n / 2) n T ( n / 2) n/2 T ( n / 4) n/4 +1 +1 +1+1 28 Mergesort: Mergesort : Eficiencia 1.

quicksort (v. ). vector. por separado.Quicksort 1. izda izda. dcha dcha). ). . 2. 3. // Posición del pivote if (izda izda< <dcha dcha) ) { pivote = partir (v. dcha dcha). 31 . 0. al que denominaremos pivote (p). pivote+1. int izda izda. izda izda. Se divide el vector de tal forma que todos los elementos a la izquierda del pivote sean menores que él. } } Uso: quicksort (vector. . Ordenamos. Se toma un elemento arbitrario del vector. mientras que los que quedan a la derecha son mayores que él.length-1). las dos zonas delimitadas por el pivote. pivote pivote-1). quicksort (v.length vector. 30 Quicksort void quicksort (double v[]. int dcha dcha) ) { int pivote. .

ahora. Se recorre el vector. 32 Quicksort 33 . hasta encontrar un elemento situado en una posición i tal que v[i] > p.Quicksort Obtención del pivote Mientras queden elementos mal colocados con respecto al pivote: Se recorre el vector. v[i] < p < v[j]). Se intercambian los elementos situados en las casillas i y j (de modo que. hasta encontrar otro elemento situado en una posición j tal que v[j] < p. de derecha a izquierda. de izquierda a derecha.

. int ultimo) { // Valor del pivote double pivote = v[primero]. 34 Quicksort: Quicksort : Eficiencia En el peor caso T(n) = T(1) + T(nT(n-1) + c·n ∈ O(n2) Tamaño de los casos equilibrado (idealmente. . ]. } } while (izda <= dcha dcha). int dcha = ultimo. v[primero] = v[dcha v[dcha]. izda ++. ). dcha-dcha --. // Variable auxiliar double temporal. int primero primero. ]. // Posición del pivote return dcha dcha. . izda++. usando la mediana como pivote) T(n) = 2T(n/2) + c·n ∈ O(n log n) Promedio 1 n −1 2 n −1 T (n) = ∑ [T (n − i ) + T (i )] + cn = ∑ T (i ) + cn ∈ O( n log n) n i =1 n i =1 35 .Quicksort int partir (double v[]. izda ++. v[dcha v[dcha] ] = temporal. // Colocar el pivote en su sitio temporal = v[primero]. while ((izda ((izda<= <=dcha dcha) ) && (v[dcha (v[dcha]>pivote)) ]>pivote)) dcha-dcha --. ]. int izda = primero+1. } while (( ((izda izda<= <=dcha dcha) ) && (v[izda (v[izda]<= ]<=pivote pivote)) )) izda++. . do { // Pivotear Pivotear… … if (izda < dcha dcha) ) { temporal = v[izda v[izda]. v[dcha v[dcha] ] = temporal. v[izda v[izda] ] = v[ v[dcha dcha].

n). 37 .Heapsort Algoritmo de ordenación de la familia del algoritmo de ordenación por selección basado en la construcción de un árbol parcialmente ordenado (“heap (“heap”). ”). el heapsort es O(n log n). n). Por tanto. 2. Heapsort O(n log n) 36 Heapsort: Heapsort : Eficiencia 1. Construcción inicial del heap: heap: n operaciones de inserción O(log n) sobre un árbol parcialmente ordenado ⇒ O(n log n). Extracción del menor/mayor elemento del heap: heap: n operaciones de borrado O(log n) sobre un árbol parcialmente ordenado ⇒ O(n log n).

1959). en varias pasadas de saltos cada vez menores.Shellsort Mejora del algoritmo de ordenación por inserción: Compara elementos separados por varias posiciones y. ordena el vector (Donald Shell. 38 Shellsort Mejora del algoritmo de ordenación por inserción: Compara elementos separados por varias posiciones y. Inserción O(n2) Shellsort O(nlog2 n) 39 . en varias pasadas de saltos cada vez menores. 1959). ordena el vector (Donald Shell.

. i < v.Bucket sort & Binsort Se divide el array en un conjunto de “urnas” y cada urna se ordena por separado: O(n2) Bajo ciertas condiciones (claves entre 0 y NN-1 sin duplicados). la ordenación se puede hacer en O(n): void binSort (int int[] [] v) { for (int i = 0.length v. v[i] = tmp tmp. } } 40 Otros algoritmos Radix sort Histogram sort Counting sort = ultra sort = math sort Tally sort Pigeonhole sort Bead sort Timsort Smoothsort … 41 . v[v[i]] = v[i]. i++) while (v[i] != i) { int tmp = v[v[i]]. .length.

Resumen Burbuja Selección 42 Resumen Inserción Shellsort 43 .

Resumen Heapsort Quicksort 44 Resumen Timsort: Timsort : Mergesort + Ordenación por inserción 45 .