Algoritmos de Ordenamiento
Algoritmos de Ordenamiento
Algoritmos de Ordenamiento
1.1 INTRODUCCIÓN:
• Clave: La parte de un registro por la cual se ordena la lista. Por ejemplo, una lista de
registros con campos nombre, dirección y teléfono se puede ordenar
alfabéticamente de acuerdo a la clave nombre. En este caso los campos dirección y
teléfono no se toman en cuenta en el ordenamiento.
• Criterio de ordenamiento (o de comparación): EL criterio que utilizamos para
asignar valores a los registros con base en una o más claves. De esta manera
decidimos si un registro es mayor o menor que otro.
• Registro: Un grupo de datos que forman la lista. Pueden ser datos atómicos
(enteros, caracteres, reales, etc.) o grupos de ellos, que en C equivalen a las
estructuras.
Por lo general, todos los algoritmos de ordenación funcionan de una forma similar. Toman una
lista de elementos, en nuestro caso un array, comparan sus elementos siguiendo una
estrategia definida y, según el resultado de dicha comparación, mueven los datos de un lugar
a otro hasta conseguir una lista (array) final ordenado.
2
Algoritmos de Ordenación y Búsqueda en C
Una colección de datos (estructura) puede ser almacenada en un archivo, un array (vector o
tabla), un array de registros, una lista enlazada o un árbol. Cuando los datos están
almacenados en un array, una lista enlazada o un árbol, se denomina ordenación interna. Si
los datos están almacenados en un archivo, el proceso de ordenación se llama ordenación
externa.
Los métodos (algoritmos) de ordenación son numerosos, por ello se debe prestar especial
atención en su elección.
Se han desarrollado muchas técnicas en este ámbito, cada una con características
específicas, y con ventajas y desventajas sobre las demás. Algunas de las más comunes son:
3
Algoritmos de Ordenación y Búsqueda en C
Hay muchas formas de clasificar datos y una de las más conocidas es la clasificación por el
método de la burbuja. Es uno de los más simples, es tan fácil como comparar todos los
elementos de una lista contra todos, si se cumple que uno es mayor o menor a otro, entonces
los intercambia de posición.
1. Comparamos el primer elemento con el segundo, el segundo con el tercero el tercero con
el cuarto, etc. Cuando el resultado de una comparación sea “mayor que”, se intercambian los
valores de los elementos comparados. Con esto conseguimos llevar el valor mayor a la
posición n.
2. Repetimos el punto 1, ahora para los N-1 primeros elementos de la lista y así
sucesivamente.
3. Repetimos el punto 1, ahora para los N-2 primeros elementos de la lista y así
sucesivamente.
4. El proceso termina después de repetir el punto 1, N-1 veces, o cuando al finalizar la
ejecución del punto 1 no haya habido ningún cambio.
4
Algoritmos de Ordenación y Búsqueda en C
Primera pasada:
{40, 21, 4, 9, 10, 35}
{21, 40, 4, 9, 10, 35} <-- Se cambia el 21 por el 40.
{21, 4, 40, 9, 10, 35} <-- Se cambia el 40 por el 4.
{21, 4, 9, 40, 10, 35} <-- Se cambia el 9 por el 40.
{21, 4, 9, 10, 40, 35} <-- Se cambia el 40 por el 10.
{21, 4, 9, 10, 35, 40} <-- Se cambia el 35 por el 40.
Segunda pasada:
{21, 4, 9, 10, 35, 40}
{4, 21, 9, 10, 35, 40} <-- Se cambia el 21 por el 4.
{4, 9, 21, 10, 35, 40} <-- Se cambia el 9 por el 21.
{4, 9, 10, 21, 35, 40} <-- Se cambia el 21 por el 10.
{4, 9, 10, 21, 35, 40} <-- No hay cambio entre el 21 y el 35.
{4, 9, 10, 21, 35, 40} <-- El 35 y el 40, no se comparan, porque el 40 es el mayor.
En este ejemplo, los datos ya están ordenados, pero para comprobarlo habría que hacer una
tercera, cuarta y quinta comprobación.
Ejemplo #1: Programa en C que permite introducir una lista con los pesos de los N
estudiantes de la asignatura de Programación Estructurada e imprime los pesos en
formato ascendente (menor a mayor).
//burbuja_ascendente.c
#include<stdio.h>
#include<stdlib.h>
void main()
{
float *pesos,temp;
int i,j,nest;
printf("Cuantos estudiantes son?: ");
scanf("%d",&nest);
pesos = (float *) malloc(nest *sizeof(float));
if(pesos==NULL)
{
printf("Insuficiente Espacio de Memoria\n");
exit(-1); //Salir del Programa
}
5
Algoritmos de Ordenación y Búsqueda en C
Ejemplo de Salida:
6
Algoritmos de Ordenación y Búsqueda en C
Ejemplo #2: Programa en C que permite introducir una lista con los pesos de los N
estudiantes de la asignatura de Programación Estructurada e imprime los pesos en
formato descendente (mayor a menor).
//burbuja_descendente.c
#include<stdio.h>
#include<stdlib.h>
void main()
{
float *pesos,temp;
int i,j,nest;
printf("Cuantos estudiantes son?: ");
scanf("%d",&nest);
pesos = (float *) malloc(nest *sizeof(float));
if(pesos==NULL)
{
printf("Insuficiente Espacio de Memoria\n");
exit(-1); //Salir del Programa
}
7
Algoritmos de Ordenación y Búsqueda en C
Ventajas:
1. Fácil implementación.
2. No requiere memoria adicional.
Desventajas:
1. Muy lento.
2. Realiza numerosas comparaciones.
3. Realiza numerosos intercambios.
8
Algoritmos de Ordenación y Búsqueda en C
Este algoritmo también es bastante sencillo. ¿Has jugado cartas? ¿Cómo las vas ordenando
cuando las recibes? Podría ser de esta manera: Se toma la primera y la coloco en mi mano.
Luego se toma la segunda y la comparo con la que tengo: si es mayor, la pongo a la derecha, y
si es menor a la izquierda (también me fijo en el color, pero omitiremos esa parte para
concentrarme en la idea principal). Después tomar la tercera y compararlas con las que se
tienen en la mano, desplazándola hasta que quede en su posición final. Continuar haciendo
esto, insertando cada carta en la posición que le corresponde, hasta tener todas en orden.
¿Lo haces así tú también? Bueno, pues si es así entonces comprenderás fácilmente este
algoritmo, porque es el mismo concepto.
Para simular esto en un programa necesitamos tener en cuenta algo: no podemos desplazar
los elementos así como así o se perderá un elemento. Lo que se hace es guardar una copia
del elemento actual (que sería como la carta que tomamos) y desplazar todos los elementos
mayores hacia la derecha. Luego copiamos el elemento guardado en la posición del último
elemento que se desplazó.
El algoritmo para este método es el siguiente: inicialmente se ordenan los dos primeros
elementos del array, luego se inserta el tercer elemento en la posición correcta con
respecto a los tres primeros elementos ya clasificados y así sucesivamente hasta llegar al
último elemento del array.
9
Algoritmos de Ordenación y Búsqueda en C
4 - 3 - 5 - 2 - 1
temp toma el valor del segundo elemento, 3. La primera carta es el 4. Ahora comparamos: 3
es menor que 4. Luego desplazamos el 4 una posición a la derecha y después copiamos el 3
en su lugar.
4 - 4 - 5 - 2 - 1
3 - 4 - 5 - 2 - 1
El siguiente elemento es 5. Comparamos con 4. Es mayor que 4, así que no ocurren
intercambios.
Continuamos con el 2. Es menor que cinco: desplazamos el 5 una posición a la derecha:
3 - 4 - 5 - 5 - 1
Comparamos con 4: es menor, así que desplazamos el 4 una posición a la derecha:
3 - 4 - 4 - 5 - 1
Comparamos con 3. Desplazamos el 3 una posición a la derecha:
3 - 3 - 4 - 5 - 1
Finalmente copiamos el 2 en su posición final:
2 - 3 - 4 - 5 - 1
El último elemento a ordenar es el 1. Cinco es menor que 1, así que lo desplazamos una
posición a la derecha:
2 - 3 - 4 - 5 - 5
Continuando con el procedimiento la lista va quedando así:
2 - 3 - 4 - 4 - 5
2 - 3 - 3 - 4 - 5
2 - 2 - 3 - 4 - 5
1 - 2 - 3 - 4 - 5
Ejemplo #3: Programa en C que permite introducir una lista con los pesos de los N
estudiantes de la asignatura de Programación Estructurada e imprime los pesos
ordenados de menor a mayor utilizando el método de inserción.
//inserción.c
#include<stdio.h>
#include<stdlib.h>
void main()
{
float *pesos,indice;
int i,j,nest,e;
printf("Cuantos estudiantes son?: ");
scanf("%d",&nest);
pesos = (float *) malloc(nest *sizeof(float));
10
Algoritmos de Ordenación y Búsqueda en C
if(pesos==NULL)
{
printf("Insuficiente Espacio de Memoria\n");
exit(-1); //Salir del Programa
}
for (i=0; i<nest; i++)
{
printf("Peso del Estudiante[%d]: ",i+1);
scanf("%f",&pesos[i]);
}
printf("\n****ARRAY ORIGINAL****\n");
for (i=0;i<nest;i++)
printf("Peso[%d]: %.1f\n",i+1,pesos[i]);
printf("\n****ARRAY ORDENADO****\n");
for (i=0;i<nest;i++)
printf("Peso[%d]: %.1f\n",i+1,pesos[i]);
}
11
Algoritmos de Ordenación y Búsqueda en C
Ejemplo de Salida:
Ejemplo #4: Programa en C que permite introducir una lista con los pesos de los N
estudiantes de la asignatura de Programación Estructurada e imprime los pesos
ordenados de mayor a menor utilizando el método de inserción.
//inserción.c
#include<stdio.h>
#include<stdlib.h>
void main()
{
float *pesos,indice;
int i,j,nest,e;
printf("Cuantos estudiantes son?: ");
scanf("%d",&nest);
pesos = (float *) malloc(nest *sizeof(float));
if(pesos==NULL)
{
printf("Insuficiente Espacio de Memoria\n");
exit(-1); //Salir del Programa
}
12
Algoritmos de Ordenación y Búsqueda en C
printf("\n****ARRAY ORIGINAL****\n");
for (i=0;i<nest;i++)
printf("Peso[%d]: %.1f\n",i+1,pesos[i]);
printf("\n****ARRAY ORDENADO****\n");
for (i = 0;i<nest;i++)
printf("Peso[%d]: %.1f\n",i+1,pesos[i]);
}
Ejemplo de Salida:
13
Algoritmos de Ordenación y Búsqueda en C
• Estabilidad: Este algoritmo nunca intercambia registros con claves iguales. Por lo
tanto es estable.
• Requerimientos de Memoria: Una variable adicional para realizar los intercambios.
• Tiempo de Ejecución: Para una lista de n elementos el ciclo externo se ejecuta n-1
veces. El ciclo interno se ejecuta como máximo una vez en la primera iteración, 2
veces en la segunda, 3 veces en la tercera, etc. Esto produce una complejidad O(n2).
Ventajas:
1 Fácil implementación.
2 Requerimientos mínimos de memoria.
Desventajas:
1 Lento.
2 Realiza numerosas comparaciones.
Este también es un algoritmo lento, pero puede ser de utilidad para listas que están
ordenadas o semiordenadas, porque en ese caso realiza muy pocos desplazamientos.
La idea del algoritmo es simple, se basa en la división en particiones de la lista a ordenar, por
lo que se puede considerar que aplica la técnica divide y vencerás. El método es,
posiblemente, el más pequeño de código, más rápido, más elegante, más interesante y
eficiente de los algoritmos de ordenación conocidos.
El método se basa en dividir los n elementos de la lista a ordenar en dos partes o particiones
separadas por un elemento: una partición izquierda, un elemento central denominado pivote o
elemento de partición, y una partición derecha. La partición o división se hace de tal forma
que todos los elementos de la primera sublista (partición izquierda) son menores que todos
los elementos de la segunda sublista (partición derecha). Las dos sublistas se ordenan
entonces independientemente.
Para dividir la lista en particiones (sublistas) se elige uno de los elementos de la lista y se
utiliza como pivote o elemento de partición. Si se elige una lista cualquiera con los elementos
en orden aleatorio, se puede seleccionar cualquier elemento de la lista como pivote, por
14
Algoritmos de Ordenación y Búsqueda en C
ejemplo, el primer elemento de la lista. Si la lista tiene algún orden parcial conocido, se
puede tomar otra decisión para el pivote. Idealmente, el pivote se debe elegir de modo que
se divida la lista exactamente por la mitad, de acuerdo al tamaño relativo de las claves.
Una vez que el pivote ha sido elegido, se utiliza para ordenar el resto de la lista en dos
sublistas: una tiene todas las claves menores que el pivote y la otra, todos los elementos
(claves) mayores que o iguales que el pivote (o al revés). Estas dos listas parciales se
ordenan recursivamente utilizando el mismo algoritmo; es decir, se llama sucesivamente al
propio algoritmo quicksort. La lista final ordenada se consigue concatenando la primera
sublista, el pivote y la segunda lista, en ese orden, en una única lista. La primera etapa de
quicksort es la división o «particionado» recursivo de la lista hasta que todas las sublistas
constan de sólo un elemento.
El algoritmo es éste:
Recorres 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 elemento de división 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 posición adecuada para colocar el elemento
de división, porque sabemos que a un lado los elementos son todos menores y al otro son
todos mayores (o habrían sido intercambiados).
Al finalizar este procedimiento el elemento de división queda en una posición en que todos
los elementos a su izquierda son menores que él, y los que están a su derecha son mayores.
15
Algoritmos de Ordenación y Búsqueda en C
// Inicialización de variables
1. elem_div = lista[sup];
2. i = inf - 1;
3. j = sup;
4. cont = 1;
// Verificamos que no se crucen los límites
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;
14. else
15. cont = 0;
// Copiamos el elemento de división en su posición 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);
16
Algoritmos de Ordenación y Búsqueda en C
5 - 3 - 7 - 6 - 2 - 1 - 4
Comenzamos con la lista completa. El elemento divisor será el 4:
5 - 3 - 7 - 6 - 2 - 1 - 4
Comparamos con el 5 por la izquierda y el 1 por la derecha.
5 - 3 - 7 - 6 - 2 - 1 – 4
5 es mayor que cuatro y 1 es menor. Intercambiamos:
1 - 3 - 7 - 6 - 2 - 5 - 4
Avanzamos por la izquierda y la derecha:
1 - 3 - 7 - 6 - 2 - 5 - 4
3 es menor que 4: avanzamos por la izquierda. 2 es menor que 4: nos mantenemos ahí.
1 - 3 - 7 - 6 - 2 - 5 - 4
7 es mayor que 4 y 2 es menor: intercambiamos.
1 - 3 - 2 - 6 - 7 - 5 - 4
Avanzamos por ambos lados:
1 - 3 - 2 - 6 - 7 - 5 - 4
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
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
17
Algoritmos de Ordenación y Búsqueda en C
• 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 Ejecución:
Caso promedio. La complejidad para dividir una lista de n es O(n). Cada sublista genera
en promedio dos sublistas más 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 expresión es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).
El peor caso ocurre cuando la lista ya está ordenada, porque cada llamada genera sólo una
sublista (todos los elementos son menores que el elemento de división). En este caso el
rendimiento se degrada a O(n2).
Con las optimizaciones mencionadas arriba puede evitarse este comportamiento.
Ventajas:
1 Muy rápido
2 No requiere memoria adicional.
Desventajas:
1 Implementación un poco más complicada.
2 Recursividad (utiliza muchos recursos).
3 Mucha diferencia entre el peor y el mejor caso.
NOTA: En conclusión, se suele recomendar que para listas pequeñas los métodos más
eficientes son burbuja y selección; y para listas grandes, el quicksort.
18
Algoritmos de Ordenación y Búsqueda en C
Ejemplo #5: Programa en C que inicializa una lista con valores e imprime los dichos
datos ordenados de menor a mayor utilizando el método de quicksort. Nota: Versión
Array.
19
Algoritmos de Ordenación y Búsqueda en C
if(inf<der)
quicksort(lista, inf,der); //mismo proceso con sublista izqda
if(izq<sup)
quicksort(lista,izq,sup); //mismo proceso con sublista derecha
}
Ejemplo de Salida:
Ejemplo #6: Programa en C que inicializa una lista con valores e imprime los dichos
datos ordenados de mayor a menor utilizando el método de quicksort. Nota: Versión
Array.
quicksort(lista,0,n_elementos-1);
20
Algoritmos de Ordenación y Búsqueda en C
/////////////Quicksort Descendente////////////////////////
void quicksort(int lista[], int inf, int sup)
{
int mitad, x,izq, der;
izq = inf; der = sup;
mitad = lista[(izq + der)/2];
do
{
while(lista[izq] > mitad && izq < sup)
izq++;
while(mitad > lista[der] && der > inf)
der--;
if(izq <= der)
{
x = lista[izq],
lista[izq] = lista[der],
lista[der] = x;
izq++;
der--;
}
}while(izq <= der);
if(inf<der)
quicksort(lista, inf,der); //mismo proceso con sublista izqda
if(izq<sup)
quicksort(lista,izq,sup); //mismo proceso con sublista derecha
}
Ejemplo de Salida:
21
Algoritmos de Ordenación y Búsqueda en C
Ejemplo #7: Programa en C que inicializa una lista con valores e imprime los dichos
datos ordenados de menor a mayor utilizando el método de quicksort. Nota: Versión
Punteros.
//metodo_quicksort.c
#include<stdio.h>
#include<stdlib.h>
void quicksort(int *izq, int *der);
void Intercambio(int *a, int *b);
void main()
{
int lista[]={9,4,2,7,5};
int i,nelem;
nelem= sizeof(lista)/sizeof(int);
printf("\n****ARRAY ORIGINAL****\n");
for (i=0;i<nelem;i++)
printf("Elemento[%d]: %d\n",i+1,lista[i]);
printf("\n****ARRAY ORDENADO****\n");
for (i=0;i<nelem;i++)
printf("Elemento[%d]: %d\n",i+1,lista[i]);
}
while(izq<der)
{
while(*izq <= pivot && izq < (der+1))
izq++;
while(*der > pivot && der > (izq-1))
der--;
22
Algoritmos de Ordenación y Búsqueda en C
Ejemplo de Salida:
Con mucha frecuencia los programadores trabajan con grandes cantidades de datos
almacenados en arrays y registros, y por ello será necesario determinar si un array contiene
un valor que coincida con un cierto valor clave. El proceso de encontrar un elemento
específico de un array se denomina búsqueda. En esta sección se examinarán dos técnicas
de búsqueda: búsqueda lineal o secuencial, la técnica más sencilla, y búsqueda binaria o
dicotómica, la técnica más eficiente.
La búsqueda secuencial busca un elemento de una lista utilizando un valor destino llamado
clave. En una búsqueda secuencial (a veces llamada búsqueda lineal), los elementos de una
lista o vector se exploran (se examinan) en secuencia, uno después de otro.
23
Algoritmos de Ordenación y Búsqueda en C
El algoritmo de búsqueda secuencial compara cada elemento del array con la clave de
búsqueda. Dado que el array no está en un orden prefijado, es probable que el elemento a
buscar pueda ser el primer elemento, el último elemento o cualquier otro. De promedio, al
menos el programa tendrá que comparar la clave de búsqueda con la mitad de los elementos
del array. El método de búsqueda lineal funcionará bien con arrays pequeños o no ordenados.
La eficiencia de la búsqueda secuencial es pobre, tiene complejidad lineal, O(n).
//busqueda_secuencial.c
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
void main()
{
int *pdatos, nelem, dbuscar,d,result;
24
Algoritmos de Ordenación y Búsqueda en C
if(pdatos==NULL)
{
printf("Insuficiente Espacio de Memoria");
exit(-1);
}
for(d=0; d < nelem;d++)
{
printf("Elemento[%d]: ",d);
scanf("%d",(pdatos+d));
}
25
Algoritmos de Ordenación y Búsqueda en C
Ejemplo de Salida:
Se selecciona el elemento del centro o aproximadamente del centro del array. Si el valor a
buscar no coincide con el elemento seleccionado y es mayor que él, se continúa la búsqueda
en la segunda mitad del array. Si, por el contrario, el valor a buscar es menor que el valor del
elemento seleccionado, la búsqueda continúa en la primera parte del array. En ambos casos,
se halla de nuevo el elemento central, correspondiente al nuevo intervalo de búsqueda,
repitiéndose el ciclo. El proceso se repite hasta que se encuentra el valor a buscar, o bien
hasta que el intervalo de búsqueda sea nulo, lo que querrá decir que el elemento buscado no
figura en el array.
//busqueda_binaria.c
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
26
Algoritmos de Ordenación y Búsqueda en C
void main()
{
int *pdatos, nelem, dbuscar,d,result;
if (clave == valorCentral)
return (central); /* encontrado, devuelve posición */
27
Algoritmos de Ordenación y Búsqueda en C
//busqueda_binaria.c
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int BusquedaBinaria(int datos[], int nelem, int clave);
void OrdenarBurbuja (int datos[],int nelem)
{
int i,j,temp;
for (i=0;i<nelem;i++)
for(j=0;j<(nelem-1);j++)
if(datos[j] > datos[j+1])
{
temp=datos[j];
datos[j] = datos[j+1];
datos[j+1] = temp;
}
}
void main()
{
int *pdatos, nelem, dbuscar,d,result;
28
Algoritmos de Ordenación y Búsqueda en C
29
Algoritmos de Ordenación y Búsqueda en C
EJERCICIOS PROPUESTOS:
30