Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Codigo en c++
El Programa esta elaborado para ordenar 5 números ingresados por teclado, si su
requerimiento es ordenar más números o menos solo cambie la longitud del vector es decir
será así:
Una técnica muy poderosa para el diseño de algoritmos es "Dividir para conquistar". Los
algoritmos de este tipo se caracterizan por estar diseñados siguiendo estrictamente las
siguientes fases:
Dividir: Se divide el problema en partes más pequeñas.
Conquistar: Se resuelven recursivamente los problemas más chicos.
Combinar: Los problemas mas chicos de combinan para resolver el grande.
Los algoritmos que utilizan este principio son en la mayoría de los casos netamente
recursivos como es el caso de mergesort.
El algoritmo de Mergesort es un ejemplo clásico de algoritmo que utiliza el principio de
dividir para conquistar. Si el vector tiene más de dos elementos se lo divide en dos
mitades, se invoca recursivamente al algoritmo y luego se hace una intercalación de las
dos mitades ordenadas.
Ejemplo en c++:
// En el código usamos la clase vector (#include <vector.h>) para crear los vectores,
// obviamente funciona igual de bien si se utilizan los arrays tipo C: TIPO V[]
template <class T, class U>
void fusiona(vector<T>& v, U ini, U med, U fin) {
vector<T> aux(fin - ini + 1);
int i = ini; // Índice de la parte izquierda
int j = med + 1; // Índice de la parte derecha
int k = 0; // Índice del vector aux
Quicksort en C++
Quicksort es un algoritmo de ordenación considerado entre los más rápidos y eficientes. Fue
diseñado en los años 60s por C. A. R. Hoare un científico en computación.
El algoritmo usa la técnica divide y vencerás que básicamente se basa en dividir un problema en
subproblemas y luego juntar las respuestas de estos subproblemas para obtener la solución al
problema central.
Me pareció una buena manera de practicar programación y C++ y hacer una explicación que permite
entender este algoritmo , bueno al menos eso intenté. Hace año y medio también publiqué unos
ejemplos de ordenación en Haskell.
Voy a explicar el funcionamiento del quicksort brevemente y después veremos su implementación
en C++.
Se tiene una array de n elementos, tomamos un valor del array como pibote(usualmente el
primero), separamos los elementos menor a este pibote a la izquierda y los mayores a la derecha,
es decir, dividimos el array en 2 subarrays.
Con estos subarrays se repite el mismo proceso de forma recursiva hasta que estos tengan más de
1 elemento. Por lo tanto la función quicksort quedaría de la siguiente manera:
Empezamos creando o generando un array de n elementos, por ejemplo yo use la función rand()
de C++ para generar aleatorios del 1 al 15, mi arreglo quedó así:
left right
0 1 2 3 4 5 6 7 8 9 10 11 12
8 1 5 14 4 15 12 6 2 11 10 7 9
Tomamos como pibote el 8 y usamos 2 índices que me indiquen la posición del array:
Uno que vaya de izquierda a derecha buscando los elementos mayores al pibote. array[left]
Y un índice que busque de derecha a izquierda los elementos menores al pibote. array[right]
El índice izquierdo irá aumentando en 1 mientras el array en la posición izquierda sea menor o
igual al pibote:
8 1 5 14 4 15 12 6 2 11 10 7 9
8 1 5 7 4 15 12 6 2 11 10 14 9
8 1 5 7 4 2 12 6 15 11 10 14 9
8 1 5 7 4 2 12 6 15 11 10 14 9
8 1 5 7 4 2 6 12 15 11 10 14 9
Cuando los índices se juntan o se cruzan ponemos el pibote en el lugar que le corresponde en el
array:
temp = array[right];
array[right] = array[start];
array[start] = temp;
Se intercambian el 8 con el 6 y el array quedaría así:
6 1 5 7 4 2 8 12 15 11 10 14 9
Ahora la función quicksort se llamaría 2 veces recursivamente para los 2 subarray que tenemos:
6 1 5 7 4 2
6 1 5 2 4 7
4 1 5 2 6 7
4 1 2 5
2 1 4 5
quicksort(array, 0, 1) // la posición del pibote es 2
quicksort(array, 3, 3) // no se ejecuta nada, el inicio no es menor al
final
Cuando se ejecuta quicksort (array, 0, 1) se intercambia los índices otra vez.
2 1
1 2
Ahora se ejecuta el mismo proceso con el segundo subarray del array original. Quicksort (a, 7, 12)
12 15 11 10 14 9
12 9 11 10 14 15
10 9 11 12 14 15
10 9 11
9 10 11
14 15
Se divide en 2 elementos este subarray y no hay nada más que hacer por que los array que
contienen al 14 y al 15 solo tienen 1 elemento.
En el peor de los casos tiene un costo de O(n^2). Cuando el pibote siempre se inclina hacia a un
lado, es decir, genera una array de sólo 1 elemento y una segunda con el resto de elementos.
Quicksort peor caso
En el caso promedio también tiene un costo de O(n*log (n)). Se produce cuando el pibote se
inclina más hacia un lado y los 2 subarrays tienen distinto tamaño de elementos.
Para calcular el tiempo de ejecución estoy usando la función clock() que determina el tiempo usado
por el procesador. En este caso defino 3 variables ini, final y total.
Queda pendiente para otro post calcular con exactitud tiempos de ejecución e implementar el
código del número de comparaciones e intercambios.
quicksort.cpp
// Función para dividir el array y hacer los intercambios
int divide(int *array, int start, int end) {
int left;
int right;
int pivot;
int temp;
pivot = array[start];
left = start;
right = end;
clock_t start_time;
clock_t final_time;
double total_time;
start_time = clock();
int a[arraySize];
final_time = clock();
total_time = ((double)(final_time - start_time)) / CLOCKS_PER_SEC;
return 0;
}