Este documento describe el algoritmo de ordenamiento de burbuja. Funciona revisando cada par de elementos adyacentes en una lista y intercambiándolos si están en orden incorrecto. Esto continúa hasta que no se requieran más intercambios, momento en el cual la lista estará ordenada. A pesar de su simplicidad, tiene un rendimiento cuadrático en el peor caso y por lo tanto no es eficiente para listas grandes.
1. Ordenamiento de burbuja
De Wikipedia, la enciclopedia libre
Saltar a navegación, búsqueda
El Ordenamiento de burbuja (Bubble Sort en inglés) es un sencillo algoritmo de
ordenamiento. Funciona revisando cada elemento de la lista que va a ser ordenada con
el siguiente, intercambiándolos de posición si están en el orden equivocado. Es
necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios,
lo cual significa que la lista está ordenada. Este algoritmo obtiene su nombre de la
forma con la que suben por la lista los elementos durante los intercambios, como si
fueran pequeñas "burbujas". También es conocido como el método del intercambio
directo. Dado que solo usa comparaciones para operar elementos, se lo considera un
algoritmo de comparación, siendo el más sencillo de implementar.
Contenido
[ocultar]
1 Descripción
2 Análisis
o 2.1 Rendimiento en casos óptimos
o 2.2 Conejos y Tortugas (Yo-yos) (?)
3 En la práctica
4 Implementación
5 Véase también
6 Enlaces externos
[editar] Descripción
Una manera simple de expresar el ordenamiento de burbuja en pseudocódigo es la
siguient
e:
En este
algorit
mo se
trata de
ordenar
una
lista de
valores:
a, de n
término
s
numera
dos del termino 0 al n-1, consta de dos bucles anidados uno con el índice i, que acota el
2. recorrido de la burbuja en sentido inverso de 2 a n, y un segundo bucle con el índice j,
con un recorrido desde 0 hasta n-i, para cada iteración del primer bucle, que indica el
lugar de la burbuja.
La burbuja son dos términos de la lista seguidos, j y j+1, que se comparan, si el primero
es menor que el segundo sus valores se intercambian.
Esta comparación se repite en el centro de los dos bucles, dando lugar a la postre a una
lista ordenada, puede verse que el número de repeticiones sola depende de n, y no del
orden de los términos, esto es si pasamos al algoritmo una lista ya ordenada, realizara
todas las comparaciones exactamente igual que para una lista no ordenada, esta es una
característica de este algoritmo, luego veremos una variante que evita este problema.
Para comprender el funcionamiento, veamos un ejemplo sencillo:
Partimos de una lista de números que hay que ordenar:
Podemos ver que la lista tiene cinco términos, luego:
El índice i hará un recorrido de 2 hasta n:
Que en este caso será de 2 a 5. Para cada uno de los valores de i, j
tomara sucesivamente los valores de 0 hasta n-i:
Para cada valor de j, obtenido en ese orden, se compara el valor del índice j con el
siguiente:
Si el termino j es menor, en su caso podría se mayor, que el termino j+1, los valores se
permutan, en caso contrario se
continúa con la iteración.
Para el caso del ejemplo,
tenemos que:
Para la primera iteración del
primer bucle:
3. y j tomara los valores de 0 hasta 3:
Cuando j vale 0, se comparan , el 55 y el 86, dado que 55 < 86 no se permutan el
orden.
Ahora j vale 1 y se comparan el 86 y el 48 Como 86 > 48, se permutan, dando
lugar a una nueva lista.
Se repite el proceso hasta que j valga 3, dando lugar a una lista parcialmente ordenada,
podemos ver que el termino de mayor
valor esta en el lugar más alto.
Ahora i vale 3, y j hará un recorrido de 0
a 2.
Primero j vale 0, se comparan , el
55 y el 48, como 55 > 48 se permutan
dando lugar a la nueva lista.
Para j = 1 se compara el 55 con el 16 y se
cambian de orden.
Para j = 2 se compara el 55 y el 82 y se dejan como están, finalizando el bucle con una
lista mejor ordenada, puede verse que los dos valores más altos ya ocupan su lugar. No
se ha realizado ninguna comparación con el termino cuarto, dado que ya se sabe que
después del primer ciclo es el mayor de la lista.
El algoritmo consiste en comparaciones sucesivas de dos términos consecutivos,
ascendiendo de abajo a arriba en cada iteración, como la ascensión de las burbujas de
aire en el agua, de ahí el nombre del procedimiento, en la primera iteración el recorrido
ha sido completo, en el segundo se ha dejado él ultimo termino, al tener ya el mayor de
los valores, en los sucesivos sé ira dejando re realizar las ultimas comparaciones, como
se puede ver.
Ahora ya i vale 4 y j recorrerá los valores de 0 a 1.
Cuando j vale 0, se comparan esto es el 48 y
el 16 dado que 48 es mayor que 16 se permutan los
valores, dando lugar a una lista algo más ordenada
que la anterior, desde esta nueva ordenación, j
pasa a valer 1, con lo que se comparan los
términos el 48 y el 55 que quedan en el
mismo orden.
En este caso la burbuja ha ascendido menos que en los casos anteriores, y la lista esta ya
ordenada, pero el algoritmo tendrá que completarse, realizando una ultima iteración.
4. Hay que tener en cuenta que el bucle para realiza un número fijo de repeticiones y para
finalizar tendrán que completarse, aun en el caso extremo, de que la lista estaría
previamente ordenada.
Por ultimo i vale 5 y j solo puede vale 0, con lo que solo se realizara una comparación
de el 16 y el 48, que ya están ordenados y se dejan
igual.
Los bucles finalizan y también el procedimiento, dejando la
lista ordenada.
Una variante que finaliza en caso de que la lista este
ordenada, puede ser la siguiente, empleando un centinela
ordenado, que detecta que no se ha modificado la lista en
un recorrido de la burbuja, y que por tanto la lista ya esta
ordenada, finalizando.
5. [editar] Análisis
Ejemplo del ordenamiento de burbuja ordenando una lista de números aleatorios.
[editar] Rendimiento en casos óptimos
El ordenamiento de burbuja tiene una complejidadΩ(n²). Cuando una lista ya está
ordenada, a diferencia del ordenamiento por inserción que pasará por la lista una vez, y
encontrará que no hay necesidad de intercambiar las posiciones de los elementos, el
método de ordenación por burbuja está forzado a pasar por dichas comparaciones, lo
que hace que su complejidad sea cuadrática en el mejor de los casos, esto lo cataloga
como el algoritmo mas ineficiente que existe aunque para muchos programadores sea
el más sencillo de implementar.
[editar] Conejos y Tortugas (Yo-yos) (?)
La posición de los elementos en el ordenamiento de burbuja juegan un papel muy
importante en la determinación del rendimiento. Los elementos mayores al principio de
la lista son rápidamente movidos hacia abajo. En cambio, elementos menores en el
fondo de la lista, se mueven a la parte superior muy lentamente. Esto llevó a nombrar
estos elementos conejos y tortugas, respectivamente.
Varios esfuerzos se han realizado para eliminar las tortugas véase Exterminación y
mejorar la velocidad del ordenamiento de burbuja, la cual será más redonda que nunca.
El Ordenamiento por sacudida es un buen ejemplo, aunque aún mantiene, en el peor de
los casos, una complejidad O (n2
). El ordenamiento por combinación compara los
elementos primero en pedazos grandes de la lista, moviendo tortugas extremadamente
rápido, antes de proceder a pedazos cada vez más pequeños para alisar la lista. Su
velocidad promedio es comparable a algoritmos rápidos (y complejos) como el
ordenamiento rápido.
[editar] En la práctica
6. A pesar de que el ordenamiento de burbuja es uno de los algoritmos más sencillos de
implementar, su orden O (n2
) lo hace muy ineficiente para usar en listas que tengan más
que un número reducido de elementos. Incluso entre los algoritmos de ordenamiento de
orden O (n2
), otros procedimientos como el Ordenamiento por inserción son
considerados más eficientes.
Dada su simplicidad, el ordenamiento de burbuja es utilizado para introducir el
concepto de algoritmo, o de algoritmo de ordenamiento para estudiantes de ciencias de
la computación. Aunque algunos investigadores como Owen Astrachan han criticado al
ordenamiento de burbuja y su popularidad en la educación de la computación,
recomendando que ya no debe ser enseñado.
El ordenamiento de burbuja es asintóticamente equivalente, en tiempos de ejecución con
el Ordenamiento por inserción en el peor de los casos, pero ambos algoritmos difieren
principalmente en la cantidad de intercambios que son necesarios. Resultados
experimentales, como los descubiertos por Astrachan han demostrado que el
ordenamiento por inserción funcionan considerablemente mejor incluso con listas
aleatorias. Por esta razón, muchos libros de algoritmos modernos evitan usar el
ordenamiento de burbuja, utilizando en cambio el ordenamiento por inserción.
El ordenamiento de burbuja interactúa vagamente con el hardware de las CPU
modernas. Requiere al menos el doble de escrituras que el ordenamiento por inserción,
el doble de pérdidas de cache, y asintóticamente más predicción de saltos. Varios
experimentos, hechos por Astrachan, de ordenamiento de cadenas en Java, muestran que
el ordenamiento de burbuja es 5 veces más lento que el ordenamiento por inserción y
40% más lento que el ordenamiento por selección.
[editar] Implementación
A continuación se muestra el Ordenamiento de burbuja en distintos lenguajes de
programación:
LUA
function burbuja_ordenar(t)
for i=1, #t do
for j=i+1, #t do
if (t[i] > t[j]) then
temp = t[i]
t[i] = t[j]
t[j] = temp
end
end
end
end
QBASIC
CLS
RANDOMIZE TIMER
n = 10
7. DIM a(n)
REM Generar e imprimir de a(0) a a(n) números aleatorios
FOR i = 0 TO n
a(i) = INT(RND * 1000)
PRINT USING "a(##)=#####"; i; a(i)
NEXT
PRINT
REM algoritmo de la burbuja
FOR j = n TO 1 STEP -1
FOR i = 1 TO j
IF a(i - 1) > a(i) THEN
aux = a(i)
a(i) = a(i - 1)
a(i - 1) = aux
END IF
NEXT
NEXT
REM imprimir datos ordenados
FOR i = 0 TO n
PRINT USING "a(##)=#####"; i; a(i)
NEXT
C
//Ordenamiento por metodo de Burbujeo
// Por Leandro D Ferro
void ordenamientoBurbuja(int v[], int util_v) {
int temp, i, j;
for (i = 0; i < util_v ; i++) {
for (j = i + 1; j < util_v - 1; j++) {
if (v[i] > v[j]) {
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
}
}
}
C++
template<typename _Ty>
void bubble_sort(vector<_Ty> & v){
for (size_t i = 0; i < v.size() - 1; ++i){
for (size_t j = i + 1; j < v.size(); ++j){
if (v[i] > v[j])
swap(v[i], v[j]);
}
}
}
C#
8. Public int[] OrdenarBurbuja(int[]x)
{
int t= x.Length, temp;
for(int i=1 ; i< t ; i++)
for(int j = t-1 ; j >= i; j--)
{
if(x[j] < x[j-1])
{
temp= x[j];
x[j]= x[j-1];
x[j-1]= temp;
}
}
}
Java
//Ordenamiento por Burbuja
// by ramses2999
public static int[] OrdenarBurbuja(int[] n){
int temp;
int t = n.length;
for (int i = 1; i < t; i++) {
for (int k = t- 1; k >= i; k--) {
if(n[k] < n[k-1]){
temp = n[k];
n[k] = n[k-1];
n[k-1]= temp;
}//fin if
}// fin 2 for
}//fin 1 for
return n;
}//fin
Visual Basic
Private Sub OrdenarBurbuja(ByRef VectorOriginal() As Integer)
Dim Temp, Longitud As Integer
Longitud = VectorOriginal.Length - 2
For b = 0 To Longitud
For a = 0 To Longitud
If VectorOriginal(a) > VectorOriginal(a + 1) Then
Temp = VectorOriginal(a + 1)
VectorOriginal(a + 1) = VectorOriginal(a)
VectorOriginal(a) = Temp
End If
Next
Next
End Sub
PHP
<?php
//Ordenamiento por burbuja
$numeros = array(9, 4, -1, 7, 8, 11, 6, 12, 10, 5);
$n = count($numeros);
9. for ($i = 1; $i<$n; $i++) {
for ($j = $n-1; $j >= $i; $j--) {
echo "i: $i, j: $jn";
echo "Comparando " . $numeros[$j-1] . " y " . $numeros[$j] .
"n";
if ($numeros[$j-1] > $numeros[$j]) {
$aux = $numeros[$j];
$numeros[$j] = $numeros[$j-1];
$numeros[$j-1] = $aux;
}
}
}
print_r($numeros);
Ordenamiento por inserción
De Wikipedia, la enciclopedia libre
Saltar a navegación, búsqueda
Ejemplo de ordenamiento por inserción ordenando una lista de números aleatorios.
El ordenamiento por inserción (insertion sort en inglés) es una manera muy natural
de ordenar para un ser humano, y puede usarse fácilmente para ordenar un mazo de
cartas numeradas en forma arbitraria. Requiere O(n²) operaciones para ordenar una lista
de n elementos.
Inicialmente se tiene un solo elemento, que obviamente es un conjunto ordenado.
Después, cuando hay k elementos ordenados de menor a mayor, se toma el elemento
k+1 y se compara con todos los elementos ya ordenados, deteniéndose cuando se
encuentra un elemento menor (todos los elementos mayores han sido desplazados una
posición a la derecha). En este punto se inserta el elemento k+1 debiendo desplazarse
los demás elementos.
Contenido
[ocultar]
10. 1 Ejemplo de funcionamiento
2 Implementación
o 2.1 C
o 2.2 C++
o 2.3 Java
o 2.4 JavaScript
o 2.5 Perl
o 2.6 PHP
o 2.7 Pascal
o 2.8 Python
o 2.9 Visual Basic .NET
3 Véase también
4 Enlaces externos
[editar] Ejemplo de funcionamiento
En el siguiente ejemplo, 32 debe ser insertado entre 26 y 47, y por lo tanto 47, 59 y 96
deben ser desplazados.
k+1
11 26 47 59 96 32
11 26 47 59 96
11 26 32 47 59 96
En la implementación computacional, el elemento k+1 va comparándose de atrás para
adelante, deteniéndose con el primer elemento menor. Simultáneamente se van haciendo
los desplazamientos.
11 26 47 59 96 32
11 26 47 59 96
11 26 47 59 96
11 26 47 59 96
11 26 32 47 59 96
El algoritmo en pseudocódigo (con listas que empiezan por 0) debería ser como el
siguiente:
algoritmo insertSort( A : lista de elementos ordenables )
para i=1 hasta longitud(A) hacer
index=A[i]
j=i-1
mientras j>=0 y A[j]>index hacer
A[j+1] = A[j]
j = j - 1
fin mientras
A[j+1] = index
fin para
fin algoritmo
11. Aunque este algoritmo tiene un mejor orden de complejidad que el de burbuja, es muy
ineficiente al compararlo con otros algoritmos como quicksort. Sin embargo, para listas
relativamente pequeñas el orden por inserción es una buena elección, no sólo porque
puede ser más rápido para cantidades pequeñas de elementos sino particularmente
debido a su facilidad de programación.
[editar] Implementación
A continuación se muestra el Ordenamiento por inserción en distintos lenguajes de
programación:
[editar] C
void insertionSort(int numbers[], int array_size) {
int i, a, index;
for (i=1; i < array_size; i++) {
index = numbers[i];
a = i-1;
while (a >= 0 && numbers[a] > index) {
numbers[a + 1] = numbers[a];
a--;
}
numbers[a+1] = index;
}
}
[editar] C++
template <class T> void insertionSort(std::vector<T>& v, int fin) {
int i, j, index;
for (i=1; i <fin; i++)
{
index = v.at(i);
j = i-1;
while (j >= 0 && v.at(j)>index) {
v.at(j+1)=v.at(j);
j--;
}
v.erase(v.begin()+j+1);
v.insert(v.begin()+j+1,index);
}
}
[editar] Java
public static void insertSort (int[] v) {
for (int i=1; i<v.length; i++) {
int aux = v[i];
int j;
for (j=i-1; j>=0 && v[j]>aux; j--)
v[j+1] = v[j];
v[j+1] = aux;
}
}
12. [editar] JavaScript
for (var i=1; i < vector.length; i++) {
var temp = vector[i];
var j = i-1;
while (j >= 0 && vector[j] > temp) {
vector[j + 1] = vector[j];
j--;
}
vector[j+1] = temp;
}
[editar] Perl
sub insercion {
my $array = shift; # Recibimos una referencia a un array
my $i; # Índice del elemento a comparar
my $j; # Índice del valor mínimo a encontrar
for ( $i = 1; $i < @$array; $i++ ) {
my $x = $array->[$i]; # Elemento $i-ésimo
# Comparamos este elemento con todos los anteriores,
# hasta que lleguemos al principio de la lista o encontremos
# un elemento que sea menor o igual que él.
for ( $j = $i; $j > 0 and $array->[$j-1] > $x; $j-- ) {
;
}
# Hacemos la inserción del elemento a comparar (posición $i)
en la
# nueva posición encontrada (posición $j), pero sólo si son
distintas
# posiciones.
# El uso de splice (extraer/insertar) permite que la solución
sea mucho
# más rápida que el movimiento de los elementos uno a uno.
splice(@$array, $j, 0, splice(@$array, $i, 1))
if $i != $j;
}
}
[editar] PHP
function insert_sort($arr){
$count = count($arr);
for($i=1; $i<$count; $i++){
$tmp = $arr[$i];
for ($j=$i-1; $j>=0 && $arr[$j] > $tmp; $j--)
$arr[$j+1] = $arr[$j];
$arr[$j] = $tmp;
}
return $arr;
}
[editar] Pascal
13. Procedure InsertionSort(var insertion:Array_integer; array_size:
Integer);
Var
i, j, index : Integer;
Begin
For i := 1 to array_size do
Begin
index := insertion[i];
j := i-1;
While ((j >= 0) AND (insertion[j] > index)) do
Begin
insertion[j+1] := insertion[j];
j := j - 1;
End;
insertion[j+1] := index;
End;
End;
[editar] Python
def insertionSort(numeros): #numeros es una lista
tama = len(numeros) #creamos una variable igual al tamaño de la
lista
i=0
for i in range(tama):
indice = numeros[i]
a = i-1
while (a >= 0 and numeros[a] > indice):
numeros[a+1] = numeros[a]
a = a-1
numeros[a+1] = indice
print numeros #imprime la lista ordenada
[editar] Visual Basic .NET
Private Sub insertionSort(ByVal numbers() As Integer) ' Es una
función,
'debemos pasarle el array de números desde el Sub Main()
Dim i, j, index As Integer
i = 1
Do
index = numbers(i)
j = i - 1
While ((j >= 0) And (numbers(j) > index))
numbers(j + 1) = numbers(j)
j = j - 1
End While
numbers(j + 1) = index
i = i + 1
Loop Until i > (UBound(v))
End Sub
Ordenamiento Shell
14. De Wikipedia, la enciclopedia libre
Saltar a navegación, búsqueda
El ordenamiento Shell (Shell sort en inglés) es un algoritmo de ordenamiento. El
método se denomina Shell en honor de su inventor Donald Shell. Su implementación
original, requiere O(n2
) comparaciones e intercambios en el peor caso. Un cambio
menor presentado en el libro de V. Pratt produce una implementación con un
rendimiento de O(nlog2
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). Aunque es fácil
desarrollar un sentido intuitivo de cómo funciona este algoritmo, es muy difícil analizar
su tiempo de ejecución.
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.
Contenido
[ocultar]
1 Ejemplo
2 Secuencia de espacios
3 Implementaciones
o 3.1 ActionScript
o 3.2 C
o 3.3 C#
o 3.4 Java
o 3.5 Perl
o 3.6 Python
o 3.7 Visual Basic
4 Referencias
5 Enlaces externos
[editar] Ejemplo
Considere un pequeño valor 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
15. valor hacia el otro extremo del vector. El Shell sort 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.
Uno puede visualizar el algoritmo Shell sort de la siguiente manera: coloque la lista en
una tabla y ordene las columnas (usando un ordenamiento por inserción). Repita este
proceso, cada vez con un número menor de columnas más largas. Al final, la tabla tiene
sólo una columna. Mientras que transformar la lista en una tabla hace más fácil
visualizarlo, el algoritmo propiamente hace su ordenamiento en contexto
(incrementando el índice por el tamaño de paso, esto es usando i += tamaño_de_paso
en vez de i++).
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 5, podríamos
visualizar esto dividiendo la lista de números en una tabla con 5 columnas. Esto
quedaría así:
13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10
Entonces ordenamos cada columna, lo que nos da
10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45
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).
El Shell sort lleva este nombre en honor a su inventor, Donald Shell, que lo publicó en
1959. Algunos libros de texto y referencias antiguas le llaman ordenación "Shell-
Metzner" por Marlene Metzner Norton, pero según Metzner, "No tengo nada que ver
con el algoritmo de ordenamiento, y mi nombre nunca debe adjuntarse a éste." [1]
[editar] Secuencia de espacios
La secuencia de espacios es una parte integral del algoritmo Shell sort. Cualquier
secuencia incremental funcionaría siempre que el último elemento sea 1. El algoritmo
comienza realizando un ordenamiento por inserción con espacio, siendo el espacio el
primer número en la secuencia de espacios. Continua para realizar un ordenamiento por
inserción con espacio para cada número en la secuencia, hasta que termina con un
espacio de 1. Cuando el espacio es 1, el ordenamiento por inserción con espacio es
simplemente un ordenamiento por inserción ordinario, garantizando que la lista final
estará ordenada.
16. La secuencia de espacios que fue originalmente sugerida por Donald Shell debía
comenzar con N / 2 y dividir por la mitad el número hasta alcanzar 1. Aunque esta
secuencia proporciona mejoras de rendimiento significativas sobre los algoritmos
cuadráticos como el ordenamiento por inserción, se puede cambiar ligeramente para
disminuir más el tiempo necesario medio y el del peor caso. El libro de texto de Weiss
demuestra que esta secuencia permite un ordenamiento O(n2
) del peor caso, si los datos
están inicialmente en el vector como (pequeño_1, grande_1, pequeño_2, grande_2, ...) -
es decir, la mitad alta de los números están situados, de forma ordenada, en las
posiciones con índice par y la mitad baja de los números están situados de la misma
manera en las posiciones con índice impar.
Quizás la propiedad más crucial del Shell sort es que los elementos permanecen k-
ordenados incluso mientras el espacio disminuye. Se dice que un vector dividido en k
subvectores esta k-ordenado si cada uno de esos subvectores esta ordenado en caso de
considerarlo aislado. Por ejemplo, si una lista fue 5-ordenada y después 3-ordenada, la
lista está ahora no sólo 3-ordenada, sino tanto 5-ordenada como 3-ordenada. Si esto no
fuera cierto, el algoritmo desharía el trabajo que había hecho en iteraciones previas, y no
conseguiría un tiempo de ejecución tan bajo.
Dependiendo de la elección de la secuencia de espacios, Shell sort tiene un tiempo de
ejecución en el peor caso de O(n2
) (usando los incrementos de Shell que comienzan con
1/2 del tamaño del vector y se dividen por 2 cada vez), O(n3 / 2
) (usando los incrementos
de Hibbard de 2k
− 1), O(n4 / 3
) (usando los incrementos de Sedgewick de 9(4i
) − 9(2i
) +
1, o 4i + 1
+ 3(2i
) + 1), o O(nlog2
n), y posiblemente mejores tiempos de ejecución no
comprobados. La existencia de una implementación O(nlogn) en el peor caso del Shell
sort permanece como una pregunta por resolver.
[editar] Implementaciones
El Shell sort se usa comúnmente en lenguajes de programación; esto es una
implementación del algoritmo en C/C++ para ordenar un vector de enteros. La
secuencia de incrementos usada en este ejemplo de código da un tiempo de ejecución
O(n2
) en el peor caso.
[editar] ActionScript
var arrayOriginal:Array = new
Array(2,5,6,8,10,2,3,64,23,76,43,27,75,33,23,45,67,89);
trace("Array desordenado: "+arrayOriginal);
ordenamiento_shell(arrayOriginal,arrayOriginal.length);
function ordenamiento_shell(arrayDesordenado:Array, tamano:uint)
{
var i:uint;
var j:uint;
var incremento:uint;
var temp:uint;
incremento = tamano / 2;
while (incremento>0)
{
for (i=incremento; i<tamano; i++)
{
17. j = i;
temp = arrayDesordenado[i];
while ((j >= incremento) &&
(arrayDesordenado[j-incremento] > temp))
{
arrayDesordenado[j] = arrayDesordenado[j
- incremento];
j = j - incremento;
}
arrayDesordenado[j] = temp;
}
incremento = incremento/2;
}
trace("Array ordenado: "+arrayDesordenado);
}
[editar] C
void shell_sort(int A[], int size)
{
int i, j, incrmnt, temp;
incrmnt = size/2;
while (incrmnt > 0)
{
for (i=incrmnt; i < size; i++)
{
j = i;
temp = A[i];
while ((j >= incrmnt) && (A[j-incrmnt] > temp))
{
A[j] = A[j - incrmnt];
j = j - incrmnt;
}
A[j] = temp;
}
incrmnt /= 2;
}
}
[editar] C#
using System;
public class ShellSorter
{
public void Sort(int [] list)
{
int j,inc;
inc=list.length/2;
while(inc>0)
{
for(int i=inc+1;i<list.length;i++)
{
j=i-inc;
while(j>0)
{
if(list[j] > list[j+inc])
{
Swap(list[j],list[j+inc]);
j=j-inc;
18. }
else
{
j=0;
}
}
}
inc=inc/2;
}
}
}
public class MainClass
{
public static void Main()
{
int[] iArrary=new int[]{1,5,3,6,10,55,9,2,87,12,34,75,33,47};
ShellSorter sh=new ShellSorter();
sh.Sort(iArrary);
for(int m=0;m<=13;m++)
Console.WriteLine("{0}",iArrary[m]);
}
}
[editar] Java
public static void shellSort(int[] a) {
for ( int increment = a.length / 2;
increment > 0;
increment = (increment == 2 ? 1 : (int) Math.round(increment
/ 2.2))) {
for (int i = increment; i < a.length; i++) {
for (int j = i; j >= increment && a[j - increment] > a[j];
j -= increment) {
int temp = a[j];
a[j] = a[j - increment];
a[j - increment] = temp;
}
}
}
}
[editar] Perl
sub shellsort {
my $array = shift; # Recibimos una referencia a un array
my $i; # Índice del elemento a comparar
my $j; # Índice del elemento actual a comparar
my $shell; # Tamaño del incremento
# Calculamos el valor del incremento
for ( $shell = 1; $shell < @$array; $shell = 2 * $shell + 1 ) {
;
}
do {
$shell = int( ( $shell - 1 ) / 2 );
# Para todos los elementos, elegidos con un incremento
19. for ( $i = $shell; $i < @$array; $i++ ) {
for ( $j = $i - $shell;
$j >= 0 && $array->[ $j ] > $array->[ $j + $shell ];
$j -= $shell ) {
# Intercambiamos valores
@$array[ $j, $j + $shell ] = @$array[ $j + $shell, $j
];
}
}
} while $shell > 1;
}
[editar] Python
def shellsort(a):
def new_increment(a):
i = int(len(a) / 2)
yield i
while i<>1:
if i==2:
i = 1
else:
i = int(round(i/2.2))
yield i
for increment in new_increment(a):
for i in range(increment, len(a)):
for j in range(i, increment-1, -increment):
if a[j-increment] < a[j]:
break
a[j],a[j-increment] = a[j - increment],a[j]
return a
[editar] Visual Basic
Sub Shell_Sort(ByRef V) 'debemos pasarle el arreglo(de enteros) desde
el programa principal()
Dim I, Medio, J, Temp As Integer
Dim Ordenado As Boolean
Medio = UBound(V)
While (Medio > 0)
Medio = Medio 2
Do
Ordenado = True
For J = 0 To UBound(V) - Medio ' se asume que el arreglo va de
0 a UBound(V) elementos
I = J + Medio
If V(J) > V(I) Then ' Se intercambian los elementos
Temp = V(J)
V(J) = V(I)
V(I) = Temp
Ordenado = False
End If
Next
Loop Until Ordenado
Wend
End Sub
20. Sub principal()
Dim Arr(99) As Integer
Dim I As Integer
For I = 0 To 99
Arr(I) = Int(Rnd() % 1000) ' Se llena el arreglo con números
menores que 1000
Next I
Call Shell_Sort(Arr)
End Sub
Quicksort
De Wikipedia, la enciclopedia libre
(Redirigido desde Ordenamiento rápido)
Saltar a navegación, búsqueda
Quicksort en acción sobre una lista de números aleatorios. Las líneas horizontales son
valores pivote.
El ordenamiento rápido (quicksort en inglés) es un algoritmo basado en la técnica de
divide y vencerás, que permite, en promedio, ordenar n elementos en un tiempo
proporcional a n log n.
Contenido
[ocultar]
1 Descripción del algoritmo
o 1.1 Demostración
2 Optimización del algoritmo
o 2.1 Técnicas de elección del pivote
o 2.2 Técnicas de reposicionamiento
o 2.3 Transición a otro algoritmo
3 Ejemplo
4 Implementaciones
5 Véase también
6 Referencias
21. [editar] Descripción del algoritmo
El algoritmo fundamental es el siguiente:
Elegir un elemento de la lista de elementos a ordenar, al que llamaremos pivote.
Resituar los demás elementos de la lista a cada lado del pivote, de manera que a
un lado queden todos los menores que él, y al otro los mayores. Los elementos
iguales al pivote pueden ser colocados tanto a su derecha como a su izquierda,
dependiendo de la implementación deseada. En este momento, el pivote ocupa
exactamente el lugar que le corresponderá en la lista ordenada.
La lista queda separada en dos sublistas, una formada por los elementos a la
izquierda del pivote, y otra por los elementos a su derecha.
Repetir este proceso de forma recursiva para cada sublista mientras éstas
contengan más de un elemento. Una vez terminado este proceso todos los
elementos estarán ordenados.
Como se puede suponer, la eficiencia del algoritmo depende de la posición en la que
termine el pivote elegido.
En el mejor caso, el pivote termina en el centro de la lista, dividiéndola en dos
sublistas de igual tamaño. En este caso, el orden de complejidad del algoritmo es
O(n·log n).
En el peor caso, el pivote termina en un extremo de la lista. El orden de
complejidad del algoritmo es entonces de O(n²). El peor caso dependerá de la
implementación del algoritmo, aunque habitualmente ocurre en listas que se
encuentran ordenadas, o casi ordenadas. Pero principalmente depende del pivote,
si por ejemplo el algoritmo implementado toma como pivote siempre el primer
elemento del array, y el array que le pasamos está ordenado, siempre va a
generar a su izquierda un array vacío, lo que es ineficiente.
En el caso promedio, el orden es O(n·log n).
No es extraño, pues, que la mayoría de optimizaciones que se aplican al algoritmo se
centren en la elección del pivote.
[editar] Demostración
Podríamos probar el orden de ejecución en el mejor caso de la siguiente manera:
Vamos a suponer que el número total de elementos a ordenar es potencia de dos, es
decir, n = 2k
. de aquí podemos ver que k = log2(n), donde k es el número de divisiones
que realizará el algoritmo.
En la primera fase del algoritmo habrán n comparaciones, en la segunda fase el
algoritmo creará dos sublistas aproximadamente de tamaño n/2. El número total de
comparaciones de estas dos sublistas es: 2(n/2) = n. En la tercera fase el algoritmo
22. procesará 4 sublistas más, por tanto el número total de comparaciones en esta fase es
4(n/4) = n.
En conclusión, el número total de comparaciones que hace el algoritmo es:
n + n + n + ..... + n = kn, donde k = log2(n), por tanto el tiempo de ejecución del
algoritmo en el mejor caso es O(n.log2n)
[editar] Optimización del algoritmo
Cabe destacar que de usarse en su versión recursiva las siguientes optimizaciones y sus
desventajas no se ven vistas en el tiempo de ejecución del mismo manteniéndose, así el
tiempo de ejecución planteado en un principio.
[editar] Técnicas de elección del pivote
El algoritmo básico del metodo Quicksort consiste en tomar cualquier elemento de la
lista al cual denominaremos como pivote, dependiendo de la partición en que se elija, el
algoritmo será más o menos eficiente.
Tomar un elemento cualquiera como pivote tiene la ventaja de no requerir
ningún cálculo adicional, lo cual lo hace bastante rápido. Sin embargo, esta
elección «a ciegas» siempre provoca que el algoritmo tenga un orden de O(n²)
para ciertas permutaciones de los elementos en la lista.
Otra opción puede ser recorrer la lista para saber de antemano qué elemento
ocupará la posición central de la lista, para elegirlo como pivote. Esto puede
hacerse en O(n) y asegura que hasta en el peor de los casos, el algoritmo sea
O(n·log n). No obstante, el cálculo adicional rebaja bastante la eficiencia del
algoritmo en el caso promedio.
La opción a medio camino es tomar tres elementos de la lista - por ejemplo, el
primero, el segundo, y el último - y compararlos, eligiendo el valor del medio
como pivote.
[editar] Técnicas de reposicionamiento
Una idea preliminar para ubicar el pivote en su posición final sería contar la cantidad de
elementos menores que él, y colocarlo un lugar más arriba, moviendo luego todos esos
elementos menores que él a su izquierda, para que pueda aplicarse la recursividad.
Existe, no obstante, un procedimiento mucho más efectivo. Se utilizan dos índices: i, al
que llamaremos índice izquierdo, y j, al que llamaremos índice derecho. El algoritmo es
el siguiente:
Recorrer la lista simultáneamente con i y j: por la izquierda con i (desde el
primer elemento), y por la derecha con j (desde el último elemento).
Cuando lista[i] sea mayor que el pivote y lista[j] sea menor, se intercambian los
elementos en esas posiciones.
Repetir esto hasta que se crucen los índices.
23. El punto en que se cruzan los índices es la posición adecuada para colocar el
pivote, porque sabemos que a un lado los elementos son todos menores y al otro
son todos mayores (o habrían sido intercambiados).
[editar] Transición a otro algoritmo
Como se comentó antes, el algoritmo quicksort ofrece un orden de ejecución O(n²) para
ciertas permutaciones "críticas" de los elementos de la lista, que siempre surgen cuando
se elige el pivote «a ciegas». La permutación concreta depende del pivote elegido, pero
suele corresponder a secuencias ordenadas. Se tiene que la probabilidad de encontrarse
con una de estas secuencias es inversamente proporcional a su tamaño.
Los últimos pases de quicksort son numerosos y ordenan cantidades pequeña de
elementos. Un porcentaje medianamente alto de ellos estarán dispuestos de una
manera similar al peor caso del algoritmo, volviendo a éste ineficiente. Una
solución a este problema consiste en ordenar las secuencias pequeñas usando
otro algoritmo. Habitualmente se aplica el algoritmo de inserción para
secuencias de tamaño menores de 8-15 elementos.
Pese a que en secuencias largas de elementos la probabilidad de hallarse con una
configuración de elementos "crítica" es muy baja, esto no evita que sigan
apareciendo (a veces, de manera intencionada). El algoritmo introsort es una
extensión del algoritmo quicksort que resuelve este problema utilizando heapsort
en vez de quicksort cuando el número de recursiones excede al esperado.
Parámetros:
o Se debe llamar a la función Quicksort desde donde quiera ejecutarse
o Ésta llamará a colocar pivote para encontrar el valor del mismo
o Se ejecutará el algoritmo Quicksort de forma recursiva a ambos lados del
pivote
int colocar(int *v, int b, int t)
{
int i;
int pivote, valor_pivote;
int temp;
pivote = b;
valor_pivote = v[pivote];
for (i=b+1; i<=t; i++){
if (v[i] < valor_pivote){
pivote++;
temp=v[i];
v[i]=v[pivote];
v[pivote]=temp;
}
}
temp=v[b];
v[b]=v[pivote];
v[pivote]=temp;
return pivote;
}
24. void Quicksort(int* v, int b, int t)
{
int pivote;
if(b < t){
pivote=colocar(v, b, t);
Quicksort(v, b, pivote-1);
Quicksort(v, pivote+1, t);
}
}
Nota: Los tres parámetros de la llamada inicial a Quicksort serán array[0], 0,
numero_elementos -1, es decir, si es un array de 6 elementos array[0], 0, 5
[editar] Ejemplo
En el siguiente ejemplo se marcan el pivote y los índices i y j con las letras p, i y j
respectivamente.
Comenzamos con la lista completa. El elemento pivote será el 4:
5 - 3 - 7 - 6 - 2 - 1 - 4
p
Comparamos con el 5 por la izquierda y el 1 por la derecha.
5 - 3 - 7 - 6 - 2 - 1 - 4
i j p
5 es mayor que 4 y 1 es menor. Intercambiamos:
1 - 3 - 7 - 6 - 2 - 5 - 4
i j p
Avanzamos por la izquierda y la derecha:
1 - 3 - 7 - 6 - 2 - 5 - 4
i j p
3 es menor que 4: avanzamos por la izquierda. 2 es menor que 4: nos mantenemos ahí.
1 - 3 - 7 - 6 - 2 - 5 - 4
i j p
7 es mayor que 4 y 2 es menor: intercambiamos.
25. 1 - 3 - 2 - 6 - 7 - 5 - 4
i j p
Avanzamos por ambos lados:
1 - 3 - 2 - 6 - 7 - 5 - 4
iyj p
En este momento termina el ciclo principal, porque los índices se cruzaron. Ahora
intercambiamos lista[i] con lista[sup] (pasos 16-18):
1 - 3 - 2 - 4 - 7 - 5 - 6
p
Aplicamos recursivamente a la sublista de la izquierda (índices 0 - 2). Tenemos lo
siguiente:
1 - 3 - 2
1 es menor que 2: avanzamos por la izquierda. 3 es mayor: avanzamos por la derecha.
Como se intercambiaron los índices termina el ciclo. Se intercambia lista[i] con
lista[sup]:
1 - 2 - 3
El mismo procedimiento se aplicará a la otra sublista. Al finalizar y unir todas las
sublistas queda la lista inicial ordenada en forma ascendente.
1 - 2 - 3 - 4 - 5 - 6 - 7
[editar] Implementaciones
El algoritmo de ordenamiento rápido (Quicksort) en:
Pseudocódigo
function quicksort(array)
var list, less, greater
if length(array) ≤ 1
return array
seleccionar y eliminar un valor pivote pivot en el array
for each x in array
if x < pivot then añadir x a less
else añadir x a greater
return concadenar(quicksort(less), pivot, quicksort(greater))
C
26. int pivotar (int v[], int izq, int der)
{
int posicionPivote = (izq + der) / 2;
int valorPivote = v[posicionPivote];
int indiceAlmacenamiento;
swap (v, posicionPivote, der);//Se situal pivote al final del
vector
indiceAlmacenamiento = izq;
for (int indiceLectura = izq; indiceLectura < der;
indiceLectura++){
if (v[indiceLectura] <= valorPivote){
swap (v, indiceLectura, indiceAlmacenamiento);
indiceAlmacenamiento++;
}
}
swap (v, indiceAlmacenamiento, der); //Se coloca el pivote en su
lugar.
return indiceAlmacenamiento;
}
void quicksort (int v[], int izq, int der)
{
int pivote;
if(izq < der){
pivote = pivotar (v, izq, der); //Esta operación coloca el
pivote en su lugar.
quicksort(v, izq, pivote-1);
quicksort(v, pivote+1, der);
}
}
Otra en C. Trabaja sólo con punteros (no índices). Ordena enteros de menor a mayor.
Pivot: El primero del vector.
void quicksort(int* izq, int* der) /*Se llama con:
quicksort(&vector[0],&vector[n-1]);*/
{
if(der<izq) return;
int pivot=*izq;
int* ult=der;
int* pri=izq;
while(izq<der)
{
while(*izq<=pivot && izq<der+1) izq++;
while(*der>pivot && der>izq-1) der--;
if(izq<der) swap(izq,der);
}
swap(pri,der);
quicksort(pri,der-1);
quicksort(der+1,ult);
}
void swap(int* a, int* b)
{
int temp=*a;
*a=*b;
27. *b=temp;
}
Java
//Recibe un vector de enteros y el índice del primer y último elemento
válido del mismo
void ordenarQuicksort(int[] vector, int primero, int ultimo){
int i=primero, j=ultimo;
int pivote=vector[(primero + ultimo) / 2];
int auxiliar;
do{
while(vector[i]<pivote) i++;
while(vector[j]>pivote) j--;
if (i<=j){
auxiliar=vector[j];
vector[j]=vector[i];
vector[i]=auxiliar;
i++;
j--;
}
} while (i<=j);
if(primero<j) ordenarQuicksort(vector,primero, j);
if(ultimo>i) ordenarQuicksort(vector,i, ultimo);
}
C#
void Quicksort(int[] v, int prim, int ult)
{
if (prim < ult)
{
/* Selecciona un elemento del vector y coloca los
menores
que él a su izquierda y los mayores a su derecha */
int p = Pivote(v, prim, ult, ult);
/* Repite el proceso para cada una de las
particiones generadas en el paso anterior */
Quicksort(v, prim, p - 1);
Quicksort(v, p + 1, ult);
}
}
/* Implementación no clásica de la función Pivote. En lugar de
recorrer el vector simultáneamente desde ambos extremos hasta el
cruce de índices, se recorre desde el comienzo hasta el final */
int Pivote(int[] v, int prim, int ult, int piv)
{
int p = v[piv];
int j = prim;
// Mueve el pivote a la última posición del vector
Intercambia(v, piv, ult);
28. /* Recorre el vector moviendo los elementos menores
o iguales que el pivote al comienzo del mismo */
for (int i = prim; i < ult; i++)
{
if (v[i] <= p)
{
Intercambia(v, i, j);
j++;
}
}
// Mueve el pivote a la posición que le corresponde
Intercambia(v, j, ult);
return j;
}
void Intercambia(int[] v, int a, int b)
{
if (a != b)
{
int tmp = v[a];
v[a] = v[b];
v[b] = tmp;
}
}
Python
def quicksort(datos, primero, ultimo):
i = primero
j = ultimo
pivote = (datos[primero] + datos[ultimo]) / 2
while i < j:
while datos[i] < pivote:
i+=1
while datos[j] > pivote:
j-=1
if i <= j:
aux = datos[i]
datos[i] = datos[j]
datos[j] = aux
i+=1
j-=1
if primero < j:
datos = quicksort(datos, primero, j)
if ultimo > i:
datos = quicksort(datos, i, ultimo)
return datos
Otra en Python
def qsort(list):
try:
x=list.pop()
except:
return []