Algoritmos de ordenamiento

Slides:



Advertisements
Presentaciones similares
Algoritmos de Ordenamiento y Complejidad
Advertisements

Presentado por: Yuli Dominguez. Portal Educa Panamá. Sistema de numeración.
Búsqueda binaria Integrantes: Humberto Raíz Walter Gómez Isabel Hernández.
PPTCES047MT22-A16V1 Clase Medidas de dispersión y muestreo MT-22.
8-Puzle consiste en un tablero cuadrado (3x3) en el que hay situados 8 bloques cuadrados numerados (con lo cual se deja un hueco del tamaño de un bloque).
Búsqueda Binaria Castillo Soria Luis Fernando Méndez Tinajero Armando Pérez Ramos Susana.
1 Ordenación, Clasificación Introducción Algoritmos Complejidad.
SISTEMAS NUMERICOS ING. SUSANA BELTRAN.
Ingreso , proceso y salida de datos
Métodos de compresión sin pérdida de información
Qué es una derivada? “La pregunta del millón…”
Técnica de evaluación y revisión de programas
Programación 1 Curso: 5to. I TT
Universidad Autónoma del Estado de México
Ingeniería en Sistemas
Selección directa “Heapsort”
Tema 4 Elementos para el Desarrollo de Algoritmos
Montículos Binarios (Binary Heaps)
Complejidad Programación II de febrero de 2009.
Unidad 3: Eficiencia de Algoritmos Tema VI: Ordenamiento.
IPOO 2 cuatrimestre 2017 Departamento de Ciencias e Ingeniería
IPOO 2 cuatrimestre 2017 Departamento de Ciencias e Ingeniería
Unidad 7: Nivel Interno Algunos Conceptos Importantes
TUTORIAL PSeint.
Matemática Quinto Básico
CREAR DIAGRAMA DE FLUJO
Listas Dinámicas.
Tipos de Datos abstractos
Carpetas y archivos.
Unidad 3. Introducción a la programación
Universidad Nacional de Loja
Introducción a las estructuras de datos
HISTORIA El lenguaje fue creado por Yukihiro "Matz" Matsumoto, quien empezó a trabajar en Ruby el 24 de febrero de 1993, y lo presentó al público en el.
Aplicaciones de RECURSIVIDAD
ARREGLOS BIDIMENSIONALES MATRICES Son un espacio de almacenamiento continuo, que contiene una serie de elementos del mismo tipo de datos. Desde el punto.
ELEMENTOS DE COMPUTACIÓN Profesor: Guillermo Figueroa
HERRAMIENTAS DE PROGRAMACIÓN
Árboles clase 6 Apoyo de Práctica. Resumen ●Árboles ○Concepto ○Características ○Dinámica ○Recorridos o barridos. ●Ejercicio Sugerido.
ÁRBOLES ESTRUCTURA DE DATOS II ING. CARLOS ALBERTO PULLAS.
Métodos de búsqueda. Introdución Esta operación se utiliza basicamente para recuperar datos que se habian almacenado con anticipación. El resultado puede.
Agentes que planifican. 1. Introduccion En la actualidad todas la mayoría de actividades en un empresa o compañía, como en el hogar o el medio ambiente.
Árboles Binarios de Búsqueda (ABB)
GRAFOS ESTRUCTURAS DE DATOS.
Método de ordenamiento SHELL Aparicio Pérez Antonio Habacuc Domínguez Hernández Jonathan Gallegos Matinés Josué Roberto Rincón Solís Adriana Elizabeth.
Estructura de Datos M.C. J. Andrés V. F. FCC/BUAP
Curso de Programación Estructurada
TEMAS *Arboles Binarios *listas Abiertas y Cerradas - Inserción - Recorrido - Eliminación *Pilas - Concepto - Inserción - Recorrido -
Tema 7 Arreglos Parte 3.
Técnicas de conteo: Permutaciones y variaciones
Análisis de rendimiento de dos algoritmos de búsqueda secuencial de texto con sus respectivas variantes Mauricio Ulate Quirós
Conversión de Binario a Decimal
CICLOS EN JAVA FOR, WHILE, DO WHILE Un ciclo en Java o bucle en Java (como prefieras llamarlo) permite repetir una o varias instrucciones cuantas veces.
MC Beatriz Beltrán Martínez Verano 2018
Capítulo 17: Recursividad.
Estructura de Datos M.C. José Andrés Vázquez Flores FCC/BUAP Árboles AVL Objetivos:  Entender la importancia que tiene el balanceo en un ABB.  Describir.
Arboles. Árboles ¿Qué son? Son Estructuras de datos “No lineales”” ¿Para que se utilizan? Representar Fórmulas Algebraicas Organizar Objetos Inteligencia.
ÁRBOLES DE EXPRESION. Un árbol de expresión sirve para evaluar expresiones del tipo: (a+b)*c/d Para que un árbol represente una expresión se deben tomar.
METODOS DE ORDENAMIENTO CHRISTIAN MICHAEL OBANDO GARCES JOAO ADRIAN BARIONUEVO.
Árboles Binarios Estructuras de Datos.
Ordenamiento Ordenar una estructura de datos consiste en reacomodar sus elementos de acuerdo a algún criterio. Por ejemplo, los mensajes pueden ordenarse.
Nelson Baloian, José A. Pino
Complejidad algorítmica
METODOS DE ORDENAMIENTO
IPOO 2 cuatrimestre 2018 Departamento de Ciencias e Ingeniería
Árboles Binarios Estructuras de Datos. Las estructuras dinámicas son las en la ejecución varia el número de elementos y uso de memoria a lo largo del.
ALGORITMO Y ESTRUCTURA DE DATOS II UNIDAD 3 ORDENAMIENTO Y BUSQUEDA MARCOS RODRIGUEZ /4/2019ALGORITMO Y ESTRUCTURA DE DATOS II 1 Prof.
ALGORITMO DE ORDENAMIENTO POR BURBUJA. El método de la burbuja es uno de los mas simples, es tan fácil como comparar todos los elementos de una lista.
ORDENAMIENTO POR EL MÉTODO DEL SHAKER SORT (SACUDIDA)
Estrategia algorítmica
SISTEMAS NUMERICOS “Introducción a la Programación” Rolando Montero.
Transcripción de la presentación:

Algoritmos de ordenamiento Capítulo 9: Algoritmos de ordenamiento

En este capítulo se tratarán los siguientes temas: 9.1 Introducción 9.2 Bubble sort (ordenamiento por burbujeo) 9.3 Selection sort (ordenamiento por selección) 9.4 Insertion sort (ordenamiento por inserción) 9.5 Quicksort (ordenamiento rápido) 9.6 Heapsort (ordenamiento por montículos) 9.7 Shellsort (ordenamiento Shell) 9.8 Binsort (ordenamiento por cajas) 9.9 Radix sort (ordenamiento de raíz)

9.1 Introducción Explicaremos la lógica de los algoritmos de ordenamiento, analizaremos su complejidad algorítmica e incluso mediremos su rendimiento, pero en todos los casos la implementación quedará a cargo del lector y constituirá la guía de ejercicios del presente capítulo. Veremos que los algoritmos más simples, como el caso de bubble sort, tienen un orden de complejidad cuadrática O(n2) mientras que los más eficientes, y también más difíciles de implementar, tienen una complejidad cuasi lineal O(n log(n)). Para facilitar la comprensión de los algoritmos de ordenamiento, solo trabajaremos sobre arrays de valores enteros. El lector ya sabe que proveyendo una adecuada implementación de Comparator, se puede extender la funcionalidad de estos algoritmos a arrays de cualquier otro tipo de datos.

9.2 Bubble sort (ordenamiento por burbujeo) El algoritmo de la burbuja consiste en recorrer el array comparando el valor del i-ésimo elemento con el valor del elemento i+1 y, si estos se encuentran desordenados, entonces hay que permutarlos. Dicho de otro modo, comenzamos comparando arr[0] con arr[1]. Si arr[0]>arr[1] entonces los permutamos. Luego comparamos arr[1] con arr[2] y, si corresponde, también los permutamos y así hasta llegar a comparar arr[len-2] con arr[len-1]. Luego de esta “pasada” o iteración a través de los elementos del array, el elemento de mayor valor o el más “pesado” quedará ubicado en la última posición. El peor escenario con el que nos podemos encontrar es el de tener que ordenar un array completamente desordenado, es decir, en orden inverso. Por ejemplo, si el array fuese: arr = {4, 3, 2, 1, 0}, entonces:

9.2 Bubble sort (ordenamiento por burbujeo)   Arr 4 3 2 1 Primera iteración Segunda iteración arr Tercera iteración Cuarta iteración Quinta iteración Como vemos, en cada iteración llevamos hacia abajo al elemento más pesado y solo podemos considerar que el array quedó ordenado luego de realizar una iteración en la que no haya sido necesario hacer ninguna permutación. Así, para ordenar el array arr de longitud 5 necesitamos realizar 5 iteraciones, en cada una de las cuales haremos 4 comparaciones. Si bien el algoritmo de ordenamiento por burbujeo es muy fácil de implementar, su complejidad cuadrática limita seriamente su capacidad para ordenar arrays de gran tamaño. Para probarlo empíricamente analizaremos su comportamiento al ordenar arrays de 10, 100, 1000, 10000, 100000 y 1000000 elementos.

9.2 Bubble sort (ordenamiento por burbujeo) Para generar arrays de semejantes tamaños desarrollaremos la clase utilitaria UArray con los siguientes métodos: generarArray – genera un array de cualquier longitud con valores aleatorios u ordenados de mayor a menor. estaOrdenado - retornará true o false según el array que reciba como parámetro esté o no ordenado ascendentemente. public class UArray { public static int[] generarArray(int n, boolean random) int arr[]=new int[n]; for( int i=0; i<n; i++ ) if( random ) arr[i]=(int)(Math.random()*n); } else arr[i]=n-i; return arr; public static boolean estaOrdenado(int arr[]) for( int i=0; i<arr.length-1; i++ ) if( arr[i+1]<arr[i] ) return false; return true; El método estaOrdenado será de mucha utilidad para poder verificar si las implementaciones de nuestros algoritmos funcionan correctamente con arrays de gran tamaño.

9.2.1 Bubble sort optimizado Si aprovechamos el hecho de que luego de cada iteración el elemento más “pesado” se ubica en la última posición del array (es decir, en su posición definitiva), podemos mejorar el algoritmo evitando comparar, innecesariamente, aquellos elementos que ya quedaron ordenados. Es decir, en la primera iteración, comparamos todos los elementos del array hasta llegar a comparar arr[len-2] con arr[len-1]. En la segunda iteración, comparamos todos los elementos, pero solo hasta comparar arr[len-3] con arr[len-2] porque, como ya sabemos, en arr[len-1] se encuentra el elemento que, definitivamente, ocupará esa posición. El desarrollo de esta variante del algoritmo queda a cargo del lector pero a título informativo podemos comentar que una implementación ejecutada sobre la misma computadora mencionada más arriba arrojó los siguientes resultados al ordenar arrays de 10, 100, 1000, 10000, 100000 y 1000000 elementos: 0 milisegundos (0 minutos, 0 segundos) true 94 milisegundos (0 minutos, 0 segundos) true 9140 milisegundos (0 minutos, 9 segundos) true 951219 milisegundos (15 minutos, 51 segundos) true El rendimiento mejoró un 300% respecto de la implementación anterior, incluso logró terminar de ordenar el array de 1 millón de elementos, aunque demoró algo más de 15 minutos.  Si bien la mejora es importante, el rendimiento del algoritmo sigue siendo inaceptable para ordenar arrays de gran tamaño.

9.3 Selection sort (ordenamiento por selección) El algoritmo de ordenamiento por selección es simple y consiste en recorrer el array buscando el menor elemento para intercambiarlo con el primero. Luego recorrer el array, pero comenzando desde la segunda posición para buscar el menor elemento e intercambiarlo por el segundo y así sucesivamente. Es decir que si consideramos un array arr y un índice i=0, debemos buscar el menor elemento de arr entre las posiciones i y len-1 e intercambiarlo con arr[i]. Luego incrementamos i para descartar el primer elemento porque, obviamente, ya contiene su valor definitivo. En el siguiente gráfico, vemos cómo se ordena un array arr = {3, 4, 1, 0, 2} luego de len-1 iteraciones. El algoritmo de ordenamiento por selección es de orden cuadrático O(n2) y tiene un rendimiento similar al de bubble sort optimizado.

9.4 Insertion sort (ordenamiento por inserción) Pensemos en un array inicialmente vacío. Luego, cualquier elemento que le agreguemos (llamémosle e1) ocupará la primera posición y el array estará ordenado. Si agregamos otro elemento (digamos e2), este deberá ubicarse antes o después de e1 según se verifique o no que e2<e1. El algoritmo de ordenamiento por inserción tiene una complejidad cuadrática O(n2) para el peor de los casos, pero su rendimiento puede mejorar si el array que queremos ordenar está parcialmente ordenado. 9.5 Quicksort (ordenamiento rápido) Este es un algoritmo relativamente simple y extremadamente eficiente cuya lógica es recursiva y, según su implementación, puede llegar a requerir el uso de arrays auxiliares.

9.5.1 Implementación utilizando arrays auxiliares Llamemos arr al array que queremos ordenar. La idea es la siguiente: tomamos cualquier elemento de arr. A este elemento lo llamaremos pivote. Luego recorremos arr para generar dos arrays auxiliares: el primero tendrá aquellos elementos de arr que resulten ser menores que pivote. El segundo tendrá los elementos de arr que sean mayores que pivote. A estos arrays auxiliares los llamaremos, respectivamente, menores y mayores. Ahora repetimos el procedimiento, primero sobre menores y luego sobre mayores. Finalmente obtenemos el array ordenado uniendo menores + pivote + mayores. Por ejemplo: arr = {4, 7, 2, 5, 1, 9, 3, 8} Si consideramos pivote = 4 (es decir, el primer elemento de arr), entonces: 4 7 2 5 1 9 3 8

9.5.2 Implementación sin arrays auxiliares Otra implementación de quicksort puede ser la siguiente: luego de seleccionar el elemento pivote movemos todos los elementos menores a su izquierda y todos los elementos mayores a su derecha. Esto podemos lograrlo utilizando dos índices: i, inicialmente, apuntando al primer elemento del array y j apuntando al último.  La idea es recorrer el array desde la izquierda hasta encontrar el primer elemento mayor que pivote. Luego recorrer desde la derecha hasta encontrar el primer elemento menor que el pivote y permutarlos.  Por último, invocamos recursivamente dos veces al algoritmo, primero pasándole el subarray comprendido entre el inicio y la posición que ocupa el pivote (no inclusive) y luego pasándole el subarray formado por los elementos que se encuentran ubicados en posiciones posteriores a la del pivote. Por ejemplo, si pivote es 3, entonces: 5 9 4 3 8 1 2 6 Luego de este proceso todos los elementos menores que pivote quedarán ubicados a su izquierda mientras que todos los elementos mayores quedarán ubicados a su derecha. Notemos que pivote quedó ubicado en su lugar definitivo. El próximo paso será repetir el proceso sobre cada uno de estos subarrays.  La complejidad algorítmica de quicksort es, en el promedio de los casos: n log(n).

9.6 Heapsort (ordenamiento por montículos) Heapsort es un algoritmo de ordenamiento no recursivo de orden O(n log(n)) que se basa en la propiedad de “montículo” (heap en inglés) de los árboles binarios semicompletos. 9.6.1 Árbol binario semicompleto Decimos que un árbol binario es semicompleto cuando todos sus niveles están completos a excepción del último cuyos nodos, de estar incompleto, deben ir apareciendo de izquierda a derecha. 6 4 8 15 5 10 7 3 2

9.6.2 Representar un árbol binario semicompleto en un array Un árbol binario semicompleto puede ser representado linealmente si asignamos cada uno de sus valores, comenzando de izquierda a derecha y desde arriba hacia abajo, en posiciones consecutivas de un array. Es decir: en la posición 0 del array colocamos el valor de la raíz y en las posiciones 1 y 2 colocamos a su hijo izquierdo y a su hijo derecho. Diremos que la raíz es el nodo número 0 y sus hijos izquierdo y derecho son los nodos número 1 y 2 respectivamente. Esto nos permite calcular las posiciones que ocupan el hijo izquierdo y el hijo derecho de cualquier nodo i de la siguiente manera:  izquierdo(i) = 2*i+1 derecho(i) = 2*i+2  Así, en el array encontramos a la raíz del árbol (6) en la posición 0. Su hijo izquierdo (4) se encuentra en la posición 2*0+1=1 y su hijo derecho (8) en la posición 2*0+2=2. El hijo izquierdo de 4 lo encontramos en la posición 2*1+1=3 y el derecho en la posición 4. Todo esto siempre y cuando 2*i sea menor que n-1 siendo n la longitud del array. 6 4 8 15 5 10 7 3 2 1

9.6.3 Montículo (heap) Un montículo es un árbol binario semicompleto que tiene la característica de que el valor de cada nodo padre resulta ser mayor que el valor de cualquiera de sus hijos. En este caso diremos que se trata de un “montículo de máxima”. Análogamente, podemos hablar de un “montículo de mínima” cuando el valor de cada nodo padre es menor que los valores de sus hijos. En adelante, siempre hablaremos de montículos de máxima salvo que se especifique lo contrario. Por ejemplo, el siguiente árbol binario puede ser considerado montículo porque, además de ser semicompleto, cumple con que el valor de cada nodo padre es mayor al valor de cada uno de sus hijos. 15 10 8 6 5 4 7 3 2

9.6.4 Transformar un árbol binario semicompleto en un montículo Para convertir un árbol binario semicompleto en montículo, alcanza con realizar algunas permutaciones como veremos en las siguientes figuras. Notemos que el orden en que haremos las permutaciones es de abajo hacia arriba y de derecha a izquierda. 6 4 8 15 5 10 3 2 7 6 4 8 15 5 10 3 2 7 Luego de las permutaciones 10 por 8, 15 por 4 y 15 por 6 el árbol quedó convertido en montículo ya que cada nodo padre tiene un valor mayor que el de sus nodos hijos. 6 15 10 4 5 8 3 2 7 15 6 10 4 5 8 3 2 7

9.6.5 Transformar un árbol binario semicompleto en un montículo Definiremos las operaciones (funciones o métodos) izq y der que retornan los valores de los hijos izquierdo y derecho respectivamente del nodo ubicado en la i-ésima posición del array.   public static int izq(int i) { return 2*i+1; } public static int der(int i) return izq(i)+1; Encontrará los ejemplos sobre este tema en la página 599 del libro.

9.6.6 El algoritmo de ordenamiento por montículos Dado que en un montículo el valor del nodo raíz siempre es el mayor entonces, al representarlo en un array este valor siempre se ubicará en la posición 0. Luego el algoritmo de ordenamiento resulta, relativamente, simple ya que consiste en los siguientes pasos:  1 - Convertir el array en montículo. Luego de esto arr[0] será el elemento de mayor valor del array.  2 – Permutar arr[0] por arr[n-1]. Como arr[0] es el elemento de mayor valor del array, al llevarlo a arr[n-1] lo estaremos ubicando en su posición definitiva.  3 – Reconstruir el montículo excluyendo al último elemento ya que éste se encuentra ordenado. Luego repetir el proceso hasta que todos los elementos del array queden ordenados.  Recordemos que n es la longitud del array.  

9.7 Shellsort (ordenamiento Shell) Este método de ordenamiento de complejidad cuadrática para el peor caso surge de una generalización del método de ordenamiento por inserción. El algoritmo consiste en dividir al array en varios subarrays más pequeños formados por aquellos elementos del array original que se encuentran separados entre sí por una determinada “distancia de paso”. Este algoritmo no requiere del uso de memoria adicional. Para su implementación podemos pensar en una función nextElement que reciba la distancia de paso y la posición actual y retorne la posición del siguiente elemento del subarray para esa distancia de paso.

9.8 Binsort (ordenamiento por cajas) Este algoritmo consiste en distribuir los elementos del array que queremos ordenar en diferentes “cajas”. Cada caja clasifica los elementos según una determinada propiedad o condición que, obviamente, debe ser mutuamente excluyente para asegurar que cada elemento del array ingrese en una única caja. 9.9 Radix sort (ordenamiento de raíz) Radix sort es diferente a todos los otros algoritmos ya que su estrategia de ordenamiento es netamente computacional. El algoritmo permite ordenar un conjunto de valores numéricos en función del valor ASCII de cada uno de sus dígitos.

9.9.1 Ordenar cadenas de caracteres con radix sort Radix sort permite ordenar cadenas de caracteres ya que cada carácter tiene asignado un valor numérico definido en la tabla ASCII. En este caso debemos completar las cadenas más cortas con espacios en blanco a la derecha para que todas tengan la misma longitud.  Si vamos a comparar las cadenas “Juan” con “Alberto” debemos tener en cuenta lo siguiente:   Correcto Incorrecto [Juan] [Juan ] [ Juan] [Alberto]