| void Insertar(int temporal[ ], int valor, int tam) { |
|||||||
| if (tam==0) | |||||||
| temporal[0]=valor; | |||||||
| else { |
|||||||
| int x = 0, y; while(temporal[x] < valor &&x < tam) |
|||||||
| x++; | |||||||
| for(y=tam; y>x; y--) | |||||||
| temporal[y]=temporal[y-1]; | |||||||
| temporal[x]=valor; | |||||||
} |
|||||||
} |
|||||||
| void ordenar3 (int arreglo[ ], int n) { |
|||||||
int *temporal, x; |
|||||||
| Insertar(temporal, arreglo[x], x); | |||||||
| for (x=0; x<n; x++) | |||||||
| arreglo[x]=temporal[x]; | |||||||
| free(temporal); | |||||||
} |
|||||||
|
|||||||
|---|---|---|---|---|---|---|---|
El algoritmo de ordenamiento rápido se basa en el principio de dividir y conquistar (ver sección 13.2 de este libro) y busca encontrar un pivote o elemento central (idealmente debe ser el elemento del medio), ubicarlo en la posición que le corresponde y luego ubicar todos los elementos menores que él a su izquierda y los mayores a su derecha; una vez realizado este proceso, se repite el proceso para el subconjunto de elementos a la izquierda del pivote y de igual manera para el subconjunto de elementos a la derecha del pivote. Este proceso implica el uso de la técnica de recursión en la cual un proceso se llama a sí mismo. La eficiencia del algoritmo depende de la escogencia del pivote, ya que si este no queda ubicado muy cerca de la mitad del conjunto puede desequilibrar el tamaño de los dos subconjuntos, generando un alto número de llamados recursivos. Analizando su eficiencia podemos encontrar que si los pivotes coinciden siempre en los extremos del arreglo, generará exactamente n particiones, lo que implicará una complejidad de O(n2), pero si el pivote esta siempre en la mitad, la complejidad será de O(nlog2n). |
|||||||
| void Intercambio(intarreglo[], intposx, int posy) { |
|||||||
| inttemporal; temporal = arreglo[posx]; arreglo[posx] = arreglo[posy]; arreglo[posy] = temporal; |
|||||||
| } | |||||||
| intmenores(intarreglo[ ], int inicio, int fin, int valor) { |
|||||||
| intcontador = 0, x; for (x=inicio; x<=fin; x++) |
|||||||
| if (arreglo[valor] > arreglo[x]) contador ++; |
|||||||
| return(contador); | |||||||
} |
|||||||
| void particion(int arreglo[ ], int inicio, int fin, int medio) { |
|||||||
| intizquierda, derecha; izquierda=inicio;derecha=fin; while (izquierda < derecha) { |
|||||||
| while (arreglo[izquierda] < arreglo[medio]) | |||||||
| izquierda++; | |||||||
| while (arreglo[derecha] > arreglo[medio]) | |||||||
| derecha--; | |||||||
| if (izquierda < derecha) | |||||||
| Intercambio(arreglo, izquierda, derecha); | |||||||
| } | |||||||
| } | |||||||
| void quicksort(int arreglo[ ], int inicio, int fin) { |
|||||||
| intmedio; if (inicio < fin) { |
|||||||
| medio=inicio + menores(arreglo, inicio, fin, inicio); intercambio(arreglo, medio, inicio); particion(arreglo, inicio, fin, medio); quicksort(arreglo, inicio, medio-1); quicksort(arreglo, medio+1, fin); |
|||||||
| } | |||||||
} |
|||||||
| void ordenar4(int arreglo[ ], int n) { |
|||||||
| quicksort(arreglo,0, n-1); | |||||||
} |
|||||||
|
|||||||
Un montículo es una estructura de datos tipo árbol binario, cuya principal característica es que el nodo padre es mayor que sus hijos, sin importar la relación que haya entre los hijos. [5]El ordenamiento por montículo es el más lento de los algoritmos de ordenamiento con complejidad O(n log2n) pero a diferencia de los ordenamientos de mezcla y rápido, no requiere de masivos llamados recursivos para encontrar una solución, lo que lo hace bastante atractivo para grandes conjuntos de datos.
El funcionamiento del ordenamiento por montículo se basa en la construcción de un montículo de datos, el cual requiere de O(log2 n) operaciones para insertar un elemento y como son n elementos, entonces la complejidad de su construcción es O(n log2 n), y luego remueve cada uno de los elementos del montículo y lo ubica al final del arreglo; después de remover cada elemento se debe reconstruir el montículo para que siga cumpliendo con sus propiedades, lo que tiene una complejidad de O(log2 n); el proceso se realiza hasta que el montículo esté vacío, indicando que el arregloestá ordenado. |
|||||||
| void undir(int arreglo[], int raiz, int tope) { |
|||||||
| nt fin, hijo, temp;fin = 0; while ((raiz*2 <= tope) && (!fin)) { |
|||||||
| if (raiz*2 == tope) | |||||||
| hijo = raiz * 2; | |||||||
| else | |||||||
| if (arreglo[raiz * 2] > arreglo[raiz * 2 + 1]) | |||||||
| hijo = raiz * 2; | |||||||
| else | |||||||
| hijo = raiz * 2 + 1; | |||||||
| if (arreglo[raiz] < arreglo[hijo]) { |
|||||||
| temp = arreglo[raiz]; arreglo[raiz] = arreglo[hijo]; arreglo[hijo] = temp;raiz = hijo; |
|||||||
| } | |||||||
| else | |||||||
| fin = 1; | |||||||
} |
|||||||
| } | |||||||
| void ordenar5(int arreglo[], int n) { |
|||||||
| int i, temp; for (i = (n / 2)-1; i >= 0; i--) |
|||||||
| undir(arreglo, i, n); | |||||||
| for (i = n-1; i >= 1; i--) { |
|||||||
| temp = arreglo[0]; arreglo[0] = arreglo[i]; arreglo[i] = temp; undir(arreglo, 0, i-1); |
|||||||
| } | |||||||
| } | |||||||
|
|||||||
Mediante el enfoque de Dividir y conquistar, este algoritmo divide el arreglo inicial en dos arreglos donde cada uno contiene la mitad de los datos (partes iguales mas o menos uno), y se ordenan mediante sucesivos llamados recursivos para luego fusionar los resultados en el arreglo inicial. Este algoritmo se basa en una función que permite mezclar dos vectores ordenados, produciendo como resultado un tercervector ordenado que contiene los elementos de los dos vectores iniciales, el cual tiene una complejidad de O(n) para mezclar dos arreglos, donde n es la suma de los tamaños de los dos arreglos. El algoritmo principal que divide el arreglo, realiza O(log2 n) particiones y como llama a la función que mezcla los dos arreglos y que tiene una complejidad de O(n), entonces la complejidad total del algoritmo será de O(n log2 n). |
|||||||
| void mezclar(int arreglo1[], int n1,int arreglo2[],int n2, int arreglo3[]) { |
|||||||
int x1,x2,x3; |
|||||||
| if (arreglo1[x1]<arreglo2[x2]) { |
|||||||
| arreglo3[x3]=arreglo1[x1];x1++; | |||||||
| } | |||||||
| else { |
|||||||
| arreglo3[x3]=arreglo2[x2]; x2++; |
|||||||
| } | |||||||
| x3++; | |||||||
} |
|||||||
| while (x1<n1) { |
|||||||
| arreglo3[x3]=arreglo1[x1]; x1++; x3++; } |
|||||||
| while (x2<n2) { |
|||||||
| arreglo3[x3]=arreglo2[x2]; x2++; x3++; |
|||||||
| } | |||||||
} |
|||||||
| void mezcla(int vector[], int n) { |
|||||||
| int *vector1, *vector2, n1, n2,x,y; if (n>1) { |
|||||||
| if (n%2 == 0) | |||||||
| n1=n2=(int) n / 2; | |||||||
| else { |
|||||||
| n1=(int) n / 2;n2=n1+1; | |||||||
| } | |||||||
| vector1=(int *) malloc(sizeof(int)*n1); vector2=(int *) malloc(sizeof(int)*n2); for(x=0;x<n1;x++) |
|||||||
| vector1[x]=vector[x]; | |||||||
| for(y=0;y<n2;x++,y++) | |||||||
| vector2[y]=vector[x]; mezcla(vector1, n1); mezcla(vector2,n2); mezclar(vector1, n1, vector2, n2, vector); free(vector1); free(vector2); |
|||||||
| } | |||||||
| } | |||||||
| void ordenar6(int arreglo[], int n) { |
|||||||
| mezcla(arreglo,n); | |||||||
} |
|||||||