Estructuras de datos dinámicas/Algoritmos de ordenamiento
Un algoritmo de ordenamiento recibe como entrada una secuencia de elementos, y devuelve una secuencia con los mismos elementos, en la cual el orden relativo de cada elemento respecto de los demás respeta un criterio dado.
Quicksort
[editar]Quicksort es un algoritmo de ordenamiento que utiliza la técnica 'divide y vencerás'. Consiste en dividir la secuencia a ser ordenada en dos partes, de tal manera que cada uno de los elementos de una de las partes sea mayor o igual a todos los elementos de la segunda parte. Cada una de las partes se divide y se le aplica a su vez este procedimiento recursivamente, hasta llegar a las secuencias unitarias. Al finalizar este procedimiento, la secuencia completa queda ordenada.
Algoritmo
[editar]- Elegir un elemento de la secuencia, llamado pivote.
- Reordenar la secuencia de tal manera que los elementos menores que el pivote aparezcan primero, y los mayores después (el orden de los elementos iguales al pivote no importa).
- Ordenar recursivamente las subsecuencias.
El caso base de esta recursión son las secuencias de un elemento.
El algoritmo se puede expresar de la siguiente forma:
public static Collection quickSort(Collection secuencia)
{
Collection salida, menores, mayores, iguales;
if(secuencia.size() == 1) return;
Iterator iteradorSecuencia = secuencia.iterator();
Comparable pivote = obtenerPivote(secuencia);
while (iteradorSecuencia.hasNext())
{
Comparable elementoActual=(Comparable) iteradorSecuencia.next();
if(pivote.compareTo(elementoActual)<0)
mayores.add(elementoActual);
else if (pivote.compareTo(elementoActual)>0)
menores.add(elementoActual);
else
iguales.add(elementoActual);
}
mayores = quickSort(mayores);
menores = quickSort(menores);
salida.addAll(menores);
salida.addAll(iguales);
salida.addAll(mayores);
return salida;
}
Versión de ordenamiento sin espacio de almacenamiento adicional
[editar]La desventaja de la versión precedente es que requiere un almacenamiento extra de . Esto puede evitarse ordenando sobre una misma secuencia:
public static void quickSort(List secuencia, int indiceInferior, int indiceSuperior)
{
int i=indiceInferior, j = indiceSuperior;
if(indiceInferior == indiceSuperior) return;
Comparable pivote = obtenerPivote(secuencia);
for(;i!=j;)
{
for(;((Comparable)secuencia.get(i)).compareTo(pivote)<0;i++);
for(;((Comparable)secuencia.get(j)).compareTo(pivote)<0;j--);
intercambiar(secuencia,i,j);
i++;
j++;
}
quickSort(secuencia, indiceInferior, i);
quickSort(secuencia, i+1, indiceSuperior);
}
public static List quickSort(List secuencia)
{
quickSort(secuencia,0,secuencia.size());
return secuencia;
}
Análisis
[editar]En el mejor de los casos, en cada paso se dividirá la secuencia en dos partes, de manera que la profundidad del árbol de llamadas iterativas será , y como la cantidad de elementos a ser recorridos en cada nivel del árbol es , el orden de la complejidad del algoritmo será .
En el peor caso, en cada paso se produce una partición completamente desbalanceada, es decir, queda un solo elemento de un lado, y el resto del otro lado, con lo que las iteraciones seguirán la siguientes reglas:
- En el paso número se debe iterar sobre elementos.
- Deberán realizarse pasos.
Esto requerirá iteraciones: el orden de la complejidad del algoritmo será .
Como para una distribución uniforme de los datos, el caso se asemejará mucho más al primero, se dice que el orden de la complejidad promedio del algoritmo es .