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

A partir de esta situacin, podemos disear un mtodo divide y vencers para

ordenar el vector: despus de hacer la particin, slo queda ordenar los dos subvectores. Lo haremos llamando recursivamente al mismo algoritmo de ordenacin, hasta

Algoritmos y Estructuras de Datos 3

que lleguemos al caso base en el cual el subvector tiene como mucho un elemento.
Una primera aproximacin al algoritmo propuesto sera la siguiente:

Prctica 2: Estudio del algoritmo Quicksort

algoritmo QUICKSORT(v:vector; ini,fin: entero)


var pos_pivote: entero;

Escuela Universitaria y Facultad de Informtica

si ini<fin entonces
hacer la particin de v[ini..fin];
{ (para todo k:ini<=k<pos_pivote:v[k]<=v[pos_pivote]) y
(para todo k:pos_pivote<k<=fin:v[k]>=v[pos_pivote]) y
ini<=pos_pivote<=fin }

Departamento de Sistemas Informticos y Computacin


Universidad Politcnica de Valencia

Curso 2000/01

QUICKSORT(v,ini,pos_pivote-1);
{ v[izq..pos_pivote-1] est ordenado }
QUICKSORT(v,pos_pivote+1,fin)
{ v[pos_pivote+1..fin] est ordenado }

1 Introduccin
El objetivo de esta prctica es el estudio terico y experimental del algoritmo rpido
de ordenacin conocido como Quicksort. Este algoritmo fue propuesto por Hoare en
1962 [Hoare, 62], y es uno de los ms ecientes algoritmos de ordenacin conocidos.
El problema de la ordenacin se puede enunciar de la manera siguiente: dado un
vector

v[1..N ]

de

tipobase,

establecer una permutacin de sus elementos de forma

fsi
fQUICKSORT

Sobre la correccin de este algoritmo hemos de sealar:

i : 1 i < N : v[i] v[i + 1],


en donde los elementos de

tipobase

En el caso general, es posible demostrar por induccin que el vector queda


ordenado, suponiendo que el algoritmo de particin se ajuste a su especicacin.
Hay que hacer notar que en este caso, se hacen llamadas recursivas sobre los

admiten un orden total.

subvectores

Vamos a plantear la solucin de este problema de forma recursiva, suponiendo que


estamos interesados en resolver la ordenacin del subvector

En el caso base, cuando el vector est vaco o tiene un elemento, ste est
trivialmente ordenado.

que queden ordenados de forma creciente (o decreciente); es decir, que se cumpla:

v[ini..f in], 1 ini, f in

v[ini..pos_pivote 1]

N.
Supongamos que somos capaces de establecer una particin de este subvector de

siendo

manera que:

v[pos_pivote + 1..f in],

lo que asegura que son de menor talla que el

vector de partida.

1. Dado un elemento
cin,

ini pos_pivote f in,

escogido de entre los de

v[ini..f in],

tras ejecutar la parti-

ocupa el lugar que le corresponde en el vector ordenado.

2. Todos los elementos a la izquierda de

son menores o iguales que

los de la derecha son mayores o iguales que el mismo.

v
Al elemento

fin
elementos<=p

se le llama

pivote o

elementos>=p
clave de la particin.

y todos

2 Algoritmo de particin
En este apartado presentamos un algoritmo para la particin en que se basa el
algoritmo Quicksort. A continuacin describimos la estrategia a seguir:

Grcamente:

ini

p,

Elegimos como pivote

un elemento de

v[ini..f in].

menores o iguales que


mayores que

Por ejemplo, se puede

v[ini].

Se hace un recorrido del vector a partir de

dos variables

tomar el primer elemento

ini + 1,

situando los elementos

en una zona a la izquierda del vector, y los elementos

p en una zona a la derecha.


izq y der , de forma que:

Para realizar este recorrido, usaremos

izq

der

ini
v

fin
elementos<=p

elementos>p

Al nal del recorrido, llegaremos al siguiente estado

QUICKSORT(v,ini,der-1);
{ v[izq..der-1] est ordenado }
QUICKSORT(v,der+1,fin)
{ v[der+1..fin] est ordenado }
fsi
fQUICKSORT

der izq
ini
v

fin
elementos<=p

4 Anlisis de la complejidad temporal de Quicksort

elementos>p
A diferencia del algoritmo de ordenacin por fusin, Quicksort puede presentar diversas instancias, debidas al comportamiento de la particin. Se puede dar que la

por lo que acabaremos la particin intercambiando

v[ini]

v[der].

aplicacin de la particin por parte de sucesivas llamadas recursivas de Quicksort,


tenga comportamientos incluso opuestos sobre el mismo vector de entrada (consultar

p:=v[ini]; izq:=ini+1; der:=fin;


mientras izq<=der hacer
si v[izq]<=p entonces
izq:=izq+1
sino
intercambiar v[izq] y v[der];
der:=der-1
fsi
fmientras;
intercambiar v[ini] y v[der]
Con este recorrido se resuelve el problema con un coste

las cuestiones 5 y 8 de este boletn).


En general, podemos expresar la complejidad temporal de Quicksort a travs de
las siguientes relaciones de recurrencia:

coste(n) =
donde


coste(n ) + coste(n ) + kn,
k ,

n y n son las tallas de los subvectores


kn es debido al coste de la particin.

si

n > 1, n + n = n 1;
n 1,

a los que da lugar la particin.

El

trmino

Esta recurrencia presenta dos casos extremos, segn como sea el resultado de la
particin del vector:

(n).

3 El algoritmo Quicksort

Cada vez que se realiza la particin, se obtiene un vector vaco y otro de talla

n 1,

de forma que

n = n 1

la recurrencia tiene la forma:

Si usamos para la particin el algoritmo propuesto en el apartado anterior, el algo-

coste(n) =

ritmo de ordenacin Quicksort queda como sigue:

algoritmo QUICKSORT(v: vector; ini,fin: entero)


var izq, der: entero; p: tipobase;
si ini<fin entonces
p:=v[ini]; izq:=ini+1; der:=fin;
mientras izq<=der hacer
si v[izq]<=p entonces
izq:=izq+1
sino
intercambiar v[izq] y v[der];
der:=der-1
fsi
fmientras;
intercambiar v[ini] y v[der];
{ (para todo k:ini<=k<der:v[k]<=p) y p=v[der] y
(para todo k:der<k<=fin:v[k]>p) }
3

si

y, por tanto, resulta

n = 0,

para cualquier


coste(n 1) + kn,
k ,

si
si

n > 1.

En este caso,

n > 1;
n1

(n2 ).

Cada vez que se realiza la particin, se obtiene dos vectores aproximadamente


de la misma talla,

n n n/2. En este caso, la



2coste(n/2) + kn,
coste(n) =
k ,

recurrencia es de la forma:

Si, por simplicar, resolvemos esta recurrencia para

si
si

n > 1;
n 1.

n potencia de 2, se obtiene

coste(n) = nk + kn log2 n,
y, por tanto, resulta

(n log n).

Vamos a estudiar la complejidad del algoritmo en el caso medio. Veremos que


asintticamente se comporta como en el mejor de los casos.
elemento

Supongamos que el

seleccionado para hacer la particin es tal que le corresponde la

i-sima

i 1, y otro
(i = 1, 2, . . . , n)

posicin en el orden. De esta forma, se genera un subproblema de talla


de talla

n i.

Si adems consideramos que todas las posibilidades

equilibrada evitando en lo posible la contribucin de casos desequilibrados al coste


promedio.
Vamos a estudiar a continuacin un algoritmo de particin debido a Weiss [Weiss,95],

son igualmente probables, tenemos:

costem (n) =

que incide en los dos aspectos indicados para obtener un algoritmo de ordenacin

n
1
(kn + costem (i 1) + costem (n i))
n
i=1

mejor.
Las dos diferencias ms signicativas entre el algoritmo de Weiss y el algoritmo

1
2costem (i 1)
= kn +
n

ya visto son, en primer lugar, la estrategia utilizada para seleccionar el pivote y, en


segundo lugar, el criterio de intercambio de elementos del vector que permite reducir

i=1

para

n > 1.

los efectuados durante la ejecucin del algoritmo.

Por tanto,

5.1 Eleccin del pivote

n1

kn + 2/n  coste (i),


m
costem (n) =
i=0

k  ,

si

n > 1,

si

n 1.

Naturalmente hay unas elecciones del pivote mejores que otras. Del estudio de costes
del algoritmo Quicksort parece razonable deducir que, cuanto ms equilibrada sea la
subdivisin realizada por particin ms prximo ser el comportamiento temporal
de Quicksort al de su caso mejor, esto es, en las expresiones del coste ms prxima

Por induccin se puede demostrar que:

ser la constante

n 2 : costem (n) k n ln n,

con

k = 2(k + k).

n1


i ln i

i=2

a su cota inferior

k.

como pivote, ya que todos ellos tienen la misma probabilidad de quedar centrados

Para ello, se puede usar la siguiente acotacin:

kr

Cuando la entrada al algoritmo es aleatoria cualquier elemento del vector servira

x ln xdx <

i=2

en la particin o en un extremo de ella; en ese caso la eleccin del primer elemento


es aceptable. Pero si el vector ya est parcialmente ordenado lo que es frecuente en

n2
n2
ln n .
2
4

la prctica entonces la eleccin del primer elemento har ms probables particiones


desequilibradas.
Una estrategia mejor consistira en usar como pivote un elemento cualquiera

Del anlisis anterior podemos sacar las siguientes conclusiones:


1. Las cotas de complejidad de Quicksort son

O(n2 )

del vector elegido al azar, evitando as elecciones decientes debido a entradas no


aleatorias. El problema de esta ltima eleccin es que la generacin de un nmero

(n log n).

aleatorio puede ser temporalmente costosa, con lo que se penalizara el algoritmo de

2. Si la particin se comporta de manera que en promedio el pivote queda cen-

particin.

instancias que hemos considerado son efectivamente igualmente

Otra estrategia posible consiste en elegir el elemento central del vector en lugar del

probables en todos los niveles de la recursin), entonces el comportamiento

primero, de modo que particin dar, por lo general, subdivisiones ms equilibradas

trado (las

promedio de Quicksort ser

(n log n).

cuando la entrada ya est parcialmente ordenada, manteniendo la aleatoriedad de la


eleccin para entradas tambin aleatorias.

3. An en el supuesto del punto anterior, al promediar la contribucin al coste de


todas las instancias consideradas, aparece un trmino

2(k

+ k) ln 2,

frente al trmino

kn log2 n

kr n log2 n,

con

k < kr

del caso mejor.

En el siguiente apartado, mostraremos cmo se pueden tener en cuenta estos


resultados para buscar mejores implementaciones del algoritmo.

5 Otro algoritmo de particin


Si consideramos el algoritmo estudiado en la seccin 3, y suponemos como entrada
un vector completamente aleatorio, entonces el coste esperado por trmino medio es

kr n log2 n,

puesto que la particin elige un valor aleatorio al tomar como pivote el

primer elemento del vector.


Pueden conseguirse mejoras en el tiempo de ejecucin del algoritmo Quicksort
que se ha estudiado reduciendo
tratando de acercar

kr

la constante asociada a particin, y tambin

modicando para ello la seleccin del pivote, de forma

La eleccin ptima del pivote consistira en seleccionar la mediana del vector,


esto es: aquel elemento que tiene un nmero igual de elementos mayores y menores
que el mismo. Esta eleccin garantizara siempre la subdivisin ms equilibrada; sin
embargo determinar la mediana de un vector tiene como mnimo un coste lineal, lo
que supone en la prctica una penalizacin temporal excesiva.
Otra estrategia distinta, la considerada por Weiss, consiste en seleccionar tres
elementos del vector:

el primero, el central y el ltimo, eligiendo como pivote la

mediana de los tres, esto es, el elemento intermedio. Este mtodo es, frecuentemente,
mejor que una eleccin puramente aleatoria (ver cuestin 11), ya que escoge como
pivote un elemento que estar con ms probabilidad cerca de la mediana que de
haberse elegido al azar; adems el mtodo elimina el caso malo que se produce
ante una entrada ordenada.
El algoritmo que mostramos a continuacin, debido a Weiss, determina el pivote
que utilizar el algoritmo de particin, para el subvector de
y

f in.

que la subdivisin en dos subvectores efectuada por el algoritmo de particin sea ms

comprendido entre

ini

{ fin - ini + 1 >= 3 }


algoritmo mediana3(v:vector; ini,fin:entero) devuelve tipobase
{ Determina la mediana de los elementos inicial, central y final,
ordena dichos elementos, y devuelve el pivote }
var centro: entero; pivote: tipobase fvar;
centro:=(ini+fin) div 2;
si v[ini]>v[centro] entonces intercambiar v[ini] y v[centro] fsi;
si v[ini]>v[fin] entonces intercambiar v[ini] y v[fin] fsi;
si v[centro]>v[fin] entonces intercambiar v[centro] y v[fin] fsi;
{ v[ini]<=v[centro]<=v[fin] }
pivote:=v[centro];
intercambiar v[centro] y v[fin-1]; {oculta el pivote}
devuelve pivote
fmediana3

(1) pivote := mediana3(v,ini,fin);


(2) izq:=ini; der:=fin-1;
repetir
(3)
repetir izq:=izq+1 hasta v[izq]>=pivote;
(4)
repetir der:=der-1 hasta v[der]<=pivote;
(5)
intercambiar v[izq] y v[der]
(6) hasta der <= izq;
(7) intercambiar v[izq] y v[der] {deshace el ltimo intercambio}
(8) intercambiar v[izq] y v[fin-1] {restaura el pivote}
{ v[izq]=pivote }
fparticin
De este algoritmo cabe resaltar lo siguiente:
1. El algoritmo

Como hemos indicado, adems de determinar el pivote, el algoritmo intercambia


entre s los elementos inicial, central y nal del subvector de forma que estn ordena-

mediana3

introduce en

ini

un elemento inferior o igual al pivote,

evitando tener que usar un centinela, o una condicin adicional, en la segunda


iteracin (lnea 4), para que la variable

der

no se salga de rango.

dos entre s lo que, adems de situar ya dichos elementos, garantiza la existencia de


un elemento inferior o igual al pivote en el extremo izquierdo, de forma que pueda

2. El intercambio que se produce en la lnea 5 tiene slo sentido cuando el valor


de

utilizarse como centinela en bsquedas posteriores.

izq

der . Esto ocurre en todas las iteraciones excepto en


izq der , como el intercambio tambin se realiza en la

es menor que el de

la ltima, en la que

5.2 Minimizacin de los intercambios efectuados

ltima iteracin es necesario deshacerlo al nalizar el bucle. La nalidad del

Del examen de la particin propuesta inicialmente (seccin 2) se puede comprobar

intercambio que no tena que haberse producido.

intercambio existente en la lnea 7 es, precisamente, la de deshacer el ltimo

que es posible intercambiar un elemento mayor que el pivote con otro que tambin lo
sea (ver cuestin 4). Este intercambio es claramente ineciente y un mtodo mejor
consiste en intercambiar solamente un elemento mayor o igual que el pivote con otro

Naturalmente puede realizarse lo mismo si se elimina la lnea 7, y se sustituye la


lnea 5 por la siguiente:

si izq<der entonces intercambiar v[izq] y v[der]

que sea menor o igual (ver cuestin 7).


La estrategia seguida por Weiss consiste en que, en cada iteracin, se avanza
tanto como se puede en el recorrido por la izquierda y por la derecha del vector,

izq

der

ini
v

fin

<=p elementos<=p >=p

<=p elementos>=p

Pero de hacerse as, se efectuara una comparacin adicional en cada iteracin,


incrementando el tiempo de ejecucin del algoritmo.

hasta encontrar dos elementos posiblemente descolocados,

>=p

6 Actividades en el laboratorio
El trabajo en el laboratorio consistir en la implementacin del algoritmo Quicksort,
el estudio experimental de su eciencia y la comparacin con un algoritmo de ordena-

intercambindolos de forma que a continuacin estn en la zona de la particin que


les corresponde. La iteracin nalizar cuando no haya elementos descolocados.
El algoritmo de particin propuesto por Weiss es el siguiente:

cin de los llamados lentos. Tambin deberis implementar una versin renada de
Quicksort, para comparar su eciencia con la primera versin estudiada. El cdigo
ya implementado que se referencia en los siguientes puntos, lo podris encontrar en
el subdirectorio

{ fin - ini + 1 >= 3 }


algoritmo particin(v:vector; ini,fin:entero);
{ Particin de v entre ini y fin }
var izq,der:entero; pivote:tipobase fvar

prac2

de

/practicas/asignaturas/ad3alum.

6.1 Estudio experimental de la eciencia de Quicksort y comparacin con el algoritmo de Insercin directa
Deberis comparar el algoritmo diseado con un algoritmo de ordenacin de coste
cuadrtico, como es en promedio Insercin directa. Estos algoritmos se os proporcionarn ya implementados. El mtodo a seguir ser el siguiente:

Deberis medir el tiempo de ejecucin de cada uno de los algoritmos en funcin

ptimo de recursin, por debajo del cual se ordene el subvector mediante Inser-

de la talla, para un rango de tallas entre 500 y 5000, a intervalos de 500.

cin directa. Una estimacin analtica de dicho umbral necesitara medidas del

Para cada talla estudiada, mediris los tiempos de ejecucin sobre un determinado nmero de instancias de prueba, que se pueden generar de forma aleatoria
con los procedimientos del mdulo

genera

ya implementado. Promediaris el

tiempo de ejecucin de este conjunto de instancias.

de esta medida.
La salida del programa debe ser en forma de chero de texto, de forma que en
cada lnea aparezcan los datos correspondientes a una talla

determinar las constantes que aparecen en los costes en ese rango de tallas.
Pero estos tiempos son menores que la precisin del reloj del sistema. Disead
un experimento en el que se puedan obtener tiempos de ejecucin signicativos
para tallas entre 20 y 100, basndose en repetir, para cada talla e instancia, los

El tiempo de ejecucin se podr calcular utilizando la rutina clock de la


librera del lenguaje C. En el anexo A se presentan los detalles de obtencin

tiempo de ejecucin de Insercin directa y de Particin con tallas bajas, para

n:

procedimientos un nmero de veces sucientemente grande.

El mtodo pro-

puesto deber tener en cuenta que, despus de ejecutar una vez la ordenacin,
el vector queda ya ordenado.
3. Un mtodo ms directo y able para estimar el umbral ptimo de recursin,
consiste en calcularlo experimentalmente. Proponed un experimento que determine un umbral ptimo de recursin, y que al mismo tiempo indique la mejora
de tiempos que se puede obtener para tallas del orden de 5000. Como hiptesis

n tiempo_quicksort tiempo_insercin_directa

de partida, suponed que el umbral buscado estar como mucho en

Estos datos se pueden procesar con el comando t de ajuste por mnimos
cuadrados del programa "gnuplot". Las curvas ajustadas obtenidas se pueden
representar grcamente con el comando "plot" del mismo programa

6.2 Inuencia del comportamiento de la particin en el algoritmo


Quicksort

como muy poco en

n = 25,

n = 2.

4. Cul es el mximo nmero de intercambios de elementos que pueden llegar a


hacer, respectivamente, la particin de la seccin 2 y de la seccin 5, sobre un
vector de talla

n?

A qu instancia corresponde en cada caso?

5. A qu instancia corresponde el comportamiento cuadrtico de Quicksort cuando usa la particin de la seccin 2?

Siguiendo el mtodo descrito en el apartado anterior, deberis comparar el comportamiento temporal del algoritmo Quicksort con dos versiones diferentes de la particin.
Para ello, implementaris el algoritmo Quicksort usando como particin la de
Weiss, descrita en la seccin 5.

Esta particin slo es aplicable a vectores de tres

o ms elementos, por lo que en esta implementacin de Quicksort, el caso general


del algoritmo se dar cuando

ini + 1 < f in.

Deberis cambiar el caso base coheren-

temente. Deberis comprobar que el algoritmo funciona correctamente.

Para ello,

probad con diferentes instancias (vector ya ordenado de forma creciente, vector ya

6. Discutid el coste espacial de Quicksort en el caso mejor y en el caso peor.


7. Suponed que se modica el algoritmo de particin de Weiss sustituyendo las
lneas 3 y 4 por las siguientes:

(3) repetir izq:=izq+1 hasta (v[izq]>pivote) o (izq=fin-2);


(4) repetir der:=der-1 hasta (v[der]<pivote) o (der=ini+1);

ordenado de forma decreciente, vector con elementos iguales,...) y con un nmero de

de forma que el intercambio entre dos elementos se produzca solamente cuando

elementos conveniente para hacer una traza.

estos son distintos al pivote.

Deberis comparar los tiempos de ejecucin de esta versin de Quicksort, con los
de la versin del apartado 6.1.

Para este experimento, se recomienda extender el

rango de tallas a estudiar hasta 15000.

Considerando como entrada un vector en el que todos los elementos son iguales,
comparad el algoritmo original y el propuesto:
(a) Estudiando el nmero de intercambios realizados.

7 Cuestiones

(b) La posicin nal del pivote.

1. Suponiendo que las curvas obtenidas para el comportamiento temporal de Insercin directa y de Quicksort (en sus dos versiones), en las actividades 6.1 y
6.2 se pudiesen extrapolar a grandes tallas, cul sera el tiempo de ejecucin
que se podra esperar en promedio para cada uno de los tres algoritmos, con

5
vectores del orden de 10 elementos?

2. Un estudio para tallas bajas (menores que 50) de Insercin directa y de Quicksort, revela que el mejor comportamiento del segundo se maniesta tempranamente. An as, se puede mejorar su comportamiento buscando un umbral

Cul es el tiempo de ejecucin de Quicksort con cada algoritmo ante la entrada


considerada?
8. Suponed que se implementa el algoritmo

mediana3

v[ini], v[f in]


empezando izq

Determinar la mediana de

v[f in].

Ejecutar particin

adems, que

v[0] = ,

(a) Dada la entrada

como sigue:

v[centro],
en ini y der
y

intercambindola con
en

f in 1.

Suponed,

de modo que hay un centinela.

2, 3, 4, ..., n 1, n, 1,

esta versin de Quicksort?

10

cul es el tiempo de ejecucin de

(b) Dada la entrada

n, n 1, ...4, 3, 2, 1,

cul es el tiempo de ejecucin de

esta versin de Quicksort?


9. En el algoritmo de particin debido a Weiss se esconde el pivote en la posicin

f in 1

para ser posteriormente restaurado.

de? Para ello demuestra que al nalizar particin se cumple que

ini <

Cmo deberan ser las llamadas recursivas que se efectan en

Quicksort utilizando este algoritmo de particin?

que tambin puede afectar al pivote), el algoritmo de particin se puede modicar para que el vector se particione en tres zonas: elementos menores que
y elementos mayores que

Un estudio temporal de ambas particiones, efectuado con una entrada aleatoria


de caractersticas similares a las de esta prctica, para tallas entre 5000 y 50000
un comportamiento uniformemente mejor (aproximadamente en un 3%) que la
de Weiss.
Un estudio temporal de Quicksort utilizando ambas particiones, en condiciones
particin debida a Weiss presentaba un comportamiento uniformemente mejor

10. Si es probable que en el vector a ordenar aparezcan elementos repetidos, (lo

para evitar que el recorrido de izquierda a

similares a las enunciadas, mostr sin embargo que el algoritmo que utilizaba la

(b) Por qu crees que se esconde el pivote?

elementos iguales a

N + 1,

(10000 instancias para cada talla), demostr que la particin de Dijkstra tena

(a) Sigue siendo correcto el algoritmo particin si el pivote no se escon-

izq f in.

un centinela en la posicin
derecha se salga de rango.

p.

p,

Escribid un algoritmo que

realice esta particin. Cul sera el comportamiento de Quicksort en el caso

(aproximadamente en un 10%) que el algoritmo que utilizaba la particin de


Dijkstra.
La siguiente tabla muestra otros resultados obtenidos en el estudio experimental de los algoritmos de particin de Weiss (parW) y el de Dijkstra (parD).
Para cada algoritmo, la columna

pos

representa la posicin que, en trmino

medio, ocupa el pivote tras la particin. Tambin, como ndice de desviacin

mejor con esta nueva particin?

de las medidas con respecto a la posicin central, se ha representado columnas


11. El algoritmo de particin siguiente fue propuesto por Dijkstra [Sedgewick,78]:

desv 

la desviacin estndar de las medidas efectuadas con respecto a la posi-

cin central.

{ v[N+1] = +infinito }
algoritmo particinD(v:vector; ini,fin:entero);
{ Particin de v entre ini y fin, segn Dijkstra }
var izq,der:entero; pivote:tipobase fvar
pivote := v[ini];
izq:=ini+1; der:=fin;
repetir
mientras v[izq]<pivote hacer izq:=izq+1 fmientras;
mientras v[der]>pivote hacer der:=der-1 fmientras;
si izq <= der entonces
intercambiar v[izq] y v[der]
izq:=izq+1; der:=der+1
fsi
hasta der < izq;
intercambiar v[ini] y v[der] { restaura el pivote }
fparticinD

talla

pos(parW)

pos(parD)

5000
10000
15000
20000
25000
30000
35000
40000
45000
50000

2516
4979
7494
9912
12489
15030
17543
19833
22751
25054

2477
4994
7506
10023
12415
14997
17508
20158
22587
24727

desv(parW) desv(parD)
1115
2235
3396
4450
5575
6708
7822
8930
10153
11104

1443
2881
4322
5788
7139
8641
10091
11536
13073
14307

Hay diferencias signicativas entre las posiciones devueltas por ambas particiones?, y entre las medidas de desviacin estndar? Qu deduces de los
resultados?

Referencias
[1] C. A. R. Hoare, Quicksort, Computer Journal, Vol. 5 (4), 1962.

El algoritmo se basa en una estrategia de intercambio similar a la del algoritmo


de Weiss: slo se intercambian dos elementos cuando ambos son, respectivamente, mayor o igual que el pivote y menor o igual que el pivote. La principal
diferencia reside en el criterio de eleccin del pivote, que en el algoritmo de

[2] R. Sedgewick, Implementing Quicksort Programas, Communications of ACM,


Vol. 21 (10), 1978.
[3] M. A. Weiss, Estructuras de datos y algoritmos, Addison-Wesley Iberoamericana, 1995.

Dijkstra es el elemento ms a la izquierda. En la nueva particin se necesita

11

12

A Compilacin: makefile
El comando

make

bash_> gnuplot
G N U P L O T
Linux version 3.5 (pre 3.6)
patchlevel beta 347
last modified Mon Jun 22 13:22:33 BST 1998

est pensado para facilitar el mantenimiento y regeneracin de

grupos de programas. En particular, es muy til cuando un programa est distribuido


en varios cheros. En este caso, el programador crea un chero (llamado

makefile

por defecto) en el que se denen las dependencias entre los diferentes cheros del
programa. Cada vez que se ejecuta el comando

make se examina

el chero

makefile

Copyright(C) 1986 - 1993, 1998


Thomas Williams, Colin Kelley and many others

para determinar las dependencias entre los distintos cheros que forman el programa.
Con esta informacin, el comando

make recompilar

aquellos cheros fuente que han

sido modicados con posterioridad a la generacin de su cdigo objeto y, a su vez,

Send comments and requests for help to info-gnuplot@dartmouth.edu


Send bugs, suggestions and mods to submit@bugs.debian.org

los que dependen de stos.


La utilizacin del comando

make

tiene, pues, dos consecuencias:

en cada momento, nicamente se recompila lo que es estrictamente necesario y

se evita el error (muy frecuente) de olvidarse de recompilar algn chero fuente

Terminal type set to 'x11'


gnuplot>

que haya sido modicado o que dependa de alguno que haya sido modicado,
Cuando lo utilices en este modo recuerda que dispones de ayuda on-line accesible

adems de ejecutar la compilacin en orden correcto.


Como ejemplo, supongamos que tenemos creado el chero

makefile,

con "help" y que sales del mismo con "quit".


cuyo con-

tenido es:

prg: modulo.o prg.c


gcc -o prg prg.c modulo.o
modulo.o: modulo.c
gcc -c modulo.c
Cuando el usuario ejecuta el comando
depende de los cheros

prg.c modulo.o (si


modulo.o, y la lnea

modulo.o y prg.c.

make,

prg, que
gcc -o prg

se genera el ejecutable

Automticamente, se ejecuta

es necesario). La lnea tercera indica de qu cheros depende


cuarta cmo se genera (si es necesario).

nom_var dentro de un chero makefile y despus


$(nom_var). Por ejemplo, el chero anterior podra ser:

Se puede denir una variable


utilizar su contenido con

Si deseamos dibujar una curva a partir de las dos primeras columnas, con la primera
columna como abcisa, y la segunda como ordenada, entonces la orden apropiada
seria:

signica

using

y indica que debe utilizarse la columna 1 para

w l signica with lines,


puntos con una lnea (hacer help plot para ver ms opciones).

esto es, que una los


Si deseamos mejorar

la presentacin, entoces puede hacerse:

B Visualizacin grcas: gnuplot


es un dibujador de grcas disponible para diversos sistemas operativos

como UNIX, MS-DOS y VMS. La documentacin sobre este programa incluye, entre
otros textos, un manual de referencia on-line.

13

0.01
0.02
0.02
0.05
0.07
0.08
0.11

En esta orden,

Por ltimo, las columnas donde se indican las rdenes a ejecutar deben comenzar

modo interactivo.

0.07
0.30
0.75
1.37
2.26
3.32
4.51

la abcisa, y la 2 para la ordenada.

con un tabulador, no con espacios.

Aunque existe la posibilidad de utilizarlo en batch,

100
200
300
400
500
600
700

f1.dat con el siguiente formato:

gnuplot> plot 'f1.dat' u 1:2 w l

nom = prg
$(nom): modulo.o $(nom).c
gcc -o $(nom) $(nom).c modulo.o
modulo.o: modulo.c
gcc -c modulo.c

gnuplot

Por ejemplo, imaginemos que tenemos un chero

gnuplot

suele utilizarse en

gnuplot>
gnuplot>
gnuplot>
gnuplot>

set xlabel "Size"


set ylabel "Time"
set title "Algorithm A"
plot 'f1.dat' u 1:2 w l

La grca obtenida con esta secuencia de comandos del

gnuplot

se ilustra en la

gura 1.
El programa

gnuplot

permite hacer ajustes por mnimos cuadrados de un con-

junto de datos. Por ejemplo, si deseamos hacer una ajuste por mnimos cuadrados
de los datos anteriores, podemos hacer:

14

Algorithm A

Algorithm A

5
kk u 1:2

f(x)
f1.dat u 1:2

4.5

4.5

3.5

3.5

3
2.5

Time

Time

3
2.5

2
1.5
1.5

0.5

0.5

0
100

200

300

400
Size

500

Figura 1: Ejemplo de la salida generada por

gnuplot>
gnuplot>
...
gnuplot>
gnuplot>
gnuplot>
gnuplot>

600

700

gnuplot.

gnuplot.

por ejemplo el siguiente fragmento de programa Pascal:


La orden para

cl1:=clock;
S;
cl2:= clock;
cl3:=cl2-cl1;

via aparecen los parmetros de


fit produce una salida que informa sobre
help fit para interpretar estos resultados). La

C Medida del coste computacional: primitiva clock


Una forma de medir el coste computacional necesario para la ejecucin de un programa o segmento del mismo, consiste en contar el nmero de veces que se realiza
algn tipo de operacin signicativa (comparaciones, productos, productos aditivos,
). Otra forma es utilizar alguna rutina del sistema que mida tiempos de eje-

cucin. Es importante sealar que si se trabaja en un sistema de tiempo compartido,


las medidas que se realicen debern ser independientes de la carga del sistema.
El sistema operativo UNIX lleva una cuenta para cada proceso y, en cada momento, del nmero de ticks de CPU consumidos. Estos ticks equivalen generalmente a

donde

{instruccin 1}
{instruccin 2}

es cualquier instruccin. El cdigo en C sera anlogo, teniendo en cuenta

que la llamada a la funcin de reloj debe explicitar la lista vaca de argumentos:

clock().

Despus de la ejecucin de este fragmento de programa tendremos:

cl1

tiempo de proceso consumido hasta la instruccin 1 (en ticks).

cl2

tiempo de proceso consumido hasta la instruccin 2 (en ticks).

cl3

tiempo de proceso consumido para la instruccin

clock

(de la librera

(en ticks) .

Hay que tener cuidado en la colocacin de las instrucciones de temporizacin, ya


que se debe evitar incluir entre ellas toda aquella parte del cdigo que no se desee
temporizar.

una pequea cantidad de tiempo (del orden de microsegundos). En Pascal y C es po-

15

700

Una llamada a esta funcin (sin argumentos), devuelve un entero que es propor-

En esta orden, despus de

sible determinar este nmero haciendo uso de la rutina

600

cional a la cantidad de tiempo de procesador utilizado por proceso en curso. As, sea

salida que se produce en este caso puede verse en la gura 2.

...

500

function clock: integer; C;

la funcin que se desea modicar. La orden

etc

400
Size

del lenguaje C). En el caso de Pascal, se debe incluir en el espacio del programa

Primero denimos la funcin a la que se desea ajustar los datos.

las caractersticas del ajuste (hacer

300

reservado para la declaracin de procedimientos y funciones:

set xlabel "Size"


set ylabel "Time"
set title "Algorithm A"
plot f(x),'f1.dat' u 1:2 w l
fit.

200

Figura 2: Ejemplo de ajuste por mnimos cuadrados producido por

f(x)=a*x+b
fit f(x) 'f1.dat' via a,b u 1:2

realizar el ajuste es

-0.5
100

time.h
16

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