INVESTIGACION SOBRE LOS TIPOS DE ORDENAMIENTOS DE DATOS INVESTIGACIÓN TI 4AMD ALUMNO: Paul Eduardo Torres Hernández 1 Contenido CONCEPTO DE ORDENACIÓN ................................................................................................... 1 METODOS DE ORDENAMIENTO ............................................................................................ 1 Ordenamiento Burbuja............................................................................................................. 2 Ordenamiento por montículos (heapsort) ............................................................................. 7 Ordenamiento por selección ................................................................................................. 12 Ordenamiento por inserción.................................................................................................. 14 Ordenamiento Rápido (Quicksort) ....................................................................................... 16 Ordenamiento Shell................................................................................................................ 20 CUADRO COMPARATIVO DE LOS METODOS DE ORDENAMIENTO.......................... 25 REFERENCIAS .......................................................................................................................... 26 CONCEPTO DE ORDENACIÓN La ordenación de los datos consiste en disponer o clasificar un conjunto de datos (o una estructura) en algún determinado orden con respecto a alguno de sus campos. Orden: Relación de una cosa con respecto a otra. Clave: Campo por el cual se ordena. METODOS DE ORDENAMIENTO Los problemas más comunes en la informática son la búsqueda y el ordenamiento. El proceso de ordenar consiste en recolocar los elementos de un array o colección ya sea de mayor a menor o viceversa con el fin de acelerar la búsqueda de la información. En este aspecto existe una multitud de algoritmos de ordenamiento clasificados de diversas formas como la estabilidad, su complejidad, ubicación del proceso al ordenar, etc. Existen diferentes tipos de métodos: Ordenamiento por burbuja Ordenamiento por montículos Ordenamiento por selección Ordenamiento por inserción Ordenamiento rápido (QuickSort) 1 Ordenamiento shell Ordenamiento Burbuja Es el algoritmo de ordenamiento más sencillo de todos, conocido también como método del intercambio directo. Funciona revisando cada elemento de la lista que va a ser ordenada con el siguiente, intercambiándolos de posición si están en el orden equivocado. Es necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios, lo cual significa que la lista está ordenada. Este algoritmo obtiene su nombre de la forma con la que suben por la lista los elementos durante los intercambios, como si fueran pequeñas "burbujas". También es conocido como el método del intercambio directo. Dado que solo usa comparaciones para operar elementos, se lo considera un algoritmo de comparación, siendo el más sencillo de implementar. Una manera simple de expresar el ordenamiento de burbuja en pseudocódigo es la siguiente: Este algoritmo realiza el ordenamiento de una lista a de n valores, en este caso de n términos numerados del 0 al n-1, consta de dos bucles anidados uno con el índice i, que da un tamaño menor al recorrido de la burbuja en sentido inverso de 2 a n, y un segundo bucle con el índice j, con un recorrido desde 0 hasta n-i, para cada iteración del primer bucle, que indica el lugar de la burbuja. La burbuja son dos términos de la lista seguidos, j y j+1, que se comparan, si el primero es menor que el segundo sus valores se intercambian. Esta comparación se repite en el centro de los dos bucles, dando lugar a la postre a una lista ordenada, puede verse que el número de repeticiones sola depende de n, y no del orden de los términos, esto es, si pasamos al algoritmo una lista ya ordenada, realizara todas las comparaciones exactamente igual que para una lista no ordenada, esta es una característica de este algoritmo. Un ejemplo del método burbuja son los siguientes: La clase con el siguiente código permite ordenar los elementos de un array unidimensional mediante este método. 2 Para comprobar se utiliza lo siguiente La salida nos da: Se comprueba el ordenamiento. Ejemplo 2 3 Supóngase que desean ordenar las siguientes claves del arreglo A, transportando en cada pasada el menor elemento hacia la parte izquierda del arreglo. A: 15 67 08 16 44 27 12 35 Las comparaciones que se realizan son las siguientes: PRIMERA PASADA: a[6]>a[7] (12>35) no hay intercambio a[5]>a[6] (27>12) si hay intercambio a[4]>a[5] (44>12) si hay intercambio a[3]>a[4] (16>12) si hay intercambio a[2]>a[3] (08>12) no hay intercambio a[1]>a[2] (67>08) si hay intercambio a[0]>a[1] (15>08) si hay intercambio A: 08 15 67 12 16 44 27 35 Obsérvese que el elemento 08 fue situado en la parte izquierda del arreglo. SEGUNDA PASADA: a[6]>a[7] (27>35) no hay intercambio a[5]>a[6] (44>27) si hay intercambio a[4]>a[5] (16>27) no hay intercambio a[3]>a[4] (12>16) no hay intercambio a[2]>a[3] (67>12) si hay intercambio a[1]>a[2] (15>12) si hay intercambio A: 08 12 15 67 16 27 44 35 y el segundo elemento más pequeño del arreglo, en este caso 12, fue situado en la segunda posición. A continuación, se muestra el resultado de las siguientes pasadas: 3era. Pasada: 08 12 15 16 67 27 35 44 4ta. Pasada: 08 12 15 16 27 67 35 44 5ta. pasada: 08 12 15 16 27 35 67 44 6ta. Pasada: 08 12 15 16 27 35 44 67 4 7ma. Pasada: 08 12 15 16 27 35 44 67 Codificación en Java : Otro ejemplo Un ordenamiento burbuja se considera frecuentemente como el método de ordenamiento más ineficiente ya que debe intercambiar ítems antes de que se conozca su ubicación final. Estas operaciones de intercambio “desperdiciadas” son muy costosas. Sin embargo, debido a que el ordenamiento burbuja hace pasadas por toda la parte no ordenada de la lista, tiene la capacidad de hacer algo que la mayoría de los algoritmos de ordenamiento no pueden. En particular, si durante una pasada no hubo intercambios, entonces sabemos que la lista ya debe estar ordenada. Un ordenamiento burbuja se puede modificar para detenerse anticipadamente si encuentra que la lista ya ha sido ordenada. Esto significa que 5 para las listas que requieran sólo unas pocas pasadas, un ordenamiento burbuja puede tener la ventaja de reconocer que la lista ya está ordenada y se detendrá. El ActiveCode 2 muestra esta modificación, que a menudo se conoce como el ordenamiento burbuja corto. Ejemplo de ordenamiento burbuja corto 6 Ordenamiento por montículos (heapsort) El ordenamiento por montículos es un algoritmo de ordenación basado en la comparación. Su nombre proviene de la estructura de datos del montón utilizada en el algoritmo. El montón es una estructura de datos especial basada en un árbol binario. Tiene las siguientes dos propiedades: Es un árbol binario completo con todos los niveles llenos excepto el último. El último puede estar parcialmente lleno, pero todos los nodos están lo más a la izquierda posible. Todos los nodos padres (parent) son más pequeños/más grandes que sus dos nodos hijos (rightchild. Leftchild). Si son más pequeños, el montón se llama min-heap, y si son más grandes, entonces el montón se llama maxheap. Para un índice dado i, el padre está dado por (i-1)/2, el hijo izquierdo (leftchild) está dado por (2*i+1) y el hijo derecho(rightchild) está dado por (2*i+2). La ordenación en pila funciona de forma muy similar a la ordenación por selección. Selecciona el elemento máximo del array usando max-heap y lo coloca en su posición al final del array. Hace uso de un procedimiento llamado heapify() para construir el montón. Supongamos que tenemos un array A[] sin ordenar que contiene n elementos. HeapSort() 1. Construye un montón máximo con los elementos presentes en el array A. 2. Para cada elemento empezando por el último elemento de A haz lo siguiente. 7 3. El elemento raíz A[0] contendrá el elemento máximo, cámbialo por este elemento. 4. Reduce el tamaño del heap en uno y Heapify() el heap máximo con el último elemento eliminado. Heapify() 1. Inicializa el índice parent con el índice del elemento actual. 2. Calcula leftChild como 2*i+1 y rightChild como 2*i+2. 3. Si el elemento en el leftChild es mayor que el valor en el índice parent establece el índice parent como leftChild. 4. Si el elemento en el rightChild es mayor que el valor en el índice parent establece el índice parent a rightChild. 5. Si el valor del índice parent ha cambiado en los dos últimos pasos, entonces intercambia parent con el elemento actual y recursivamente heapify el subárbol del índice parent. En caso contrario, la propiedad heap ya está satisfecha. Supongamos contiene n elementos. que tenemos un array A[] sin ordenar que Ejemplo de ordenamiento por montículos Supongamos que tenemos el array (5, 3, 4, 2, 1, 6). Vamos a ordenarlo utilizando el algoritmo de ordenación del montón. Después de construir el montón, obtenemos el array como: (6 3 5 2 1 4). Primera Iteración: Swap(A[5],A[0]) 4 3 5 2 1 6 Heapify() 5 3 4 2 1 6 Segunda Iteración: Swap(A[4],A[0]) 1 3 4 2 5 6 Heapify() 4 3 1 2 5 6 8 Tercera Iteración: Swap(A[3],A[0]) 2 3 1 4 5 6 Heapify() 3 2 1 4 5 6 Cuarta Iteración: Swap(A[2],A[0]) 1 2 3 4 5 6 Heapify() 2 1 3 4 5 6 Quinta Iteración: Swap(A[1],A[0]) 1 2 3 4 5 6 Heapify() 1 2 3 4 5 6 Sexta Iteración: Swap(A[0],A[0]) 1 2 3 4 5 6 Heapify() 1 2 3 4 5 6 Obtenemos el array ordenado como : (1,2,3,4,5,6) Implementación del Algoritmo de ordenamiento por montículos #include<bits/stdc++.h> using namespace std; 9 void heapify(int arr[], int n, int i) { int parent = i; int leftChild = 2 * i + 1; int rightChild = 2 * i + 2; if (leftChild < n && arr[leftChild] > arr[parent]) parent = leftChild; if (rightChild < n && arr[rightChild] > arr[parent]) parent = rightChild; if (parent != i) { swap(arr[i], arr[parent]); heapify(arr, n, parent); } } void heapSort(int arr[], int n) { for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i); 10 for (int i = n - 1; i >= 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); } } int main() { int n = 6; int arr[6] = {5, 3, 4, 2, 1, 6}; cout << "Input array: "; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << "\n"; heapSort(arr, n); // Sort elements in ascending order cout << "Output array: "; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << "\n"; } 11 Complejidad del algoritmo de ordenamiento por montículos Complejidad de tiempo Caso medio La altura de un árbol binario completo con n elementos es como máximo logn. Por lo tanto, la función heapify() puede tener un máximo de logn comparaciones cuando un elemento se mueve de la raíz a la hoja. La función Heapify() es llamada para n/2 elementos haciendo que la complejidad de tiempo total para la primera etapa sea n/2*logn o T(n) = nlogn. La función HeapSort() requiere el peor tiempo de logn para cada elemento, y n elementos hacen que su complejidad de tiempo sea también nlogn. Tanto la complejidad temporal de la construcción del montón como la del ordenamiento del montón se suman y nos dan la complejidad resultante como nlogn. Por lo tanto, la complejidad temporal total es del orden de [Big Theta]: O(nlogn). El peor caso La complejidad temporal en el peor caso es [Big O]: O(nlogn). El mejor caso La complejidad temporal en el mejor de los casos es [Big Omega]: O(nlogn). Es la misma que la complejidad temporal del peor caso. Complejidad espacial La complejidad espacial del algoritmo de ordenación del montón es O(1) porque no se necesita más memoria que la de las variables temporales. Ordenamiento por selección El ordenamiento por selección mejora el ordenamiento burbuja haciendo un sólo intercambio por cada pasada a través de la lista. Para hacer esto, un ordenamiento por selección busca el valor mayor a medida que hace una pasada y, después de completar la pasada, lo pone en la ubicación correcta. Al igual que con un ordenamiento burbuja, después de la primera pasada, el ítem mayor está en la ubicación correcta. Después de la segunda pasada, el siguiente mayor está en su ubicación. Este proceso continúa y requiere n−1 pasadas para ordenar los n ítems, ya que el ítem final debe estar en su lugar después de la (n−1)-ésima pasada. Es decir, el método de ordenación por selección consiste en repetir los siguientes pasos: 12 Se busca el elemento más pequeño del array y se coloca en la primera posición. Entre los restantes, se busca el elemento más pequeño y se coloca en la segunda posición. Entre los restantes se busca el elemento más pequeño y se coloca en la tercera posición. Este proceso se repite hasta colocar el último elemento. De forma gráfica el proceso sería el siguiente: Array original a ordenar: [50, 26, 7, 9, 15, 27] El método de ordenación por selección en java para ordenar un array de enteros A es el siguiente: //método java public static int for el primero de ordenación por selección void seleccion(int A[]) { i, j, menor, pos, tmp; (i = 0; i < A.length - 1; i++) { // tomamos como menor menor = A[i]; // de los elementos que quedan por ordenar pos = i; // y guardamos su posición for (j = i + 1; j < A.length; j++){ // buscamos en el resto if (A[j] < menor) { // del array algún elemento menor = A[j]; // menor que el actual pos = j; } } if (pos != i){ // si hay alguno menor se intercambia tmp = A[i]; A[i] = A[pos]; A[pos] = tmp; } } } 13 Ordenamiento por inserción El ordenamiento por inserción es un algoritmo de ordenación simple basado en la comparación. En este algoritmo, mantenemos dos submatrices: una ordenada y otra sin ordenar. Un elemento de la subarray sin ordenar encuentra su posición correcta en la subarray ordenada y se inserta allí. Es análogo a la forma en que alguien ordena una baraja de cartas en su mano. Se llama ordenamiento por inserción porque funciona insertando un elemento en su posición correcta. Este algoritmo es eficiente para conjuntos de datos pequeños pero no es adecuado para conjuntos de datos grandes. Este método básicamente consiste en recorrer todo el array comenzando desde el segundo elemento hasta el final. Para cada elemento, se trata de colocarlo en el lugar correcto entre todos los elementos anteriores a él o sea entre los elementos a su izquierda en el array. Dada una posición actual p, el algoritmo se basa en que los elementos A[0], A[1], ..., A[p-1] ya están ordenados. De forma gráfica el proceso que sigue el método de inserción directa es el siguiente: El método de Ordenamiento por inserción directa en Java es el siguiente: public static void insercionDirecta(int A[]){ int p, j; int aux; 14 for (p = 1; p < A.length; p++){ //desde el segundo elemento hasta aux = A[p]; // el final, guardamos el elemento y j = p - 1; // empezamos a comprobar con el anterior while ((j >= 0) && (aux < A[j])){ // mientras queden posiciones y el // valor de aux sea menor que los A[j + 1] = A[j]; //de la izquierda,se desplaza a j--; // la derecha } A[j + 1] = aux; // colocamos aux en su sitio } Ejemplos Ordenamiento de un “Array” de enteros utilizando el método de ordenamiento por inserción. public class OrdenamientoInsercion { /** * @param args the command line arguments */ public static void main(String[] args) { OrdenamientoInsercion orden = new OrdenamientoInsercion(); int[] nums = {1,4,9,59,23,26,20,1,23,56,7}; int[] ordenarInsercion = orden.ordenarInsercion(nums); for (int i = 0; i < ordenarInsercion.length; i++) { System.out.println(ordenarInsercion[i]); } } public int[] ordenarInsercion(int[] array){ int aux; for (int i = 1; i < array.length; i++) { aux = array[i]; for (int j = i-1; j >=0 && array[j]>aux; j--) { array[j+1]=array[j]; array[j]=aux; } } return array; } } 15 Ordenamiento Rápido (Quicksort) Es el algoritmo de ordenamiento más eficiente de todos, el ordenamiento rápido usa dividir y conquistar para obtener las mismas ventajas que el ordenamiento por mezcla, pero sin utilizar almacenamiento adicional. 16 Un ordenamiento rápido primero selecciona un valor, que se denomina el valor pivote. Aunque hay muchas formas diferentes de elegir el valor pivote, simplemente usaremos el primer ítem de la lista. El papel del valor pivote es ayudar a dividir la lista. La posición real a la que pertenece el valor pivote en la lista final ordenada, comúnmente denominado punto de división, se utilizará para dividir la lista para las llamadas posteriores a la función de ordenamiento rápido. 54 servirá como nuestro primer valor pivote. Como ya hemos visto este ejemplo unas cuantas veces, sabemos que 54 eventualmente terminará en la posición que actualmente contiene a 31. El proceso de partición sucederá a continuación. Encontrará el punto de división y al mismo tiempo moverá otros ítems al lado apropiado de la lista, según sean menores o mayores que el valor pivote. El primer valor pivote para un ordenamiento rápido El particionamiento comienza localizando dos marcadores de posición llamémoslos marcaIzq y marcaDer- al principio y al final de los ítems restantes de la lista (posiciones 1 y 8 en la Figura 13). El objetivo del proceso de partición es mover ítems que están en el lado equivocado con respecto al valor pivote mientras que también se converge en el punto de división. 17 Encontrar el punto de división para el 54 Comenzamos incrementando marcaIzq hasta que localicemos un valor que sea mayor que el valor pivote. Luego decrementamos marcaDer hasta que encontremos un valor que sea menor que el valor pivote. En tal punto habremos descubierto dos ítems que están fuera de lugar con respecto al eventual punto de división. Para nuestro ejemplo, esto ocurre en 93 y 20. Ahora podemos intercambiar estos dos ítems y luego repetir el proceso de nuevo. Nos detendremos en el punto donde marcaDer se vuelva menor que marcaIzq. La posición de marcaDer es ahora el punto de división. El valor pivote se puede intercambiar con el contenido del punto de división y el valor pivote está ahora en su lugar. Además, todos los ítems a la izquierda del punto de división son menores que el valor pivote y todos los ítems a la derecha del punto de división son mayores que el valor pivote. La lista ahora se puede dividir en el punto de división y el ordenamiento rápido se puede invocar recursivamente para las dos mitades. 18 Finalización para completar el proceso de partición para encontrar el punto de división para 54 La función ordenamientoRapido mostrada en el ActiveCode 1 invoca una función recursiva. La función ordenamiento Rapido Auxiliar comienza con el mismo caso base que el ordenamiento por mezcla. Si la longitud de la lista es menor o igual a uno, ya está ordenada. Si es mayor, entonces puede ser particionada y ordenada recursivamente. La función partición implementa el proceso descrito anteriormente. Codificación en Java: Hay diferentes maneras de elegir el valor pivote. En particular, podemos tratar de aliviar algunas de las posibilidades de una división desigual mediante el uso de una técnica denominada mediana de tres. Para elegir el valor pivote, 19 consideraremos el primer ítem, el ítem medio y el último ítem de la lista. En nuestro ejemplo, son 54, 77 y 20. Ahora escogemos el valor de la mediana, en nuestro caso 54, y lo usamos para el valor pivote (por supuesto, ése era el valor pivote que utilizamos originalmente). La idea es que en caso que el primer ítem de la lista no pertenezca al centro de la lista, la mediana de tres elegirá un mejor valor “central”. Esto será particularmente útil cuando la lista original ya está algo ordenada al comenzar. Ordenamiento Shell El ordenamiento de Shell, a veces llamado “ordenamiento de incremento decreciente”, mejora el ordenamiento por inserción al romper la lista original en varias sublistas más pequeñas, cada una de las cuales se ordena mediante un ordenamiento por inserción. La manera única en que se eligen estas sublistas es la clave del ordenamiento de Shell. En lugar de dividir la lista en sublistas de ítems contiguos, el ordenamiento de Shell usa un incremento i, a veces denominado brecha, para crear una sublista eligiendo todos los ítems que están separados por i ítems. 20 Se puede apreciar en lo siguiente: La lista tiene nueve ítems. Si usamos un incremento de tres, hay tres sublistas, cada una de las cuales puede ordenarse mediante un ordenamiento por inserción. Después de completar estos ordenamientos, obtenemos la lista que se muestra en la Figura 7. Aunque esta lista no está completamente ordenada, ha ocurrido algo muy interesante. Al ordenar las sublistas, hemos acercado los ítems a donde realmente pertenecen. Un ordenamiento de Shell con incrementos de tres. Un ordenamiento de Shell después de ordenar cada sublista. A continuación se presenta muestra de un ordenamiento por inserción final que usa un incremento de uno; en otras palabras, un ordenamiento por inserción estándar. Se puede apreciar que mediante la realización anticipada de los ordenamientos de las sublistas, se ha reducido el número total de operaciones de desplazamiento necesarias para poner la lista en su orden definitivo. Para este caso, sólo se necesita cuatro desplazamientos más para completar el proceso. 21 Ordenamiento de Shell: Un ordenamiento por inserción final con incremento de 1. Sublistas iniciales para el ordenamiento de Shell. La forma en que se eligen los incrementos es la característica única del ordenamiento de Shell. La función mostrada en el siguiente ActiveCode 1 utiliza un conjunto diferente de incrementos. En este caso, comenzamos con n2 sublistas. En la siguiente pasada, se ordenan n4 sublistas. Eventualmente, se ordena una sola lista con el ordenamiento por inserción básico. La Figura 9 muestra las primeras sublistas para nuestro ejemplo usando este incremento. La siguiente invocación a la función ordenamientoDeShell muestra las listas parcialmente ordenadas después de cada incremento, siendo el ordenamiento final un ordenamiento por inserción con un incremento de uno. 22 En resumen, es una mejora del método de inserción directa, utilizado cuando el array tiene un gran número de elementos. Cualquier algoritmo de ordenación que intercambia elementos adyacentes (como los algoritmos burbuja, selección o inserción) tiene un tiempo promedio de ejecución de orden cuadrático (n2). El método Shell mejora este tiempo comparando cada elemento con el que está a un cierto número de posiciones llamado salto, en lugar de compararlo con el el que está justo a su lado. Este salto es constante, y su valor inicial es N/2 (siendo N el número de elementos, y siendo división entera). Se van dando pasadas con el mismo salto hasta que en una pasada no se intercambie ningún elemento de sitio. Entonces el salto se reduce a la mitad, y se vuelven a dar pasadas hasta que no se intercambie ningún elemento, y así sucesivamente hasta que el salto vale 1. El método Shell de ordenación en Java para ordenar un array A de enteros es el siguiente: public static void shell(int A[]) { int salto, aux, i; boolean cambios; for (salto = A.length / 2; salto != 0; salto /= 2) { cambios = true; while (cambios) { // Mientras se intercambie algún elemento cambios = false; for (i = salto; i < A.length; i++) // se da una pasada { if (A[i - salto] > A[i]) { aux = A[i]; // y si están desordenados // se reordenan A[i] = A[i - salto]; A[i - salto] = aux; cambios = true; // y se marca como cambio. 23 } } } } } Ejemplo de ejecucion Con sólo 6 intercambios se ha ordenado el array, cuando por inserción se necesitaban muchos más. El rendimiento del método Shell de ordenación es bastante aceptable, aún para el caso de un número de elementos muy grande. Se ha comprobado que el tiempo de ejecución promedio es de O(n2/3) para la mayoría de las secuencias de salto. A primera vista usted podría pensar que un ordenamiento de Shell no puede ser mejor que un ordenamiento por inserción, ya que ejecuta un ordenamiento por inserción completo como último paso. Resulta, sin embargo, que este ordenamiento por inserción final no necesita hacer muchas comparaciones (o desplazamientos) ya que la lista ha sido pre-ordenada mediante ordenamientos por inserción incrementales anteriores, como se describió antes. En otras palabras, cada pasada produce una lista que está “más ordenada” que la anterior. Esto hace que la pasada final sea muy eficiente. 24 CUADRO COMPARATIVO DE LOS METODOS DE ORDENAMIENTO 25 REFERENCIAS o Métodos de Ordenamiento. (s/f). Blogspot.com. Recuperado el 17 de octubre de 2021, de https://gl-epn-programacionii.blogspot.com/2010/06/metodos-de-ordenamiento.html o De datos, U. V. E. (s/f). Métodos de Ordenamiento. Edu.mx. Recuperado el 17 de octubre de 2021, de http://mapaches.itz.edu.mx/~mbarajas/edinf/Ordenamiento.pdf o El ordenamiento rápido — Solución de problemas con algoritmos y estructuras de datos. (s/f). Runestone.academy. Recuperado el 17 de octubre de 2021, de https://runestone.academy/runestone/static/pythoned/SortSearch/ElOrdena mientoRapido.html o El ordenamiento por selección — Solución de problemas con algoritmos y estructuras de datos. (n.d.). Runestone.Academy. Retrieved October 19, 2021,fromhttps://runestone.academy/runestone/static/pythoned/SortSearch/ ElOrdenamientoPorSeleccion.html o Macaray, J.-F., & Nicolas, C. (1996). Programacion java. Gestion 2000. o o Hernandez, P. P. G. (s/f). Ordenación por montículos (Heapsort). Com.mx. Recuperado el 17 de octubre de 2021, de https://pier.guillen.com.mx/algorithms/03-ordenacion/03.4-heapsort.htm o Jindal, H. (2021, February 25). Ordenamiento por montículos. Delftstack.com. https://www.delftstack.com/es/tutorial/algorithm/heap-sort/ o Tipos de ordenamiento. (2013, abril 15). Wordpress.com. https://cotearratia.wordpress.com/unidad-i-algoritmo-de-busqueda-yordenamiento/eficiencia-de-los-algoritmos/tipos-de-ordenamiento/ 26