5.1.3 ShellShort Algoritmo de ordenamiento Shell: El método se denomina así en honor de su inventor Donald Shell. Su implementación original, requiere O(n2) comparaciones e intercambios en el peor caso, aunque un cambio menor presentado en el libro de V. Pratt produce una implementación con un rendimiento de O(n log2 n) en el peor caso. Esto es mejor que las O(n2) comparaciones requeridas por algoritmos simples pero peor que el óptimo O(n log n). El Shell sort es una generalización del ordenamiento por inserción, teniendo en cuenta dos observaciones: El ordenamiento por inserción es eficiente si la entrada está "casi ordenada". El ordenamiento por inserción es ineficiente, en general, porque mueve los valores sólo una posición cada vez. El algoritmo Shell sort mejora el ordenamiento por inserción comparando elementos separados por un espacio de varias posiciones. Esto permite que un elemento haga "pasos más grandes" hacia su posición esperada. Los pasos múltiples sobre los datos se hacen con tamaños de espacio cada vez más pequeños. El último paso del Shell sort es un simple ordenamiento por inserción, pero para entonces, ya está garantizado que los datos del vector están casi ordenados. El algoritmo Shell es una mejora de la ordenación por inserción, donde se van comparando elementos distantes, al tiempo que se los intercambian si corresponde. A medida que se aumentan los pasos, el tamaño de los saltos disminuye; por esto mismo, es útil tanto como si los datos desordenados se encuentran cercanos, o lejanos. Es bastante adecuado para ordenar listas de tamaño moderado, debido a que su velocidad es aceptable y su codificación es bastante sencilla. Su velocidad depende de la secuencia de valores con los cuales trabaja, ordenándolos.El siguiente ejemplo muestra el proceso de forma gráfica: Considerando un valor pequeño que está inicialmente almacenado en el final del vector. Usando un ordenamiento O(n2) como el ordenamiento de burbuja o el ordenamiento por inserción, tomará aproximadamente n comparaciones e intercambios para mover este valor hacia el otro extremo del vector. El Shellsort primero mueve los valores usando tamaños de espacio gigantes, de manera que un valor pequeño se moverá bastantes posiciones hacia su posición final, con sólo unas pocas comparaciones e intercambios. Ejemplo Por ejemplo, considere una lista de números como [13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10]. Si comenzamos con un tamaño de paso de 8, podríamos visualizar esto dividiendo la lista de números en una tabla con 5 columnas. Esto quedaría así: Entonces ordenamos cada columna, lo que nos queda: Cuando lo leemos de nuevo como una única lista de números, obtenemos [ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ]. Aquí, el 10 que estaba en el extremo final, se ha movido hasta el extremo inicial. Esta lista es entonces de nuevo ordenada usando un ordenamiento con un espacio de 3 posiciones, y después un ordenamiento con un espacio de 1 posición (ordenamiento por inserción simple). 5.1.4 Radix Ordenamiento Radix es un algoritmo de ordenación no comparativo. Este algoritmo evita las comparaciones insertando elementos en cubos de acuerdo con el radix (Radix/Base es el número de dígitos únicos utilizados para representar números. Por ejemplo, los números decimales tienen diez dígitos únicos). Ordena los elementos basándose en los dígitos de los elementos individuales. Realiza la ordenación por conteo de los dígitos desde el menos significativo hasta el más significativo. También se ha llamado ordenación en cubo o digital y es muy útil en máquinas paralelas. Supongamos que tenemos un array A[] sin ordenar que contiene n elementos. Encuentre el elemento más grande maxm en el array. Ordena cada dígito de maxm empezando por el menos significativo utilizando un algoritmo de ordenación estable. La mayor parte de los ordenadores digitales representan internamente todos sus datos como representaciones electrónicas de números binarios, por lo que procesar los dígitos de las representaciones de enteros por representaciones de grupos de dígitos binarios es lo más conveniente. Existen dos clasificaciones de radix sort: el de dígito menos significativo (LSD) y el de dígito más significativo (MSD). Radix sort LSD procesa las representaciones de enteros empezando por el dígito menos significativo y moviéndose hacia el dígito más significativo. Radix sort MSD trabaja en sentido contrario. Las representaciones de enteros que son procesadas por los algoritmos de ordenamiento se les llama a menudo "claves", que pueden existir por sí mismas o asociadas a otros datos. Radix sort LSD usa típicamente el siguiente orden: claves cortas aparecen antes que las claves largas, y claves de la misma longitud son ordenadas de forma léxica. Esto coincide con el orden normal de las representaciones de enteros, como la secuencia "1, 2, 3, 4, 5, 6, 7, 8, 9, 10". Radix sorts MSD usa orden léxico, que es ideal para la ordenación de cadenas de caracteres, como las palabras o representaciones de enteros de longitud fija. Una secuencia como "b, c, d, e, f, g, h, i, j, ba" será ordenada léxicamente como "b, ba, c, d, e, f, g, h, i, j". Si se usa orden léxico para ordenar representaciones de enteros de longitud variable, entonces la ordenación de las representaciones de los números del 1 al 10 será "1, 10, 2, 3, 4, 5, 6, 7, 8, 9", como si las claves más cortas estuvieran justificadas a la izquierda y rellenadas a la derecha con espacios en blanco, para hacerlas tan largas como la clave más larga, para el propósito de este ordenamiento. Ejemplo Vector original: 25 57 48 37 12 92 86 33 Asignamos los elementos en colas basadas en el dígito menos significativo de cada uno de ellos. 0: 1: 2:12 92 3:33 4: 5:25 6:86 7:57 37 8:48 9: Después de la primera pasada, la ordenación queda: 12 92 33 25 86 57 37 48 Colas basadas en el dígito más significativo. 0: 1:12 2:25 3:33 37 4:48 5:57 6: 7: 8:86 9:92 Lista ordenada: 12 25 33 37 48 57 86 92 5.2.3 Mezcla natural La Ordenamiento por mezcla es uno de los algoritmos de ordenación más populares y eficientes. Se basa en el principio del algoritmo divide y vencerás. Funciona dividiendo el array en dos mitades repetidamente hasta que obtenemos el array dividido en elementos individuales. Un elemento individual es un array ordenado en sí mismo. La ordenamiento por mezcla combina repetidamente estas pequeñas matrices ordenadas para producir submatrices ordenadas más grandes hasta que obtenemos una array final ordenada. Se utiliza mucho en aplicaciones de comercio electrónico. Algoritmo de ordenamiento por mezcla El método de ordenamiento por mezcla descendente comienza desde la parte superior con el array completo y procede hacia abajo a los elementos individuales con recursión. Supongamos que tenemos un array sin ordenar A[] que contiene n elementos. MergeSort() Toma dos variables beg y end y almacena el índice del elemento inicial y del elemento final. Encuentra el punto medio del array para dividirlo en dos mitades utilizando la fórmula mid =(beg+end)/2. Divide el array en dos partes arr[beg, .... , mid] y arr[mid+1, .... , end]. Dividir repetidamente el array en subarrayas con elementos individuales utilizando la recursividad. Llama a la función merge para empezar a construir el array ordenado. Merge() Inicializa el array auxiliar output para almacenar la salida ordenada. Inicializa 3 punteros i, j y k. i apunta al principio de la primera subarray beg. j apunta al principio de la segunda subarray mid+1. k inicializado con beg mantiene el índice actual del array ordenado output. Hasta que lleguemos al final de la subarray arr[beg, .... ,mid] o arr[mid+1, .... ,end], escogemos el valor más pequeño entre los elementos en el índice i &j y lo insertamos en output. Escoge los elementos restantes y los inserta en output una vez que uno de los arrays se ha agotado. Copiar output en arr[beg, ... , end]. Ejemplo de ordenamiento por Acción (5,3,4,2,1,6) mergesort(0,5) divide (5,3,4) (2,1,6) mergesort(0,2) mergesort(3,5) divide (5,3) (4) (2,1) (6) mergesort(0,1) mergesort(2,2) mergesort(3,4) ordenamiento(5,5) divide (5) (3) (4) (2) (1) (6) Matriz dividida en elementos individuales merge (3,5) (4) (1,2) (6) merge(0,1) merge(2,2) merge(3,4) merge(5,5) merge (3,4,5) (1,2,6) merge(0,2) merge(3,5) merge (1,2,3,4,5,6) merge(0,5) mezcla Supongamos que tenemos el array (5,3,4,2,1,6). Vamos a ordenarlo utilizando el algoritmo de ordenamiento por mezcla. Obtenemos el array ordenado - (1 2 3 4 5 6)