Вы находитесь на странице: 1из 15

`

QUICKSORT

JAMES GUARIN CARO


JAHIR ARDILA
GERMAN ORTEGON
DAVID GOMEZ

UNIVERSIDAD PILOTO DE COLOMBIA


INGENIERIA DE SISTEMAS
BOGOTA 2010

1
`

TABLA DE CONTENIDO

1. Descripcin
2. Pseudocdigo
3. Optimizado
4. Anlisis del algoritmo
5. Implementacin en JAVA
6. Conclusin
7. Bibliografa

2
`

DESCRIPCIN

Esta es probablemente la tcnica ms rpida conocida. Fue desarrollada por C.A.R.


Hoare en 1960. El algoritmo original es recursivo, pero se utilizan versiones iterativas para
mejorar su rendimiento (los algoritmos recursivos son en general ms lentos que los
iterativos, y consumen ms recursos). El algoritmo fundamental es el siguiente:
Eliges un elemento de la lista. Puede ser cualquiera
(en Optimizando veremos una forma ms efectiva). Lo llamaremos elemento
de divisin.
Buscas la posicin que le corresponde en la lista ordenada (explicado ms
abajo).
Acomodas los elementos de la lista a cada lado del elemento de divisin, de
manera que a un lado queden todos los menores que l y al otro los mayores
(explicado ms abajo tambin). En este momento el elemento de divisin
separa la lista en dos sub-listas (de ah su nombre).
Realizas esto de forma recursiva para cada sub-lista mientras stas tengan
un largo mayor que 1. Una vez terminado este proceso todos los elementos
estarn ordenados.
Una idea preliminar para ubicar el elemento de divisin en su posicin final sera contar la
cantidad de elementos menores y colocarlo un lugar ms arriba. Pero luego habra que
mover todos estos elementos a la izquierda del elemento, para que se cumpla la
condicin y pueda aplicarse la recursividad. Reflexionando un poco ms se obtiene un
procedimiento mucho ms efectivo. Se utilizan dos ndices: i, al que llamaremos contador
por la izquierda, y j, al que llamaremos contador por la derecha. El algoritmo es ste:
Recorres la lista simultneamente 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 elemento de divisin y lista[j] sea menor los
intercambias.
Repites esto hasta que se crucen los ndices.
El punto en que se cruzan los ndices es la posicin adecuada para colocar el
elemento de divisin, porque sabemos que a un lado los elementos son todos
menores y al otro son todos mayores (o habran sido intercambiados).
Al finalizar este procedimiento el elemento de divisin queda en una posicin en que
todos los elementos a su izquierda son menores que l, y los que estn a su derecha son
mayores.

3
`

Pseudocdigo
Tabla de variables
Nombre Tipo Uso
lista Cualquiera Lista a ordenar
inf Entero Elemento inferior de la lista
sup Entero Elemento superior de la lista
El mismo que los elementos de la
elem_div El elemento divisor
lista
El mismo que los elementos de la
temp Para realizar los intercambios
lista
i Entero Contador por la izquierda
j Entero Contador por la derecha
El ciclo continua mientras cont tenga el
cont Entero
valor 1

Nombre Procedimiento: ordenarQuicksort


Parmetros:
lista a ordenar (lista)
ndice inferior (inf)
ndice superior (sup)

// Inicializacin de variables
1. elem_div = lista[sup];
2. i = inf - 1;
3. j = sup;
4. cont = 1;

// Verificamos que no se crucen los lmites


5. if (inf >= sup)
6. retornar;

// Clasificamos la sublista
7. while (cont)
8. while (lista[++i] < elem_div);
9. while (lista[--j] > elem_div);
10. if (i < j)
11. temp = lista[i];
12. lista[i] = lista[j];
13. lista[j] = temp;

4
`

14. else
15. cont = 0;

// Copiamos el elemento de divisin


// en su posicin final
16. temp = lista[i];
17. lista[i] = lista[sup];
18. lista[sup] = temp;

// Aplicamos el procedimiento
// recursivamente a cada sublista
19. OrdRap (lista, inf, i - 1);
20. OrdRap (lista, i + 1, sup);

5
`

Optimizando.
Slo voy a mencionar algunas optimizaciones que pueden mejorar bastante el
rendimiento de quicksort:
Hacer una versin iterativa: Para ello se utiliza una pila en que se van
guardando los lmites superior e inferior de cada sub-lista.
No clasificar todas las sub-listas: Cuando el largo de las sub-listas va
disminuyendo, el proceso se va encareciendo. Para solucionarlo slo se
clasifican las listas que tengan un largo menor que n. Al terminar la
clasificacin se llama a otro algoritmo de ordenamiento que termine la labor.
El indicado es uno que se comporte bien con listas casi ordenadas, como el
ordenamiento por insercin por ejemplo. La eleccin de n depende de varios
factores, pero un valor entre 10 y 25 es adecuado.
Eleccin del elemento de divisin: Se elige desde un conjunto de tres
elementos: lista[inferior], lista[mitad] y lista[superior]. El elemento elegido es el
que tenga el valor medio segn el criterio de comparacin. Esto evita el
comportamiento degenerado cuando la lista est prcticamente ordenada.

6
`

Anlisis del algoritmo.


Estabilidad: No es estable.
Requerimientos de Memoria: No requiere memoria adicional en su forma
recursiva. En su forma iterativa la necesita para la pila.
Tiempo de Ejecucin:
o Caso promedio. La complejidad para dividir una lista de n es
O(n). Cada sub-lista genera en promedio dos sub-listas ms de
largo n/2. Por lo tanto la complejidad se define en forma
recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresin es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).
o El peor caso ocurre cuando la lista ya est ordenada, porque
cada llamada genera slo una sub-lista (todos los elementos son
menores que el elemento de divisin). En este caso el
rendimiento se degrada a O(n2). Con las optimizaciones
mencionadas arriba puede evitarse este comportamiento.
Ventajas:
Muy rpido
No requiere memoria adicional.
Desventajas:
Implementacin un poco ms complicada.
Recursividad (utiliza muchos recursos).
Mucha diferencia entre el peor y el mejor caso.
La mayora de los problemas de rendimiento se pueden solucionar con las optimizaciones
mencionadas arriba (al costo de complicar mucho ms la implementacin). Este es un
algoritmo que se emplea muy a menudo para ordenamientos.

7
`

Anlisis del algoritmo

Entrada: La secuencia o arreglo a0, ..., an-1con n elementos


Salida: Se cambian los elementos de la secuencia de tal manera que los elementos
a0, ..., aj son menores o iguales a todos los elementos donde ai, ..., an-1 (i > j)
Mtodo:
elegir el elemento en el medio de la secuencia como elemento de comparacin x
1. Tomando i = 0 and j = n-1
while i j
1. Buscar el primer elemento ai el cual es mayor o igual que x
Buscar el ltimo elemento aj que es menor o igual que x
if i j
1. Intercambiar ai y aj
Hacer i = i+1 y j = j-1

Despus de dividir la secuencia, quicksort trata a las dos partes de forma recursiva
mediante el mismo procedimiento. La recursin termina cuando una parte se compone de
un nico elemento.

El tiempo total necesario para reordenar un arreglo es siempre O (n)^1, o n en donde


es una constante Supongamos que el pivote que acaba de elegir ha dividido al arreglo en
dos partes - una de tamao k y la otra de tamao n - k. hay que tener en cuenta que las
portes necesitan ser ordenadas.

Esto nos da la siguiente relacin:

T(n) = T(1) + T(n 1) + n

ANLISIS DEL PEOR DE LOS CASOS

Ahora se analizara el caso, cuando el pivote result ser el menor elemento de la matriz,
de modo que tuvimos k = 1 y n - k = n - 1. En tal caso, tenemos:

T(n) = T(1) + T(n 1) + n

8
`

A continuacin analizaremos el tiempo de complejidad de quicksort:

T(n) = T(n 1) + T(1) + n


= [T(n 2) + T(1) + (n 1)] + T(1) + n
= T(n 2) + 2T(1) + (n 1 + n) (simplificando y agrupando trminos)
= [T(n 3) + T(1) + (n 2)] + 2T(1) + (n 1 + n)
= T(n 3) + 3T(1) + (n 2 + n 1 + n)
= [T(n 4) + T(1) + (n 3)] + 3T(1) + (n 2 + n 1 + n)
= T(n 4) + 4T(1) + (n 3 + n 2 + n 1 + n)
= T(n i) + iT (1) + (n i + 1 + ..... + n 2 + n 1 + n) (y as sucesivamente hasta el
paso i-esimo)

=T(n i) + iT (1) + ( (n j))

T(n) = T(1) + (n 1)T(1) +


= nT(1) + (n(n 2) (n 2)(n 1)/2)

Observamos entonces = = (n 2)(n 1)/2 lo cual segn teorema es O(n^2)

ANLISIS DEL MEJOR DE LOS CASOS

El mejor de los casos sucede cuando se divide el pivote que escogemos divide el arreglo
en dos partes iguales en cada paso As pues, tenemos k = n / 2 y n-k = n / 2 de la matriz
original de tamao n.

T(n) = 2T(n/2) + n
= 2(2T(n/4) + n/2) + n
= 22T(n/4) + 2 n (simplificando y agrupando trminos semejantes).
= 22(2T(n/8) + n/4) + 2 n
= 23T(n/8) + 3 n
= 2kT(n/2k) + k n (continuando hasta el paso k- esimo)

Debemos tener en cuenta que esta recurrencia se mantendr slo hasta que n = 2^k (de
lo contrario tenemos n/2^k <1), es decir,
hasta k = log n. As, al poner k = log n, tenemos la siguiente ecuacin

T(n) = nT(1) + n log n, el cual es O(n log n).

Este sera el mejor de los casos.

9
`

Implementacin en Java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

/*
* Principal.java
*
* Created on Oct 4, 2010, 7:25:38 PM
*/

package jahir;

import java.util.Random;
import javax.swing.*;
/**
*
* @author darkgayOn
*/
public class Principal extends javax.swing.JFrame {

/** Creates new form Principal */

private int vec[];

public Principal() {
initComponents();

this.setSize(500, 250);

ButtonGroup b = new ButtonGroup();


b.add(b1);
b.add(b2);
b.add(b3);

this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

/** This method is called from within the constructor to


* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-
BEGIN:initComponents

10
`

private void initComponents() {

jPanel1 = new javax.swing.JPanel();


b1 = new javax.swing.JRadioButton();
b2 = new javax.swing.JRadioButton();
b3 = new javax.swing.JRadioButton();
jButton1 = new javax.swing.JButton();
jPanel2 = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
s1 = new javax.swing.JTextArea();
jScrollPane2 = new javax.swing.JScrollPane();
s2 = new javax.swing.JTextArea();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

b1.setSelected(true);
b1.setText("10");
jPanel1.add(b1);

b2.setText("100");
jPanel1.add(b2);

b3.setText("1000");
jPanel1.add(b3);

jButton1.setText("Iniciar");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jPanel1.add(jButton1);

getContentPane().add(jPanel1, java.awt.BorderLayout.PAGE_START);

jPanel2.setLayout(new java.awt.GridLayout());

s1.setColumns(20);
s1.setRows(5);
jScrollPane1.setViewportView(s1);

jPanel2.add(jScrollPane1);

s2.setColumns(20);
s2.setRows(5);
jScrollPane2.setViewportView(s2);

jPanel2.add(jScrollPane2);

getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);

11
`

pack();
}// </editor-fold>//GEN-END:initComponents

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-


FIRST:event_jButton1ActionPerformed

int n = 0;

if(b1.isSelected())
n = 10;
else if(b2.isSelected())
n = 100;
else
n = 1000;

this.vec = new int[n];

Random r = new Random();


for(int x=0;x<n;x++)
{
this.vec[x] = r.nextInt(1000);
}

this.p(s1);

double t1 = System.nanoTime();
ordenarQuicksort(this.vec,0,this.vec.length-1);
double t2 = System.nanoTime();

this.p(s2);
JOptionPane.showMessageDialog(this, "Se demoro: " + (t2-t1) + " Nano segundos");

}//GEN-LAST:event_jButton1ActionPerformed

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

12
`

} while (i<=j);

if(primero<j) ordenarQuicksort(vector,primero, j);


if(ultimo>i) ordenarQuicksort(vector,i, ultimo);
}

public void p(JTextArea s)


{
s.setText("");
for(int x=0;x<this.vec.length;x++)
{
s.append("\n" + this.vec[x]);
}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Principal().setVisible(true);
}
});
}

// Variables declaration - do not modify//GEN-BEGIN:variables


private javax.swing.JRadioButton b1;
private javax.swing.JRadioButton b2;
private javax.swing.JRadioButton b3;
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JTextArea s1;
private javax.swing.JTextArea s2;
// End of variables declaration//GEN-END:variables

13
`

CONCLUSIONES

RENDIMIENTO DEL QUICKSORT


1400000

1200000

1000000
timpo (nano seg)

800000

600000
Series1

400000

200000

0
-200 0 200 400 600 800 1000 1200
-200000
tama;o del vector

Analizamos que entre ms grande el vector, el


mtodo QUICKSORT se tarda ms en su
procesamiento.

14
`

Bibliografa
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/quick/quicken.htm
http://www.conclase.net/c/orden/?cap=quicksort
http://es.wikipedia.org/wiki/Quicksort
H.M. Deitel, P.J. Deitel: "Cmo programar en C/C++". Editorial Prentice Hall.
Charles Bowman: "Algoritmos y estructuras de datos: Aproximacin en C".

15

Вам также может понравиться