Al igual que Merge Sort, QuickSort es un algoritmo Divide and Conquer. Selecciona un elemento como pivote y divide la matriz dada alrededor del pivote elegido. Hay muchas versiones diferentes de quickSort que eligen pivotar de diferentes maneras.
- Elija siempre el primer elemento como pivote.
- Elija siempre el último elemento como pivote (implementado a continuación)
- Elija un elemento aleatorio como pivote.
- Elija mediana como pivote.
El proceso clave en quickSort es la partición (). El objetivo de las particiones es, dado una matriz y un elemento x de la matriz como pivote, poner x en su posición correcta en la matriz ordenada y poner todos los elementos más pequeños (menores que x) antes de x, y poner todos los elementos mayores (mayores que x) después X. Todo esto debe hacerse en tiempo lineal.
Pseudo código para la función recursiva QuickSort:
Algoritmo de partición
Puede haber muchas formas de realizar una partición, el siguiente pseudocódigo adopta el método dado en el libro CLRS. La lógica es simple, comenzamos desde el elemento más a la izquierda y hacemos un seguimiento del índice de elementos más pequeños (o iguales a) como i. Mientras atravesamos, si encontramos un elemento más pequeño, intercambiamos el elemento actual con arr. De lo contrario, ignoramos el elemento actual.
Pseudo código para la partición ()
Ilustración de la partición ():
Implementación:
A continuación se muestran las implementaciones de QuickSort:
Resultado:
Sorted array:1 5 7 8 9 10
Análisis de QuickSort
El tiempo que tarda QuickSort en general se puede escribir de la siguiente manera.
T(n) = T(k) + T(n-k-1) + (n)
Los dos primeros términos son para dos llamadas recursivas, el último término es para el proceso de partición. k es el número de elementos que son más pequeños que pivote.
El tiempo que tarda QuickSort depende de la matriz de entrada y la estrategia de partición. A continuación se muestran tres casos.
Peor caso: El peor caso ocurre cuando el proceso de partición siempre elige el elemento más grande o más pequeño como pivote. Si consideramos la estrategia de partición anterior donde el último elemento siempre se elige como pivote, el peor de los casos ocurriría cuando la matriz ya está ordenada en orden creciente o decreciente. Lo siguiente es la recurrencia para el peor de los casos.
T(n) = T(0) + T(n-1) + (n)which is equivalent to T(n) = T(n-1) + (n)
La solución de la recurrencia anterior es (n2).
Mejor caso: El mejor caso ocurre cuando el proceso de partición siempre elige el elemento intermedio como pivote. A continuación se muestra la recurrencia en el mejor de los casos.
T(n) = 2T(n/2) + (n)
La solución de la recurrencia anterior es (nLogn). Se puede resolver usando el caso 2 del Teorema maestro.
Caso promedio:
Para hacer un análisis de caso promedio, debemos considerar todas las posibles permutaciones de la matriz y calcular el tiempo que toma cada permutación que no parece fácil.
Podemos tener una idea del caso promedio considerando el caso en el que la partición coloca elementos O (n / 9) en un conjunto y elementos O (9n / 10) en otro conjunto. A continuación se muestra la recurrencia para este caso.
T(n) = T(n/9) + T(9n/10) + (n)
La solución de la recurrencia anterior también es O (nLogn)
Aunque la complejidad temporal del peor caso de QuickSort es O (n2) que es más que muchos otros algoritmos de clasificación como Merge Sort y Heap Sort, QuickSort es más rápido en la práctica, porque su bucle interno se puede implementar de manera eficiente en la mayoría de las arquitecturas y en la mayoría de los datos del mundo real. QuickSort se puede implementar de diferentes maneras cambiando la elección del pivote, de modo que el peor de los casos rara vez ocurre para un tipo de datos determinado. Sin embargo, la ordenación por combinación generalmente se considera mejor cuando los datos son enormes y se almacenan en un almacenamiento externo.
¿QuickSort es estable?
La implementación predeterminada no es estable. Sin embargo, cualquier algoritmo de clasificación puede estabilizarse si se consideran índices como parámetro de comparación.
¿QuickSort está en el lugar?
Según la definición amplia de algoritmo en el lugar, califica como un algoritmo de clasificación en el lugar, ya que utiliza más espacio solo para almacenar llamadas a funciones recursivas, pero no para manipular la entrada.
¿Cómo implementar QuickSort para listas enlazadas?
QuickSort en una lista enlazada individual
QuickSort en una lista doblemente enlazada
¿Podemos implementar QuickSort de forma iterativa?
Sí, consulte la clasificación rápida iterativa.
Por qué se prefiere la clasificación rápida a MergeSort para clasificar las matrices
La clasificación rápida en su forma general es una clasificación en el lugar (es decir, no requiere ningún almacenamiento adicional) mientras que la clasificación por combinación requiere O (N) almacenamiento adicional, N indica el tamaño de la matriz, que puede ser bastante costoso. Asignar y desasignar el espacio adicional utilizado para la ordenación por combinación aumenta el tiempo de ejecución del algoritmo. Al comparar la complejidad promedio, encontramos que ambos tipos tienen una complejidad promedio O (NlogN) pero las constantes difieren. En el caso de las matrices, la ordenación por combinación pierde debido al uso de espacio de almacenamiento O (N) adicional.
La mayoría de las implementaciones prácticas de la ordenación rápida utilizan una versión aleatoria. La versión aleatoria tiene una complejidad temporal esperada de O (nLogn).El peor de los casos también es posible en la versión aleatoria, pero el peor de los casos no ocurre para un patrón en particular (como una matriz ordenada) y la clasificación rápida aleatoria funciona bien en la práctica.
La clasificación rápida también es una clasificación compatible con caché algoritmo, ya que tiene una buena localidad de referencia cuando se usa para arreglos.
La ordenación rápida también es recursiva de cola, por lo tanto, se realizan optimizaciones de llamadas de cola.
Por qué se prefiere MergeSort sobre QuickSort para listas enlazadas ?
En el caso de listas vinculadas, el caso es diferente principalmente debido a la diferencia en la asignación de memoria de matrices y listas vinculadas. A diferencia de las matrices, los nodos de listas vinculadas pueden no estar adyacentes en la memoria. A diferencia de la matriz, en la lista vinculada, podemos insertar elementos en el medio en O (1) espacio extra y O (1) tiempo. Por lo tanto, la operación de combinación de clasificación de combinación se puede implementar sin espacio adicional para las listas vinculadas.
En las matrices, podemos hacer acceso aleatorio ya que los elementos son continuos en la memoria. Digamos que tenemos una matriz A de números enteros (4 bytes) y que la dirección de A sea x, entonces para acceder a A, podemos acceder directamente a la memoria en (x + i * 4). A diferencia de las matrices, no podemos hacer un acceso aleatorio en la lista vinculada. Quick Sort requiere mucho de este tipo de acceso. En la lista enlazada para acceder al i-ésimo índice, tenemos que recorrer todos y cada uno de los nodos desde la cabecera hasta el i-ésimo nodo, ya que no tenemos un bloque continuo de memoria. Por lo tanto, la sobrecarga aumenta para una clasificación rápida. Merge sort accede a los datos de forma secuencial y la necesidad de acceso aleatorio es baja.
¿Cómo optimizar QuickSort para que ocupe O (Log n) espacio adicional en el peor de los casos?
Consulte Optimización de llamadas de cola de QuickSort (Reducir el espacio del peor caso a Log n)
Instantáneas:
- Cuestionario sobre QuickSort
- Artículos recientes sobre QuickSort
- Práctica de codificación para clasificación.
Otros algoritmos de clasificación en GeeksforGeeks / GeeksQuiz:
Clasificación por selección, clasificación por burbujas, clasificación por inserción, clasificación por fusión, clasificación por montón, clasificación rápida , Ordenar por base, Ordenar por recuento, Ordenar por cubeta, Ordenar por concha, Ordenar por peine, Ordenar por casillero