Algoritmos de ordenamiento interno

Anuncio
En computación y matemáticas un algoritmo de ordenamiento recursivo es un algoritmo
que pone elementos de una lista o un vector en una secuencia dada por una relación de
orden, es decir, el resultado de salida ha de ser una permutación —o reordenamiento— de
la entrada que satisfaga la relación de orden dada. Las relaciones de orden más usadas son
el orden numérico y el orden lexicográfico. Ordenamientos eficientes son importantes para
optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas
ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica y
para generar resultados legibles por humanos.
Desde los comienzos de la computación, el problema del ordenamiento ha atraído gran
cantidad de investigación, tal vez debido a la complejidad de resolverlo eficientemente a
pesar de su planteamiento simple y familiar. Por ejemplo, BubbleSort fue analizado desde
1956.1 Aunque muchos puedan considerarlo un problema resuelto, nuevos y útiles
algoritmos de ordenamiento se siguen inventado hasta el día de hoy (por ejemplo, el
ordenamiento de biblioteca se publicó por primera vez en el 2004). Los algoritmos de
ordenamiento son comunes en las clases introductorias a la computación, donde la
abundancia de algoritmos para el problema proporciona una gentil introducción a la
variedad de conceptos núcleo de los algoritmos, como notación de O mayúscula, algoritmos
divide y vencerás, estructuras de datos, análisis de los casos peor, mejor, y promedio, y
límites inferiores.
Clasificación
Los algoritmos de ordenamiento se pueden clasificar de las siguientes maneras:

La más común es clasificar según el lugar donde se realice la ordenación
o Algoritmos de ordenamiento interno: en la memoria del ordenador.
o Algoritmos de ordenamiento externo: en un lugar externo como un disco
duro.

Por el tiempo que tardan en realizar la ordenación, dadas entradas ya ordenadas o
inversamente ordenadas:
o Algoritmos de ordenación natural: Tarda lo mínimo posible cuando la
entrada está ordenada.
o Algoritmos de ordenación no natural: Tarda lo mínimo posible cuando la
entrada está inversamente ordenada.

Por estabilidad: un ordenamiento estable mantiene el orden relativo que tenían
originalmente los elementos con claves iguales. Por ejemplo, si una lista ordenada
por fecha se reordena en orden alfabético con un algoritmo estable, todos los
elementos cuya clave alfabética sea la misma quedarán en orden de fecha. Otro caso
sería cuando no interesan las mayúsculas y minúsculas, pero se quiere que si una
clave aBC estaba antes que AbC, en el resultado ambas claves aparezcan juntas y en
el orden original: aBC, AbC. Cuando los elementos son indistinguibles (porque
cada elemento se ordena por la clave completa) la estabilidad no interesa. Los
algoritmos de ordenamiento que no son estables se pueden implementar para que sí
lo sean. Una manera de hacer esto es modificar artificialmente la clave de
ordenamiento de modo que la posición original en la lista participe del
ordenamiento en caso de coincidencia.
Los algoritmos se distinguen por las siguientes características:


Complejidad computacional (peor caso, caso promedio y mejor caso) en términos
de n, el tamaño de la lista o arreglo. Para esto se usa el concepto de orden de una
función y se usa la notación O(n). El mejor comportamiento para ordenar (si no se
aprovecha la estructura de las claves) es O(n log n). Los algoritmos más simples son
cuadráticos, es decir O(n²). Los algoritmos que aprovechan la estructura de las
claves de ordenamiento (p. ej. bucket sort) pueden ordenar en O(kn) donde k es el
tamaño del espacio de claves. Como dicho tamaño es conocido a priori, se puede
decir que estos algoritmos tienen un desempeño lineal, es decir O(n).
Uso de memoria y otros recursos computacionales. También se usa la notación
O(n).
Estabilidad
Los algoritmos de ordenamiento estable mantienen un relativo preorden total. Esto significa
que un algoritmo es estable solo cuando hay dos registros R y S con la misma clave y con R
apareciendo antes que S en la lista original.
Cuando elementos iguales (indistinguibles entre sí), como números enteros, o más
generalmente, cualquier tipo de dato en donde el elemento entero es la clave, la estabilidad
no es un problema. De todas formas, se asume que los siguientes pares de números están
por ser ordenados por su primer componente:
(4, 1)
(3, 7)
(3, 1)
(5, 6)
En este caso, dos resultados diferentes son posibles, uno de los cuales mantiene un orden
relativo de registros con claves iguales, y una en la que no:
(3, 7)
(3, 1)
(3, 1)
(3, 7)
(4, 1)
(4, 1)
(5, 6)
(5, 6)
(orden mantenido)
(orden cambiado)
Los algoritmos de ordenamiento inestable pueden cambiar el orden relativo de registros con
claves iguales, pero los algoritmos estables nunca lo hacen. Los algoritmos inestables
pueden ser implementados especialmente para ser estables. Una forma de hacerlo es
extender artificialmente el cotejamiento de claves, para que las comparaciones entre dos
objetos con claves iguales sean decididas usando el orden de las entradas original. Recordar
este orden entre dos objetos con claves iguales es una solución poco práctica, ya que
generalmente acarrea tener almacenamiento adicional.
Ordenar según una clave primaria, secundaria, terciara, etc., puede ser realizado utilizando
cualquier método de ordenamiento, tomando todas las claves en consideración (en otras
palabras, usando una sola clave compuesta). Si un método de ordenamiento es estable, es
posible ordenar múltiples ítems, cada vez con una clave distinta. En este caso, las claves
necesitan estar aplicadas en orden de aumentar la prioridad.
Ejemplo: ordenar pares de números, usando ambos valores
(4, 1)
(4, 1)
valor)
(3, 1)
valor)
(3, 7)
(3, 1)
(3, 1)
(4, 6)
(4, 6) (original)
(3, 7) (después de ser ordenado por el segundo
(3, 7)
(4, 1)
(4, 6) (después de ser ordenado por el primer
(3, 1)
(4, 1)
(4, 6) (después de ser ordenado por el primer
(4, 1)
(4, 6)
(3, 7) (después de ser ordenando por el segundo
Por otro lado:
(3, 7)
valor)
(3, 1)
valor,
el orden por el primer valor es
perturbado)
Lista de algoritmos de ordenamiento
Algunos algoritmos de ordenamiento agrupados según estabilidad tomando en cuenta la
complejidad computacional.
Estables
Nombre traducido
Nombre
original
Complejidad
Memoria Método
Ordenamiento de burbuja Bubblesort
O(n²)
O(1)
Intercambio
Ordenamiento de burbuja
Cocktail sort
bidireccional
O(n²)
O(1)
Intercambio
Ordenamiento por
inserción
Insertion sort
O(n²)
O(1)
Inserción
Ordenamiento por
casilleros
Bucket sort
O(n)
O(n)
No
comparativo
Ordenamiento por
cuentas
Counting sort
O(n+k)
O(n+k)
No
comparativo
Ordenamiento por
mezcla
Merge sort
O(n log n)
O(n)
Mezcla
Ordenamiento con árbol
Binary tree sort O(n log n)
binario
O(n)
Inserción
Ordenamiento Radix
Pigeonhole sort O(n+k)
O(k)
Radix sort
O(n)
O(nk)
No
comparativo
Distribution
sort
O(n³) versión
recursiva
Gnome sort
O(n²)
O(n²)
Inestables
Nombre traducido
Nombre
original
Complejidad
Memoria Método
Ordenamiento Shell
Shell sort
O(n1.25)
O(1)
Inserción
Comb sort
O(n log n)
O(1)
Intercambio
Ordenamiento por
selección
Selection sort
O(n²)
O(1)
Selección
Ordenamiento por
montículos
Heapsort
O(n log n)
O(1)
Selección
Smoothsort
O(n log n)
O(1)
Selección
Quicksort
Promedio: O(n log n),
O(log n) Partición
peor caso: O(n²)
Ordenamiento rápido
Promedio: O(n u),
Several Unique peor caso: O(n²);
Sort
u=n; u = número único
de registros
Nombre traducido
Cuestionables, imprácticos
Nombre
Complejidad
original
Bogosort
O(n × n!), peor: no
termina
O(n), excepto en
Pancake sorting máquinas de Von
Neumann
Randomsort
Memoria Método
Para todos los algoritmos se cuenta con la siguiente estructura de datos
Const MAX = 100
A = arreglo[1..MAX] de enteros
Variable N:entero
ORDENAMIENTO DIRECTO. MÉTODO DE BURBUJA.
Ordena los elementos del arreglo usando el método de burbuja. Transporta en cada pasada
el elemento más pequeño a la parte izquierda del arreglo A de N elementos.
Burbuja1(A,N)
Inicio
Declarar i,j,aux:entero
Para i 2 hasta N haga
Para j  i hasta 2 inc (–1) haga
Si (A[j-1]>A[j]) entonces
Aux  A[j-1]
A[j-1]  A[j]
A[j]  aux
Fin si
Fin para
Fin para
Fin
ORDENAMIENTO DIRECTO. METODO DE LA BURBUJA. CONTRARIO AL
ANTERIOR.
La lógica de este algoritmo cambia con el anterior, en el hecho de que en cada pasada se
lleva el valor mas grande a hacia la parte derecha del arreglo A de N elementos.
Burbuja2(A,N)
Inicio
Declarar i,j,aux:entero
Para i 1 hasta N-1 haga
Para j  1 hasta N-i haga
Si (A[j]>A[j+1]) entonces
Aux  A[j]
A[j]  A[j+1]
A[j+1]  aux
Fin si
Fin para
Fin para
Fin
ORDENAMIENTO DIRECTO CON SEÑAL
Algoritmo que usa el principio de ordenamiento del método de la burbuja, usando una señal
para saber si en cada pasada hubo intercambios. Arreglo A de N elementos enteros.
Burbujaconseñal(A, N)
Inicio
Declarar i,j,aux:entero
Declarar band:booleano
i1
Band  FALSO
Mientras Que (i<= N-1) y (band = FALSO) haga
Band  VERDADERO
Para j  1 hasta N-i haga
Si (A[j]>A[j+1]) entonces
Aux  A[j]
A[j]  A[j+1]
A[j+1]  aux
Band  FALSO
Fin si
Fin para
Fin MQ
Fin
ORDENAMIENTO POR EL MÉTODO DE LA SACUDIDA (SHAKER SORT)
Este método es una optimización del método de la burbuja. Consiste en mezclar las dos
formas como se puede realizar el método de ordenamiento directo. En cada pasada hay dos
etapas, el la primera etapa se trasladan los elementos más pequeños hacia la izquierda
almacenando en una variable el último elemento intercambiado. En la segunda etapa, se
trasladan los elementos más grandes hacia la parte derecha del arreglo almacenando en otra
variable la posición del último elemento intercambiado.
Algoritmo que ordena los elementos del arreglo A, de N elementos, por el método de la
sacudida.
Shakersort(A,N)
Inicio
Declarar i, izq, der, k, aux: entero
izq  2
der N
kN
Repetir
Para i  der hasta izq inc (-1) haga
Si (A[i-1]>A[i]) entonces
Aux  A[i-1]
A[i-1]  A[i]
A[i]  aux
ki
Fin si
Fin para
Izq  k + 1
Para i  izq hasta der haga
Si (A[i-1] > A[i]) entonces
Aux  A[i-1]
A[i-1]  A[i]
A[i]  Aux
ki
Fin si
Fin para
Der  k-1
Hasta que izq>der
Fin
METODO DE ORDENAMIENTO POR INSERCIÓN DIRECTA
El objetivo de este método es copiar la forma como los jugadores de cartas ordenan la
baraja en una mano. El objetivo de este método es insertar un elemento en la parte
izquierda del arreglo que ya se encuentra ordenada. El proceso se repite desde el segundo
hasta el n-esimo elemento.
Algoritmo que ordena los elementos del arreglo usando el método de inserción directa.
Arreglo A de N elementos.
insercion(A,N)
Inicio
Declarar i, aux, k: entero
Para i  2 hasta N haga
Aux  A[i]
k  i-1
Mientras Que ((k>=1) y (aux<A[k])) haga
A[k+1]  A[k]
k  k -1
Fin MQ
A[k+1]  aux
Fin para
Fin
ORDENAMIENTO POR MÉTODO DE INSERCIÓN BINARIA
Es una mejora del método de inserción directa, ya que se hace una búsqueda binaria en
lugar de una búsqueda secuencial para insertar el elemento a la izquierda del arreglo, que ya
se encuentra ordenado. Y el proceso se repite hasta el n-esimo elemento.
Algoritmo que ordena los elementos del arreglo usando el método de inserción binara.
Arreglo A de N elementos.
insercionbinaria(A,N)
Inicio
Declarar i, aux, izq, der, m, j: entero
Para i  2 hasta N haga
Aux  A[i]
Izq  1
Der  i-1
Mientras Que (izq<=der) haga
m  parteentera((izq+der)/2)
Si (aux <= A[m]) entonces
Der  m-1
Sino
Izq  m+1
Fin si
Fin MQ
j  i-1
Mientras Que (j>=izq) haga
A[j+1]  A[j]
j  j-1
Fin MQ
A[izq]  aux
Fin para
Fin
ORDENAMIENTO POR SELECCIÓN DIRECTA
La idea de este algoritmo es buscar el menor elemento del arreglo y colocarlo en la primera
posición, luego se busca el segundo elemento más pequeño del arreglo y se coloca en la
segunda posición y así. El algoritmo se basa en:
1. Seleccionar el menor elemento del arreglo.
2. Intercambiar dicho elemento con el primero.
3. Repetir los pasos anteriores con los (n-1), (n-2)... elementos y así sucesivamente
hasta que solo quede el elemento mayor.
Algoritmo que ordena los elementos de un arreglo usando el método de selección directa. A
arreglo de N elementos.
seleccion(A,N)
Inicio
Declarar i, menor, k, j: entero
Para i  1 hasta N-1 haga
Menor  A[i]
ki
Para j  i+1 hasta N haga
Si (A[j]<menor) entonces
Menor  A[j]
kj
Fin si
Fin para
A[k]  A[i]
A[i]  menor
Fin para
Fin
COMPARACIÓN DE LOS MÉTODOS DIRECTOS DE ORDENAMIENTO
Método
item
Ordenada
Desordenada
Orden Inverso
Intercambio
Directo
Inserción
Directa
Selección
Directa
comp.
Mov
0
comp.
Mov
0
comp.
Mov
ORDENAMIENTO CON EL MÉTODO DE SHELL (INSERCIÓN CON
INCREMENTOS DECRECIENTES)
Este algoritmo compara cada elemento del arreglo para su ubicación correcta, con los
elementos que se encuentran en la parte izquierda del mismo. Este método propone que las
comparaciones entre los elementos se efectúen con saltos de mayor tamaño, pero con
incrementos decrecientes.
Algoritmo que ordena los elementos de un arreglo usando el método de shell. A arreglo de
N elementos.
shell(A,N)
Inicio
Declarar int, i, aux: entero
Declarar band: booleano
Int  N+i
Mientras Que (int>1) haga
int  parteentera(int/2)
band  VERDADERO
Mientras Que (band=VERDADERO) haga
Band  FALSO
i1
Mientras Que ((I+int)<=N) haga
Si (A[i]>A[i+int]) entonces
aux  A[i]
A[i]  A[i+int]
A[i+int]  aux
Band  VERDADERO
Fin si
i  i+1
Fin MQ
Fin MQ
Fin MQ
Fin
ORDENAMIENTO POR EL MÉTODO DE QUICKSORT (MÉTODO RÁPIDO DE
ORDENACIÓN POR PARTICIÓN)
Este algoritmo es el mas eficiente y veloz de los métodos de ordenación interna. La idea
central del algoritmo es:
1. Se toma un elemento X de una posición cualquiera del arreglo
2. Se trata de ubicar a X en la posición de correcta del arreglo, de tal forma que todos
los elementos que se encuentran a su izquierda sean menores o iguales a X y todos
los elementos que se encuentran a su derecha sean mayores o iguales a X.
3. Se repiten los pasos anteriores, pero con los conjuntos de datos que se encuentran a
la izquierda y a la derecha de la posición correcta de X en el arreglo.
4. El proceso termina cuando todos los elementos se encuentran en su posición
correcta en el arreglo.
El paso 3 se puede hacer de forma iterativa o recursiva. En este ejemplo, se hará de forma
iterativa, dejando el método recursivo para más adelante en el curso.
Se necesitan dos algoritmos. Quicksortitera y reduceitera.
Algoritmo que ordena los elementos de un arreglo A de N elementos, usando el método
Quicksort iterativo.
Quicksortitera(A, N)
Inicio
Declarar top, ini, fin, pos: entero
Pilamayor: Arreglo[1..MAX] de entero
Pilamenor: Arreglo[1..MAX] de entero
Top  1
Pilamenor[top]  1
Pilamayor[top]  N
Mientras Que (top>0) haga
Ini  pilamenor[top]
Fin  pilamayor[top]
Top  top-1
Pos  Reduceitera(ini, fin)
Si (ini<(pos-1)) entonces
Top  top+1
Pilamenor[top]  ini
Pilamayor[top]  pos-1
Fin si
Si (fin>(pos+1)) entonces
Top  top+1
Pilamenor[top]  pos+1
Pilamayor[top]  fin
Fin si
Fin MQ
Fin
Reduceitera(INI, FIN)
/* INI y FIN representa las posiciones de los extremos izquierdo y
derecho respectivamente del conjunto de elementos a evaluar. En POS es
una variable donde se almacenará el resultado de este algoritmo */
Inicio
Declarar izq, der, aux, pos: entero
Declarar band: booleano
Izq  ini
Der  fin
Pos  ini
Band  VERDADERO
Mientras Que (band=VERDADERO) haga
Mientras Que ((A[pos]<=A[der]) y (pos<>der)) haga
der  der-1
Fin MQ
Si (Pos=der) entonces
Band  FALSO
Sino
Aux  A[pos]
A[pos]  A[der]
A[der]  aux
Pos  der
Mientras Que ((A[pos]>=A[izq])y(pos<>izq)) haga
Izq  izq+1
Fin MQ
Si (pos=izq) entonces
Band  Falso
Sino
Aux  A[pos]
A[pos]  A[izq]
A[izq]  aux
Pos  izq
Fin si
Fin si
Fin MQ
Retornar Pos
Fin
Descargar