import java.util.Scanner; public class MetodoIntercambio { public static void main(String[] args) { Scanner entrada = new Scanner(System.in); System.out.print("Ingrese la longitud del arreglo: "); int kevin = entrada.nextInt(); int arreglo[] = new int[kevin]; for (int i = 0; i < arreglo.length; i++) { System.out.print("Ingrese: "); arreglo[i]= entrada.nextInt(); } ordIntercambiar(arreglo); } public static void intercambiar(int []a, int i, int j){ int aux = a[i]; a[i] = a[j]; a[j] = aux; } public static void ordIntercambiar(int a[]){ int i, j; for(i=0; i<a.length-1; i++){ for (j = i+1; j < a.length; j++) { if(a[i]>a[j]){ intercambiar(a,i,j); } } } System.out.println("\nORDENAMIENTO POR INTERCAMBIO..."); for (int k = 0; k < a.length; k++) { System.out.print(a[k]+"\t"); } } } import java.util.Scanner; public class MetodoInsercionDirecta { public static void main(String[] args) { Scanner entrada = new Scanner(System.in); System.out.print("Ingrese la longitud del arreglo: "); int kevin = entrada.nextInt(); int arreglo[] = new int [kevin]; for (int i = 0; i < arreglo.length; i++) { System.out.print("Ingrese: "); arreglo[i] = entrada.nextInt(); } ordInsercion(arreglo); } public static void ordInsercion(int []a){ int i, j; int aux; for (i = 1; i < a.length; i++) { j=i; aux=a[i]; while(j>0 && aux <a[j-1]){ a[j]= a[j-1]; j--; } a[j] = aux; } System.out.println("\nORDENAMIENTO POR INSERCION DIRECTA..."); for (int k = 0; k < a.length; k++) { System.out.print(a[k]+"\t"); } } } import java.util.Scanner; public class MetodoSeleccionDirecta { public static void main(String[] args) { Scanner entrada = new Scanner (System.in); System.out.print("Ingrese la longitud del arreglo: "); int kevin = entrada.nextInt(); double arreglo[] = new double[kevin]; for (int i = 0; i < arreglo.length; i++) { System.out.print("Ingrese: "); arreglo[i]= entrada.nextDouble(); } ordSeleccion(arreglo); } public static void ordSeleccion(double a[]){ int indiceMenor, i, j, n; n = a.length; for (i = 0; i < n-1; i++) { indiceMenor = i; for (j = i+1; j<n; j++) { if(a[j] < a[indiceMenor]) indiceMenor=j; if(i != indiceMenor){ a = intercambiar(a, i, indiceMenor); indiceMenor = i; } } } System.out.println("\nORDENAMIENTO POR SELECCION DIRECTA..."); for (int k = 0; k < n; k++) { System.out.print(a[k]+"\t"); } } public static double[] intercambiar(double a[], int i, int j){ double aux = a[i]; a[i] = a[j]; a[j] = aux; return a; } } import java.util.Scanner; public class MetodoShellSort { public static void main(String[] args) { Scanner entrada = new Scanner (System.in); System.out.print("Ingrese la longitud del arreglo : "); int kevin = entrada.nextInt(); int arreglo[] = new int[kevin]; for (int i = 0; i < arreglo.length; i++) { System.out.print("Ingrese numero: "); arreglo[i] = entrada.nextInt(); } shellSort(arreglo); } public static void shellSort(int a[]) { for( int gap = a.length / 2; gap > 0; gap = gap == 2 ? 1 : (int) ( gap / 2.2 ) ){ for( int i = gap; i < a.length; i++ ){ int tmp = a[ i ]; int j; for(j = i; j >= gap && tmp < a[ j - gap ] ; j -= gap ){ a[ j ] = a[ j - gap ]; } a[ j ] = tmp; } } System.out.println("\nORDENAMIENTO POR SHELL SORT..."); for (int i = 0; i < a.length; i++) { System.out.print(a[i]+"\t"); } } } import java.util.Scanner; public class MetodoQuickSort { public static void main(String[] args) { Scanner kc = new Scanner(System.in); System.out.print("Ingrese la longitud del arreglo: "); int kevin = kc.nextInt(); int arreglo[] = new int[kevin]; for (int i = 0; i < arreglo.length; i++) { System.out.print("Ingrese numero: "); arreglo[i] = kc.nextInt(); } Quicksort(arreglo, 0, kevin - 1); System.out.print("\nArreglo ordenado: "); for(int i = 0; i < kevin; i++) System.out.print(arreglo[i] + " "); } public static void Quicksort(int arr[], int p, int r){ if(p < r){ int q = Intercambio(arr, p, r); Quicksort(arr, p, q - 1); Quicksort(arr, q + 1, r); } } public static int Intercambio(int arr[], int p, int r) { int x = arr[r]; int i = p - 1, t; for(int j = p; j < r; j++){ if(arr[j] <= x){ i++; t = arr[i]; arr[i] = arr[j]; arr[j] = t; } } t = arr[i + 1]; arr[i + 1] = arr[r]; arr[r] = t; return i + 1; } } La ordenación o clasificación de datos (sort, en inglés) es una operación consistente en disponer un conjunto — estructura— de datos en algún determinado orden con respecto a uno de los campos de los elementos del conjunto. Una colección de datos (estructura) puede ser almacenada en memoria central o en archivos de datos externos guardados en unidades de almacenamiento magnético (discos, cintas, CD-ROM, DVD, etc.). Cuando los datos se guardan en un array, en una lista enlazada o en un árbol, se denomina ordenación interna; estos datos se almacenan exclusivamente para tratamientos internos que se utilizan para gestión masiva de datos, se guardan en arrays de una o varias dimensiones. 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. ¿Cómo se sabe cuál es el mejor algoritmo? La eficiencia es el factor que mide la calidad y el rendimiento de un algoritmo. En el caso de la operación de ordenación, se suelen seguir dos criterios a la hora de decidir qué algoritmo —de entre los que resuelven la ordenación— es el más eficiente: 1) tiempo menor de ejecución en computadora; 2) menor número de instrucciones. Los métodos de ordenación se suelen dividir en dos grandes grupos: Directos burbuja, selección, inserción (para listas pequeñas) Indirectos (avanzados) shell, ordenación rápida, ordenación por mezcla (listas de mayor número de elementos) ORDENAMIENTO POR INTERCAMBIO (BURBUJA) El algoritmo de ordenación tal vez más sencillo sea el denominado de intercambio, que ordena los elementos de una lista en orden ascendente. El algoritmo se basa en la lectura sucesiva de la lista a ordenar, comparando el elemento inferior de la lista con los restantes y efectuando un intercambio de posiciones cuando el orden resultante de la comparación no sea el correcto. En cada comparación se comprueba si el elemento siguiente es más pequeño que el elemento de índice 0 y en ese caso, se intercambian. Después de terminar todas las comparaciones, el elemento más pequeño se sitúa en el índice 0., luego seguimos el mismo procedimiento con la siguiente posición. ORDENAMIENTO POR INSERCION DIRECTA El método de ordenación por inserción es similar al proceso típico de ordenar tarjetas de nombres (cartas de una baraja) por orden alfabético consistente en insertar un nombre en su posición correcta dentro de una lista que ya está ordenada. El algoritmo correspondiente a la ordenación por inserción contempla los siguientes pasos: 1. El primer elemento a[0] se considera ordenado; es decir, la lista inicial consta de un elemento. 2. Se inserta a[1] en la posición correcta; delante o detrás de a[0], dependiendo de si es menor o mayor. Por cada bucle o iteración i (desde i=1 hasta n-1) se explora la sublista a[i-1] ...a[0] buscando la posición correcta de inserción de a[i]; a la vez, se mueven hacia abajo (a la derecha en la sublista) una posición todos los elementos mayores que el elemento a insertar a[i], para dejar vacía esa posición. 4. Insertar el elemento a[i] a la posición correcta. La codificación del algoritmo se realiza en el método ordInsercion(). Se pasa como argumento el array, a[], que se va a ordenar de modo creciente; el número de elementos a ordenar coincide con el atributo del array length. Los elementos del array son de tipo entero; en realidad, pueden ser de cualquier tipo básico y ordinal de Java. A la hora de analizar este algoritmo, se observa que el número de instrucciones que realiza depende del bucle automático for (bucle externo) que anida al bucle condicional while. Siendo n el número de elementos (n == a.length), el bucle externo realiza n-1 pasadas; por cada una de ellas y en el peor de los casos (aux siempre menor que a[j-1]), el bucle interno while itera un número creciente de veces que da lugar a la sucesión 1, 2, 3, ... n-1 (para i == n-1). La suma de los términos de la sucesión se ha obtenido y se ha comprobado que el término dominante es n2. Como conclusión, la complejidad del algoritmo de inserción es 0(n2). ORDENAMIENTO POR SELECCIÓN DIRECTA Consiste en buscar el menor elemento del arreglo y colocarlo en la primera posición. Luego se busca el segundo elemento más pequeño del arreglo y se coloca en la segunda posición. El proceso continua hasta que todos los elementos del arreglo han sido ordenados. El método ordSeleccion() ordena un array de números reales de n elementos, n coincide con el atributo length del array. En la pasada i, el proceso de selección explora la sublista a[i] a a[n-1] y fija el índice del elemento más pequeño. Después de terminar la exploración, los elementos a[i] y a[indiceMenor] se intercambian; operación que se realiza llamando al método intercambiar(). ORDENAMIENTO POR SHELL La ordenación Shell debe el nombre a su inventor, D. L. Shell. Se suele denominar también ordenación por inserción con incrementos decrecientes. Se considera que el método Shell es una mejora del método de inserción directa. En el algoritmo de inserción, cada elemento se compara con los elementos contiguos de su izquierda, uno tras otro. Si el elemento a insertar es el más pequeño, hay que realizar muchas comparaciones antes de colocarlo en su lugar definitivo. El algoritmo de Shell modifica los saltos contiguos resultantes de las comparaciones por saltos de mayor tamaño, y con ello se consigue que la ordenación sea más rápida. Generalmente, se toma como salto inicial n/2 (siendo n el número de elementos), y luego se reduce el salto a la mitad en cada repetición hasta que sea de tamaño 1. 74, 14, 21, 44, 38, 97, 11, 78, 65, 88, 30 En nuestro ejemplo, n=11 (porque hay 11 elementos). Así que k=n/2=11/2=5 Empezamos con k=5. Así pues, vamos a dividir nuestro arreglo original en 5 sub-arreglo, en los cuales, sus elementos estarán separados por 5 lugares del arreglo original (el salto o gap es 5). RECURSIVIDAD Un método recursivo es aquel que se llama a sí mismo, bien directamente o bien indirectamente, a través de otro método. La recursividad es un tópico importante examinado frecuentemente en cursos que estudian la resolución de algoritmos y en cursos relativos a estructuras de datos. Un enfoque recursivo se elige, normalmente, con preferencia a un enfoque iterativo cuando resulta más natural para la resolución del problema y produce un programa más fácil de comprender y de depurar. Otra razón para elegir una solución recursiva es que una solución iterativa puede no ser clara ni evidente. ORDENAMIENTO QUICKSORT El algoritmo conocido como quicksort (ordenación rápida) recibe su nombre de su autor, Tony Hoare. La idea del algoritmo es simple, se basa en la división en particiones de la lista a ordenar, por ello 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 y más interesante y eficiente de los algoritmos conocidos de ordenación. Este 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) sean 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 elegir cualquier elemento de la lista como pivote, por ejemplo, el primer elemento de la lista. Si la lista tiene algún orden parcial que se conoce, se puede tomar otra decisión para escogerlo. 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. Por ejemplo, si se tiene una lista de enteros de 1 a 10, 5 o 6 serían pivotes ideales, mientras que 1 o 10 serían elecciones “pobres” de pivotes. 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 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. ORDE NAMI ENTO MERG ESORT Este ordenamiento fue desarrollado en 1945 por John Von Neumann. Merge sort es un ordenamiento estable, paraleliza mejor, y es más eficiente manejando medios secuenciales de acceso lento. El algoritmo de ordenamiento por mezcla (merge sort) es un algoritmo de ordenamiento externo estable basado en la técnica divide y vencerás. Es a menudo la mejor opción para ordenar una lista enlazada. Conceptualmente, el ordenamiento por mezcla funciona de la siguiente manera: Si la longitud de la lista es 0 ó 1, entonces ya está ordenada. En otro caso: Dividir la lista desordenada en dos sublistas de aproximadamente la mitad del tamaño. Ordenar cada sublista recursivamente aplicando el ordenamiento por mezcla. Mezclar las dos sublistas en una sola lista ordenada. Lo que hace este método, es dividir en 2 partes el arreglo, después en otras 2 y así hasta tener los elementos separados. Comparamos los elementos y escribimos el menor. Volvemos a comparar y así hasta tener nuestro arreglo acomodado. La eficiencia de este algoritmo es bastante notable en tiempo de ejecución en comparación con otros, ya que su manera de trabajo por grupos pequeños agiliza la organización de los datos. Su utilización se da con mucha frecuencia cuando la cantidad de registros no es muy grande ya que para hacer las mezclas éste método utiliza el doble del espacio que gasta el arreglo original de valores. Este es un algoritmo estable (no intercambia los registros con claves iguales) dependiendo de la forma en que se implemente, recursivo y por tanto de complejidad O(n log2n) tanto en el peor caso como en el mejor o en el caso promedio pues el tiempo que emplea no depende de la disposición inicial de los datos.