martes, 15 de noviembre de 2016

HTML/CSS - Posicionamientos: estático, relativo, absoluto y fijo

Posicionamiento de elementos de HTML

Hay una gran cantidad de elementos HTML, imágenes, párrafos, listas, contenedores, entre muchos otros, por lo cual hay una infinidad de formas de utilizar dichos elementos para conseguir diferentes efectos. Una de las propiedades más comunes que pueden manipularse para conseguir efectos o comportamientos poco comunes en las páginas, es el atributo position.

Document Flow

Primeramente, es necesario hablar un poco del flujo del documento o document flow. Aunque el nombre suene elegante, en realidad es un concepto muy sencillo de entender.

El flujo del documento, no es otra cosa más que la forma en que los elementos HTML se acomodan al momento de ser renderizados/dibujados por el navegador. Este orden, está plasmado en el código HTML ya que conforme el navegador va interpretando el código, va acomodando los elementos. Cada elemento ocupa su propio lugar dentro del documento y si uno de ellos llegase a desaparecer, los demás ocuparían su lugar.

Otra forma más sencilla de verlo es pensar en el famoso juego de Tetris. En el juego, los bloques (de diferentes formas) van cayendo poco a poco hasta apilarse en el fondo de la pantalla. Cuando un bloque cabe enmedio de otros dos, ocupa ese lugar vacío. Cuando no encuentra un lugar que llenar, simplemente se apila encima de los demás bloques. Es lo mismo que ocurre en el flujo del documento, la diferencia es que los elementos HTML (bloques de Tetris) "caen" de abajo hacia arriba.

La parte importante de hablar sobre el flujo del documento HTML, es que quede razonablemente claro que cada elemento ocupa un lugar dentro de la estructura y que si movemos algún elemento, en mayor o menor medida afectamos también al documento en conjunto. A menos que manipulemos la propiedad position.

Posicionamiento

Ahora bien, habiendo hablado de Document Flow, podemos hablar de los distintos tipos de posicionamiento CSS, sus principales características, cómo funcionan y cómo afectan al flujo del documento.

position: static;
position: relative;
position: absolute;
position: fixed;

Posicionamiento: Estático

position: static;

El posicionamiento estático es aquel con el que los elementos HTML vienen por defecto, viene de fábrica. Éste establece que cada elemento se irá colocando debajo del anterior, ocupando los espacios que le sean posibles (exactamente igual que los bloques de Tetris que mencionábamos anteriormente).

El posicionamiento estático es muy simple, tanto así que no permite desplazar los elementos de su posicion original en el documento a través de CSS.

Ejemplo:

  • 1
  • 2
  • 3

Posicionamiento: Relativo

position: relative;

Es exactamente igual al posicionamiento estático en el sentido de que los elementos se renderizan tal cual vienen en el código HTML y se acomodan uno debajo del otro.

Estático y relativo difieren en que el segundo sí permite despalzar los elementos HTML de su posición original a través de coordenadas, las cuales, se definen tomando como referencia el lugar original del elemento, por medio de las propiedades top, right, bottom y left, donde como se puede deducir, cada propiedad se refiere a la distancia que tiene el elemento respecto a su posicion original.

Los elementos con posicionamiento relativo pueden ser desplazados de su lugar pero este desplazamiento afecta al flujo del documento, ya que aunque el elemento se desplace, el lugar donde estaba se conserva como "ocupado", es decir, como si el elemento siguiera ahí.

Ejemplo:

// código del recuadro desplazado
position: relative;
left:-100px;
background-color:  #088A85;
padding:20px;
width: 30px;
margin: 10px auto;

Como podemos ver, el primer cuadrado está desplazado y a pesar de eso, los demás elementos conservan su posicion en vez de recorrerse hacia arriba.

Posicionamiento: Absoluto

position: absolute;

Es similar, es más, casi igual al posicionamiento relativo. Los elementos con este posicionamiento pueden ser desplazados de su lugar original por medio de las propiedades antes descritas, dichas propiedades se definen respecto al contenedor padre con posicionamiento relativo más próximo.

Ejemplo:

//código de los recuadros
background-color:  #088A85;
padding:20px;
width: 30px;
position: absolute;
left:5px;
top:5px;

En estos dos ejemplos, ambos recuadros verdes tienen los mismos valores en sus propiedades left y top (ambos estan a left:5px; top:5px; de distancia de su contenedor de referencia), pero no están en el mismo lugar debido a que en el primer ejemplo el contenedor externo es el que tiene el posicionamiento relativo mientras que en el segundo ejemplo es el contenedor interno

La diferencia fundamental, es que mover estos elementos de lugar no afecta al flujo del documento, es decir, el lugar donde solía estar el elemento no continúa ocupado.

Ejemplo:

//código del recuadro
left:80px;
position: absolute; 
background-color: #088A85;
padding:20px;
width: 30px;
margin: 10px auto;

En este caso, el primer recuadro está desplazado y a la vez, el resto de los elementos se acomodan como si el recuadro nunca hubiera estado ahí.

Posicionamiento: Fijo

position: fixed;

Los elementos con posicionamiento fijo se comportan de una forma similar a los elementos relativos y absolutos en el sentido de que los tres son relativos a un elemento padre en funcion del cual se definen sus posiciones. Relativos y absolutos se posicionan en relación al contenedor padre más proximo como se menciona anteriormente mientras que los elementos con position: fixed; son relativos al viewport o puerto de visión del navegador. Es decir, los elementos con posicion fija, como su nombre indica, se mantienen fijos siempre en el mismo lugar independientemente de lo que suceda en el documento HTML o si el navegador scrollea hacia abajo o a los lados. Podemos ver un ejemplo en el siguiente enlace: esto es un enlace. Al hacer scroll hacia abajo, llega un punto en el que el menu se queda pegado en la parte de superior de la ventana del navegador.

Dudas, sugerencias, saludos y zings, dejar un comentario por favor c:

lunes, 14 de noviembre de 2016

HTML/CSS - Cómo centrar elementos y no morir en el intento

Centrando elementos

Después de un periodo de inactividad, vacaciones, letargo quizás, de alrededor 3 años, estamos de vuelta para seguir publicando una que otra cosilla útil. En esta ocasión, vamos a hablar un poco de cómo centrar elementos horizontal y verticalmente, lo cual, es muchas veces un dolor de cabeza incluso para aquellos con un poco o un mucho de experiencia en programación web.

Centrando elementos horizontalmente

Esta parte es muy sencilla realmente. Solo es necesario saber qué tipo de elemento HTML es el que estamos tratando de centrar; elementos block o elementos inline (se recomienda ampliamente leer los enlaces anteriores).

Una vez teniendo razonablemente clara la diferencia entre elementos y habiendo identificado a qué categoría pertenece lo que queremos centrar, podemos comenzar.

Centrando elementos horizontalmente: Elementos block

Esta es una tarea sencilla y para ello se usa la propiedad margin. Lo único que hay que hacer es establecer márgenes horizontales automáticos, de esta manera, el navegador sabe que es necesario colocar la misma "porcion" de margen a la izquierda y a la derecha de manera que se pueda "rellenar" horizontalmente el contenedor padre.

<div class="parent">
  <div class="child"></div>
</div>


.parent .child{
  margin: 0 auto;
}

Ejemplo:

  • margen vertical
  • margen automático
  • Elemento centrado
  • margen automático
  • margen vertical

Como podemos ver hay dos márgenes; los horizontales automáticos que se encargan de centrar la imagen y los verticales que están definidos por el usuario/programador que corresponden al 0 de

margin: 0 auto;

Centrado elementos horizontalmente: Elementos inline/inline-block

Por otro lado, tenemos a los elementos inline/inline-block. Los cuales, como podemos leer en los enlaces anteriores, no forman bloques y no ocupan toda la línea donde aparecen sino que ajustan su tamaño a su contenido, entre otras cosas.

Para centrar elementos inline/inline-block es necesario estilizar al padre.

<div class="parent">
  <div class="child"></div>
</div>


.parent{
  text-align: center;
}

Ejemplo:

Elemento centrado

Como vemos, en este caso es el contenedor padre el que hace que su contenido se centre. El elemento a centrar (en este caso del tipo inline/inline-block) no ocupa todo el ancho de su contenedor padre, por lo que queda "espacio libre" donde puede "moverse" a la izquierda/derecha, es precisamente ese "espacio libre" el que permite que el padre pueda centrarlo, muy similar a cuando centramos texto con esa misma propiedad,

text-align: center;

Centrando elementos: verticalmente

Esta parte es quizás una de las más complicadas para algunos (incluído yo). Hay muchos, muchos enfoques y métodos para centrar elementos verticalmente, algunos son más sencillos que otros, otros son más elegantes, algunos brindan soporte crossbrowser y otros simplemente explotan catastroficamente en navegadores no tan recientes. En el sitio donde trabajo, nos vemos obligados a apostar por compatibilidad crossbrowser antes que cualquier cosa, debido a que muchos de los clientes para los que creamos contenido utilizan navegadores un poco retro, por decirlo de una forma bonita.

Teniendo este detalle en mente, el método que vamos a ver aquí sí aporta compatibilidad crossbrowser además de que es bastante sencillo. Se trata de jugar un poco con la propiedad display. A continuación el código.

<div class="parent">
  <span></span>
</div>
 
.parent{
  display: table;
  width: 100%;
}

.parent span{
  display: table-cell;
  vertical-align: middle;
}

Es bien sabido (o quizás no tanto) que los elementos de tipo list item se pueden alinear verticalmente con facilidad, además, las propeidades descritas anteriormente no son nuevas por lo que este enfoque da soporte desde Internet Explorer 9 lo cual ya es decir bastante. El width:100%; que aparece en el codigo CSS es para ajustar el ancho del contenedor padre, ya que al establecer su propiedad display en table, su ancho se ajusta automaticamente a su contenido, igual que los elementos inline/inline-block. Todo lo demás es sencillo y no requiere de explicaciones muy profundas.

Ejemplo:

Elemento centrado verticalmente c:

Como siempre, cualquier duda, pregunta, sugerencia será razonablemente leída y atendida a la brevedad (ahora sí). Saludos c:

martes, 5 de febrero de 2013

Arreglos - Recorridos

Arreglos: Recorridos

Los arreglos, no son otra cosa mas que matrices dentro de los lenguajes de programación. Se utilizan para almacenar, organizar y manipular grandes cantidades de información, por grandes nos referimos a cantidades para las cuales no resulta muy conveniente o práctico utilizar variables separadas.

Una de las operaciones más importantes en los arreglos y que puede llegar a resultar algo confusa, son los recorridos. Antes de entrar a hablar sobre recorridos, recordemos un poco sobre los arreglos. 

Los arreglos, al igual que las matrices, son estructuras que contienen información en cada "casilla" o posición del arreglo. Para hacer referencia a una "casilla" o posición especifica del arreglo, se hacen uso de los índices, que sirven para identificar la fila y columna a la que nos estamos refiriendo en caso de los arreglos bidimensionales, en el caso de los arreglos unidimensionales se necesita un sólo numero para hacer referencia a algún elemento del arreglo. 



Como podemos observar, en C# es muy sencillo hacer referencia a una celda específica del arreglo. Ahora bien, ya que vimos como se hace eso, podemos hablar de recorridos. El mas común y sencillo se basa en dos estructuras de iteración, como puede ser el for, while o do-while, en este caso usaremos el for. Se dice que es el recorrido mas común porque es sencillo, empieza en la posición [0,0] del arreglo, recorre toda la primera fila hasta quedar en la posición final [5,0], después repite la operación pero ahora comenzando en la posición [0,1] para terminar en la posición [5,1]; se repite el mismo procedimiento para las otras 4 filas. 

El algoritmo para este procedimiento es bastante sencillo, apenas unas cuantas lineas;

Para i = 0 hasta i = n - 1 hacer
   Para j = 0 hasta j = n - 1 hacer
       Escribir "["+j+","+i+"]"
   Fin Para
Fin Para

Donde n es la dimensión del arreglo, por ejemplo para un arreglo de 5x5, n = 5.

Y esto en código de C# es aún más sencillo. Por ejemplo, para llenar un arreglo con números en orden, es decir, 1,2,3,4... n*n, podría implementarse el siguiente código.


public int[,] numOrden(int[,] arreglo, int n)
{

int c = 1;
for(int i = 0; i < n; i++)
   for(int j = 0; j < n; j++)
   {
      arreglo[ j , i ] = c;
      c = c + 1;
   } 
return arreglo;

}

Imaginando que n = 3, este método lo que hará, en un principio será situarse en la posición [j,i] del arreglo, en un inicio tanto i como j valen 0, por lo tanto estariamos situados en [0,0] y es ahí donde se almacena el valor de c (1 al principio). Después, el for mas interno hace la comparación j < 3, como j vale 0, el ciclo se repite, la próxima vez que se ejecute la comparación, j valdrá 1, la siguiente 2 y por último 3 < 3, como eso es falso, entonces el for interno no se ejecuta de nuevo, ahora el for externo es el que entra en ejecución y hace la comparación i < 3, como i  en un principio vale 0, todo el proceso se repite nuevamente. 

En otras palabras, el for interno se ejecuta 3 veces por sí mismo, y el for externo hace que éste se ejecute 3 veces, por lo tanto las repeticiones del for interno por las repeticiones del for externo nos dan un total de 9 repeticiones, es decir, habrá visitado cada lugar del arreglo.

Éste mismo código puede utilizarse para recorrer el arreglo columna por columna en vez de fila por fila, solamente tendria que cambiar arreglo[j,i] por arreglo[i,j]. De la misma forma podría usarse para recorrer el arreglo desde el final ( [n-1,n-1] ) hasta el principio, todo depende de las necesidades del programador así como de su imaginación. 

Recorrido en espiral

Arreglo 3x3

Uno de los sencillos recorridos que se pueden hacer sobre un arreglo, es el recorrido de espiral. A simple vista, y sobre todo en arreglos grandes, puede parecer un procedimiento difícil de programar, pero nada mas lejos de la realidad, solo hay que encontrar patrones.

Primero que nada, si nos detenemos a observar con atención el recorrido, podemos darnos cuenta que independientemente de las dimensiones del arreglo, siempre y cuando sea cuadrado, los primeros 3 movimientos (derecha, abajo, izquierda) son de la misma longitud, es decir, si en el arreglo de la imagen estamos posicionados en [0,0] para llegar al final de la fila hay que movernos 2 unidades ( [0,0] → [2,0] ), desde el final de la fila, hasta el final de la columna también son 2 unidades ( [2,0] → [2,2] ), desde el final de la fila hasta el principio son otras 2 unidades ( [2,2] → [0,2] ) hasta ahí, esos 3 movimientos son iguales. Como decíamos al principio, esos 3 movimientos son iguales en todos los arreglos, en términos generales, si el arreglo es de 3x3 entonces n = 3, y podemos decir que los 3 primeros movimientos son de n - 1 unidades.

Habiendo definido esto, los desplazamientos a partir de aquí están dados por un patrón. El siguiente movimiento es hacia arriba, pero esta vez el movimiento no será de n - 1 unidades, a partir de aquí el movimiento es de n - 2 unidades, es decir de 3 - 2 = 1 unidad hacia arriba ( [0,2] → [0,1] ), después 1 unidad hacia la derecha ( [0,1] → [1,1] ), en este punto  el desplazamiento es de n - 3 = 3 - 3 = 0 unidades, entonces el proceso termina cuando el desplazamiento llega a ser de 0 unidades. 

Si observamos con atención, existe un patrón que describe el movimiento en espiral dentro del arreglo. A continuación el algoritmo.

Teniendo un arreglo de 3x3 por ejemplo, donde;

n  = 3
mov = n - 1;



col = 0
fil = 0
Para i = 0 hasta i = mov hacer
   Escribir arreglo[col,fil]
   col = col + 1
Fin para
Para i = 0 hasta i = mov hacer
   Escribir arreglo[col,fil]
   fil = fil + 1
Fin para
Para i = 0 hasta i = mov hacer
   Escribir arreglo[col,fil]
   col = col - 1
Fin para
mov = mov - 1
Mientras( mov >= 1) hacer   //Comienza el patrón
   Para i = 0 hasta i = mov hacer
      Escribir arreglo[col,fil]
      fil = fil - 1
   Fin para
   Para i = 0 hasta i = mov hacer
      Escribir arreglo[col,fil]
      col = col + 1
   Fin para
   mov = mov - 1
   Para i = 0 hasta i = mov hacer
   Escribir arreglo[col,fil]
      col = col + 1
      Fin para
   Para i = 0 hasta i = mov hacer
      Escribir arreglo[col,fil]
      fil = fil + 1
   Fin para
   mov = mov -1
Fin Mientras



Este algoritmo esta hecho para funcionar con cualquier arreglo cuadrado sin importar sus dimensiones y utiliza estructuras básicas de iteración. No es ni por mucho el único algoritmo ni el más eficiente, pero sirve para dar una idea de cómo se puede hacer este recorrido en un arreglo cuadrado. A continuación el código en C#.

public int[,] Espiral(int[,] a, int n)
{
int c = 1;
int cx = 0;
int cy = 0;
int lim = n - 1;
for(int i = 0; i< lim; i++)
{
  a[cx,cy] = c;
  cx++; //mueve hacia la derecha
  c++;
}
for(int i = 0; i < lim; i++)
{
  a[cx,cy] = c;
  cy++; //mueve hacia abajo
  c++;
}
for(int i = 0; i < lim; i++)
{
   a[cx,cy] = c;
   cx--; //mueve hacia la izquierda
   c++;
}
lim--;
while(lim>=1)
{
   if(lim>=1)
       for(int i = 0; i<lim; i++)
       {
           a[cx,cy] = c;
           cy--; //hacia arriba
           c++;
       }
    if(lim>=1)
        for(int i = 0; i<lim; i++)
        {
            a[cx,cy] = c;
            cx++; //hacia la derecha
            c++;
        }
     lim--;
     if(lim>=1)
         for(int i = 0; i<lim; i++)
         {
            a[cx,cy] = c;
            cy++; //hacia abajo
            c++;
         }
     if(lim>=1)
         for(int i = 0; i<lim; i++)
         {
             a[cx,cy] = c;
             cx--; //hacia la izquierda
             c++;
          }
      lim--;
}
return a

}


Claramente, este código contiene algunas validaciones que el algoritmo original no tiene, aunque dichas validaciones aparecen por si mismas al estar implementando el algoritmo en un lenguaje de programación. 
El recorrido análogo del espiral, el espiral desde el centro, funciona de una manera muy similar, comienza del centro, hace un movimiento en alguna dirección, hace otro movimiento, aumenta la cantidad de desplazamientos, hace un movimiento en cierta dirección, hace otro movimiento, nuevamente aumenta en 1 la cantidad de desplazamientos y el ciclo se repite hasta llegar al principio del arreglo. 

Próximamente se incluirán algunos otros recorridos típicos de los arreglos de cuadrados. 




lunes, 4 de febrero de 2013

Recursividad - Triángulo de Sierpinski

Triángulo de Sierpinski 


La recursividad está presente en todo, incluso en el mundo real y tangible donde vivimos. Por ejemplo los átomos, los átomos de un mismo elemento son idénticos, y estos a su vez, están presentes miles de millones de veces para formar algún material, podemos decir entonces que son estructuras que se repiten muchas veces para formar una estructura mas grande. 

Otros ejemplos son por ejemplo las hojas de los árboles o los copos de nieve, son estructuras que se repiten varias veces a distintas escalas. A estos patrones se les conoce como fractales.

Existe un fractal muy curioso llamado triángulo de Sierpinski, el cual presenta una característica muy interesante, es una figura que a medida que más se repiten los patrones, su área tiende a 0.





Otro punto importante de éste fractal, y que como programadores nos concierne un poco más que su área, es que su construcción puede llevarse a cabo mediante un proceso recursivo. 

Antes de entrar al aspecto programático, haciendo un pequeño análisis de este fractal, podemos darnos cuenta que su construcción es bastante sencilla; partiendo del triangulo  equilátero inicial, basta con unir con una linea los 3 puntos medios de cada lado del triangulo, de esa manera el triangulo queda dividido en 4 triángulos mas pequeños de los cuales 3, son similares al triangulo inicial. Si aplicamos el mismo procedimiento a cada uno de los 3 triángulos que obtuvimos en el paso anterior,  tendremos ahora 13 triángulos de los cuales 9 son similares al triangulo inicial, y así sucesivamente.

Aquí es donde entramos nosotros como programadores a elaborar un algoritmo recursivo que nos permita construir este fractal.

Como se mencionaba, basta con tomar el triángulo equilátero inicial, determinar sus puntos medios, y en base a ellos dibujar los 3 triángulos mas pequeños, el proceso se repite en cada uno de los triángulos obtenidos las veces que se desee.

A partir de esa definición podemos construir el algoritmo y posteriormente el código en C# tomando como información de entrada las coordenadas de los vértices y una variable para determinar cuántas veces ha de repetirse el proceso. vert_1 es el vértice izquierdo, vert_2 el de arriba y vert_3 el derecho. p_medio1 es el punto medio de la izquierda, p_medio2 es el punto medio de abajo y p_medio3 el de la derecha.

Algoritmo:

fractal( vert_1, vert_2, vert_3, repe)                    
    Si( repe == 0 )                                       
       dibujar triangulo con las coordenadas              
    Sino                                                  
       calcular p_medio1                                  
       calcular p_medio2                                  
       calcular p_medio3                                  
       fractal(vert_1, p_medio1, p_medio2, repe - 1)      
       fractal(p_medio1, vert_2, p_medio3, repe - 1)      
       fractal(p_medio2, p_medio3, vert_3, repe - 1)      


En esas sencillas lineas se puede resumir la construcción de este particular fractal. Únicamente cabe destacar como se mencionaba en una entrada anterior, que la recursividad funciona en base a una pila de llamadas, y las llamadas empiezan a retornar valores hasta que se llega al caso base, es decir, aquel en el que no es necesario que el método vuelva a llamarse a si mismo. En este caso, dado un triángulo inicial, el método continuaría llamándose a si mismo las veces que sea necesario hasta llegar al caso en que repe es igual a 0, entonces es cuando empezaría a dibujar los triángulos, lógicamente los que corresponden a las últimas llamadas del método, es decir, los triángulos mas pequeños.

En palabras menos complicadas, el método lo único que hace es tomar un triángulo inicial, y dividirlo n veces, hasta el momento que lo tiene dividido las veces necesarias, es cuando comienza a dibujar. 

Ahora bien, pasemos a analizar el código en C#

 private void Triangulo(int x1, int y1, int x2, int y2, int x3, int y3, Graphics g,  int n)
 {
    if (n == 0)
    {
    SolidBrush b = new SolidBrush(Color.Teal);
    Point[] puntos = new Point[3];
    puntos[0] = new Point(x1, y1);
    puntos[1] = new Point(x2, y2);
    puntos[2] = new Point(x3, y3);
    g.FillPolygon(b, puntos);
    }
    else
    {
    int pm1x = (x1 + x2) / 2;
    int pm1y = (y1 + y2) / 2;
    int pm2x = (x1 + x3) / 2;
    int pm2y = (y1 + y3) / 2;
    int pm3x = (x2 + x3) / 2;
    int pm3y = (y2 + y3) / 2;
    Triangulo(x1, y1, pm1x, pm1y, pm2x, pm2y,g,n - 1);
    Triangulo(pm1x, pm1y, x2, y2, pm3x, pm3y, g, n - 1);
    Triangulo(pm2x, pm2y, pm3x, pm3y, x3, y3, g ,n - 1);
    }
 }     

Adjunto el proyecto Sierpinski en Visual C# 2010 
Descargar


Recursividad


Recursividad :B

Introducción

"Para entender la recursividad, primero hay que entender la recursividad"

Para aquellos que están metidos en esto de la programación, en algún momento tendrán que toparse con el concepto de la recursividad. Para muchos de nosotros no es algo sencillo de comprender y mucho menos sencillo de aplicar. Formalmente se dice que es un procedimiento o función que está definido en términos de sí mismo. Esto quiere decir que, hablando en términos de programación orientada a objetos, es un método que para poder ejecutarse, puede llegar a requerir llamarse a si mismo en varias ocasiones.

La recursividad aplica la conocida filosofía de divide y vencerás, es decir, toma un problema grande y lo va dividiendo en problemas mas pequeños que sean mas sencillos de resolver. Todo esto quedara un poco mas claro con un pequeño ejemplo.

Todos conocemos lo que es el factorial de un numero, y para los que no, no es otra cosa mas que la multiplicación sucesiva de un numero, por cada uno de sus antecesores. Por ejemplo si tenemos 5! = 5x4x3x2x1 = 120. Aunque no se aprecie claramente, en esa operación se hace uso de la recursividad :p

Para calcular el factorial de un numero, hay dos reglas sencillas, el factorial de 1 y de 0, en ambos casos es 1, para todos los demás números, hay que multiplicarse por cada antecesor, entonces podemos hacer un pequeño ejemplo;

"Fulanito quería saber cuanto era 4!, entonces le marcó a su hermano Sutanito para preguntarle, él le contesto que era fácil, 4! era 4 x 3!, pero se quedo con la duda y tuvo que marcarle a Manganito para preguntar cuanto era 3!, él le contesto que 3! era 3 x 2!, pero él también se quedo con la duda de cuanto era 2! asi que tuvo que preguntarle a Perenganito y él le contesto que 2! era 2 x 1!, pero él no sabia cuanto era 1!, así que busco en Gúgl, y se dio cuenta que 1! era 1,  entonces pudo contestarle a Manganito y decirle que 2! era 2. Después como Manganito ya sabía que 2! era 2, pudo contestarle a Sutanito que 3x2! era 6. Luego como Sutanito ya sabía que 3! era 6, pudo contestarle a Fulanito que 4x3! era 24, y por último, fue como Fulanito pudo saber que 4! era 24."

Intentado descifrar la enredosa llamada telefónica, podemos observar algo como lo siguiente











A grandes rasgos es así como trabaja la recursividad, toma un problema grande (el 4! por ejemplo), y lo va dividiendo en problemas más pequeños y lógicamente mas sencillos de resolver (las llamadas entre fulanitos) hasta que llega a un punto en que no se necesitan hacer mas divisiones (el 1!) y se pueden empezar a retornar los datos (las llamadas devueltas) para resolver el problema inicial (el dichoso 4!).

El ejemplo del factorial es un clásico para tratar de explicar como trabaja la recursividad, aunque es un ejemplo muy básico a comparación de los problemas donde realmente tiene aplicaciones la recursividad, sirve para dar un panorama general, como en todo, el dominio de esta técnica de programación reside en la práctica :p

El código en C# del método que sirve para calcular factoriales sería el siguiente:

public long fact(int n)
{
   if(n == 1 || n == 0)
      return 1;
   else
      return n * fact(n - 1);
}

Más a fondo

A un nivel un poco más profundo, se puede decir que las estructuras de datos y la recursividad están íntimamente ligadas. Por un lado, la recursividad es posible gracias a una estructura llamada Pila o Stack, que tiene sus propias características en las que no vamos a profundizar de momento, solamente como dato general la pila es una estructura de tipo lifo o último en entrar, primero en salir, por ejemplo; en una pila de platos, para tomar el plato que se encuentra hasta abajo primero hay que comenzar extrayendo el plato que se encuentra en la cima, después el que le sigue y así sucesivamente.

Con eso en mente, podemos darnos cuenta que en la imagen anterior, la primera llamada (Fulanito preguntando cuanto era 4!) fue la última en ser contestada, y a su vez, la última llamada (Perenganito investigando cuanto era 1!) fue la primera en devolver información sin dudas. Entonces a nivel estructura de datos, podemos explicar el orden de llamadas del código anterior utilizando una pila.












Como se puede apreciar, las llamadas se van almacenando en una pila dependiendo del orden en que se hacen. Otro punto remarcable es el hecho de que las últimas llamadas en realizarse, son las primeras en ser desapiladas, y las primeras llamadas en la pila son las últimas en ser desapiladas. Tal es el caso de la llamada inicial fact(4), es la última en devolver una respuesta.