You are on page 1of 10

Ordenamiento por Shell (Shell Sort) Concepto: La ordenación Shell debe el nombre a su inventor, D. L. Shell.

Se suele denominar también ordenación por inserción con incrementos decrecientes. Se considera que el método Shell es una mejora de los métodos de inserción directa. Este método también se conoce con el nombre de inserción con incrementos decrecientes. En el método de ordenación por inserción directa cada elemento se compara para su ubicación correcta en el arreglo, con los elementos que se encuentran en la parte izquierda del mismo. Si el elemento a insertar es más pequeño que el grupo de elementos que se encuentran a su izquierda, es necesario efectuar entonces varias comparaciones antes de su ubicación. Shell propone que las comparaciones entre elementos se efectúen con saltos de mayor tamaño pero con incrementos decrecientes, así los elementos quedarán ordenados en el arreglo más rápidamente. El Shell Sort es una generalización del ordenamiento por inserción, teniendo en cuenta dos observaciones: 1. El ordenamiento por inserción es eficiente si la entrada está "casi ordenada". 2. 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.

Explicación: En el algoritmo de inserción, cada elemento se compara con los elementos contiguos de su izquierda, uno tras otro. Si el elemento a insertar es el más pequeño hay que realizar muchas comparaciones antes de colocarlo en su lugar definitivo. A diferencia del algoritmo de ordenación por inserción, este algoritmo intercambia elementos distantes. Es por esto que puede deshacer más de una inversión en cada intercambio, hecho que se aprovecha para ganar velocidad. El algoritmo de Shell modifica los saltos contiguos resultantes de las comparaciones por saltos de mayor tamaño y con ello se consigue que la ordenación sea más rápida. Generalmente se toma como salto inicial n/2 (siendo n el número de elementos), luego se reduce el salto a la mitad en cada repetición hasta que el salto es de tamaño 1.

n] intercambiara (si hay que hacerlo) A[i] con alguno de los elementos anteriores a i con distancia múltiplo de k (es decir. El tiempo de ejecución promedio con esta secuencia de incrementos será O(n2). . La única condición que debe respetar la secuencia de incrementos es hp=1 de modo tal que en la última etapa se hace una 1-ordenación (o sea una ordenación normal). . la 1-ordenación tiene un array "casi ordenado". Desventajas: no optimiza mucho la velocidad del algoritmo puesto que los incrementos tienen factores comunes (no son primos relativos). n/4. . Esta "casi ordenación" se efectúa mediante hKordenaciones para algunos hK. pero comparando sólo elementos k-distanciados.La velocidad del algoritmo dependerá de una secuencia de valores (llamados incrementos) con los cuales trabaja utilizándolos como distancias entre elementos a intercambiar. en la última etapa.n].). . La ordenación por inserción trabaja mucho más rápido si la secuencia de datos está "casi ordenada". Se dice que una secuencia A de n elementos está k-ordenada (siendo k un natural) si.. usara el mismo algoritmo para k-ordenar.. es en realidad una ordenación por inserción pero a la cual se le pasa el array "casi ordenado". es aceptable en la práctica y su implementación (código) es relativamente sencillo.. O(n^(3/2)) y O(n^(4/3)). siendo h un entero y siempre que el índice i+hk esté en [0. En algunas secuencias se pueden obtener ordenes de tiempo de ejecución en el peor caso de O(n2). para cada i de [k+1. .. si bien no es la mejor de todos los algoritmos. Secuencia k-ordenada.. intercambiara A[i] con alguno de los elementos A[i-k].. Se puede decir entonces que la ordenación de Shell.n] se cumple que los elementos A[i + hk] están ordenados.. para todo i de [0. Así.. por lo que el algoritmo se ejecuta más rápidamente. Secuencias de incrementos usadas comúnmente La propuesta por Shell: n/2. Una propiedad importante de implementar una k-ordenación de este modo es que si k>p entonces realizar una p-ordenación luego de una k-ordenación conserva el k-orden. Más detalladamente. Se considera la ordenación de Shell como el algoritmo más adecuado para ordenar entradas de datos moderadamente grandes (decenas de millares de elementos) ya que su velocidad. La velocidad del algoritmo dependerá de esta secuencia de incrementos hK y una buena secuencia de incrementos constará de naturales primos relativos entre sí. h2. Ventajas: es fácil de calcular. n/(2k). Dado que la ordenación por inserción lo que hace es una 1-ordenación. A[i-2k].. 1.. hp y en la etapa k-esima realizar una hk-ordenación de los datos. luego de efectuar varias k-ordenaciones.. El algoritmo de ordenación de Shell lo que hace en realidad es tomar una secuencia de incrementos h1.

6 0.6 0..6 0. 1.1.La propuesta por Hibbard: 2k-1.1. 3.3. Ejemplo: ordenar una lista de elementos siguiendo paso a paso el método de Shell..6 0. . 5. (4. (6. donde k se elige de modo tal que 2k-1 < n/2 y 2k+1-1 > n/2. 19.2). Recorrido 1 2 3 4 5 Salto 3 3 3 1 1 Lista Ordenada 2.0. utilizar esta secuencia de incrementos hace que el algoritmo de Shell tenga un tiempo de ejecución promedio O(n5/4).5.2..3.5.1.4.4. .. 0] El número de elementos que tiene la lista es 7.4.. 7.1. (5.4). 1.1.3) Ninguno Algoritmo de ordenación Shell Los pasos a seguir por el algoritmo para una lista de n elementos: 1. 2. por lo que el salto inicial es 7/2 = 3.2).5. Aunque no se ha podido demostrar formalmente (sólo por medio de simulaciones). Una cota para el peor caso (que se puede demostrar utilizando la teoría de números y combinatoria avanzada) es O(n3/2). La siguiente tabla muestra el número de recorridos realizados en la lista con los saltos correspondientes.3. Obtener las secuencias parciales del vector al aplicar el método Shell para ordenar en orden creciente la lista: Para el arreglo a = [6.2.6 Intercambio (6. 5.0) Ninguno (4. comparando las parejas de elementos y si no están ordenados se intercambian.5.2. 3. Se divide la lista original en n/2 grupos de dos..3.3.0) (2.4. con la cual se pueden obtener tiempos de ejecución O(n4/3) para el peor caso y O(n7/6) para el caso promedio. considerando un incremento o salto entre los elementos de n/2.2.5. Se clasifica cada grupo por separado.4. . 4. 2. La propuesta por Sedgewick: 4k-3·2k+1. 1.

j = 2. Los siguiente valores que toman i = 6. desde i j (intervalo + 1) hasta n hacer i . Así.intervalo fin_si fin_mientras fin_desde Se puede observar que se comparan pares de elementos indexados por j y k. y nuevamente se clasifica cada grupo por separado. intervalo intervalo / 2 . El algoritmo termina cuando se alcanza el tamaño de salto 1. (a[j]. y los índices i = 5.3.a[k]). los recorridos por la lista están condicionados por el bucle. separados por un salto. a[k]). con un incremento o salto entre los elementos también mitad (n/4). k = 7 y así hasta recorrer la lista. j = 1. intervalo . si n = 8 el primer valor de intervalo = 4.intervalo mientras (j > 0) hacer k j + intervalo si (a[j] <= a[k])entonces j 0 sino Intercambio (a[j]. k = 6. Por consiguiente. Para realizar un nuevo recorrido de la lista con la mitad de grupos. intervalo n/2 mientras (intervalo > 0) hacer Para dividir la lista en grupos y clasificar cada grupo se anida este código. Así sucesivamente. el intervalo se hace la mitad. 5. 4. se sigue dividiendo la lista en la mitad de grupos que en el recorrido anterior con un incremento o salto decreciente en la mitad que el salto anterior y después clasificando cada grupo por separado. j j . Se divide ahora la lista en la mitad de grupos (n/4).

Codificación del método Shell Al codificar en C este método de ordenación es necesario tener en cuenta que el operador / realiza una división entera si los operandos son enteros y esto es importante al calcular el ancho del saltos entre pares de elementos: intervalo = n/2. temp = a[j]. void ordenacionShell(double a[]. i < n. while (j >= 0) { k = j + intervalo.Y así sucesivamente se repiten los recorridos por la lista. k. while (intervalo > 0) { for (i = intervalo. a[j] = a[k]. int n) { int intervalo.intervalo. intervalo = n / 2. . con el bucle: mientras intervalo > 0. par ordenado */ else { double temp. /* así termina el bucle. j. C toma como base el índice 0. i. En cuanto a los índices. i++) { j = i . if (a[j] <= a[k]) j = -1. como consecuencia hay que desplazar una posición a la izquierda las variables índice respecto a lo expuesto en el algoritmo.

{19. 55. 25. 24. 19. 25.Cambia el 36 y el 25. 25.Cambia el 25 y el 19. {19. 19. 55. {24. 25. 50} <-. 50. 36. 19. . 19. 25. 24. 50} <-.Cambia el 55 y el 24. 25. 36. 36. 55.a[k] = temp. 24.Cambia el 55 y el 36. 50} <-. 36. 25.Cambia el 24 y el 19. 36. } } Ejercicio: Teniendo el siguiente array {55. 36. 24. Salto=1: Primera iteración: {24. 50} Salto=3: Primera iteración: {24. } } } intervalo = intervalo / 2.Cambia el 55 y el 50. 50} <-. 50} <-. 55. 36. 55. Segunda iteración: {19. j -= intervalo. 55} <-.

for(l=1. while(j>0) {k = j + intb.j. int Cantidad. scanf("%d"..l<=Cantidad. intb. while(intb>0) {for(i=intb+1.h> void main(){ clrscr(). Aux.i). } intb = Cantidad / 2. l. Vector[j] = Vector[k].i++) {j = i .i++) {printf("\tVector[%d]=". k. scanf("%d".i<=Cantidad. Vector[%d]=%d por Vector[%d]=%d\n".} else {printf("\n\n\tCambiando.h> #include<conio. Vector[k] = Aux. for(i=1.l++) .k.Vector[k]).&Vector[i]).. opcion.Vector[j].intb.#include<stdio.&Cantidad). printf("\n").i<=Cantidad. int Vector[100]. j. {printf("\n\n\tCuantos numeros seran introducidos: "). Aux = Vector[j]. if(Vector[j]<Vector[k]) {j=0. i.

i<=Cantidad.Vector[i]). } printf("\n\n\t\tVECTOR ORDENADO\n").intb.{printf("\t%d". } } intb = intb / 2. for(i=1.Vector[l]).i++) {printf("\t%d".} .} }getch().} } j = j .

fácil de implementar. . no consume memoria extra dinámicamente y se comporta bastante bien para unos datos de entrada de mediano tamaño. relativamente eficiente en la mayoría de los casos.Conclusiones Este es un algoritmo eficaz.

http://es.shtml .dcc.cl/~bebustos/files/Bus99.rincondelvago.http://latecladeescape.uchile.Bibliografía .http://html.com/algoritmos/1124-ordenacion-por-el-metodo-de-shell-shellsort .http://www.pdf .org/wiki/Ordenamiento_Shell .com/wy2/est_info/shell.monografias.angelfire.http://es.scribd.html .com/doc/1739233/Ordenamiento-en-C .http://www.com/trabajos/algordenam/algordenam.wikipedia.http://www.http://www.html .mcgraw-hill.pdf .com/ordenacion-por-shell.es/bcv/guide/capitulo/8448198441.