Mostrando entradas con la etiqueta métodos de ordenamiento en c#. Mostrar todas las entradas
Mostrando entradas con la etiqueta métodos de ordenamiento en c#. Mostrar todas las entradas

Método de Ordenamiento Merge Sort en C#

Método de Ordenamiento Merge Sort en C#

Esta vez estaremos hablando de Ordenación por Mezcla (Merge Sort), otro algoritmo recursivo bastante eficiente para ordenar un array, que tiene un orden de complejidad O(nlogn) al igual que Quick Sort. Fue desarrollado en 1945 por John Von Neumann según wikipedia.

Estrategia de Merge Sort

Merge Sort está basado en la técnica de diseño de algoritmos Divide y Vencerás, de la cual se habló aquí mismo hace un tiempo. Recordando un poco, esta técnica consiste en dividir el problema a resolver en sub problemas del mismo tipo que a su vez se dividirán, mientras no sean suficientemente  pequeños o triviales.

Merge Sort

Veamos una panorámica de la estrategia que sigue este algoritmo para ordenar una secuencia S de n elementos:

  • Si S tiene uno o ningún elemento, está ordenada
  • Si S tiene al menos dos elementos se divide en dos secuencias S1 y S2
  • S1 contiene los primeros n/2 elementos y S2 los restantes
  • Ordenar S1 y S2, aplicando recursivamente este procedimiento
  • Mezclar S1 y S2 en S, de forma que ya S1 y S2 estén ordenados
  • Veamos ahora como sería la estrategia para mezclar las secuencias:

Se tienen referencias al principio de cada una de las secuencias a mezclar (S1 y S2). Mientras en alguna secuencia queden elementos, se inserta en la secuencia resultante (S) el menor de los elementos referenciados y se avanza esa referencia una posición.

Pseudocódigo del Método de Ordenamiento Merge Sort

Como ven, la idea es bastante simple, pero programarla no tanto. Para no dar de golpe la solución, veamos primero un pseudocódigo del algoritmo:
  function mergesort(array A[x..y])
  begin
    if (x-y > 1)):
      array A1 := mergesort(A[x..(int( x+y / 2))])
      array A2 := mergesort(A[int(1+(x+y / 2))..y])
      return merge(A1, A2)
    else:
      return A
  end
  function merge(array A1[0..n1], array A2[0..n2])
  begin
    integer p1 := 0
    integer p2 := 0
    array R[0..(n1 + n2 + 2)]//suponiendo que n1 y n2 son las posiciones
    //del array y no el length de este mismo, de otro modo seria (n1 + n2)
    while (p1 <= n1 or p2 <= n2):
      if (p1 <= n1 and A1[p1] <= A2[p2]):
         R[p1 + p2] := A1[p1]
         p1 := p1 + 1
      else
         if (p2 <= n2 and A1[p1] > A2[p2]):
           R[p1 + p2] := A2[p2]
           p2 := p2 + 1
    return R
  end

Ejemplo del Método de Ordenamiento Merge Sort en C# 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MergeSort
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] nums = new int[40];
            Console.WriteLine("Metodo de Merge Sort");
            Console.Write("Cuantos longitud del vector: ");
            string linea;
            linea = Console.ReadLine();
            int cant;
            cant = int.Parse(linea);
            nums = new int[cant];
            for (int f = 0; f < nums.Length; f++)
            {
                Console.Write("Ingrese elemento " + (f + 1) + ": ");
                linea = Console.ReadLine();
                nums[f] = int.Parse(linea);
            }
            MergeSort(nums);
            Console.WriteLine("Vector Ordenado Ascendentemente");
            for (int i = 0; i < nums.Length; i++)
                Console.Write(nums[i] + " ");
            Console.ReadLine();
        }
        //Método portal que llama al método recursivo inicial
        public static void MergeSort(int[] x)
        {
            MergeSort(x, 0, x.Length - 1);
        }
        static private void MergeSort(int[] x, int desde, int hasta)
        {
            //Condicion de parada
            if (desde == hasta)
                return;
            //Calculo la mitad del array
            int mitad = (desde + hasta) / 2;
            //Voy a ordenar recursivamente la primera mitad
            //y luego la segunda
            MergeSort(x, desde, mitad);
            MergeSort(x, mitad + 1, hasta);
            //Mezclo las dos mitades ordenadas
            int[] aux = Merge(x, desde, mitad, mitad + 1, hasta);
            Array.Copy(aux, 0, x, desde, aux.Length);
        }
        //Método que mezcla las dos mitades ordenadas
        static private int[] Merge(int[] x, int desde1, int hasta1, int desde2, int hasta2)
        {
            int a = desde1;
            int b = desde2;
            int[] result = new int[hasta1 - desde1 + hasta2 - desde2 + 2];
            for (int i = 0; i < result.Length; i++)
            {
                if (b != x.Length)
                {
                    if (a > hasta1 && b <= hasta2)
                    {
                        result[i] = x[b];
                        b++;
                    }
                    if (b > hasta2&& a <= hasta1)
                    {
                        result[i] = x[a];
                        a++;
                    }
                    if (a <= hasta1&& b <= hasta2)
                    {
                        if (x[b] <= x[a])
                        {
                            result[i] = x[b];
                            b++;
                        }
                        else
                        {
                            result[i] = x[a];
                            a++;
                        }
                    }
                }
                else
                {
                    if (a <= hasta1)
                    {
                        result[i] = x[a];
                        a++;
                    }
                }
            }
            return result;
        }
    }
}
Al ejecutar el código muestra el siguiente resultado



Método de Ordenamiento Burbuja en C#

Método de Ordenamiento Burbuja en C# 

Este método consiste en ir comparando cada par de elementos del array e ir moviendo el mayor elemento hasta la última posición, comenzando desde la posición cero. Una vez acomodado el mayor elemento, prosigue a encontrar y acomodar el segundo más grande comparando de nuevo los elementos desde el inicio de la lista, y así sigue hasta ordenar todos los elementos del arreglo. Al ser necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios, hace que el ordenamiento por burbuja sea uno de los algoritmos más ineficientes que existen. Incluso entre los algoritmos de ordenamiento del mismo orden, otros como el “Ordenamiento por inserción” son considerados más eficientes. Y lo más curioso es que este procedimiento es uno de los más usados para ordenar listas en todos los lenguajes de programación.
Estos serían los pasos a seguir por este algoritmo para ordenar una lista a1, a2, a3, … an
1) Comparar a1 con a2 e intercambiarlos si a1>a2
2) Seguir hasta que se haya comparado an-1 con an
3) Repetir el proceso anterior n-1 veces
Ejemplo:
            25 57 48 37 12 92 86 33
En el primer paso se realizan las siguientes operaciones:
          x[0] con x[1] (25 con 57)  no intercambio.
          x[1] con x[2] (57 con 48)      intercambio.
          x[2] con x[3] (57 con 32)      intercambio.
          x[3] con x[4] (57 con 12)      intercambio.
          x[4] con x[5] (57 con 92)  no intercambio.
          x[5] con x[6] (92 con 86)      intercambio.
          x[6] con x[7] (92 con 33)      intercambio.
Así después del primer paso, el arreglo está en el siguiente orden:
          25 48 37 12 57 86 33 92
Observe que después del primer paso, el elemento mayor (en este caso 92) está en la posición correcta dentro del arreglo. En general x[n-i] estará en su posición correcta después de la iteración i. El método se lama ordenamiento de burbuja porque cada número “burbujea” con lentitud hacia su posición correcta. El conjunto completo de iteraciones es:
         iteración 0 :                     25 57 48 37 12 92 86 33
         iteración 1:                       25 48 37 12 57 86 33 92
         iteración 2:                       25 37 12 48 57 33 86 92
         iteración 3:                       25 12 37 48 33 57 86 92
         iteración 4:                       12 25 37 33 48 57 89 92
         iteración 5:                       12 25 33 37 48 57 89 92

A continuación veamos un ejemplo en Pseudo-Código Para el Método Burbuja 





Ejemplo del Método de Ordenamiento Burbuja en C# 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Burbuja
{
    class Burbuja
    {
        private int[] vector;
        public void Cargar()
        {
            Console.WriteLine("Metodo de Burbuja");
            Console.Write("Cuantos longitud del vector: ");
            string linea;
            linea = Console.ReadLine();
            int cant;
            cant = int.Parse(linea);
            vector = new int[cant];
            for (int f = 0; f < vector.Length; f++)
            {
                Console.Write("Ingrese elemento "+(f+1)+": ");
                linea = Console.ReadLine();
                vector[f] = int.Parse(linea);
            }
        }
        public void MetodoBurbuja()
        {
            int t;
            for (int a = 1; a < vector.Length; a++)
                for (int b = vector.Length - 1; b >= a; b--)
                {
                    if (vector[b - 1] > vector[b])
                    {
                        t = vector[b - 1];
                        vector[b - 1] = vector[b];
                        vector[b] = t;
                    }
                }
        }
        public void Imprimir()
        {
            Console.WriteLine("Vector ordenados en forma ascendente");
            for (int f = 0; f < vector.Length; f++)
            {
                Console.Write(vector[f]+"  ");
            }
            Console.ReadKey();
        }
        static void Main(string[] args)
        {
            Burbuja pv = new Burbuja();
            pv.Cargar();
            pv.MetodoBurbuja();
            pv.Imprimir();
        }
    }
}


Al ejecutar el código muestra el siguiente resultado



Método de Ordenamiento Shell Sort en C#

Es un algoritmo de ordenación interna muy sencillo pero muy ingenioso, basado en comparaciones e intercambios, y con unos resultados radicalmente mejores que los que se pueden obtener con el método de la burbuja, el des elección directa o el de inserción directa.
Sin embargo, es necesario romper una lanza a favor del algoritmo ShellSort, ya que es el mejor algoritmo de ordenación in-situ... es decir, el mejor de aquellos en los que la cantidad de memoria adicional que necesita -aparte de los propios datos a ordenar, claro está- es constante, sea cual sea la cantidad de datos a ordenar. El algoritmo de la burbuja, el de selección directa, el de inserción directa y el de Shell son todos in-situ, y éste último, el de Shell, es el que mejor resultados da, sin ninguna duda de todos ellos y sus posibles variantes.

El ShellSort es una mejora del método de inserción directa que se utiliza cuando el número de elementos a ordenar es grande. El método se denomina “shell” –en honor de su inventor Donald Shell – y también método de inserción con incrementos decrecientes.
En el método de clasificación por inserción, cada elemento se compara con los elementos contiguos de su izquierda, uno tras otro. Si el elemento a insertar es más pequeño - por ejemplo -, hay que ejecutar muchas comparaciones antes de colocarlo en su lugar definitivamente. Shell modifico los saltos contiguos resultantes de las comparaciones por saltos de mayor tamaño y con eso se conseguía la clasificación más rápida. El método se basa en fijar el tamaño de los saltos constantes, pero de más de una posición.

Considere un valor pequeño que está inicialmente almacenado en el final del vector. Usando un ordenamiento O(n2) como el ordenamiento de burbuja o el ordenamiento por inserción, tomará aproximadamente n comparaciones e intercambios para mover este valor hacia el otro extremo del vector. El Shell sort primero mueve los valores usando tamaños de espacio gigantes, de manera que un valor pequeño se moverá bastantes posiciones hacia su posición final, con sólo unas pocas comparaciones e intercambios.

Uno puede visualizar el algoritmo Shell sort de la siguiente manera: coloque la lista en una tabla y ordene las columnas (usando un ordenamiento por inserción). Repita este proceso, cada vez con un número menor de columnas más largas. Al final, la tabla tiene sólo una columna.
Mientras que transformar la lista en una tabla hace más fácil visualizarlo, el algoritmo propiamente hace su ordenamiento en contexto (incrementando el índice por el tamaño de paso, esto es usando i += tamaño_de_paso en vez de i++).

Por ejemplo, considere una lista de números como [ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]. Si comenzamos con un tamaño de paso de 8, podríamos visualizar esto dividiendo la lista de números en una tabla con 5 columnas. Esto quedaría así:


13 14 94 33 82
25 59 94 65 23
45 27 73 25 39
10


Entonces ordenamos cada columna, lo que nos da:


10 14 73 25 23
13 27 94 33 39
25 59 94 65 82
45


Cuando lo leemos de nuevo como una única lista de números, obtenemos:

 [ 10 14 73 25 23 13 27 94 33 39 25 59 94 65 82 45 ]

 Aquí, el 10 que estaba en el extremo final, se ha movido hasta el extremo inicial. Esta lista es entonces de nuevo ordenada usando un ordenamiento con un espacio de 3 posiciones, y después un ordenamiento con un espacio de 1 posición (ordenamiento por inserción simple).
El Shell sort lleva este nombre en honor a su inventor, Donald Shell, que lo publicó en 1959. Algunos libros de texto y referencias antiguas le llaman ordenación "Shell-Metzner" por Marlene Metzner Norton, pero según Metzner, "No tengo nada que ver con el algoritmo de ordenamiento, y mi nombre nunca debe adjuntarse a éste."

A continuación veamos un ejemplo en Pseudo-Código Para el Método de Shell Sort



Ejemplo del Método de Ordenamiento Shell Sort en C# 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PruebaVector
{
    class PruebaVector
    {
        private int[] vector;
        public void Cargar()
        {
            Console.WriteLine("Metodo de Shell Sort");
            Console.Write("Cuantos longitud del vector:");
            string linea;
            linea = Console.ReadLine();
            int cant;
            cant = int.Parse(linea);
            vector = new int[cant];
            for (int f = 0; f < vector.Length; f++)
            {
                Console.Write("Ingrese elemento "+(f+1)+": ");
                linea = Console.ReadLine();
                vector[f] = int.Parse(linea);
            }
        }
        public void Shell()
        {
            int salto = 0;
            int sw = 0;
            int auxi = 0;
            int e = 0;
            salto = vector.Length / 2;
            while (salto > 0)
            {
                sw = 1;
                while (sw != 0)
                {
                    sw = 0;
                    e = 1;
                    while (e <= (vector.Length - salto))
                    {
                        if (vector[e - 1] > vector[(e - 1) + salto])
                        {
                            auxi = vector[(e - 1) + salto];
                            vector[(e - 1) + salto] = vector[e - 1];
                            vector[(e - 1)] = auxi;
                            sw = 1;
                        }
                        e++;
                    }
                }
                salto = salto / 2;
            }
        }
        public void Imprimir()
        {
            Console.WriteLine("Vector ordenados en forma ascendente");
            for (int f = 0; f < vector.Length; f++)
            {
                Console.Write(vector[f]+"  ");
            }
            Console.ReadKey();
        }
        static void Main(string[] args)
        {
            PruebaVector pv = new PruebaVector();
            pv.Cargar();
            pv.Shell();
            pv.Imprimir();
        }
    }
}
Al ejecutar el código muestra el siguiente resultado