Vous êtes sur la page 1sur 5

ALGORITMO DE ORDENAMIENTO QUICKSORT

Conceptos básicos
En programación, el término quicksort hace referencia al algoritmo de ordenación
inventado en el año 1960 por el científico británico Charles Antony Richard Hoare1. En general,
dicho algoritmo busca realizar un ordenamiento de una gran cantidad de datos, dividiendo el
problema de gran complejidad en varios de una complejidad mucho menor, lo que permite mayor
rapidez y sencillez a la hora de realizar la ejecución. Es por ello que se dice que dicho algoritmo
se basa en el proverbio “divide y vencerás” utilizado por grandes líderes tales como Julio Cesar
y Napoleón.
Tal como se comentaba anteriormente, el método se basa en dividir los n elementos de
una lista, en dos partes separadas. A partir de ese momento encontraremos que nuestra lista
contiene: una partición izquierda, un elemento central llamado Pivote y una partición derecha.
Para poder realizar la división de esta lista en dos sublistas, se elige un elemento y se utiliza como
pivote (dicha elección será explicada en un apartado posterior). Una vez elegido este, se utiliza
para ordenar el resto de la lista en dos sublistas, una tiene todos los valores menores que el pivote
y la otra todos los elementos mayores o igual que el pivote. (también puede ser programado para
que se realice en forma inversa). Es en este momento en el que aparece el concepto de recursividad
del algoritmo, ya que estas dos listas parciales se ordenan recursivamente utilizando el mismo
algoritmo, llamándose sucesivamente al mismo algoritmo de ordenamiento rápido. La lista
finalmente ordenada se consigue concatenando la primera sublista junto con el pivote y la segunda
sublista, llevándola a convertirse nuevamente en una sola lista. Como se demostraba
anteriormente, la primera parte del algoritmo será la división recursiva de la lista hasta que todas
las sublistas constan de un solo elemento.
Complejidad del algoritmo
Cabe destacar que la eficiencia del algoritmo depende la posición en la que termine el
pivote elegido. Frente a ello podemos destacar que, en el mejor de los casos, el pivote termina en
el centro de la lista, dividiendo la misma en el dos sublistas de igual tamaño. La complejidad del
algoritmo en este caso será de:
𝑂(𝑛 ln(𝑛)) -> es log en base 2
Por el contrario, en el peor de los casos, el pivote se encontrará en el extremo de la lista,
para lo cual la complejidad del mismo será de:
𝑂(𝑛2 )
Cabe destacar que, si bien la elección del pivote dependerá de una correcta
implementación del algoritmo, este “peor de los casos” podrá ser alcanzado en forma regular en
listas que ya se encuentren ordenadas o casi ordenadas.

1
Charles Antony Richard Hoare. Científico Británico nacido el 11 de enero de 1934 en la ciudad de
Colombo en Sri Lanka. Estudio en la Universidad de Oxford. Su logro más conocido es la invención del
Algoritmo Quicksort

Página 1 de 5
Pese a todo lo expuesto anteriormente, la realidad nos dice que en si el caso promedio de
implementación reviste una complejidad de:
𝑂(𝑛 log(𝑛)) -> es log en base 2
Elección del pivote
Como se comentaba anteriormente, la elección del pivote es fundamental a la hora de
reducir la complejidad del algoritmo. Es por ello que existen una serie de técnicas para lograr una
selección más eficiente.
Tomar un elemento cualquiera: esta técnica posee la ventaja de no requerir ningún otro
tipo de cálculo adicional, lo que reduce la cantidad de operaciones. Esta técnica será
recomendable en listas pequeñas donde el incremento de la complejidad por elegir un pivote al
azar no revista importancia en relación al incremento de la complejidad por cuestiones de cálculo
de pivote promedio o demás.
Recorrida de la lista: esta técnica consistirá en el recorrido previo de la lista, comparando
los mismo mediante algún otro algoritmo, que permita seleccionar el mejor elemento para
funcionar como pivote. Dicho algoritmo puede revestir una complejidad de 𝑂(𝑛), pero
asegurarnos que nuestro algoritmo de ordenación posea una complejidad de 𝑂(𝑛 log(𝑛)).
Three ways (tres bandas): consistirá en la selección de tres elementos de la lista (por azar
o por selección), comparándolos y eligiendo el valor medio como pivote.

Ejemplos gráficos

Página 2 de 5
Implementación del código
#include <stdio.h>
#include <stdlib.h>

typedef struct lista


{
int num;
int pos;
struct lista *sig;
}nodo;

void quicksort(nodo**, nodo*);


nodo* crearnodo(int, int);
void insertar(nodo **, nodo *);
void intercambiar(nodo **, nodo**);
void mostrar(nodo*);
nodo* calcularfinal(nodo*);
nodo* anterior(nodo*, nodo*);

int main()
{
nodo* cab = NULL;
nodo* aux = NULL;
nodo* final = NULL;
int numero, i;
for (i = 0; i < 9; i++) {
int numero = 0;
printf("Ingrese el número (USTED NO DEBE INGRESAR NUMEROS
REPETIDOS)");

Página 3 de 5
scanf("%d", &numero);
nodo* aux = crearnodo(numero, i);
insertar(&cab, aux);
}
final = calcularfinal(cab);
quicksort(&cab, final);
mostrar(cab);
scanf("%d", &numero);
return 0;
}

nodo* crearnodo(int numero, int pos)


{
nodo* aux;
aux = (nodo*)malloc(sizeof(nodo));
aux->num = numero;
aux->pos = pos;
aux->sig = NULL;
return aux;
}

void intercambiar(nodo** n1, nodo** n2) {


int a = 0;
a = (*n2)->num;
(*n2)->num = (*n1)->num;
(*n1)->num = a;
}

void quicksort(nodo** cab, nodo* j) {


if ((*cab)->sig != NULL && (j) != NULL) {
nodo* i = (*cab)->sig;
do {
while (i->num < (*cab)->num && i->pos < j->pos)
i = i->sig;
while (j->num >(*cab)->num && j->pos > i->pos)
j = anterior(*cab, j);
if (i->pos < j->pos) {
intercambiar(&i, &j);
j = anterior(*cab, j);
}
} while (i->pos < j->pos);

if ((*cab)->num > j->num) {


intercambiar(cab, &j);
j = anterior(*cab, j);
quicksort(cab, j);
quicksort(&i, calcularfinal(i));
}
if ((*cab) != &j && (i->num) == (j->num)) {
j = anterior(*cab, j);
quicksort(cab, j);
if (i->sig != NULL)
quicksort(&i->sig, calcularfinal(i));
}

quicksort(&i, calcularfinal(i));
}

Página 4 de 5
void mostrar(nodo* cab) {
printf("mostrando lista ordenada ");
while (cab != NULL) {
printf("%d\t", cab->num);
cab = cab->sig;
}
printf("\n");

nodo* calcularfinal(nodo* cab) {


if (cab->sig == NULL) {
return cab;
}
while (cab->sig != NULL)
{
cab = cab->sig;
}
return cab;
}

nodo* anterior(nodo* cab, nodo *j) {


nodo* act = cab->sig;
nodo* ant = cab;
if (ant->num == j->num)
return ant;
while (act != NULL)
{

if ((act->num) == (j->num)) {
return ant;
}
else
{
ant = act;
act = act->sig;
}

}
return ant;
}

void insertar(nodo **c, nodo *n) {


nodo* aux = *c;
if (*c == NULL) {
*c = n;
}
else {

while (aux->sig != NULL) {


aux = aux->sig;
}
aux->sig = n;
}
}

Página 5 de 5

Vous aimerez peut-être aussi