Está en la página 1de 12

Quick Sort

PDF generado usando el kit de herramientas de fuente abierta mwlib. Ver http://code.pediapress.com/ para mayor información.
PDF generated at: Sat, 16 Oct 2010 04:12:12 UTC
Quicksort 1

Quicksort
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.

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 Quicksort en acción sobre una lista de números aleatorios. Las líneas
pueden ser colocados tanto a su derecha como horizontales son valores pivote.
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.

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, . de aquí
podemos ver que , 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 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:
Quicksort 2

, donde , por tanto el tiempo de ejecución del algoritmo en el mejor


caso es

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.

Técnicas de elección del pivote


El algoritmo básico Quicksort permite tomar cualquier elemento de la lista como pivote, dependiendo de la partición
n 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.

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.
• 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).

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.
Quicksort 3

• Parámetros:
• Se debe llamar a la función Quicksort desde donde quiera ejecutarse
• Ésta llamará a colocar pivote para encontrar el valor del mismo
• 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;
}

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
Quicksort 4

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. 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

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))

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


Quicksort 5

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;
*b=temp;
}

Java

//Recibe un vector de enteros y el índice del primer y último elemento


válido del mismo
Quicksort 6

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;
Quicksort 7

// Mueve el pivote a la última posición del vector


Intercambia(v, piv, ult);

/* 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
Quicksort 8

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 []
return qsort(filter((lambda y: y<x), list)) + [x] + qsort(filter((lambda y: y>=x), list))

Haskell

qsort :: Ord a => [a] -> [a]


qsort [] = []
qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

Otra en Haskell

qsort :: Ord a => [a] -> [a]


qsort [] = []
qsort (x:xs) = qsort elmts_lt_x ++ [x] ++ qsort elmts_greq_x
where
elmts_lt_x = [y | y <- xs, y < x]
elmts_greq_x = [y | y <- xs, y >= x]

Asm

quicksort:
push ebp
mov ebp,esp
push esi
push ebx
push ecx
push edx
mov ebx,dword[ebp + 12]
mov ecx,dword[ebp + 16]
cdq
mov eax, ebx
add eax, ecx
push ecx
mov ecx,2
div ecx
pop ecx
xchg edx,eax
Quicksort 9

mov esi, [ebp + 8]


mov edx,dword[esi + edx * 4]
qs@L1:
qs@L1@L1:
cmp dword[esi + ebx * 4],edx
jge qs@L1@L1@out
inc ebx
jmp qs@L1@L1
qs@L1@L1@out:
qs@L1@L2:
cmp dword[esi + ecx * 4],edx
jle qs@L1@L2@out
dec ecx
jmp qs@L1@L2
qs@L1@L2@out:
qs@L1@IF1:
cmp ebx, ecx
jg qs@L1@IF1@out
mov eax, dword[esi + ebx * 4]
xchg eax, dword[esi + ecx * 4]
mov dword[esi + ebx * 4], eax
inc ebx
dec ecx
qs@L1@IF1@out:
cmp ebx,ecx
jle qs@L1
qs@L1@out:
qs@IF1:
cmp dword[ebp + 12],ecx
jge qs@IF1@out
push ecx
push dword[ebp + 12]
push esi
call quicksort
qs@IF1@out:
qs@IF2:
cmp ebx, dword[ebp + 16]
jge qs@IF2@out
push dword[ebp + 16]
push ebx
push esi
call quicksort
qs@IF2@out:
pop edx
pop ecx
pop ebx
pop esi
Quicksort 10

pop ebp
retn 12

Prolog

quicksort([], []).
quicksort([CABEZA | COLA], ORDENADO) :- partir(CABEZA, COLA, IZDA,
DCHA),
quicksort(IZDA, ORDENADO_IZDA),
quicksort(DCHA, ORDENADO_DCHA),
concatenar(ORDENADO_IZDA, [CABEZA |
ORDENADO_DCHA], ORDENADO).

partir(PIVOTE, [], [], []).


partir(PIVOTE, [CABEZA | COLA], [CABEZA | IZDA], DCHA) :- CABEZA @=< PIVOTE,
partir(PIVOTE,
COLA, IZDA, DCHA).
partir(PIVOTE, [CABEZA | COLA], IZDA, [CABEZA | DCHA]) :- CABEZA @>
PIVOTE,
partir(PIVOTE,
COLA, IZDA, DCHA).

concatenar([], LISTA, LISTA).


concatenar([CABEZA | LISTA_1], LISTA_2, [CABEZA | LISTA_3]) :-
concatenar(LISTA_1, LISTA_2, LISTA_3).

Véase también
• Algoritmo de ordenamiento.

Referencias
• Quick Sort [1] - Implementación en C
• Ordenamiento rápido, Implementación y descripción [2]
• Explicación vídeo de Quicksort usando tarjetas y del código en C++ Video [3]
• Quick Sort [4] - Implementación en C, PHP, C++,C#,Java, VB, Perl, Prolog, Ruby
• QuickSort C Code [5]

Referencias
[1] http:/ / www. mis-algoritmos. com/ source-81. html
[2] http:/ / www. mis-algoritmos. com/ 2006/ 12/ 27/ ordenamiento-rapido-quicksort/
[3] http:/ / www. datastructures. info/ what-is-quicksort-and-how-does-it-work-quick-sort-algorithm/
[4] http:/ / www. algorithm-code. com/ wiki/ Quick_Sort
[5] http:/ / www. codeuu. com/ Quicksort
Fuentes y contribuyentes del artículo 11

Fuentes y contribuyentes del artículo


Quicksort  Fuente: http://es.wikipedia.org/w/index.php?oldid=40738318  Contribuyentes: Aclapes, Arlm1000, Ascánder, Camilo, CarlosHoyos, Chebi, Dealonso, Dem, DevilishFreak,
Eduardosalg, Elabra sanchez, Execoot, Fortran, Gafotas, GermanX, Gothmog, Human, JMPerez, Jacobo Tarrio, Joanumbert, Juen, Kelwin, LevanenG, LordT, Matdrodes, Mkucharuk, Netito777,
Pablo.cl, Pandemon, Papagorila, Paredero, Pino, Rafael josem, Tostadora, Wariou, Xavigivax, Yago AB, 143 ediciones anónimas

Fuentes de imagen, Licencias y contribuyentes


Archivo:Sorting quicksort anim.gif  Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Sorting_quicksort_anim.gif  Licencia: Creative Commons Attribution-Sharealike 2.5
 Contribuyentes: Berrucomons, Cecil, Chamie, Davepape, Diego pmc, Editor at Large, German, Gorgo, Howcheng, Jago84, JuTa, Lokal Profil, MaBoehm, Minisarm, Miya, Mywood, NH,
PatríciaR, Qyd, Soroush83, Stefeck, Str4nd, W like wiki, 11 ediciones anónimas

Licencia
Creative Commons Attribution-Share Alike 3.0 Unported
http:/ / creativecommons. org/ licenses/ by-sa/ 3. 0/

También podría gustarte