Metodo Shell

Share Embed Donate


Short Description

Download Metodo Shell...

Description

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 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 l a 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. pequeños. El último paso del Shell Sort es un simple ordenamiento por inserción, pero para entonces, ya está garantizado g arantizado 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.

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 algunas secuencias se pueden obtener ordenes de tiempo de ejecución en el peor caso de O(n2), O(n^(3/2)) y O(n^(4/3)). 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, si bien no es la mejor de todos los algoritmos, es aceptable en la práctica y su implementación (código) es relativamente sencillo. Secuencia k-ordenada. Se dice que una secuencia A de n elementos está k-ordenada (siendo k un natural) si, para todo i de [0,n] se cumple que los elementos A[i + hk] están ordenados, siendo h un entero y siempre que el índice i+hk esté en [0,n]. El algoritmo de ordenación de Shell lo que hace en realidad es tomar una secuencia de incrementos h1, h2, ..., hp y en la etapa k-esima realizar una hk-ordenación de los datos. 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). Dado que la ordenación por inserción lo que hace es una 1-ordenación, usara el mismo algoritmo para k-ordenar, pero comparando sólo elementos k-distanciados. Más detalladamente, para cada i de [k+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, i ntercambiara A[i] con alguno de los elementos A[i-k], A[i-2k], ...). 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. La ordenación por inserción trabaja mucho más rápido si la secuencia de datos está "casi ordenada". Así, luego de efectuar varias k-ordenaciones, en la última etapa, la 1-ordenación tiene un array "casi ordenado", por lo que el algoritmo se ejecuta más rápidamente. Se puede decir entonces que la ordenación de Shell, es en realidad una ordenación por inserción pero a la cual se le pasa el array "casi ordenado". Esta "casi ordenación" se efectúa mediante h Kordenaciones para algunos hK. La velocidad del algoritmo dependerá de esta secuencia de incrementos h K y una buena secuencia de incrementos constará de naturales primos relativos entre sí. Secuencias de incrementos usadas comúnmente  La propuesta por Shell: n/2, n/4, ..., n/(2k), ..., 1. Ventajas: es fácil de calcular. Desventajas: no optimiza mucho la velocidad del algoritmo puesto que los incrementos tienen factores comunes (no son primos relativos). El tiempo de ejecución promedio con esta secuencia de incrementos será O(n2).

 La propuesta por Hibbard: 2k-1, ..., 7, 3, 1; donde k se elige de modo tal que 2k-1 < n/2 y 2k+1-1 > n/2. Aunque no se ha podido demostrar formalmente (sólo por medio de simulaciones), utilizar esta secuencia de incrementos hace que el algoritmo de Shell tenga un tiempo de ejecución promedio O(n5/4). 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 propuesta por Sedgewick: 4k-3·2k+1, ..., 19, 5, 1; 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. Ejemplo: ordenar una lista de elementos siguiendo paso a paso el método de Shell. Obtener las secuencias parciales del vector al aplicar el método Shell para ordenar en orden creciente la lista: Para el arreglo a = [6, 1, 5, 2, 3, 4, 0] El número de elementos que tiene la lista es 7, por lo que el salto inicial es 7/2 = 3. La siguiente tabla muestra el número de recorridos reali zados en la lista con los saltos correspondientes.

Recorrido

Salto

Lista Ordenada

Intercambio

1

3

2,1,4,0,3,5,6

(6,2), (5,4), (6,0)

2

3

0,1,4,2,3,5,6

(2,0)

3

3

0,1,4,2,3,5,6

Ninguno

4

1

0,1,2,3,4,5,6

(4,2), (4,3)

5

1

0,1,2,3,4,5,6

Ninguno

Algoritmo de ordenación Shell Los pasos a seguir por el algoritmo para una lista de n elementos: 1. Se divide la lista original en n/2 grupos de dos, considerando un incremento o salto entre los elementos de n/2. 2. Se clasifica cada grupo por separado, comparando las parejas de elementos y si no están ordenados se intercambian.

3. Se divide ahora la lista en la mitad de grupos (n/4), con un incremento o salto entre los elementos también mitad (n/4), y nuevamente se clasifica cada g rupo por separado. 4. Así sucesivamente, 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. 5. El algoritmo termina cuando se alcanza el tamaño de salto 1. Por consiguiente, los recorridos por la l ista están condicionados por el bucle, intervalo  n / 2 mientras (intervalo > 0) hacer Para dividir la lista en grupos y clasificar cada grupo se anida este código, desde i  (intervalo + 1) hasta n hacer  j  i - intervalo mientras (j > 0) hacer k  j + intervalo si (a[j] 0.

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. En cuanto a los índices, C toma como base el índice 0, como consecuencia hay que desplazar una posición a la izquierda las var iables índice respecto a lo expuesto en el alg oritmo. void ordenacionShell(double a[], int n) { int intervalo, i, j, k; intervalo = n / 2; while (intervalo > 0) { for (i = intervalo; i < n; i++) {  j = i - intervalo; while (j >= 0) { k = j + intervalo; if (a[j]
View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF