Librería de códigos C# (Compartan aquí sus códigos)

Iniciado por DarK_FirefoX, 19 Mayo 2015, 18:36 PM

0 Miembros y 2 Visitantes están viendo este tema.

DarK_FirefoX

Librería de Códigos - C#

Me he decido a crear este tema con el objetivo de ayudar a las personas a las cuales les pueda ser útil estos códigos. Mi idea es ir posteando códigos que de una manera u otra son útiles para personas que estén aprendiendo a programar en C# y tengan alguna duda. No hay otra manera de explicarlo así que voy a comenzar:

1 - Hallar el máximo número entero de un array de enteros

Aquí introducimos como parámetro al método un array de enteros llamando "numeros", aquí estará la colección de numeros en la cual queremos buscar el máximo (Dígase máximo al número más grande). Para que entiendan:

int.MinValue es una constante dentro de la clase Int32 que representa el menor valor posible representable por un entero. Este valor es: -2,147,483,648. Por lo tanto, cualquier entero representable con el tipo de dato int, será mayor o igual que la constante MinValue.
Lo que hacemos es recorrer el array de int números y vamos indexando y comprobando cada posición del array con la variable maximo (int.MinValue en un principio), en caso de que el número sea mayor le asignamos a esa variable el valor en la posición i del array (o sea, la que se está comprobando) y seguimos recorriendo el array hasta que se hayan comprobado todos los elementos del array. Luego, la variable maximo tendrá almacenado el valor máximo del array. Lo que hacemos es devolverlo.

Código (csharp) [Seleccionar]
public static int Maximo(int[] numeros)
       {
           int maximo = int.MinValue;
           for (int i = 0; i < numeros.Length; i++)
           {
               if (numeros[i] > maximo)
                   maximo = numeros[i];
           }
           return maximo;
       }





2 - Hallar el segundo mayor elemento en un array de enteros

La idea es parecida a como hallar el mayor elemento, de hecho, lo que se va a hacer es recorer el array e ir buscando el mayor elemento, pero cuando se encuentre uno mayor del que ya se encontró, ese que ya se había encontrado se va a guardar en otra variable. Entonces vamos a tener dos variables, una "mayor" y otra "sMayor" (segundo mayor). La idea es el que se encuentre se pone en la variable mayor y lo que estaba en la variable mayor se pone en la variable sMayor. De esta manera vamos llevando control de las dos variables. Hay que tener en cuenta que la comparación se realiza primero si el elemento indexado es mayor que "mayor", sino, hay que comprobar si es mayor que "sMayor" pues puede darse el caso que existan elementos entre las dos una vez después que se haya asignado los valores una vez y este elemento vendría a ser el segundo mayor.
Una vez recorrido todo el array solo resta devolver la variable "sMayor"

Código (csharp) [Seleccionar]
public static int SegundoMayor(int[] numeros)
       {
           int mayor = int.MinValue;
           int sMayor = int.MinValue;
           for (int i = 0; i < numeros.Length; i++)
           {
               if (numeros[i] > mayor)
               {
                   sMayor = mayor;
                   mayor = numeros[i];
               }
               else if (numeros[i] > sMayor)
                   sMayor = numeros[i];
           }
           return sMayor;
       }





3 - Invertir los elementos de un array

Invertir los elementos viene siendo como hacer un Reverse (Invertir el orden de los elementos del array). Voy a exponer como hacerlo de dos maneras, que es prácticamente lo mismo con la diferencia que en un método modificamos el mismo array y en el otro devolvemos un array nuevo.

Modificando el mismo array

Aquí, recibimos como parámetro de entrada un array (en este caso es un array de int, esto puede servir para otros tipos de datos, o incluso se podría haber hecho genérico, lo expongo con int para simplificar). Básicamente vamos a recorrer el array hasta la mitad, utilizando la facilidad de indexar un array podemos cambiar los valores. Pues el primer elemento del array sería 0 y el último a.Length -1. Lo que utilizando la variable i del ciclo, podemos ir aumentando y disminuyendo a la vez de una forma desde afuera hacia adentro y haciendo lo que se conoce como Swap (intercambio) en esos elementos. Si nos damos cuenta el último elemento siempre nos vamos a referir como a[a.Length-1-i], puesto que i va aumentando ese valor va a ir reduciéndose. Por lo tanto el objetivo es: Cambiar el primero con el último, el segundo con el penúltimo, y así sucesivamente. Este método es void, puesto que no devolvemos nada, solamente trabajamos sobre el mismo array.

Nota: Para hacer el Swap lo que hacemos es crear una variable temporal donde asignamos uno de los valores, luego en esta variable que ya guardamos, ponemos el otro elemento a intercambiar, por último, el elemento que guardamos en la variable temporal se lo asignamos a la variable de donde sacamos el valor a intercambiar.

Código (csharp) [Seleccionar]
public static void InvierteV(int[] a)
       {
           for (int i = 0; i < a.Length / 2; i++)
           {
               int temp = a[i]; //Asignamos valor a la variable temporal
               a[i] = a[a.Length - 1 - i]; //Copiamos el valor de la parte trasera del array a la frontal
               a[a.Length - 1 - i] = temp; //Copiamos el valor guardado en la variable temporal a la parte trasera del array
           }
       }


Devolviendo un nuevo array

Código (csharp) [Seleccionar]
public static int[] InvierteN(int[] a)
       {
           int[] newInt = new int[a.Length];

           //Copiamos los elementos del array al nuevo array
           for (int i = 0; i < a.Length; i++)
               newInt[i] = a[i];

           for (int i = 0; i < newInt.Length/2; i++)
           {
               int temp = newInt[i]; //Asignamos valor a la variable temporal
               newInt[i] = newInt[newInt.Length - 1-i]; //Copiamos el valor de la parte trasera del array a la frontal
               newInt[newInt.Length - 1-i] = temp; //Copiamos el valor guardado en la variable temporal a la parte trasera del array
           }
           return newInt;
       }


Esta forma funciona casi idéntico, solo que hacemos primero una copia del array en un array nuevo con la misma longitud y los mismos valores, para luego trabajar sobre este array y después devolverlo tras realizarle el proceso de invertir los elementos explicados en la forma anterior.

Nota: El proceso de crear la copia del array lo hago inicializando un array de la misma longitud que el que entra como parámetro y recorriendo este array y copiando los valores a este nuevo array. Quería destacar que para hacer la copia del array podíamos usar el método Array.Copy(), pasándole el array desde donde se quiere copiar, el array a donde se va a copiar y la cantidad de elementos a copiar, en este caso todos. Hubiera sido algo así:

Código (csharp) [Seleccionar]
Array.Copy(a, newInt, a.Length);

De esta forma nos hubiéramos ahorrado el primer ciclo del método (aunque en términos de eficiencia es prácticamente lo mismo)




4 - EsPrimo

Básicamente esto es algo bastante utilizado, aunque esta manera de implementarlo es "sencilla" a simple vista, puede ser un proceso extremadamente largo para números muy grandes.

Código (csharp) [Seleccionar]
public static bool EsPrimo(int a)
       {
          int raizDelNumero = (int)Math.Sqrt(a);
           for (int i = 2; i <= raizDelNumero; i++)
               if (a % i == 0)
                   return false;
           return true;
       }


Lo que hacemos es calcular la raiz del numero y guardarla en una variable. Utilizamos el metodo .Sqrt dentro de la clase Math. El cuál calcula la raíz cuadrada de un número. Este método devuelve un double, por eso le hacemos un cast a int (cast es una conversión forzada a un tipo de datos). El objetivo del método es recorrer todos los números desde 2 hasta la raíz del número y ver si alguno de esos números divide al número (o sea, deja resto 0 con el número). En caso de que alguno de esos números divida al número, implica que el número no es primo. Si el ciclo termina sin devolver false, entonces devolvemos true pues el numero es primo.





Bueno, aquí les dejo los cuatro primeros, luego sigo añadiendo más de acuerdo al tiempo que tenga libre. Si alguien quiere aportar sean libres de hacerlo. Esto son cosas sencillas, pero que para personas que están aprendiendo pueden ser muy útiles. Recuerden, si añaden, comentar los códigos y/o explicarlos.

Salu2s


Eleкtro

#1
Todos los códigos rehusables que tengo están desarrollados en VB.Net, pero éste lo convertí hace ya tiempo, así que lo comparto por aquí :P.

Es una función que sirve para darle un formato a un documento XML sin formatear (es decir, sin indentación), lo que comúnmente se denomina cómo "Beautifier" o embellecedor, el código es simple pero efectivo.

• Before/After:


• Código:
Código (csharp) [Seleccionar]
using ControlChars = Microsoft.VisualBasic.ControlChars;
using Encoding = System.Text.Encoding;
using StringBuilder = System.Text.StringBuilder;
using System;
using Xml = System.Xml;

namespace Tools
{
   class XmlUtil
   {
       /// <remarks>
       /// *****************************************************************
       /// Snippet Title: XML Beautifier
       /// Code's Author: Elektro
       /// Date Modified: 18-February-2015
       /// *****************************************************************
       /// </remarks>
       /// <summary>Beautifies the contents of an XML document.</summary>
       /// <param name="XMLText">
       /// The XML text content.
       /// It can be an entire document or a fragment.
       /// </param>
       /// <param name="IndentChars">
       /// The string that is used to indent the XML.
       /// Default value is: <see cref="Microsoft.VisualBasic.ControlChars.Tab"/>
       /// </param>
       /// <param name="IndentOnAttributes">
       /// If set to <c>true</c>, attributes will be separated by newlines.
       /// Default value is: <c>false</c>
       /// </param>
       /// <param name="TextEncoding">
       /// The XML text encoding to use.
       /// Default value is: <see cref="System.Text.Encoding.Default"/>.
       /// </param>
       /// <returns>The beautified XML text.</returns>
       /// <exception cref="System.ArgumentNullException"></exception>
       public static string XmlBeautifier(string xmlText,
                                          string indentChars = null,
                                          bool indentOnAttributes = false,
                                          Encoding textEncoding = null)
       {
           if (string.IsNullOrEmpty(xmlText) || string.IsNullOrWhiteSpace(xmlText))
           {
               throw new ArgumentNullException(xmlText);
           }

           StringBuilder sb = new StringBuilder();
           Xml.XmlDocument doc = new Xml.XmlDocument();
           Xml.XmlWriterSettings settings = new Xml.XmlWriterSettings();

           settings.Indent = true;
           settings.CheckCharacters = true;
           settings.OmitXmlDeclaration = false;
           settings.ConformanceLevel = Xml.ConformanceLevel.Auto;
           settings.NamespaceHandling = Xml.NamespaceHandling.Default;
           settings.NewLineHandling = Xml.NewLineHandling.Replace;
           settings.NewLineChars = ControlChars.NewLine;
           settings.NewLineOnAttributes = indentOnAttributes;
           settings.IndentChars = indentChars != null ? indentChars : Convert.ToString(ControlChars.Tab);
           settings.Encoding = textEncoding != null ? textEncoding : Encoding.Default;

           using (Xml.XmlWriter writer = Xml.XmlWriter.Create(sb, settings))
           {
               doc.LoadXml(xmlText);
               doc.WriteContentTo(writer);
               writer.Flush();
           }

           return sb.ToString();
       }

   }
}


• Características:

   · IndentChars
      This parameter determines the spacing character(s) used to indent the XML document.

   · IndentOnAttributes
      This parameter determines whether to indent the XML attributes.

   · TextEncoding
      This parameter determines the encoding used to read the XML document.

• Modo de empleo:
Código (csharp) [Seleccionar]
Encoding textEncoding = Encoding.Default;

string unformattedXmlDocument = File.ReadAllText("C:\\Unformatted Document.xml", textEncoding);
string formattedXmlDocument = XmlBeautifier(xmlText: unformattedXmlDocument,
                                           indentChars: new string(' ', 2),
                                           indentOnAttributes: true,
                                           textEncoding: textEncoding);

File.WriteAllText("C:\\Formatted Document.xml", formattedXmlDocument, textEncoding);


Saludos








DarK_FirefoX

#2
5 - Hallar el número primo más cercano a un número

Esté código sirve para encontrar el número primo más cercano a un entero n. En éste código utilizamos el código para encontrar un número primo expuesto anteriormente (Lo añado aquí para que no tengan que ir a buscarlo al post anterior.

Código (csharp) [Seleccionar]
public static bool EsPrimo(int a)
       {
           int raizDelNumero = (int)Math.Sqrt(a);
           for (int i = 2; i <= raizDelNumero; i++)
               if (a % i == 0)
                   return false;
           return true;
       }


La idea del método es comprobar si el número entrado es primo, si lo es, entonces el mismo es el primo más cercano, sino tendremos dos variables, numeroDer y numeroIzq, lo que podemos interpretarlas y usarlas para almacenar los números que hay a la izquierda y a la derecha del número n de la entrada. El objetivo es iterar por los números a la izquierda/derecha del número de la entrada y contar las distancia que tienen entre el y el número n de la entrada. Cuando encontremos un número primo a la derecha tendremos almacenado ese número y la distancia al número n, luego haremos lo mismo hacia la izquierda. Al final comprobaremos las distancias respectivas y devolveremos el número que tenga menor distancia.

Nota: Sabemos que un número primo es un número mayor que 1 tal que tiene únicamente dos divisores naturales distintos: él mismo y el 1. Por lo que si la entrada n viene dada por un número menor o igual que 1, tendrá como primo mas cercano al 2.

Código (csharp) [Seleccionar]
public static int PrimoMasCercano(int n)
       {
           int contadorDer = 0;
           int contadorIzq = 0;
           int numeroDer = n;
           int numeroIzq = n;
           if (n <= 1) return 2;
           if (EsPrimo(n)) return n;
           else
           {
                   while (!EsPrimo(numeroDer))
                   {
                       numeroDer++;
                       contadorDer++;
                   }  
                   while (!EsPrimo(numeroIzq))
                   {
                       numeroIzq--;
                       contadorIzq++;
                   }              
           }
           if (contadorPos < contadorNeg) return numeroDer;
           return numeroIzq;
             
       }





6 - Hallar el máximo común divisor de un número (MCD)

El siguiente código muestra como hallar el MCD de un número utilizando el Método de Euclides, que utiliza el algoritmo de la división. Voy a mostrarlo de manera iterativa y de manera recursiva. En la manera iterativa utilizo una función auxiliar Swap(int a, int b), para hacer un intercambio de valores de dos variables

Código (csharp) [Seleccionar]
static void Swap(int a, int b)
       {
           int temp = b;
           b = a;
           a = temp;
       }


Forma iterativa

El método recibe las dos variables entre las cuales queremos el MCD. El MCD es el mayor número entero que los divide a ambos sin dejar resto.

(No voy a explicar cómo funciona el algoritmo de Euclides ni el algoritmo de la división. Asumo que lo conocen)

Lo primero que debemos hacer es comprobar si los números son iguales, en ese caso, el mismo es el MCD. Sino, comprobamos y determinamos cuál de los dos es el mayor, para comenzar con el mayor como dividendo. Luego planteamos nuestra división teniendo los términos definidos, dividendo, divisor y resto. El resto viene dado por:

Código (csharp) [Seleccionar]
int resto = dividendo % divisor

Luego vamos a ir "dividiendo" mientras el resto sea distinto de 0. Para cada iteración se van a ir cambiando los valores de los términos de la división. El dividendo pasa a ser el divisor, el divisor pasa a ser el resto, y el resto pasa a ser el nuevo resto (nuevo dividendo % nuevo divisor).
Por último, vamos a signarle a la variable answer el valor del resto si este es distinto de 0, para así garantizar que cuando termine el ciclo, esta variable (que es la que se va a devolver) tenga asignado el MCD, que el algoritmo de Euclides define como el último resto distinto de 0.

Código (csharp) [Seleccionar]
public static int MCD(int a, int b)
       {
           if(a==b) return a;
           if(b>a)
               Swap(a,b);
           int dividendo = a;
           int divisor = b;
           int resto = dividendo % divisor;
           int answer = a;
           while (resto!=0)
           {
               dividendo = divisor;
               divisor = resto;
               resto = dividendo % divisor;
               if (resto != 0) answer = resto;
           }
           return answer;
       }


Forma recursiva

Gracias a la recursividad tenemos un método mucho más limpio y corto. Básicamente, el método realiza lo mismo. Comprobamos inicialmente si el resto entre ellos es 0, y si lo es retornamos b (utilizada como divisor). En caso contrario llamamos recursivo, esta vez utilizamos a b (divisor) como dividendo, y utilizamos al resto entre a y b (resto) como divisor, y así recursivamente.

Nota: Pueden preguntarse ¿Por qué no se comprueba cual es el mayor para hacer el Swap? El caso es que si a es menor que b, al realizarse la comprobación nos damos cuenta que el resto entre a y b va a ser a, entonces no va a ser 0, por lo tanto va a llamar recursivo, con b (la variable mayor) como a, y al resto entre a y b (que era a) como b

Código (csharp) [Seleccionar]
static int MCD(int a, int b)
       {
           if (a % b == 0) return b;
           return MCD(b, a % b);
       }





7 - Descomposición de un número en factores primos

Descomponer un número en factores primos consiste en descomponer un número compuesto en divisores no triviales primos que multiplicados den el número.

En este código muestro como descomponer un número n en factores primos.

Nota - 1: Utilizo el método EsPrimo(), explicado anteriormente.
Nota - 2: En este código muestro el resultado en consola utilizando:

Código (csharp) [Seleccionar]
Console.WriteLine()

Pueden modificarlo para que se almacenen en una lista.

Primero que todo comprobamos si el número es primo, en caso de que lo sea, no tiene otros divisores, por lo tanto, devolvemos el único divisor primo que tiene, él mismo.

Ahora, lo que vamos a hacer es ir iterando con una variable desde 2 hasta que encontremos un número que sea primo y que divida al número. En caso de que se cumplan esas dos condiciones, vamos a dividir el número por la variable i (con la cual se está iterando), vamos a devolver el valor de i pues este es el primer factor primo encontrado, y vamos a volver a hacer la variable i de nuevo 2. En caso de que el alguna de las condiciones no se cumpla, se incrementará la variable i y se realizaran las mismas comprobaciones con este nuevo valor. Estas comprobaciones se van a realizar mientras la variable numero sea distinta de 1. Como vemos, al estar dividiendo esta variable va a ir disminuyendo su valor hasta llegar a 1. En este caso terminará el ciclo.


Código (csharp) [Seleccionar]
public static void DescomposicionPrimos(int n)
       {
           if (EsPrimo(n)) Console.WriteLine(n);
           else
           {
               int i = 2;
               int numero = n;
               while (numero!=1)
               {
                   if (EsPrimo(i))
                   {
                       if (numero % i == 0)
                       {
                           numero = numero / i;
                           Console.WriteLine(i);
                           i = 2;
                       }
                       else i++;
                   }
                   else i++;
               }
           }
           
       }


8 - Comprobar si un número es perfecto

Un número perfecto es un número natural que es igual a la suma de sus divisores positivos, sin incluirse a si mismo.

Nota: Aquí utilizamos también el método EsPrimo, puesto que si el número n de la entrada es primo entonces no es perfecto.

La variable suma va a ir controlando la suma de los divisores de n. Esta siempre va a comenzar ya con 1 pues el 1 divide a todos los números, por lo tanto siempre se cuenta. Vamos iterar desde 2 hasta la mitad del número. Puesto que ningún número mayor que la mitad va a dividir al número. Entonces lo que haremos es comprobar que la variable sobre la cual se está iterando deje resto 0 con n y se lo sumamos a la variable suma. una vez que termine el ciclo, devolvemos true en caso de que suma sea igual a n, o falso en caso contrario

Código (csharp) [Seleccionar]
public static bool EsPerfecto(int n)
       {
           if (EsPrimo(n)) return false;
           int suma = 1;
           for (int i = 2; i <= n / 2; i++)
               if (n % i == 0)
                   suma += i;
           return suma == n;
       }


Esto son los otros 4 que he ido terminando. Seguiré luego.

Salu2s

DarK_FirefoX

9 - Hallar el n-ésimo término de la sucesión de Fibonacci (Recursivo)

La sucesión de Fibonacci es una sucesión infinita de números naturales:

1, 1, 2, 3, 5, 8, 13, 21...

la cual viene dada por la siguiente definición recursiva:

fn = fn-1 + fn-2

donde los dos primeros valores son predeterminados:

f0 = 0 y f1 = 1

Lo que voy a mostrar es un método para calcular el n-ésimo término de la sucesión:

Código (csharp) [Seleccionar]
static int Fibonacci(int n)
        {
            if (n == 0) return 0;
            if (n == 1) return 1;
            return Fibonacci(n - 2) + Fibonacci(n - 1);
        }


Este código es muy sencillo de entender (si entendemos recursividad). Primero que todo planteamos los casos base. Si n=0 retornamos 0 (caso para f0 = 0) y si n=1 retornamos 1 (caso para f1 = 1). En caso contrario devolvemos el resultado de la suma de las llamadas recursivas de Fibonacci para n-2 y para n-1. Lo cual define la ecuación recursiva.

Esta definición nos lleva al siguiente código que quiero mostrar de acuerdo con la sucesión de Fibonacci. Si nos damos cuenta, esté código realiza operaciones duplicadas, puesto que si queremos calcular el 5 término de la sucesión, debido al llamado recursivo calculamos el 4 término y el 3 término, pero a su vez el 4 término debe calcular el 3 término y el 2 término, entonces nos damos cuenta que el 3 término se va a calcular 2 veces en el árbol de recursión. Esto se conoce como subproblemas superpuestos ¿Que podemos hacer? Utilizaremos programación dinámica.

Fibonacci Dinámico

Código (csharp) [Seleccionar]
static long[] fibonacci; //Para ir almacenando los valores de los términos calculados.

        static void Main(string[] args)
        {
            long n = long.Parse(Console.ReadLine());
            fibonacci = new long[n+1];
            Console.WriteLine(Fibonacci(n));

        }

        static long Fibonacci(long n)
        {
            if (fibonacci[n] != 0)
                return fibonacci[n];
            if (n == 1 || n==2)
                return 1;
            fibonacci[n - 2] = Fibonacci(n - 2);
            fibonacci[n - 1] = Fibonacci(n - 1);
            return fibonacci[n - 2] + fibonacci[n - 1];
        }


Bueno, lo que vamos a hacer es ir almacenando los términos que se vayan calculando en un array cuya longitud va a ser el término de Fibonacci que se quiera calcular más 1. Y el método cambia un poco.

Primero que todo revisamos si ese término ya se calculó (comprobando si el array en esa posición es distinto de 0). Si se calculó lo devolvemos. Sino, vamos a analizar los casos base, en este caso añadimos una condición con un OR, para los 2 primeros términos de la sucesión. Retornamos 1 en caso de que n=1 o n=2. Luego de esto, en vez de devolver la suma de los llamados recursivos, llamamos recursivo asignándole los valores a las respectivas posiciones en el array. Una vez calculadas/devueltas los valores, entonces se devuelve la suma de los valores contenidos en el array.

Espero esto se haya entendido




10 - Devolver el Reverse de un string

El objetivo del siguiente código es devolver un string con sus char invertidos. El método recibe un string y devuelve un nuevo string. Por lo tanto lo primero que hacemos dentro del método es crear un string que será el que se devolverá. Recorreremos el string de entrada de atrás hacia adelante con un ciclo for. Luego solo nos queda dentro del ciclo concatenarle al string recién creado cada carácter que nos vayamos encontrando en el string original por medio de la posibilidad de indexar en el string.

Código (csharp) [Seleccionar]
public static string Reverse(string original)
        {
            string reverse = "";
            for (int i = original.Length-1; i >= 0; i--)
                reverse += original[i];
            return reverse;
        }


11 - Convertir de decimal a binario

Forma iterativa

Voy a mostrar como iterativamente convertir un número decimal (en este caso un int) a un número binario. La conversión de decimal a binario se realiza haciendo divisiones sucesivas por 2 al número y a sus cocientes. Luego, cuando el número a dividir sea 1 se finaliza la división y se ordena los restos en el orden inverso al que fueron apareciendo.

Lo primero que hacemos es comprobar si el número es 0, si lo es, devolvemos un string con el carácter 0. O sea, el número binario 0. Luego, lo que vamos hacer es ir almacenando los restos a medidas que aparezcan en un string que creamos dentro del método. Utilizamos un while para controlar el ciclo. Aquí utilizo un while(true), el cual va a estar corriendo siempre a no ser que se haga un break (el cual se hace). Lo primer que hacemos es establecer la condición para la cual se va a salir del ciclo, la cual es en el caso de que se divida y el número de 1. Por lo tanto concatenamos al principio el último resto, y luego el 1, que viene siendo el último número que apareció en la división. Entonces hacemos break. En caso de que no se cumpla la condición de n/2 == 1. Vamos a hacer el proceso de concatenar al principio el resto que encontremos y después dividir el número. Proceso que se ejecutará hasta que se cumpla la condición explicada anteriormente. Al final devolvemos el string.


Código (csharp) [Seleccionar]
public static string DecimalABinario(int n)
        {
            if (n == 0) return "0";
            string a = "";
            while (true)
            {
                if (n / 2 == 1)
                {
                    a = n % 2 + a;
                    a = 1 + a;
                    break;
                }
                a = n % 2 + a;
                n = n / 2;
            }
            return a;
        }


Quiero que esto podría hacerse de otra forma, en vez de concatenar al principio del string, podemos concatenar al final utilizando el operador += sobre el string a devolver, solo que la hora de devolver el string lo hacemos llamando al método Reverse, que explique anteriormente.

Forma recursiva

En esta forma iterativa voy a tener una cosa a la que yo llamo: "Método portal", el cuál es el método público (que se le muestra al usuario) el cual tiene una sobrecarga (método con otros parámetros) de tipo privado.

Código (csharp) [Seleccionar]
/// <summary>
        /// Método portal
        /// </summary>
        public static string DecimalABinario(int dec)
        {
            return DecimalABinario(dec, ""); //Llamamos al método
        }

        private static string DecimalABinario(int dec, string result)
        {
            if (dec == 0)
                return "0" + result;
            if (dec == 1)
                return "1" + result;
            return DecimalABinario(dec / 2, (dec % 2) + result);
        }


El método portal recibe el número a convertir a través de la variable dec (int) (cuyo significado semántico es "decimal"l). Entonces a partir de ahi le pasamos al método recursivo esa variable y un string vacío. Los casos bases vienen dado por si el número es 0, devolvemos 0 concatenado al principio del string, si el número es 1 devolvemos 1 concatenado al principio del string. En caso contrario se hace la llamada recursiva, donde el número que se le pasa es la el número dividido por 2 y el string es el resto que deja el número con 2 concatenado al principio del string.

Espero esto se entienda. La verdad es necesario que tengan conocimientos de recursividad para entender esto, sino, miren la forma iterativa.

12 - Convertir de binario a decimal

Convertir de binario decimal es un proceso que viene dado por la suma de las multiplicaciones sucesivas de los dígitos de un número por 2 elevado al índice que ocupa este número (comenzando por 0). Por ejemplo el número binario 1011 seria igual a 1*23 + 0*22 + 1*21 + 1*20 = 8 + 0 + 2 + 1 = 11 (decimal)

Forma iterativa

Primero que todo voy a aclarar que recibimos el número binario a través de un string, los números binarios es mejor representarlos en un string pues si la representación binaria de un número es muy grande puede no ser representable por un int.

Código (csharp) [Seleccionar]
static int BinarioADecimal(string bin)
        {
            int dec = 0;
            for (int i = 0; i < bin.Length; i++)
                dec += (bin[i] - '0') * (int)Math.Pow(2, bin.Length - 1 - i);
            return dec;
        }


Primero voy a explicar ue cosa es:

Código (csharp) [Seleccionar]
bin[i]-'0'

Lo que estamos aquí es convirtiendo un char a int. ¿Cómo? Pues como sabemos un char es básicamente un entero con un puntero a la tabla ASCII. A todos los chars le corresponden un valor entero. Haciéndole la substracción por el char '0' lo que hace es buscar el valor de este caracter en la tabla, el cual es el valor base y se los substrae al valor del char
Código (csharp) [Seleccionar]
bin[i], lo cual nos devuelve el número original.

Una vez entendido esto, veamos que el método lo que hace es crear un int para devolver el valor, e ir sumándole a él la multiplicación del dígito por la potencia de dos. Recorremos el string (representación binaria del número) y vamos sumándole al int creado la multiplicación del digito
Código (csharp) [Seleccionar]
bin[i]-'0' por la potencia.

La potencia la calculamos utilizando el método Pow() de la clase Math. El método recibe un double que  representa la base (en este caso 2) y un double que representa el exponente (en este caso bin.Length - 1 -i. Decimos -1 pues los índices de los dígitos van desde 0 hasta la longitud -1, y decimos -i pues queremos que este valor vaya disminuyendo a medida que avancemos en el string. Aclaro que al resultado de este método se le hace un cast a int pues el método devuelve un double, y no podemos multiplicar un int por un double sin hacer la conversión.

Cuando termine el ciclo devolvemos el número entero (representación decimal del número.

Forma recursiva

Código (csharp) [Seleccionar]

        /// <summary>
        /// Método portal
        /// </summary>
        static int BinarioADecimal(string bin)
        {
            return BinarioADecimal(bin, 0);
        }

        static int BinarioADecimal(string bin, int result)
        {
            if (bin.Length == 0)
                return result;
            return BinarioADecimal(bin.Remove(0, 1), result + (int)(Math.Pow(2, bin.Length - 1) * (bin[0] - '0')));
        }


En este método es casi lo mismo, solo con un pequeño cambio, en vez de ir recorriendo los índices vamos a utilizar el método Remove() dentro de la clase String, el cual devuelve un substring de un string con los caracteres eliminados desde una posición especificada y la cantidad que se le especifiquen.

Lo que hacemos es comprobar si el string ya está vacío, en este caso devolvemos el resultado.

Sino, llamamos recursivo con el resultado del método Remove sobre el string bin eliminándole el primer carácter. Y también le pasamos la suma de la variable result por la multiplicación del dígito (primer) por la potencia de dos.

Espero se entienda.




En cuanto tenga tiempo hago más.
Salu2s

DarK_FirefoX

#4
13 - Saber si una cadena (string) es palíndromo

Primero que todo ¿Qué es palíndromo? Bueno, palíndromo es una palabra, número o frase que se lee igual hacia adelante que hacia atrás.

Ejemplo: anita lava la tina (anitalavalatina)

Este código es extremadamente sencillo. Supongamos que la entrada es un string y que no tiene espacios.

Forma iterativa

Código (csharp) [Seleccionar]
public static bool EsPalindromo(string cadena)
       {
           for (int i = 0; i < cadena.Length / 2; i++)
           {
               if (cadena[i] != cadena[cadena.Length - 1 - i])
                   return false;
           }
           return true;
       }


Simplemente recorremos el string hasta la mitad, pues gracias a los índices y a la propiedad Length de la clase string podemos acceder a los caracteres de la segunda mitad del string

El objetivo es comprobar el primer carácter con el último, el segundo con el penúltimo y así sucesivamente. Si se encuentra que alguno es diferente del otro, se devuelve false (no es palíndromo). Si se llega al final del ciclo sin devolver false, entonces se devuelve true (es palíndromo)

Forma recursiva:

Código (csharp) [Seleccionar]
static bool EsPalindromo(string s)
       {
           int lIzq = 0;
           int lDer = s.Length - 1;
           if (lIzq >= lDer) return true;
           return s[lIzq] == s[lDer] &&
               EsPalindromo(s.Substring(lIzq + 1, lDer - 1));
       }


En la forma recursiva vamos a ir llevando un control de los índices manualmente. Utilizaremos también el método Substring() de la clase string. Este método devuelve un substring de un string dado desde una posición dada con una longitud dada.

Lo primero que hacemos es definir los índices del string. En este caso 0 y la s.Length-1. Luego comprobamos que no hayamos terminado de revisar el string completo. La comprobación viene dada por si los índices se superpusieron. Luego viene el llamado recursivo. Aqui viene dado por un AND entre si el string en las posiciones dadas son iguales y el llamado recursivo en sí. Al llamado recursivo en si se le pasa como parámetro el substring con la posición izquierda más 1 y la posición derecha menos 1. Desta forma garantizamos que seguir funcionando si en la posición actual los caracteres son iguales y solo si también es palíndromo lo que está entre esos caracteres.




14 - Saber el factorial de un número

El factorial de un número se define como el producto de todos los números enteros positivos desde 1 hasta el número.

Por ejemplo: 5! = 1*2*3*4*5 = 120

Forma iterativa

Código (csharp) [Seleccionar]
public static long Factorial(long numero)
       {
           long result = 1;
           for (long i = 2; i <= numero; i++)
               result *= i;
           return result;
       }


Este código es algo relativamente sencillo. Se basa en una productoria desde 1 hasta el número. Con un ciclo for resolvemos este problema sencillamente. Creamos una variable de tipo long, puesto que el factorial de un número puede llegar a ser un número grande y puede no caber en un int. La iniciamos en 1 pues el número 1 siempre se va a multiplicar. Luego el ciclo va desde 2 hasta el número y vamos multiplicando la variable result por la variable iteradora del ciclo y asignándosela a ella misma utilizando el operador *=

Nota: Quiero aclarar que el 0! es igual a 1. Y este código funcionara perfecto, pues si el número es 0, no se ejecutará nunca la instrucción dentro del ciclo pues nunca se cumplirá la condición de iteración y no se entrará al ciclo. Por lo tanto se devolverá result = 1

Forma recursiva

Código (csharp) [Seleccionar]
static long Factorial(long n)
       {
           if (n == 0) return 1;
           return n * Factorial(n - 1);
       }


Si entendemos recursividad esto sale straight-forward. El caso base es para n=0 devolvemos 1 sino, devolvemos n * la llamada recursiva del factorial de n-1. Si planteamos esto explícitamente quedaría algo así como:

n * Factorial(n - 1) * Factorial (n - 2) * ... * Factorial (n - i) * ... * Factorial(0)




15 - Saber si un año es bisiesto

Un año es bisiesto si es divisible entre 4 y no es divisible por 100, también es bisiesto si el año es divisible por 400.

Llevar esto a un código es algo muy sencillo. Aquí les dejo:

Código (csharp) [Seleccionar]
public static bool EsBisiesto(int anno)
       {
           return (anno % 4 == 0 && anno % 100 != 0 || anno % 400 == 0);
       }


Realizamos la comprobación si es divisible entre 4 (deja resto 0 con 4) y no es divisible por 100 (no deja resto 0 con 100), también comprobamos si es divisible por 400 (deja resto 0 con 400). Si se cumple alguna de estas dos condiciones entonces se devuelve true, si no se cumple ninguna de las dos, se devuelve false

16 - Hallar la potencia de un número

La potencia es el resultado de multiplicar un número por sí mismo una cantidad de veces n. Un número elevado a la 0 es igual a 1.

Forma iterativa

Código (csharp) [Seleccionar]
static long PotenciaIterativo(int _base, int _potencia)
       {
           long result = 1;
           for (int i = 1; i <= _potencia; i++)
               result *= _base;
           return result;
       }


Esto se plantea de una forma sencilla. Recibimos como parámetro la base y la potencia. (Utilizo el underscore (_base) para que no entre en conflicto pues en C# existe la palabra reservada base). El objetivo es multiplicar la base un cantidad de veces igual a la variable _potencia. Creamos una variable, que será que se va a devolver (long result), con el valor 1. Luego vamos a multiplicar la variable por _base dentro del ciclo que va a hacer tantas iteraciones como el valor de la variable _potencia. Cabe destacar que si la variable _potencia es 0. Nunca se ejecutará el ciclo pues no se cumplirá la condición de iteración por lo tanto no entrará al ciclo y se devolverá la variable result con el valor 1.

Forma recursiva

Código (csharp) [Seleccionar]
static long Potencia(int _base, int _potencia)
       {
           if (_potencia == 0) return 1;
           if (_potencia == 1) return _base;
           return _base * Potencia(_base, _potencia - 1);
       }


Básicamente es lo mismo, planteamos los casos bases. Si la potencia es 0 entonces se devuelve 1; Si la potencia es 1 se devuelve la base. En caso contrario se multiplica la base por el llamado recursivo. El llamado recursivo va a ir convergiendo a los casos bases, pues se le resta a la potencia 1.

Nota: También puedes hacer uso del método .Pow() dentro de la clase Math. Algo así como:

Código (csharp) [Seleccionar]
double potencia = Math.Pow(2, 4) //Esto eleva 2 a la 4




17 - Búsqueda binaria (colección ordenada)

Este código es algo más interesante. Este algoritmo reduce significativamente el número de comparaciones que se realiza para buscar en un array (previamente ordenado) un elemento que cumpla determinada propiedad. En este código voy a tratar con un array de int y voy a utilizar un método portal.

Código (csharp) [Seleccionar]
/// <summary>
       /// Método portal
       /// </summary>
      public static bool BusquedaBinaria(int[] numerosOrdenado, int aBuscar)
       {
           return BusquedaBinaria(numerosOrdenado, aBuscar, 0, numerosOrdenado.Length - 1);
       }

       private static bool BusquedaBinaria(int[] numerosOrdenado, int aBuscar, int inf, int sup)
       {
           if (inf > sup)
               return false;
           int medio = (inf + sup) / 2;
           if(aBuscar==numerosOrdenado[medio])
               return true;
           if (aBuscar > numerosOrdenado[medio])
               return BusquedaBinaria(numerosOrdenado, aBuscar, medio + 1, sup);
           return BusquedaBinaria(numerosOrdenado, aBuscar, inf, medio - 1);
       }


En este algoritmo se compara el elemento a buscar con el elemento del medio del array, si el valor a buscar es menor que este, se repite el procedimiento en la parte del array que va desde el principio hasta el elemento del medio, sino se toma la parte del array que va desde el elemento central hasta el final del array. De esta manera se realiza sucesivamente con los pedazos hasta que cada vez van a ser más pequeños, hasta que se obtenga un intervalo que no se pueda dividir. Si el elemento no se encuentra dentro de este último entonces se deduce que el elemento buscado no se encuentra en el array.

Desde el método portal llamamos al método recursivo que tiene otros parámetros. Los parámetros son el array de los números (ordenado), el elemento a buscar, la posición inferior y la posición superior.
Lo primero que se hace es comprobar los extremos del intervalo. Si el inferior es mayor que el superior significa que el array se acabó y no se encontró el elemento, por lo tanto se retorna false. Sino se calcula la posición del medio. Luego se revisa si este elemento del medio es el que se está buscando, si lo es, se devuelve true. Entonces si esto no se cumple, vamos a revisar las mitades del array. Si el elemento a buscar es mayor que el elemento del medio se retorna el llamado recursivo pasándole como índice inferior al medio + 1 y manteniendo el superior (mitad de la derecha). En caso contrario se retorna el llamado recursivo pasándole como índice superior al medio - 1 y manteniendo el inferior.

Espero que este algoritmo se haya entendido.

Nota: Si quieres buscar en un array también puedes hacer uso de el método Contains() dentro de la clase array que devuelve un bool dependiendo si el elemento esta dentro del array. Seria algo así:

Código (csharp) [Seleccionar]
int valor = 2;
bool estaElElemento = nombreArray.Contains(valor);


Mod: Agregado el método IndexOf(), utilizando el algoritmo de búsqueda binaria que a la vez devuelve el índice en el cual está el elemento buscado o devolviendo -1 si no se encuentra.

Código (csharp) [Seleccionar]
/// <summary>
        /// Método portal
        /// </summary>
        static int IndexOf(int[] orderedArray, int toSearch)
        {
            return IndexOf(orderedArray, toSearch, 0, orderedArray.Length - 1);
        }

        static int IndexOf(int[] orderedArray, int toSearch, int min, int max)
        {
            if (min > max)
                return -1;
            int medio = (min + max) / 2;
            if (toSearch > orderedArray[medio])
                return IndexOf(orderedArray, toSearch, medio + 1, max);
            if (toSearch < orderedArray[medio])
                return IndexOf(orderedArray, toSearch, min, medio - 1);
            return medio;
        }


Tenemos un método portal al igual que en el otro método. Lo único que cambia es lo que se devuelve, que en este caso se devuelve el valor del índice. En este método comprobamos si los límites del "sub-array" en el cual estamos comprobando se sobrepasan entre ellos. Luego calculamos la posición en el medio. Y comprobamos si el valor que se busca es mayor/menor que el elemento en la posición del medio calculada. En caso de que se cumpla una u otra, se llama recursivo, ajustando los límites del sub-array. Si no es mayor o menor, entonces se devuelve el valor "medio" o sea, es el elemento que está en el medio, por lo tanto se devuelve la posición.





Luego seguiré con más. Salu2s

DarK_FirefoX

#5
18 - Hallar la menor cantidad de inserciones necesarias para que una cadena sea palíndromo

Ya expliqué anteriormente que es un palíndromo.

CitarPalíndromo es una palabra, número o frase que se lee igual hacia adelante que hacia atrás.

Este código es extremadamente sencillo. Supongamos que la entrada es un string y que no tiene espacios.

Este código lo hice de manera recursiva, tenemos también un método portal:

Código (csharp) [Seleccionar]
/// <summary>
       /// Método portal
       /// </summary>
       static int PalindromInsertions(string line)
       {
           if (line.Length == null)
               throw new NullReferenceException("La cadena no puede ser null");
           if (line.Length == 1)
               return 0;
           return PalindromInsertions(line, 0, line.Length - 1);
       }

       static int PalindromInsertions(string line, int inf, int sup)
       {
           if (inf > sup)
               return 0;
           if (line[inf] == line[sup])
               return PalindromInsertions(line, inf + 1, sup - 1);
           else
               return Math.Min(1 + PalindromInsertions(line, inf + 1, sup),
                   1 + PalindromInsertions(line, inf, sup - 1));
       }


El método portal lo utilicé para validar la entrada de que no sea null y si tiene longitud 1 entonces no es necesario hacer inserciones para que sea palíndromo, pues ya es palíndromo.

Luego se llama al método PalindromInsertions() pasándole la cadena, el límite inferior y el superior (en principio, 0 y line.Length - 1 respectivamente).

El objetivo del método y de la recursividad en este caso es ver si la los caracteres de la cadena evaluada en los límites son iguales, si lo son, se llama recursivo aumentado y disminuyendo los limites inferior y superior respectivamente, en caso de que no lo sea, se va a devolver el Mínimo de hacer una inserción por la izquierda y haber una inserción por la derecha. Para esto utilizamos el método Min() de la clase Math. Este método devuelve el mínimo entre dos enteros (tiene otras sobrecargas para distintos tipos de datos). Representamos hacer 1 inserción sumándole 1 al llamado recursivo del método manteniendo un límite y aumentando o disminuyendo el límite inferior o superior respectivamente.

Al principio del método, comprobamos si los límites se superpusieron (ya revisamos la cadena completa). En este caso base, devolvemos 0. (No es necesario hacer inserciones)

Espero se entienda.




19 - Rotar un array n veces a la derecha

En este caso utilizaré nuevamente un array de int para simplificar. El método recibe un array de int y un int que representa la cantidad de posiciones a rotar.

Código (csharp) [Seleccionar]
public static void RotarDerecha(int[] a, int veces)
       {
           if (veces == a.Length || veces % a.Length == 0) return;
           int aMover = a[0];
           int posicion = 0;
           int contador = 0;
           while (contador < a.Length)
           {
               int proxPosicion = (posicion + veces) % a.Length; //Calculamos nueva posición
               int proxValor = a[proxPosicion]; //Guardamos el elemento que esta en esa nueva posición
               a[proxPosicion] = aMover; //Ponemos el elemento a mover en la nueva posición
               aMover = proxValor; //Asignamos a la variable del elemento a mover el valor que estaba en la nueva posición
               posicion = proxPosicion; //Guardamos la posición del nuevo elemento
               contador++; //Hicimos un movimiento
           }
       }


Lo primero que tenemos que darnos cuenta es que rotar a la derecha significa mover cada elemento a la derecha n veces. En caso de que las rotaciones sobrepasen la longitud del array se deberá comenzar desde el inicio del array. ¿Cómo resolvemos esto? Bueno, cada posición nueva viene dada por el resto que deja la posición más la cantidad de rotaciones con la longitud del array. Esto nos garantiza que siempre nos va a quedar en una posición (y en la que es) dentro del array.

Lo primero que hacemos es comprobar si la cantidad de veces es igual a la longitud del array o si la cantidad de veces deja resto 0 con la longitud del array. En este caso no se hace ninguna rotación.

Luego, debemos tener una variable, para saber cuántas rotaciones estamos haciendo y saber cuándo vamos a parar. También una variable para llevar el elemento que estamos moviendo (en principio, el primero) y una variable para llevar su posición.

Ahora, utilizaremos el ciclo while para controlar la cantidad de movimientos que se han hecho. Vamos a ejecutar el ciclo while mientras la variable contador sea menor que la longitud del array.

Dentro del ciclo lo que haremos será calcular la posición nueva de ese elemento. Guardar en una variable el elemento en esa nueva posición y hacer un Swap entre el elemento que llevamos para mover y ese nuevo (que será el nuevo que queremos mover). También debemos guardar en la variable posicion la posición de ese nuevo elemento. Por último, incrementar la variable contador pues ya se hizo un movimiento.




He tenido poco tiempo, por eso solo dejo estos dos.
Salu2s

DarK_FirefoX

20 - Saber si dos cadenas son anagramas

El objetivo del siguiente código es comprobar si dos cadenas son anagramas. Lo primero ¿Qué es un anagrama? Es una palabra o frase que resulta de la transposición de letras de la otra palabra o frase. En el siguiente código vamos solo a tener en cuenta "palabras".

Código (csharp) [Seleccionar]
public static bool SonAnagramas(string a, string b)
        {
            if (a.Length != b.Length) return false;
            for (int i = 0; i < a.Length; i++)
            {
                bool igualdad = false;
                for (int j = 0; j < b.Length; j++)
                {
                    if (a[i] == b[j])
                    {
                        b = b.Remove(j,1);
                        igualdad = true;
                        break;
                    }
                }
                if (!igualdad) return false;
            }
            return b.Length == 0;
        }


El objetivo del código es ir verificando los caracteres de una cadena con la otra. Primero verificamos si las longitudes son iguales. En caso de que no lo sean, se devuelve false pues una tiene caracteres que no tiene la otra. El objetivo es iterar por una cadena y fijar un carácter, y entonces iterar sobre la segunda y comprobar si se encuentra uno igual. En caso de que se encuentre uno igual se modifica la segunda cadena y se elimina el carácter. El objetivo de esto es que si al final de iterar la longitud de esta cadena es mayor que 0 entonces no es un anagrama. Si lo es, en caso contrario. También hay que tener en cuenta que si por un carácter fijado en la primera cadena no se elimina ningún carácter en la segunda cadena, entonces ya podemos decir que no es un anagrama.

Para eliminar un carácter de la cadena, utilizamos el método Remove() que pertenece a la clase string, el método recibe una posición a partir de la cual se va a eliminar caracteres y la cantidad de caracteres a eliminar. El método devuelve un nuevo string, por lo tanto hay que asignárselo a la variable pues este no modifica la instancia sobre la cual se llame.




21 - Contar ficheros de una extensión dada dentro de un directorio incluyendo subcarpetas (recursivamente)

El siguiente código lo que hará es contar la cantidad de ficheros de una extensión dada dentro de un directorio y sus subdirectorios.

Primero que todo, utilizaremos un método portal al cual le pasaremos como parámetro la ruta del directorio, y la extensión (Ej.: ".txt", ".jpg", etc.) En este método utilizaremos dos cosas que voy a explicar a continuación:

Primero, la clase DirectoryInfo dentro del namespace System.IO (recuerden añadirlo). Esta clase tiene métodos para copiar, mover, renombrar, eliminar y enumerar directorios y subdirectorios. Aquí creamos una instancia de esta clase pasándole como parámetro al constructor de la misma la ruta del directorio.

También utilizamos un delegate Func que encapsula un método y devuelve un valor, en este caso utilizamos:

Código (csharp) [Seleccionar]
Func<FileInfo, bool>

Que recibe un parámetro FileInfo como parámetro de entrada y devuelve bool. Este delegate lo vamos a utilizar como condición para comprobar si el fichero tiene una extensión dada. El delegate devuelve true si la extensión del archivo referido por la instancia de FileInfo es igual a la extensión definida por el usuario.

Nota: Asumo que tienen algún conocimiento sobre delegate y encapsulamiento de métodos. Sino, pueden investigar sobre esto.

Ahora, FileInfo es otra clase dentro del namespace System.IO. Tiene métodos para copiar, mover, renombrar, eliminar y abrir ficheros. La misma referencia a un fichero dentro de un directorio.

Código (csharp) [Seleccionar]
/// <summary>
        /// Método portal
        /// </summary>
        public static int ContarFicheros(string path, string extension)
        {
            DirectoryInfo dir = new DirectoryInfo("Prueba"); //Creamos el DirectoryInfo pasándole la ruta del directorio

            Func<FileInfo, bool> extensionCondition = delegate(FileInfo fileInfo) { return fileInfo.Extension == extension; }; //Creamos el delegate

            return ContarFicheros(dir, extension, extensionCondition);
        }


Ahora, el método que se llama para contar los ficheros:

Código (csharp) [Seleccionar]
public static int ContarFicheros(DirectoryInfo directory, string extension, Func<FileInfo, bool> extensionCondition)
        {
            int total = 0;
            if (directory.GetDirectories().Count() == 0)
            {
                total = directory.GetFiles().Count(extensionCondition);
                return total;
            }
            else
            {
                total += directory.GetFiles().Count(extensionCondition);
                foreach (var directorio in directory.GetDirectories())
                    total += ContarFicheros(directorio, extension, extensionCondition);
                return total;
            }
        }


Recibe como parámetro el DirectoryInfo, la extensión y el delegate. El método tiene un enfoque recursivo, utilizando como caso de parada la condición de que un directorio no tenga más subdirectorios. En este caso solamente cuenta los ficheros en este directorio.
En caso contrario, cuenta los ficheros y llama recursivo por cada subdirectorio.

Para obtener los directorios utilizamos el método GetDirectories() dentro de la clase DirectoryInfo el cual devuelve un DirectoryInfo[] con todos los subdirectorios dentro del directorio actual. Y para contar los ficheros utilizamos el método de extensión Count() del método GetFiles() contenido en la clase DirectoryInfo. El método GetFiles() devuelve un FileInfo[] que representa todos los ficheros en el directorio actual. Y con el método Count() los contamos, utilizando una sobrecarga donde se le pasa un delegate

Código (csharp) [Seleccionar]
Func<FileInfo, bool>

El cual representa la condición que tienen que cumplir los ficheros para contarlos.

Nota: En vez de definir el delegate con un método anónimo como lo hice en el código, se puede también definir utilizando expresiones Lambda (aunque esto ya es otro tema)

Código (csharp) [Seleccionar]
Func<FileInfo, bool> extensionCondition = s => s.Extension == extension; ;

Espero que este código sea útil y se entienda.




22 - Saber si una cadena tiene paréntesis balanceados

El objetivo del siguiente código es saber si una cadena esta balanceada en cuanto a los paréntesis. Dígase paréntesis a (), [], {}. El objetivo es saber si están correctamente puestos.

Para esto utilizaremos una Pila de caracteres. (Stack<char>). Una pila es una estructura de datos en la que el modo en el que se accede a sus elementos es de tipo LIFO (Last In First Out - último en entrar, primero en salir). Utilizaremos el método Push() que se utiliza para empilar (meter) un elemento en la pila, el método Pop() para desempilar (quitar) el elemento en el tope de la pila y devolverlo, también el método Peek() que devuelve el último elemento en la pila, pero no lo desempila. Por último la propiedad Count que nos da que cantidad de elementos hay en la pila.

El objetivo es ir recorriendo la cadena y a medida que encontramos un paréntesis abierto meterlo en la  pila, en caso de que no sea un paréntesis abierto comprobar si es cerrado, y ver si la pila tiene elementos y en el tope de la pila está el paréntesis correspondiente abierto entonces sacarlo de la pila y seguir recorriendo la cadena. En caso de que el elemento no sea un paréntesis entonces ignorar y seguir recorriendo. Al final, el método devuelve true si la pila está vacía, false en caso contrario pues hubo algún paréntesis que no tenía su correspondiente paréntesis cerrado

Código (csharp) [Seleccionar]
static bool ParentesisBalanceados(string cadena)
        {
            Stack<char> pila = new Stack<char>();
            for (int i = 0; i < cadena.Length; i++)
            {
                if (cadena[i] == '(')
                    pila.Push('(');
                else if (cadena[i] == '{')
                    pila.Push('{');
                else if (cadena[i] == '[')
                    pila.Push('[');
                else
                {
                    if (cadena[i] == ')')
                        if (pila.Count != 0 && pila.Peek() == '(')
                            pila.Pop();
                        else return false;
                    else if (cadena[i] == '}')
                        if (pila.Count != 0 && pila.Peek() == '{')
                            pila.Pop();
                        else return false;
                    else if (cadena[i] == ']')
                        if (pila.Count != 0 && pila.Peek() == '[')
                            pila.Pop();
                        else return false;
                }
            }
            return pila.Count == 0;
        }


Ejemplo de uso:

Código (csharp) [Seleccionar]
Console.WriteLine(ParentesisBalanceados("ab(xa[y*c](..[.]+++){{}}cc)*"")); //Devuelve true
Console.WriteLine(ParentesisBalanceados("ab(xa[y*c)bb]**")); //Devuelve false
Console.WriteLine(ParentesisBalanceados("a(b))(")); //Devuelve false


Nota: También se podría haber hecho utilizando un Swtich

Código (csharp) [Seleccionar]
static bool ParentesisBalanceadosSwitch(string cadena)
        {
            Stack<char> pila = new Stack<char>();
            for (int i = 0; i < cadena.Length; i++)
            {
                switch (cadena[i])
                {
                    case '(':
                        pila.Push('(');
                        break;
                    case '{':
                        pila.Push('{');
                        break;
                     case '[':
                        pila.Push('[');
                        break;

                     case ')':
                        if (pila.Count != 0 && pila.Peek() == '(')
                            pila.Pop();
                        else return false;
                        break;
                    case '}':
                         if (pila.Count != 0 && pila.Peek() == '{')
                            pila.Pop();
                        else return false;
                        break;
                     case ']':
                        if (pila.Count != 0 && pila.Peek() == '[')
                            pila.Pop();
                        break;
                    default:
                        break;
                }
            }
            return pila.Count == 0;
        }





En cuanto pueda sigo haciendo!
Salu2s

DarK_FirefoX

#7
Voy a adentrarme ahora en lo que se conoce por combinatoria, exponiendo ejemplos sencillos y clásicos de esta rama de las matemáticas discretas.

23 - Variaciones con repetición

Lo primero que voy a hacer es poner un ejemplo:

Si quisiéramos hallar todas las variaciones con repetición en secuencias de 3 de este array:

Código (csharp) [Seleccionar]
string[] valores = {"a", "b", "c", "d", "e"};

Obtendríamos el siguiente resultado:

Citara a a
a a b
a a c
a a d
a a e
a b a
a b b
a b c
a b d
a b e
...
...
e e a
e e b
e e c
e e d
e e e

El orden de la complejidad temporal sería un equivalente a NM, siendo N la cantidad de elementos y M el tamaño de la secuencia. Esto es deducible de la posibilidad de por cada espacio de la secuencia (M), en este caso 3, se pueden poner (N), en este caso 5 posibles elementos. Por lo tanto sería 5 * 5 * 5 = 53.

Veamos el código:

Código (csharp) [Seleccionar]
//Variaciones con repetición de N elementos en M
       /// <summary>
       ///  Método portal
       /// </summary>
       static void VariacionesConRepeticion(string[] original, int size)
       {
           VariacionesConRepeticion(original, new string[size], 0);
       }

       static void VariacionesConRepeticion(string[] original, string[] variacion, int pos)
       {
           if (pos == variacion.Length)
           {
               Print(variacion); //Llama al método Print(), el cual lo que hace es imprimir un array en pantalla.
               Console.WriteLine();
           }
           else
           {
               for (int i = 0; i < original.Length; i++)
               {
                   variacion[pos] = original[i];
                   VariacionesConRepeticion(original, variacion, pos + 1);
               }
           }
       }


Primero que todo, veamos que utilizamos un método portal, el cual recibe el array (en este caso es de string para facilidad, pero se puede hacer de cualquier otro tipo incluso lo pueden implementar para que el método sea genérico). Lo otro que recibe es el tamaño de la variación (M) (M<=N) (N -> Cantidad de elementos).

En el método portal llamamos al método recursivo pasándole como parámetro el array original, un array "variacion" vacío con longitud M y una variable "pos" para iterar sobre este array "variacion"

Ahora, veamos, como todo método recursivo, tenemos una condición de parada que se cumplira cuando la variable "pos" (la cual itera sobre "variacion") sea igual al Length del array "variacion" (o lo que es lo mismo, que ya se ha haya rellenado ese array). En este caso, ya tenemos una variación completa, por lo tanto lo que haremos será Imprimirla en pantalla (lo que se haga puede variar de acuerdo al problema que estemos tratando de resolver.

Para imprimirlo en pantalla, utilizamos un método:

Código (csharp) [Seleccionar]
static void Print<T>(T[] array)
       {
           for (int i = 0; i < array.Length; i++)
           {
               if (i == array.Length - 1)
                   Console.Write(array[i]); //Imprimimos el elemento del array es el último elemento
               else
                   Console.Write(array[i] + " "); //Imprimimos el elemento del array más un espacio si no es el último elemento
           }
       }


Ahora, en caso de que no se cumpla la condición de parada significa que todavía estamos "armando" la variación.

Para armar tenemos un ciclo for, que recorre el array "original", y lo que hacemos es asignarle al array "variacion" en la posición "pos" (que itera sobre "variacion") el valor del array original en la posición i (itera sobre el array "original" utilizando el ciclo for.

Luego lo que hacemos es llamar recursivo pasándole al método el array "original", "variacion" y la variable "pos" incrementada en 1 (pos + 1), ya que pusimos un elemento en el array y ahora vamos a poner otro en la siguiente posición.

Voy a poner un ejemplo:

Imaginen el array "original" como había dicho:

Código (csharp) [Seleccionar]
string[] valores = {"a", "b", "c", "d", "e"};

Y ahora, el array "variacion" estaría así en un principio

[ ] | [ ] | [ ]

O sea, vacío

[ a ] | [ ] | [ ]    - pos = 0

[ a ] | [ a ] | [ ]    - pos = 1

[ a ] | [ a ] | [ a ]    - pos = 2

Luego se retorna la llamada y entonces  pos=3, aquí se imprime la variación pues ya está completa. Luego el ciclo for camina y entonces la próxima asignación que se hace es:

[ a ] | [ a ] | [ b ]  - pos = 2

Espero esto se haya entendido.
Si tienen alguna duda pregunten, pues esto a veces es enredado para verlo si no se ha visto alguna vez y/o no entienden bien la recursividad. Sobre todo, también es algo difícil explicarlo así en plan texto.




Seguimos con combinatoria (espero hayan entendido el anterior, pues no explicaré tan a fondo debido a la similitud

24 - Variaciones sin repetición

Este algoritmo es algo parecido, simplemente que no vamos a repetir elementos en cada variación.

Lo primero que voy a hacer es poner un ejemplo:

Utilicemos el mismo array que teníamos en el código anterior:

Código (csharp) [Seleccionar]
string[] valores = {"a", "b", "c", "d", "e"};

Si quisiéramos hallar todas las variaciones sin repetición en secuencias de 3 de este array obtendríamos:

Citara a a
a b c
a b d
a b e
a c b
a c d
a c e
a d c
a d b
a d e
...
...
e a c
e a d
e a b

El orden de la complejidad temporal sería un equivalente a N!/(N-M)!, siendo N la cantidad de elementos y M el tamaño de la secuencia. Esto es deducible de la posibilidad de por cada espacio de la secuencia (M), en este caso 3, se pueden poner (N-1), este caso 4 elementos posibles en la próxima posición, y después en la próxima (N-2), y asi sucesivamente, por lo que quedaría algo como: 5*4*3 = 5*(5-1)*(5-2) = 5!/(5-3)! = N!/(N-M)!

Primero voy a explicar un método que vamos a utilizar aquí. Utilizaremos un método para hacer Swap entre dos elementos. Este método ya lo había explicado anteriormente en otro código, pero este tiene dos peculiaridades diferentes, primero que lo hice genérico para mostrar esto, y segundo que hace el intercambio pero de las referencias.

Este es el código:

Código (csharp) [Seleccionar]
static void Swap<T>(ref T a, ref T b)
       {
           T temp = a;
           a = b;
           b = temp;
       }


Primero explico la palabra clave (keyword) ref. Esta palabra clave a un argumento causa que el argumento sea pasado al método por referencia y no por valor. El efecto de pasar un argumento por referencia implica que cualquier cambio que se realice al parámetro dentro del método es reflejado en el argumento en el método desde cual fue llamado.

Para llamar a un método pasándole un argumento por referencia se haría algo así:

Código (csharp) [Seleccionar]
static void Main(string[] args)
{
    int numberOne = 1;
    Inc(ref numberOne);
    Console.WriteLine(numberOne); //El valor que se imprimirá será 2
}

public static void Inc(ref int number)
{
    number++;
}


Ahora, que el método sea genérico, implica que se utilizará un placeholder, dentro de todo el método para las operaciones con este tipo de datos dentro del método. Se podrá utilizar el método con cualquier tipo de dato siempre que no cause error en tiempo de ejecución de acuerdo a la función que se realice con él. Genéricas pueden ser clases, estructuras, interfaces y métodos.

Esto es una forma EXTREMADAMENTE lazy de explicarla, recomiendo ir a la MSDN para leer sobre esto.

Una vez visto, solo resta decir sobre este método que funciona intercambiando las referencias de las variables.

Ahora veamos el método como tal:

Código (csharp) [Seleccionar]
//Variaciones sin repetición de N elementos en M
       /// <summary>
       ///  Método portal
       /// </summary>
       static void VariacionesSinRepeticion(string[] original, int size)
       {
           VariacionesSinRepeticion(original, size, 0);
       }

       static void VariacionesSinRepeticion(string[] original, int size, int pos)
       {
           if (pos == size)
           {
               Print(original, size);
               Console.WriteLine();
           }
           else
           {

               for (int i = pos; i < original.Length; i++)
               {
                   Swap(ref original[pos], ref original[i]);
                   VariacionesSinRepeticion(original, size, pos+1);
                   Swap(ref original[pos], ref original[i]);
               }
               
           }
           
       }


Primero que todo démonos cuenta que es bastante parecido al otro método (VariacionesConRepeticion()). Tenemos el método portal y el método recursivo, pero vemos que solo trabajamos sobre un array, pues por eso utilizamos un método Swap para hacer intercambio de valores (que después lo volvemos a intercambiar para ponerlos en la posición original. Tenemos la condición de parada que se cumple cuando "pos" sea igual al tamaño (M) de la variación que viene dado por la variable "size"

Ahora, hay un pequeño cambio en el ciclo for, y es que el ciclo no empieza con la variable i en 0, sino que empieza con el valor de "pos". Y se hace un Swap antes del llamado recursivo y uno después, el cual pone los valores en la posición anterior a cambiarlo. Igual que en el método anterior se llama recursivo incrementando la variable "pos"

Veamos un ejemplo utilizando el siguiente array y calculando las variaciones con tamaño 3:

Código (csharp) [Seleccionar]
string[] letras = { "a", "b", "c" };

Como trabajamos sobre le array "original", el mismo estaría así al principio:

[ a ] | [ b ] | [ c ] - i= 0 y pos = 0
[ a ] | [ b ] | [ c ] - i= 0 y pos = 1
[ a ] | [ b ] | [ c ] - i= 0 y pos = 2

[ a ] | [ b ] | [ c ] - i= 0 y pos = 3 (Se cumplió la condición de parada y por lo tanto se tiene una variación, se imprime)

Luego, cuando se retorne el llamado tenemos a pos = 2 e i = 2 y cuando se incremente en el ciclo no se va a cumplir la condición del ciclo, va a terminar y va retornar la llamada, donde tendremos a pos = 1 e i = 1. Aquí ahora se va a incrementar i, pues va a cumplirse la condición del ciclo y tendremos a pos = 1 e i = 2, y por lo tanto se va a hacer el Swap y va a quedar así:

[ a ] | [ c ] | [ b ] - i= 2 y pos = 1

Y después de se cumplirá la condición de parada y tendremos la variación lista. Así es prácticamente el funcionamiento del algoritmo, les recomiendo que le hagan un Debug Step-By-Step para entenderlo mejor.

Nota: Como ven en ningón momento tenemos una variación en un array nuevo, si nuestro problema requiere devolver esta variación debemos hacer una copia del array original a uno nuevo copiando "size" elementos.

Código (csharp) [Seleccionar]
string[] destino = new string[size];
Array.Copy(original, destino, size);





25 - Combinaciones

Primero que todo, veamos un ejemplo:

Si quisiéramos hallar todas las combinaciones posibles de secuencias de 5 de este array:

Código (csharp) [Seleccionar]
string[] valores = {"a", "b", "c", "d", "e"};

Obtendríamos:

Citara b c d e

En caso de que quisiéramos hallarlas en secuencias de 3, obtendríamos:

Citara b c
a b d
a b e
a c d
a c e
a d e
b c d
b c e
b d e
c d e

Consideremos cada secuencia un subconjunto del conjunto original (el array valores). Cada uno de estos subconjuntos son diferentes dos a dos.

Llamemos "combinaciones" a todas las formas posibles de tomar un subconjunto de elementos de un conjunto con un tamaño predefinido donde ninguno de estas formas son iguales y cada subconjunto no repite elemento.

Nota: Tengan en cuenta que vamos a utilizar el método Print() que declaramos y utilizamos arriba (Variaciones con repetición)

Como en casos anteriores vamos a tener un método portal, al cual le pasaremos como parámetro el array con los elementos. Ambos métodos los declaré genéricos. Repito, para entender mejor cómo funciona la genericidad de parámetros les recomiendo ir a la MSDN

Código (csharp) [Seleccionar]
        /// <summary>
        /// Método portal
        /// </summary>
        static void Combinaciones<T>(T[] letras, int m)
        {
            Combinaciones(letras, new T[m], 0, 0);
        }


Esté método recibe como parámetro el array con los elementos y un int que representa el tamaño de las combinaciones a buscar. Este int debe ser menor o igual que la cantidad de elementos del array. Por lo tanto les recomiendo que hagan una validación a este parámetro en el método portal.

El método recursivo recibe 4 parámetros, dos array y dos int. El primer array es el original, el segundo es el array para ir creando cada combinación, por lo tanto lo que se le pasa es un array nuevo con tamaño igual al int que recibió el método portal (new T[m]]. Ahora, los int que recibe son para iterar sobre los array original y combinacion respectivamente.

Luego, veamos el código del método recursivo:

Código (csharp) [Seleccionar]
static void Combinaciones<T>(T[] original, T[] combinacion,
            int posOriginal, int posCombinacion )
        {
            if (posCombinacion == combinacion.Length)
            {
                Print(combinacion); //Imprimimos la combinación
                Console.WriteLine(); //Hacemos un salto de linea en la consola
            }
            else if (posOriginal == original.Length)
                return;
            else
            {
                combinacion[posCombinacion] = original[posOriginal];
                Combinaciones(original, combinacion, posOriginal + 1, posCombinacion + 1);
                Combinaciones(original, combinacion, posOriginal + 1, posCombinacion);
            }
        }


En este método lo primero que hacemos es establecer las condiciones de parada (para la recursividad).

La primera es si se completó una combinación, por lo tanto vemos que la variable que itera sobre el array combinacion llego a la longitud del array. En tal caso, imprimimos la combinación.

La segunda condición es si ya se utilizaron todos los elementos originales en las combinaciones que antecedían con un elemento fijo.

Veamos un ejemplo de cómo funcionaría la otra parte del código:

Supongamos que el array original es:

Código (csharp) [Seleccionar]
string[] original = {"a", "b", "c", "d", "e"};

Antes de que se ejecute la línea:

Código (csharp) [Seleccionar]
combinacion[posCombinacion] = original[posOriginal];

Tendremos el array combinacion:

[ null ] | [ null ] | [ null ]

Luego:

[ a ] | [ null ] | [ null ]

Luego se ejecutará el llamado recursivo:

Código (csharp) [Seleccionar]
Combinaciones(original, combinacion, posOriginal + 1, posCombinacion + 1);

Y despues tendremos esto:

[ a ] | [ b ] | [ null ]

[ a ] | [ b ] | [ c ]

Y al llamar recursivo se cumplirá la primera condición de parada pues ya tenemos la primera combinación. Luego al salir de la recursividad, se llama recursivo de nuevo:

Código (csharp) [Seleccionar]
Combinaciones(original, combinacion, posOriginal + 1, posCombinacion);

Pero esta vez solo incrementamos la variable que itera sobre el array original. Por lo tanto esa variable estará apuntando al elemento (d) del array original

Y tras hacer:

Código (csharp) [Seleccionar]
combinacion[posCombinacion] = original[posOriginal];

Tendremos:

[ a ] | [ b ] | [ d ]

Luego:

[ a ] | [ b ] | [ e ]

Y Luego se cumplirá la segunda condición de parada, por lo tanto saldremos de la recursividad hasta que la variable que itere por el array combinacion este sobre el elemento 1.

Todo ira funcionando de esa manera.

Espero que se entienda, es un poco enredado, pero una vez que le hagas un step-by-step debug lo entenderán.




Luego continúo con los códigos.

Salu2s

Eleкtro

#8
Este hilo ya ha llegado a las 900 visitas, es un poco frustrante que nadie se haya molestado en opinar sobre los códigos o el esfuerzo en desarrollarlos y publicarlos para compartirlos con ustedes... no sean tan descortés.

Genial aporte y gracias por tu colaboración desinteresada.

Hace falta más gente como tu en el foro ...en toda la WWW en general.

Saludos








DarK_FirefoX

26 - Evaluar una expresión en Notación Posfija (Notación Polaca Inversa)

Primero que todo, ¿Qué es la Notación Posfija (Notación Polaca Inversa)? Pues, es un método algebraico alternativo de introducción de datos, en está notación primero están los operandos y después viene el operador que se va a utilizar para realizar el cálculo sobre los operandos. En esta notación no se necesitan utilizar paréntesis para indicar el orden de las operaciones.

Veamos un ejemplo de notación posfija:

'4' '2' '10' '+' '*' '5' '-' = '43'

Para implementar esto, primero veamos el algoritmo que se utiliza:

Citar
-Si hay elementos en la bandeja de entrada
  -Leer el primer elemento de la bandeja de entrada.
    -Si el elemento es un operando.
      -Poner el operando en la pila.
    -Si no, el elemento es una función (los operadores, como "+", no son más que funciones que toman dos argumentos).
      -Se sabe que la función x toma n argumentos.
      -Si hay menos de n argumentos en la pila
        -(Error) El usuario no ha introducido suficientes argumentos en la expresión.
      -Si no, tomar los últimos n operandos de la pila.
      -Evaluar la función con respecto a los operandos.
      -Introducir el resultado (si lo hubiere) en la pila.
-Si hay un sólo elemento en la pila
  -El valor de ese elemento es el resultado del cálculo.
-Si hay más de un elemento en la pila
  -(Error) El usuario ha introducido demasiados elementos.

^^ Fuente: Wikipedia

En la implementación que hice, que estoy seguro, no es la mejor, solo tuve en cuenta los operadores +, -, *, /. Pueden añadirle más operadores para la raíz, potencia, etc.

Código (csharp) [Seleccionar]
static long EvalPosFixed(string[] exp)
        {
            Stack<long> values = new Stack<long>();
            long first, second = 0;
            for (int i = 0; i < exp.Length; i++)
            {
                switch (exp[i])
                {
                    case "+":
                        if (values.Count < 2)
                            throw new Exception("There are not enough arguments to operate");
                        second = values.Pop();
                        first = values.Pop();
                        values.Push(first + second);
                        break;
                    case "-":
                        if (values.Count < 2)
                            throw new Exception("There are not enough arguments to operate");
                        second = values.Pop();
                        first = values.Pop();
                        values.Push(first - second);
                        break;
                    case "*":
                        if (values.Count < 2)
                            throw new Exception("There are not enough arguments to operate");
                        second = values.Pop();
                        first = values.Pop();
                        values.Push(first * second);
                        break;
                    case "/":
                        if (values.Count < 2)
                            throw new Exception("There are not enough arguments to operate");
                        second = values.Pop();
                        if (second == 0)
                            throw new DivideByZeroException("Can't divide by 0");
                        first = values.Pop();
                        values.Push(first / second);
                        break;
                    default:
                        values.Push(long.Parse(exp[i]));
                        break;
                }
            }
            if (values.Count > 1)
                throw new Exception("The expression had more arguments than it should have");
            return values.Peek();
        }


El método no tiene nada complicado, recibe un array de string, el cual representa la expresión posfija, donde cada elemento del array representa un operando o un operador. En el método se recorre el array y se hace un switch para identificar los operadores. Lo demás se rige al algoritmo expuesto anteriormente.

Nota: No vuelvo a explicar el uso de una pila (Stack), pues ya lo expliqué en el código 22 - Saber si una cadena tiene paréntesis balanceados

Voy a ilustrarles, de cierta manera, el funcionamiento del algoritmo:

Supongamos que la entrada es:

Código (csharp) [Seleccionar]
string[] expresion = { "4", "2", "10", "+", "*", "5", "-"};

Luego:








EntradaOperaciónPilaComentario
4Introducir en la pila4
2Introducir en la pila4, 2
10Introducir en la pila4, 2, 10
+Suma4, 12Toma los dos últimos valores de la pila (2, 10) y los sustituye por el resultado (12)
*Multiplicación48Toma los dos últimos valores de la pila (4, 12) y los sustituye por el resultado (48)
5Introducir en la pila48 5
-Resta43Toma los dos últimos valores de la pila (48, 5) y los sustituye por el resultado (43)

Al finalizar, el resultado (en este caso 43) será el único elemento en la pila.

Espero que hayan entendido este código.

Salu2s