Bienvenidos a mi blog

Los cambios tecnologicos especialmente en lo que ha informatica y sistemas se refiere, cambian dia a dia a pasos insospechados.
Todo aquel que le interese o se mueva en este fabuloso mundo
tiene que estar actualizado en cuanto esos cambios. Este Blog tiene esa intencion, por eso pongo a su disposicion informacion variada y de una gran gama de temas compilados para el fortalecimiento de sus conocimientos."Ojo no es competir con nadie, solo servir de medio de transmision de la informacion y de la apropiasion del conocimiento".

miércoles, 22 de diciembre de 2010

Seven OS 1.1 x86 Live DVD - Instalable

Seven OS es una distribución GNU Linux basada en Ubuntu 10.04 LTS. La apariencia de este SO está basada en la interfaz Aero de Windows 7, para una transición más cómoda hacia el mundo linux; no está hecha precisamente para imitar el aspecto de windows, sino también para demostrar que linux es un sistema tan poderoso y versátil como amigable y personalizable. De hecho, actualmente muchas de las aplicaciones más populares para windows tienen una versión desarrollada especialmente para ser utilizada en plataformas linux, como Firefox, Thunderbird, Google Chrome, Picasa, Pidgin, Opera, Skype, Vlc, Virtualbox, etc. Ademas, hay programas como OpenOffice.org, Evince y GIMP que cumplen perfectamente las mismas funciones y son compatibles con los formatos de archivo propios de software privativos como MS Office, Adobe Reader y Adobe Photoshop respectivamente.
Incluso se pueden ejecutar varios programas de windows en linux bajo una máquina virtual o bien con Wine emulando las librerías de windows. Aunque la principal crítica que se le hace a los sistemas GNU Linux es la falta de versiones de juegos que corran baja esa plataforma, eso no significa que no haya juegos de calidad. Uno de estos casos se trata de Frets On Fire, un clon libre del Guitar Hero que no solo permite importar canciones en el mismo formato, sino que es muchísimo mas liviano que aquél, incluso en maquinas no tan potentes. En resumen, esta distribución GNU Linux está orientada a aquellas personas acostumbradas al uso de MS Windows y sus aplicaciones comunes que deseen probar algo distinto, gratuito y fácil de manejar y sin los mismos problemas del sistema operativo de Microsoft, como los virus y los altos requerimientos de hardware, ademas de evitarse comprar costosas licencias.

Aplicaciones incluidas:
INTERNET
Navegadores Web:
- Mozilla Firefox 3.6.6
- Google Chrome 5.0.375
- Opera 10.60
Comunicación y Redes Sociales:
- Pidgin
- Emesene
- Skype
- XChat IRC
- Gwibber social networking client
- Flickr Uploader
- Liferea RSS reader
Cloud Computing:
- Ubuntu One
- Dropbox
- Google Picasa
- Google Gadgets
- Google Earth
- Office Live
- Zoho Web Apps
File sharing:
- Amule
- Vuze Azureus
- Limewire
- Frostwire
- Giver
- JDownloader
- Tucan Uploader
- Transmission BitTorrent
- FileZilla FTP
OFICINA
- Suite OpenOffice.org:
.Writer (procesador de textos)
.Calc (planilla de cálculo)
.Impress (creador de diapositivas)
.Draw (programa de dibujo)
.Base (bases de datos)
.Math (trabajo con fórmulas)
- Mozilla Thunderbird c/extension Lightning (correo y calendario)
- Getting Things Gnome organizer
- HomeBank
MULTIMEDIA
Reproductores:
- VLC Media Player
- SMPlayer
- Gxine
- Rythmbox audio player
- Totem video player
- RealPlayer 11
- Audacious (clon de Winamp)
- Songbird (clon de ITunes)
- Miro Internet TV
- Moovida Media Center
Capturadores de pantalla:
- Shutter
- GTK Record My Desktop
- Cheese Webcam
Editores de audio y video:
- Pitivi video editor
- Audacity
- Sound Converter
- Arista Transcoder
- EasyTag
- OSD Lyrics
- Grabador de sonido
CD/DVD:
- Brasero
- Handbrake DVD Ripper
- Sound Extractor
- AcetoneISO
GRAFICOS
- GIMP (GNU Image Manipulation Program)
- Inkscape (gráficos vectoriales)
- Gestor de fotos F-Spot
- Comix viewer
- Simple Scan
- Evince PDF viewer
- Visor de imágenes Eye Of Gnome
SISTEMA
Backup y Seguridad:
- DejaDup
- Remastersys
- APTonCD
- Creador de discos de arrnaque USB
- Unetbootin
- Clam Antivirus
- Firestarter firewall
- Cortafuegos Gufw
Control del sistema:
- Ubuntu Control Center 0.3
- Ailurus
- Ubuntu Tweak
- EveInstaller
- Ubuntu Tools
- BleachBit cleaner
- HardInfo
- Gparted
- NVidia Control Center
Personalización:
- Compiz Fusion
- Emerald
- Epidermis
- Gnome Color Chooser
- Gstyle
- Screenlets
- Avant Window Navigator
- Docky
- DockbarX
- Cover Gloobus
- Gloobus Preview
- Cover Thumbnailer
Emuladores y máquinas virtuales:
- Sun Virtualbox OSE
- Wine
- Wine Game
- Play On Linux
ACCESORIOS
- Calculadora
- CHM See help files viewer
- Diccionario
- Gedit
- Notas Tomboy
- PyRenamer
- Terminator multiterminal
- Administrador de Bluetooth
- Gestor de telefonos
ACCESIBILIDAD
- Orca magnification tool
- Teclado OnBoard
JUEGOS
- Frets On Fire
- Game Conqueror
- Gbrainy
- Quadrapassel tetris
- Mahjong
- Minas
- Solitario AisleRiot
- Sudoku

Para todos aquellos que no se animaban a Linux.
Para utilizar en modo live:
USER: seven
PASS: sevenos11

Para descargar fuente origen: http://sourceforge.net/projects/seven-os/files/seven-os10.04.1.iso/download?use_mirror=ufpr

lunes, 1 de noviembre de 2010

Ciberlinux

Ciberlinux es una distribucion Linux de origen argentino derivada o "adaptada" de Ubuntu compartiendo paquete de software y archivos con esta última, creada y orientada para ser utilizada en cibercafes, administraciones publicas, empresas etc.

CIBERLINUX es una personalización" de la distribución Ubuntu donde se trató de hacer que muchos programas y el ambiente gráfico, sean similares al de un sistema operativo de Microsoft para que sea más sencillo de usar tanto en lugares públicos (cibercafes, administraciones publicas,etc.) como en empresas. Con esto, no se logra hacer otra distribución más sino tener "todo listo" para que una vez instalado sea completamente "usable" por el usuario y que no haya que instalar paquetes adicionales.

Entorno de escritorio y licencia

Ciberlinux utiliza (desde la versión 1.3 "pingüinos") Gnome como entorno de escritorio con un tema modificado estilo Windows XP y como programa de control de las estaciones de trabajo el programa de licencia freeware cbm.

La versión 1.0(2007) de Ciberlinux realizaba una instalación automática, con la aplicación modo rescue la cual está bien documentada en la página de la aplicacion. Ocupa dos CD de auto-instalación.








Escritorio CIBERLINUX 1.0


Para la versión Vistoso (1.2) (2008) se utilizaba Kde como entorno de escritorio ocupa un DVD, que puede ser usado en forma de Live DVD o instalable a través de la aplicación Ubiquity en discos duros IDE o SATA








Escritorio CIBERLINUX 1.2


Para la versión "Pingüinos" (1.3) (2010) ocupa un DVD (3.8 gb), que puede ser usado en forma de Live DVD. Se utilizo remastersys para generar tanto el backup del sistema, como el live-DVD.








Escritorio CIBERLINUX 1.3

Caracteristicas:

- Basado en Ubuntu 10.04 LTS.

- Wicd como administrador de conexiones.

- Nueva imagen de booteo, exclusivo de CIBERLINUX.

- GNOME como gestor de escritorio, reemplazando a KDE de versiones anteriores.

- Autologin por defecto.

- Tendrá pre-instalada la versión cliente de CBM (control de ciber) y tendrá para instalar la versión servidor (bajo wine).

- Pre-instalado el sistema de restauración del perfil de usuario (bajo scripts en bash).

- Un único usuario habilitado (con permisos de sudo) y password de root no configurado.

- Tendrá mas de 10 temas seleccionables para GNOME: Simil WIN 7 (por defecto) , WinVISTA , Simil XP, entre otros.

- Juegos Libres Instalados: Alíen Arena, FlightGear, Glest, OpenArena, Torcs, Urban Terror, entre otros...

- Aplicaciones configuradas: Firefox 3.6 + plugins + theme, Open Office, Edición de audio y video, y otros…

- Instalado samba para Poder compartir archivos e impresoras desde el equipo.

- Aplicaciones extras: Picaza, Dropbox, Frostwire, Jdownloader, Skype, Google Apps, y más.

- Un único usuario por defecto. Si será instalado para mutli-usuarios, cada nuevo usuario mantendrá la configuración (skel) full como el usuario por defecto.

- Ubuntu-tweak para “customizar” opciones generales.

El tamaño completo del DVD es de 3.8 gb, que luego de ser instalado, ocupa un total de 8.2 gb totalmente funcional.desde el DVD se puede usar en modo “vivo” (live-DVD) y probarlo en forma completa antes de instalar CIBERLINUX.

Por el momento, CIBERLINUX esta solo disponible via torrent. (descarga el archivo desde AQUI).


martes, 28 de septiembre de 2010

Instalar Ubuntu 10.04 LTS paso a paso


El siguiente manual o how-to fue extraído de Slice of Linux. Todos los créditos correspondientes son para dicho sitio web. ¡Visítalo!

Ya está disponible Ubuntu 10.04 Lucid Lynx y estás deseando instalarlo en tu equipo. Sin embargo, tienes instalado Windows 7 (Vista o XP es lo mismo) y te preocupa instalarlo por si pierdes tus archivos al hacer las particiones o no te arranca después el equipo. ¡Olvídate de tus preocupaciones porque estás en el sitio correcto, en Slice of Linux!

En este tutorial vamos a ver la instalación de Ubuntu 10.04 paso a paso partiendo de un equipo con Windows 7 y dos particiones ya creadas, que es la configuración que traen por defecto muchos equipos actualmente. En este artículo es imposible perderse porque cada paso tiene su captura de pantalla correspondiente. Y además el particionado del disco duro va a dejar de tener secretos porque lo vamos a ver con todo lujo de detalles y todas las opciones posibles.

Aunque es muy recomendable leer el tutorial completo, sobretodo para aquellos que vayáis a instalar Ubuntu por primera vez, aquí tenéis el índice del artículo para acceder directamente a la sección que os interese:

Preparar Windows

Si tenemos instalado Windows (ya sea XP, Vista o 7) en nuestro equipo y queremos instalar Ubuntu 10.04 sin complicaciones, es necesario desfragmentar el disco duro. La desfragmentación consiste en colocar todos los archivos de forma contigua sin que queden espacios entre ellos o entre sus partes. Por eso podemos cambiar el tamaño de la partición de Windows y dejar espacio para instalar Ubuntu sin problemas en un sistema desfragmentado.

Para ilustrar este tutorial tenemos un equipo con un disco duro y Windows 7 instalado en él. El disco duro tiene 2 particiones aunque sólo se ve una de ellas, como ocurre con una instalación normal de Windows 7. Por eso para desfragmentar el disco local (C:) hacemos clic con el botón derecho sobre él y hacemos clic sobre Propiedades.

Hacemos clic con el botón derecho sobre el disco duro o partición

Hacemos clic con el botón derecho sobre el disco duro o partición

En la ventana que nos aparece hacemos clic en la pestaña Herramientas y de las tres herramientas de las que disponemos sólo nos interesa en esta ocasión la de desfragmentación. Así que hacemos clic sobre el botón Desfragmentar ahora…

En la pestaña Herramientas hacemos clic sobre Desfragmentar ahora...

En la pestaña Herramientas hacemos clic sobre Desfragmentar ahora...

En la nueva ventana seleccionamos el disco (C:) y pulsamos sobre Desfragmentar disco.

Seleccionamos el disco y pulsamos Desfragmentar disco

Seleccionamos el disco y pulsamos Desfragmentar disco

Dependiendo de nuestro disco duro este proceso puede tardar entre unos minutos y varias horas. Y cuando termine, hacemos clic sobre el botón Cerrar.

Al terminar pulsamos en Cerrar

Al terminar pulsamos en Cerrar

De esta forma tan sencilla ya tenemos Windows 7 preparado para poder instalar Ubuntu 10.04 junto a él.

¿32 bits o 64 bits?

Lo siguiente que debemos saber es si nuestro procesador (CPU) es de 32 ó 64 bits, ya que Ubuntu tiene versiones específicas para cada uno, aunque para empezar es mejor hacerlo con la versión de 32 bits. La mayoría de los equipos que se venden en la actualidad son de 64 bits sin embargo, lo mejor es asegurarse y comprobar qué tipo de CPU tenemos nosotros.

Para averiguar el tipo de nuestro procesador hacemos clic con el botón derecho sobre Equipo y después, en el menú contextual, hacemos clic en Propiedades.

Hacemos clic en las Propiedades del Equipo

Hacemos clic en las Propiedades del Equipo


A continuación hacemos clic sobre Evaluación de la experiencia de Windows. Si no la hemos hecho nunca, la hacemos (no tarda mucho).

Pulsamos sobre Evaluación de la experiencia en Windows

Pulsamos sobre Evaluación de la experiencia en Windows

Y por último, pulsamos sobre el enlace Ver e imprimir información detallada del sistema y su rendimiento.

Hacemos clic en Ver e imprimir información detallada del sistema y su rendimiento

Hacemos clic en Ver e imprimir información detallada del sistema y su rendimiento

En el informe podremos ver el tipo de sistema instalado (de 32 bits) y si el equipo es compatible con 64 bits. Si nuestro equipo es compatible con 64 bits, significa que nuestra CPU es de 64 bits (independientemente que tengamos instalado un Windows de 32 bits). Si el tipo de sistema fuera de 64 bits, no haría falta nada más porque significaría que nuestro procesador es de 64 bits.

Comprobamos si nuestra CPU es de 32 ó 64 bits

Comprobamos si nuestra CPU es de 32 ó 64 bits

Con esta información, ya podemos pasar a descargar la versión correspondiente de Ubuntu 10.04 para nuestro equipo.

Descargar Ubuntu 10.04 Lucid Lynx

Para instalar Ubuntu 10.04 en nuestro equipo debemos disponer de una imagen ISO que grabaremos en una memoria USB o en un CD. Por lo tanto, lo primero que tenemos que hacer es descargar la imagen ISO desde aquí.

El enlace anterior nos lleva a la página de descarga oficial de Ubuntu en la que tendremos que seleccionar el tipo de nuestro procesador, que averiguamos en la sección anterior. Eso sí, nos recomiendan usar la versión de 32 bits por lo que si estás empezando sería la mejor opción. Después hacemos clic en el botón Start download.

Descargamos Ubuntu 10.04 LTS

Descargamos Ubuntu 10.04 LTS

Grabar Ubuntu 10.04 en una memoria USB o en un CD

Una vez descargada la imagen ISO podemos grabarla tanto en una memoria USB como en un CD. Desde aquí me gustaría recomendar la grabación en una memoria USB porque se puede reutilizar. En cualquier caso, si optas por grabarlo en un CD, posiblemente te interese ponerle la funda y etiqueta oficial de Ubuntu 10.04 LTS.

Sin embargo, la forma más cómoda de instalar Ubuntu 10.04 en nuestro equipo consiste en grabarlo en una memoria USB (pendrive). Para esto necesitaremos una memoria de al menos 1 GB y un programa que se llama UNetbootin. Para descargar el programa accedemos la la página oficial de UNetbootin y hacemos clic sobre Download (for Windows).

Descargamos UNetbootin para Windows

Descargamos UNetbootin para Windows

El programa no necesita instalación, por lo tanto una vez descargado lo ejecutamos haciendo doble clic sobre él y veremos la siguiente pantalla:

Seleccionamos la imagen ISO, la unidad USB y pulsamos Aceptar

Seleccionamos la imagen ISO, la unidad USB y pulsamos Aceptar

En ella deberemos seleccionar la imagen ISO de Ubuntu 10.04 que nos acabamos de descargar y la unidad USB antes de hacer clic sobre Aceptar.

Una vez finalizada la copia de los archivos en la memoria USB podemos pasar directamente a la instalación de Ubuntu pulsando Reiniciar ahora sin extraer la memoria del equipo.

Hacemos clic en Reiniciar ahora

Hacemos clic en Reiniciar ahora

No debemos olvidarnos de cambiar la secuencia de arranque de la BIOS para que lo intente arrancar primero desde la memoria USB.

Instalar Ubuntu 10.04 Lucid Lynx

Ubuntu 10.04 se instala siguiendo un sencillo asistente de tan solo 7 pasos en el que lo único que tiene un poco más de complicación es el particionado del disco. Tanto si vamos a instalar Ubuntu desde una memoria USB como si lo hacemos desde un CD deberemos arrancar el equipo con la memoria o el CD insertado en él y habiendo modificado la secuencia de arranque en la BIOS. En la mayoría de los sistemas se puede hacer pulsando la tecla F12 mientras aparecen las primeras letras después de encender el ordenador.

Ahora pasamos a describir cada uno de los 7 pasos de los que consta la instalación de Lucid Lynx.

Paso 1

El primer paso del asistente para la instalación de Ubuntu 10.04 consiste en seleccionar el idioma que queremos usar en el asistente de instalación y el predeterminado del sistema final. En nuestro caso, seleccionamos Español. Después tenemos dos opciones Probar Ubuntu 10.04 o Instalar Ubuntu 10.04. Si es la primera vez que vas a usar Ubuntu, puedes probarlo antes. Pero si lo tienes claro, pulsa sobre Instalar Ubuntu 10.04.

Seleccionamos el idioma y hacemos clic en Instalar Ubuntu 10.04 LTS

Seleccionamos el idioma y hacemos clic en Instalar Ubuntu 10.04 LTS

Paso 2

A continuación, deberemos indicar dónde nos encontramos para así poder establecer la zona horaria. Por lo tanto, cada uno selecciona su región aunque nosotros no hemos tenido que hacer nada porque el asistente ha elegido automáticamente España y la zona horaria España (Madrid), por lo que hacemos clic en Adelante.

Elegimos nuestra zona horaria

Elegimos nuestra zona horaria

Paso 3

Después seleccionamos la distribución de nuestro teclado. Ubuntu nos sugiere España que es la correcta y hacemos clic en Adelante.

Seleccionamos la distribución de nuestro teclado

Seleccionamos la distribución de nuestro teclado

Paso 4

En este paso llega el momento más importante de la instalación: hacer las particiones. Sin embargo, antes de particionar el disco duro vamos a recordar un par de cosas importantes sobre las particiones:

  • El número de particiones. En un disco duro podemos tener un máximo de 4 particiones primarias y un número ilimitado de particiones lógicas. Todas las particiones de Ubuntu pueden ir en particiones lógicas aunque en este tutorial pongamos la partición raíz en una primaria. Si al particionar el disco, nos encontramos con espacio libre que no podemos particionar y aparece como inútil será porque tengamos las 4 particiones primarias y no se puede crear ninguna partición más. Para solucionar este caso, debemos eliminar la última partición (que será primaria) y volver a crearla de tipo lógica. Así podremos seguir creando tantas particiones como necesitemos.
  • El orden de creación de las particiones tiene su importancia. Según la web Linux Disk Partitioning Guide la zona exterior (los cilindros más externos) de los discos duros giran a mayor velocidad que los más internos. Por lo tanto, sería lógico colocar en la zona exterior del disco las particiones que más se vayan a utilizar y en la más interior las que menos. En un sistema doméstico, en teoría las particiones que más se usan son la partición raíz y la home, y estas deberían ser las primeras (así es como lo vamos a hacer en el tutorial). También hay quien opina que la partición de swap debe colocarse en la zona más rápida del disco para que cuando se use responda de la mejor manera posible. Esto significaría colocar la partición de swap la primera. Pero por otra parte, lo mejor es no tener que usar nunca la partición de swap. Además, hay quien dice que el acceso más rápido está en mitad del disco porque las cabezas tienen que desplazarse menos que cuando lo hacen a las zonas exteriores o interiores. ¿Conclusión? Cada uno que las cree en el orden que considere más conveniente.

Ahora para particionar el disco duro, vamos a ver tres posibilidades:

  1. Instalar Ubuntu 10.04 junto a los otros (Windows XP, Vista o Windows 7), eligiendo entre ellos al arrancar el equipo (sencillo pero poco configurable).
  2. Borrar y usar el disco entero. Elimina cualquier otro sistema operativo del disco duro e instala sólo Ubuntu 10.04.
  3. Especificar particiones manualmente (avanzado). Esta opción es la más recomendable si queremos sacar el máximo rendimiento a Ubuntu y también permite instalarlo junto a Windows XP, Vista o Windows 7.

A continuación vamos a ver detalladamente cada una de estas opciones:

1. Instalarlo junto a los otros, eligiendo entre ellos al arrancar el equipo

Con esta opción sólo tenemos que indicar el tamaño de la partición que queremos que use Ubuntu y el instalador creará automáticamente dos particiones:

  • Partición raíz (/): contendrá, en este caso, los directorios y archivos del sistema operativo y los datos de los usuarios (documentos, imágenes, música, etc.).
  • Partición de intercambio (swap): necesaria cuando nos quedamos sin memoria RAM o para hibernar el sistema. Es posible que esta partición no sea lo suficientemente grande para hibernar el sistema según se indica en las notas de la versión.

Por lo tanto, reducimos el tamaño de la partición de Windows 7 para especificar el tamaño de la partición que dejaremos para Ubuntu como se ve en la imagen (haz clic sobre ella para ver una pequeña animación. Pero… ¿qué tamaño es el adecuado? Eso depende del uso que vayamos a darle. Lo mínimo serían unos 4 GB y lo máximo, lo que queramos. Para empezar a disfrutar de Ubuntu, con 10 GB sería suficiente.

Cambiamos el tamaño de la partición (haz clic sobre la imagen para ver una animación)

Cambiamos el tamaño de la partición (haz clic sobre la imagen para ver una animación)


2. Borrar y usar el disco entero

De esta forma eliminaríamos Windows 7 (o el que tuviésemos instalado) y Ubuntu se instalaría ocupando todo el disco con las mismas particiones que en el caso anterior:

  • Partición raíz (/): contendrá, en este caso, los directorios y archivos del sistema operativo y los datos de los usuarios (documentos, imágenes, música, etc.).
  • Partición de intercambio (swap): necesaria cuando nos quedamos sin memoria RAM o para hibernar el sistema. Igual que en el caso anterior es posible que esta partición no sea lo suficientemente grande para hibernar el sistema según se indica en las notas de la versión.

Eso sí, en este caso no podremos especificar el tamaño de las particiones, cosa que hará el instalador.

Eliminamos Windows 7 y usamos el disco entero para Ubuntu

Eliminamos Windows 7 y usamos el disco entero para Ubuntu





3. Especificar particiones manualmente (avanzado)

La mejor opción de todas, es la más flexible y más difícil (no para nosotros). Consiste en hacer las particiones nosotros mismos (en vez de el instalador). De esta forma podemos seleccionar el número de particiones, su tamaño, tipo de sistema de ficheros… todo lo que necesitemos según nuestras necesidades. Para un sistema de escritorio conviene tener tres particiones:

  • Partición raíz (/): contendrá los directorios y archivos del sistema operativo y de los programas que instalemos.
  • Partición home (/home): contendrá los directorios y datos de los usuarios (documentos, imágenes, música, etc.). Así si cambiamos de distribución o actualizamos a otra nueva, por ejemplo Ubuntu 10.10, no tendremos que preocuparnos de nuestros datos porque se encuentran en una partición distinta.
  • Partición de intercambio (swap): necesaria cuando nos quedamos sin memoria RAM y para hibernar el equipo. Aquí si podremos darle el tamaño adecuado para que el sistema pueda hibernar.

Para iniciar este modo de particionado elegimos Especificar particiones manualmente (avanzado) y hacemos clic en Adelante.

Especificamos las particiones manualmente (avanzado)

Especificamos las particiones manualmente (avanzado)

Lo primero que tenemos que hacer es disminuir el tamaño de una de las dos particiones que tenemos en este ejemplo porque en otro caso no tendríamos sitio para instalar Ubuntu. Dicho de otra forma, no podríamos crear ninguna partición nueva. Así que seleccionamos la partición que queramos (en nuestro caso la más grande) y hacemos clic en Cambiar… (no pulses el botón Adelante).

Seleccionamos la partición más grande y pulsamos Cambiar...

Seleccionamos la partición más grande y pulsamos Cambiar...

Escribimos el nuevo tamaño de la partición en MB y hacemos clic en Aceptar. Esto es un poco incómodo porque implica que tenemos que tener pensado el tamaño que vamos a dejar para Ubuntu. En este caso tenemos una partición con Windows con 250 GB y vamos a reducirla a 125 GB (125000 MB). Así tendríamos la mitad para Windows y la otra mitad para Ubuntu.

Cambiamos el tamaño de la partición de Windows

Cambiamos el tamaño de la partición de Windows

Antes de seguir debemos confirmar el cambio de tamaño de la partición porque es una operación que no se puede deshacer. No te preocupes que no pasa nada. Hacemos clic en Continuar.

Hacemos clic sobre Continuar

Hacemos clic sobre Continuar

El instalador nos devuelve a la pantalla anterior pero ahora contamos con un espacio libre que será el que usaremos para crear las particiones para Ubuntu. Nos situamos en espacio libre y hacemos clic en Añadir…

Seleccionamos el espacio libre y pulsamos Añadir...

Seleccionamos el espacio libre y pulsamos Añadir...

En la ventana que aparece debemos indicar:


  • Tipo de la nueva partición: la partición raíz (/) puede ir en una partición primaria o lógica. En este ejemplo he elegido primaria.
  • Tamaño nuevo de la partición en MB: como mínimo debe tener 3000 MB pero con 10000 tendríamos más que suficiente. Sin embargo, en este ejemplo elijo 15000 MB y sé que por muchos programas que instale me va a sobrar.
  • Ubicación de la nueva partición: principio.
  • Utilizar como: ext4 es el sistema que usa Ubuntu 10.04 por defecto.
  • Punto de montaje: / (la raíz). No nos podemos olvidar de esto, es fundamental.

Y hacemos clic en Aceptar.

Definimos la partición raíz (/)

Definimos la partición raíz (/)

Ya tenemos nuestra primera partición para Ubuntu 10.04 y vamos a por la siguiente. Seleccionamos el espacio libre y hacemos clic en Añadir…

Seleccionamos la partición libre y pulsamos en Añadir...

Seleccionamos la partición libre y pulsamos en Añadir...

La siguiente partición que vamos a definir es el área de intercambio (swap) que se utilizará cuando no tengamos suficiente memoria RAM para mantener todas las aplicaciones en memoria o cuando hibernemos el sistema. Sobre el tamaño de esta partición hay muchas discusiones pero según las notas de la versión de Ubuntu 10.04 debe tener al menos el mismo tamaño que la memoria RAM que tengamos. Por ejemplo, si tenemos 2 GB de RAM, dejamos 2 GB para esta partición. El tipo tampoco importa en este caso pudiendo ser primaria o lógica. Sin embargo, el sistema de archivos será área de intercambio.

  • Tipo de la nueva partición: la partición de intercambio puede ir indistintamente en una primaria o lógica. Sin embargo, solamente puede haber 4 particiones primarias en un disco duro aunque el número de particiones lógicas es ilimitado (como se explicó antes). Tenemos creadas ya 3 particiones primarias (las 2 de Windows y la raíz para Ubuntu) y como nos quedan por definir 2 particiones más, tenemos que poner las nuevas particiones que vayamos a crear como lógicas. Por lo tanto, seleccionamos lógica.
  • Tamaño nuevo de la partición en MB: como en este ejemplo tenemos 2 GB de RAM, le vamos a asignar 2048 MB.
  • Ubicación de la nueva partición: final.
  • Utilizar como: área de intercambio.

Y hacemos clic en Aceptar.

Definimos la partición de intercambio (swap)

Definimos la partición de intercambio (swap)

por último, nos queda definir la partición para los datos de los usuarios, /home. Seleccionamos el espacio libre que nos queda y volvemos a hacer clic sobre Añadir…

Seleccionamos la partición libre y pulsamos en Añadir...

Seleccionamos la partición libre y pulsamos en Añadir...

El tamaño de esta partición es el que nos quede. Como ya hemos definido las otras particiones, podemos usar todo el espacio que nos sobre. Los características de esta nueva partición son:

  • Tamaño nuevo de la partición en MB: todo el que queda disponible. En este ejemplo 126282.
  • Ubicación de la nueva partición: principio.
  • Utilizar como: ext4 es el sistema que usa Ubuntu 10.04 por defecto.
  • Punto de montaje: /home. No nos podemos olvidar de esto, es fundamental.

Y hacemos clic en Aceptar.

Definimos la partición /home

Definimos la partición /home

En pantalla podemos observar todas las particiones que tenemos en nuestro disco duro y ya podemos continuar pulsando Adelante.

Una vez creadas las particiones hacemos clic en Adelante

Una vez creadas las particiones hacemos clic en Adelante

Paso 5

Dejando atrás la parte más difícil de la instalación (crear las particiones), nos relajamos. Ahora tenemos que introducir nuestro nombre, nombre de usuario, contraseña (Ubuntu nos recomienda que tenga 8 caracteres como mínimo), nombre del equipo y si queremos entrar automáticamente o no. Además tenemos la posibilidad de cifrar el contenido de nuestra carpeta personal (home) seleccionando la última opción (solicitar mi contraseña para iniciar sesión y descifrar mi carpeta personal).

Escribimos nuestro nombre, nombre de usuario, contraseña y nombre del equipo

Escribimos nuestro nombre, nombre de usuario, contraseña y nombre del equipo


Paso 6

En el paso 6 tenemos la posibilidad de importar a Ubuntu los documentos, música, imágenes y los marcadores o favoritos desde nuestras cuentas de Windows. Yo he preferido no importar nada pero porque realmente no uso Windows ;-) Después hacemos clic en Adelante.

Seleccionamos los datos que queramos importar de Windows

Seleccionamos los datos que queramos importar de Windows


Paso 7

El último paso antes de que se instale Ubuntu 10.04 en nuestro equipo es un resumen con los datos que hemos ido completando con el asistente de instalación. Y si comprobamos que todo es correcto, hacemos clic sobre el botón Instalar. En caso contrario, si quisiéramos cambiar algo pulsaríamos Atrás.

Leemos el resumen y pulsamos Instalar


Leemos el resumen y pulsamos Instalar

Comenzará a partir de ese momento la instalación de Ubuntu 10.04 en nuestro equipo. Mientras

se instala podremos ir leyendo algunas de sus características principales.

Progreso de la instalación

Progreso de la instalación

Una vez que se ha terminado la instalación debemos pulsar el botón Reiniciar ahora para empezar a disfrutar de nuestro nuevo Ubuntu 10.04 Lucid Lynx.

Hacemos clic en Reiniciar ahora

Hacemos clic en Reiniciar ahora

Eso sí, antes de reiniciarse nos pedirá que retiremos la memoria USB o el CD y pulsemos Intro cuando lo hayamos hecho.

Extraemos la memoria USB o el CD y pulsamos Intro

Extraemos la memoria USB o el CD y pulsamos Intro

Arrancar el equipo

A partir de ahora, al arrancar el equipo nos aparecerá el siguiente menú (GRUB) en el que podremos elegir entre arrancar en Ubuntu y arrancar en Windows 7. Con el tiempo, seguro que nos olvidamos de Windows sobretodo porque nos dará pereza arrancarlo por lo lento que es comparado con Ubuntu. En el menú tenemos 2 líneas que empiezan por Ubuntu pero ¿qué hace cada una? Y ¿cuál hay que elegir?

  • Ubuntu, Linux 2.6.32-21-generic: arranca Ubuntu de forma normal. Es la opción que seleccionaremos el 99,9% de las veces.
    Menú de arranque (GRUB)

    Menú de arranque (GRUB)

  • Ubuntu, Linux 2.6.32-21-generic (modo de recuperación): nos permite entrar en modo recuperación. Con esta opción podemos, entre otras cosas, cambiar la contraseña si la hemos olvidado.
  • Memory test (memtest86+): realiza un test de memoria. Conviene usarla si tenemos problemas con el equipo y pensamos que pueda ser de un fallo de memoria.
  • Memory test (memtest86+, serial console 115200): realiza un test de memoria. De momento, no la he usado nunca.
  • Windows 7 (loader) (on /dev/sda1): nos permite arrancar el Windows 7 que teníamos instalado.

Una vez que se inicia Ubuntu 10.04 nos encontramos con el GDM en el que seleccionamos nuestro usuario, escribimos nuestra contraseña y pulsamos Intro (o pulsamos sobre Iniciar sesión).

GDM para entrar al sistema

GDM para entrar al sistema

Una vez que se inicia Ubuntu 10.04 nos encontramos frente a su interfaz gráfica basada en GNOME 2.30.

Interfaz de Ubuntu 10.04

Interfaz de Ubuntu 10.04

¡ENHORABUENA! Ahora a disfrutar de Ubuntu 10.04 LTS y no dejes de leer Slice of Linux.

El siguiente paso que deberías dar sería instalar una serie de programas para sacarle el máximo partido a tu nuevo sistema. Nosotros te proponemos algunas cosas que hacer después de instalar Ubuntu 10.04 paso a paso con el terminal, gráficamente sin usar el terminal o usando un script.


Informacion tomada de: ClubSO.com.ar, visitenla es una buenisima fuente de informacion para los que nos apasiona el mundo de la informatica.

domingo, 23 de mayo de 2010

Instalación de MySQL en Windows

Uno de los puntos fuertes de las páginas en PHP es la posibilidad de explotar bases de datos mediante funciones de una simplicidad y potencia muy agradecidas. Estas bases de datos pueden servir a nuestro sitio para almacenar contenidos de una forma sistemática que nos permita clasificarlos, buscarlos y editarlos rápida y fácilmente. Una base de datos es sencillamente un conjunto de tablas en las que almacenamos distintos registros (artículos de una tienda virtual, proveedores o clientes de una empresa, películas en cartelera en el cine...). Estos registros son catalogados en función de distintos parámetros que los caracterizan y que presentan una utilidad a la hora de clasificarlos. Así, por ejemplo, los artículos de una tienda virtual podrían catalogarse a partir de distintos campos como puede ser un número de referencia, nombre del artículo, descripción, precio, proveedor... La base de datos más difundida con el tandem UNIX-Apache es sin duda MySQL. Como para el caso de Apache, una versión para Windows está disponible y puede ser descargada gratis. Su puesta a punto no entraña mucha dificultad. Una vez instalado el programa podemos ejecutar nuestras ordenes en modo MS-DOS. Para ello abrimos una ventana MS-DOS y nos colocamos en el directorio bin de mysql. En este directorio se encuentran los archivos ejecutables. Aquí habrá que encontrar un archivo llamado mysqld. En el caso de la versión más actual durante la redacción de este articulo este archivo es llamado mysqld-shareware. Una vez ejecutado este archivo podemos ejecutar el siguiente: mysql. Llegados a este punto veremos cómo un mensaje de bienvenida aparece en nuestra pantalla. En estos momentos nos encontramos dentro de la base de datos. A partir de ahí podemos realizar todo tipo de operaciones por sentencias SQL. No vamos a entrar en una explicación pormenorizada del funcionamiento de esta base de datos ya que esto nos daría para un manual entero. Daremos como referencia nuestro tutorial de SQL a partir del cual se puede tener una idea muy práctica de las sentencias necesarias para la creación y edición de las tablas. También existe una documentación extensa en inglés en el directorio Docs de MySQL. A modo de resumen, aquí os proponemos además las operaciones más básicas que, combinadas nuestro tutorial de SQL pueden dar solución a gran parte de los casos que se nos presenten:















Para evitarnos el tener que editar nuestras tablas directamente sobre archivos de texto, puede resultar muy práctico usar cualquier otra base de datos con un editor y exportar a continuación la tabla en un archivo de texto configurado para dejar tabulaciones entre cada campo. Esto es posible en Access por ejemplo pinchando con el botón derecho sobre la tabla que queremos convertir y eligiendo la opción exportar. Una ventana de dialogo aparecerá en la que elegiremos guardar el archivo en tipo texto. El paso siguiente será elegir un formato delimitado por tabulaciones sin cualificador de texto. Otra posibilidad que puede resultar muy práctica y que nos evita trabajar continuamente tecleando órdenes al estilo de antaño es servirse de programas en PHP o Perl ya existentes y descargables en la red. El más popular sin duda es phpMyAdmin. Este tipo de scripts son ejecutados desde un navegador y pueden ser por tanto albergados en nuestro servidor o empleados en local para, a partir de ellos, administrar MySQL de una forma menos sufrida. Asimismo, dentro del directorio bin de MySQL, podemos encontrar una pequeña aplicación llamada MySqlManager. Se trata de una interface windows, más agradable a la vista y al uso que la que obtenemos ejecutando el archivo mysql. En este caso, las sentencias SQL deben realizarse sin el punto y coma final.:

Tomado del libro: Diseño y programcion de paginas Web
Autor: Miguel Angel Pedregosa Pareja

viernes, 21 de mayo de 2010

Configuración de PHP con Apache en Windows

Configuración de PHP con Apache en Windows

El presente artículo trata de cómo configurar PHP y Apache para que trabajen conjuntamente en un sistema Windows. Además, este articulo asume que hay un servidor Apache configurado en el Windows, y que funciona correctamente.

Existen dos formas de configurar PHP para trabajar con Apache, instalar como un módulo o instalar como un CGI. Para instalar PHP como un CGI hay que seguir los siguientes pasos: En primer lugar, hay que descargarse PHP desde la página de php.net. Existen dos versiones, una que tiene un instalador, y otra que es un fichero ZIP. Hay que descargarse esta última. Una vez descargado, hay que descomprimirlo dentro de una carpeta, esta no tiene que estar bajo el árbol de directorios de Apache. El artículo asumirá que se descomprime dentro de la carpeta C:\PHP. Comprobar que los contenidos del archivo ZIP no quedan en un subdirectorio de la carptea C:\PHP, sino directamente en dicha carpeta. Dentro de la carpeta c:\PHP se encuentra un fichero llamado PHP4ts.dll, hay que mover el fichero dentro de la carpeta: c:\windows\system ó c:\winnt\system A continuación, dentro de la carpeta c:\php se encuentra un fichero llamado php.ini-recomended. Hay que copiar este fichero dentro de la carpeta c:\Windows, y renombrarlo a php.ini. En este fichero se encuentra toda la configuración de PHP, y las modificaciones en la configuración de PHP (mostrar Errores, variables globales etc...) se encuentra dentro del mismo. Es muy recomendable cambiar la directiva display_errors que por defecto esta en OFF, y pornerla en ON, para poder ver los errores que se producen en las páginas durante el desarrollo. Para un servidor en producción en conveniente dejarla en OFF.
Una vez se han hecho estos cambios, queda indicarle al Apache, donde se encuentra instalado el PHP, para ello hay que editar el fichero httpd.conf que se encuentra dentro de la carpeta conf, en la carpeta de instalación del apache (por defecto c:\archivos de programa\apache group\apache2\conf) Abrir el fichero, y situarse al final del mismo, y escribir las siguientes líneas: ScriptAlias /php/ "c:/php/" AddType application/x-httpd-php .php Action application/x-httpd-php "/php/php.exe" En ellas se indica donde se encuentra el ejecutable de php, y lo asocia a los ficheros .php que se encuentren dentro de apache. A continuación reiniciar el servidor Apache, y ya esta! Por último, indicar que para probar la nueva instalación, es recomendable crear un fichero php con el siguiente contenido: Luego lo guardamosdentro de la carpeta raíz de documentos del Apache (por defecto c:\archivos de programa\apache group\apache2\htdocs ), con un nombre terminado en .php, por ejemplo info.php Para ejecutarlo, a través de un navegador, escribir la dirección http://localhost/info.php. Debería aparecer una pantalla como la que se muestra a continuación.































Si la vemos correctamente, es que ya tenemos instalado perfectamente PHP en nuestro servidor Apache







viernes, 26 de marzo de 2010

Programacion Orientada a Aspectos

El concepto de programación orientada a aspectos fue introducido por Gregor Kiczales y su grupo, aunque el equipo Deméter había estado utilizando ideas orientadas a aspectos antes incluso de que se acuñara el término.
El trabajo del grupo Deméter [7] estaba centrado en la programación adaptativa, que no es más que una instancia temprana de la programación orientada a aspectos. La programación adaptativa se introdujo alrededor de 1991. Aquí los programas se dividían en varios bloques de cortes. Inicialmente, se separaban la representación de los objetos del sistema de cortes. Luego se añadieron comportamientos de estructuras y estructuras de clases como bloques constructores de cortes. Cristina López [2] propuso la sincronización y la invocación remota como nuevos bloques.

No fue hasta 1995 cuando se publicó la primera definición temprana del concepto de aspecto [7], realizada también por el grupo Deméter, a la que se hace referencia en el apartado siguiente. Gracias a la colaboración de Cristina López y Karl J. Lieberherr con Gregor Kiczales y su grupo se introdujo el término de programación orientada a aspectos.

Para mayor información del tema los invito a visitar el siguiente enlace:

Programación Orientada a Aspectos

domingo, 7 de marzo de 2010

Recursividad

Recursividad
1. Introducción.
2. Recursividad.
3. Propiedades de las definiciones o algoritmos recursivos.
4. Cadenas recursivas.
5. Definición recursiva de expresiones algebraicas.
6. Programación Recursiva.
7. Asignación estática y dinámica de memoria.
8. Ejemplos.
9. Conclusión.


INTRODUCCIÓN
El área de la programación es muy amplia y con muchos detalles. Los programadores necesitan ser capaces de resolver todos los problemas que se les presente a través del computador aun cuando en el lenguaje que utilizan no haya una manera directa de resolver los problemas. En el lenguaje de programación C, así como en otros lenguajes de programación, se puede aplicar una técnica que se le dio el nombre de recursividad por su funcionalidad. Esta técnica es utilizada en la programación estructurada para resolver problemas que tengan que ver con el factorial de un número, o juegos de lógica. Las asignaciones de memoria pueden ser dinámicas o estáticas y hay diferencias entre estas dos y se pueden aplicar las dos en un programa cualquiera.
1.-Recursividad:
La recursividad es una técnica de programación importante. Se utiliza para realizar una llamada a una función desde la misma función. Como ejemplo útil se puede presentar el cálculo de números factoriales. Él factorial de 0 es, por definición, 1. Los factoriales de números mayores se calculan mediante la multiplicación de 1 * 2 * ..., incrementando el número de 1 en 1 hasta llegar al número para el que se está calculando el factorial.
El siguiente párrafo muestra una función, expresada con palabras, que calcula un factorial.
"Si el número es menor que cero, se rechaza. Si no es un entero, se redondea al siguiente entero. Si el número es cero, su factorial es uno. Si el número es mayor que cero, se multiplica por él factorial del número menor inmediato."
Para calcular el factorial de cualquier número mayor que cero hay que calcular como mínimo el factorial de otro número. La función que se utiliza es la función en la que se encuentra en estos momentos, esta función debe llamarse a sí misma para el número menor inmediato, para poder ejecutarse en el número actual. Esto es un ejemplo de recursividad.
La recursividad y la iteración (ejecución en bucle) están muy relacionadas, cualquier acción que pueda realizarse con la recursividad puede realizarse con iteración y viceversa. Normalmente, un cálculo determinado se prestará a una técnica u otra, sólo necesita elegir el enfoque más natural o con el que se sienta más cómodo.
Claramente, esta técnica puede constituir un modo de meterse en problemas. Es fácil crear una función recursiva que no llegue a devolver nunca un resultado definitivo y no pueda llegar a un punto de finalización. Este tipo de recursividad hace que el sistema ejecute lo que se conoce como bucle "infinito".
Para entender mejor lo que en realidad es el concepto de recursión veamos un poco lo referente a la secuencia de Fibonacci.
Principalmente habría que aclarar que es un ejemplo menos familiar que el del factorial, que consiste en la secuencia de enteros.
0,1,1,2,3,5,8,13,21,34,...,
Cada elemento en esta secuencia es la suma de los precedentes (por ejemplo 0 + 1 = 0, 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, ...) sean fib(0) = 0, fib (1) = 1 y así
sucesivamente, entonces puede definirse la secuencia de Fibonacci mediante la definición recursiva (define un objeto en términos de un caso mas simple de
si mismo):
fib (n) = n if n = = 0 or n = = 1
fib (n) = fib (n - 2) + fib (n - 1) if n >= 2
Por ejemplo, para calcular fib (6), puede aplicarse la definición de manera
recursiva para obtener:
Fib (6) = fib (4) + fib (5) = fib (2) + fib (3) + fib (5) = fib (0) + fib
(1) + fib (3) + fib (5) = 0 + 1 fib (3) + fib (5)
1. + fib (1) + fib (2) + fib(5) =
1. + 1 + fib(0) + fib (1) + fib (5) =
2. + 0 + 1 + fib(5) = 3 + fib (3) + fib (4) =
3. + fib (1) + fib (2) + fib (4) =
3 + 1 + fib (0) + fib (1) + fib (4) =
4. + 0 + 1 + fib (2) + fib (3) = 5 + fib (0) + fib (1) + fib (3) =
5. + 0 + 1 + fib (1) + fib (2) = 6 + 1 + fib (0) + fib (1) =
6. + 0 + 1 = 8
Obsérvese que la definición recursiva de los números de Fibonacci difiere de las definiciones recursivas de la función factorial y de la multiplicación . La definición recursiva de fib se refiere dos veces a sí misma . Por ejemplo, fib (6) = fib (4) + fib (5), de tal manera que al calcular fib (6), fib tiene que aplicarse de manera recursiva dos veces. Sin embargo calcular fib (5) también implica calcular fib (4), así que al aplicar la definición hay mucha redundancia de cálculo. En ejemplo anterior, fib(3) se calcula tres veces por separado. Sería mucho mas eficiente "recordar" el valor de fib(3) la primera vez que se calcula y volver a usarlo cada vez que se necesite. Es mucho mas eficiente un método iterativo como el que sigue parar calcular fib (n).

If (n < = 1) return (n); lofib = 0 ; hifib = 1 ; for (i = 2; i < = n; i ++) { x = lofib ; lofib = hifib ; hifib = x + lofib ; } /* fin del for*/ return (hifib) ; Compárese el numero de adiciones (sin incluir los incrementos de la variable índice, i) que se ejecutan para calcular fib (6) mediante este algoritmo al usar la definición recursiva. En el caso de la función factorial, tienen que ejecutarse el mismo numero de multiplicaciones para calcular n! Mediante ambos métodos: recursivo e iterativo. Lo mismo ocurre con el numero de sumas en los dos métodos al calcular la multiplicación. Sin embargo, en el caso de los números de Fibonacci, el método recursivo es mucho mas costoso que el iterativo. 2.- Propiedades de las definiciones o algoritmos recursivos: Un requisito importante para que sea correcto un algoritmo recursivo es que no genere una secuencia infinita de llamadas así mismo. Claro que cualquier algoritmo que genere tal secuencia no termina nunca. Una función recursiva f debe definirse en términos que no impliquen a f al menos en un argumento o grupo de argumentos. Debe existir una "salida" de la secuencia de llamadas recursivas. Si en esta salida no puede calcularse ninguna función recursiva. Cualquier caso de definición recursiva o invocación de un algoritmo recursivo tiene que reducirse a la larga a alguna manipulación de uno o casos mas simples no recursivos. 3.- Cadenas recursivas: Una función recursiva no necesita llamarse a sí misma de manera directa. En su lugar, puede hacerlo de manera indirecta como en el siguiente ejemplo: a (formal parameters) b (formal parameters) { { . . b (arguments); a (arguments); . . } /*fin de a*/ } /*fin de b*/

En este ejemplo la función a llama a b, la cual puede a su vez llamar a a, que puede llamar de nuevo a b. Así, ambas funciones a y b, son recursivas, dado que
se llamas a sí mismo de manera indirecta. Sin embargo, el que lo sean no es obvio a partir del examen del cuerpo de una de las rutinas en forma individual.
La rutina a, parece llamar a otra rutina b y es imposible determinar que se puede llamar así misma de manera indirecta al examinar sólo a a.
Pueden incluirse mas de dos rutinas en una cadena recursiva. Así, una rutina a puede llamar a b, que llama a c, ..., que llama a z, que llama a a. Cada rutina de la cadena puede potencialmente llamarse a sí misma y, por lo tanto es recursiva.
Por supuesto, el programador debe asegurarse de que un programa de este tipo no genere una secuencia infinita de llamadas recursivas.
4.- Definición recursiva de expresiones algebraicas:
Como ejemplo de cadena recursiva consideremos el siguiente grupo de definiciones:
a. una expresión es un término seguido por un signo mas seguido por un término, o un término solo.

b. un término es un factor seguido por un asterisco seguido por un factor, o un factor solo.
c. Un factor es una letra o una expresión encerrada entre paréntesis.
Antes de ver algunos ejemplos, obsérvese que ninguno de los tres elementos anteriores está definido en forma directa en sus propios términos. Sin embargo, cada uno de ellos se define de manera indirecta. Una expresión se define por medio de un término, un término por medio de un factor y un factor por medio de una expresión. De manera similar, se define un factor por medio de una expresión, que se define por medio de un término que a su vez se define por
medio de un factor. Así, el conjunto completo de definiciones forma una cadena recursiva.
La forma mas simple de un factor es una letra. Así A, B, C, Q, Z y M son factores. También son términos, dado que un término puede ser un factor solo. También son expresiones dado que una expresión puede ser un término solo. Como A es una expresión, (A) es un factor y, por lo tanto, un término y una expresión. A + B es un ejemplo de una expresión que no es ni un término ni un factor, sin embargo (A + B) es las tres cosas. A * B es un término y, en consecuencia, una expresión, pero no es un factor. A * B + C es una expresión, pero no es un factor.
Cada uno de los ejemplos anteriores es una expresión valida. Esto puede mostrarse al aplicar la definición de una expresión de cada uno. Considérese, sin embargo la cadena A + * B. No es ni una expresión, ni un término, ni un factor. Sería instructivo para el lector intentar aplicar la definición de expresión, término y factor para ver que ninguna de ellas describe a la cadena A + * B. De manera similar, (A + B*) C y A + B + C son expresiones nulas de acuerdo con las definiciones precedentes.
A continuación se codificará un programa que lea e imprima una cadena de caracteres y luego imprima "valida" si la expresión lo es y "no valida" de no serlo. Se usan tres funciones para reconocer expresiones, términos y factores, respectivamente. Primero, sin embrago se presenta una función auxiliar getsymb que opera con tres parámetros: str, length y ppos. Str contiene entrada de la cadena de cadena de caracteres; length representa el número de caracteres en str. Ppos apunta a un puntero pos cuyo valor es la posición str de la que obtuvimos un carácter la ultima vez. Si pos <> = length, getsymb regresa un espacio en blanco.
getsymb (str, length, ppos)
char str[];
int length, *ppos;
{
char C;
if (*ppos < c =" str" c =" ‘">
# include
# define TRUE 1
# define FALSE =
# define MAXSTRINGSIZE 100
main ()
{
char str [MAXSTRINGSIZE];
int length, pos;
readstr (str, &length);
pos = 0;
if (expr (str, length, &pos) = = TRUE && por >= length)

printf ("%s", "valida");
else
printf ("%s", "no valida");
/* la condición puede fallar por una de dos razones (o ambas). Si expr(str,
length, &pos) = = FALSE entonces no hay una expresión valida al inicio de pos.

Si pos <>

int length, *ppos;
{
if (factor(str, length, ppos) = = FALSE)
return (FALSE);
if (getsymb (str, length, ppos) ! = ‘+’) {
(*ppos) -- ;
return (TRUE) ;
} /* fin del if */
return (factor(str, length, ppos));
} /* fin de term */
La función factor reconoce factores y debería ser ahora bastante sencilla. Usa el programa común de biblioteca isalpha (esta función se encuentra en la biblioteca ctype.h), que regresa al destino de cero si su carácter de parámetro es una letra y cero (o FALSO) en caso contrario.
factor (str, length, ppos)
char str[];
int length, *ppos;
{
int c;
if ((c = getsymb (str, length, ppos)) ! = ‘)’ )
return (isalpha(c));
return (expr(str, length, ppos) && getsymb (str, length, ppos) == ‘)’ );
} /* fin de factor */
Las tres rutinas son recursivas, dado que cada una puede llamar a sí misma da manera indirecta. Pos ejemplo, si se sigue la acción del programa para la cadena de entrada " (a * b + c * d) + (e * (f) + g) " se encontrará que cada una de las tres rutinas expr, term y factor se llama a sí misma.
5.- Programación Recursiva:
Es mucho mas difícil desarrollar una solución recursiva en C para resolver un problema especifico cuando no se tiene un algoritmo. No es solo el programa
sino las definiciones originales y los algoritmos los que deben desarrollarse. En general, cuando encaramos la tarea de escribir un programa para resolver un problema no hay razón para buscar una solución recursiva. La mayoría de los problemas pueden resolverse de una manera directa usando métodos no recursivos. Sin embargo, otros pueden resolverse de una manera mas lógica y elegante mediante la recursión.
Volviendo a examinar la función factorial. El factor es, probablemente, un ejemplo fundamental de un problema que no debe resolverse de manera recursiva, dado que su solución iterativa es directa y sim ple. Sin embargo, examinaremos los elementos que permiten dar una solución recursiva. Antes que nada, puede reconocerse un gran número de casos distintos que se deben resolver. Es decir, quiere escribirse un programa para calcular 0!, 1!, 2! Y así sucesivamente. Puede identificarse un caso "trivial" para el cual la solución no recursiva pueda obtenerse en forma directa. Es el caso de 0!, que se define como 1. El siguiente paso es encontrar un método para resolver un caso "complejo" en términos de uno mas "simple", lo cual permite la reducción de un problema complejo a uno mas simple. La transformación del caso complejo al simple resultaría al final en el caso trivial. Esto significaría que el caso complejo se define, en lo fundamental, en términos del mas simple.
Examinaremos que significa lo anterior cuando se aplica la función factorial. 4! Es un caso mas complejo que 3!. La transformación que se aplica al numero a
para obtener 3 es sencillamente restar 1. Si restamos 1 de 4 de manera sucesiva llegamos a 0, que es el caso trivial. Así, si se puede definir 4! en términos de 3! y, en general, n! en términos de (n – 1)!, se podrá calcular 4! mediante la definición de n! en términos de (n – 1)! al trabajar, primero hasta llegar a 0! y luego al regresar a 4!. En el caso de la función factorial se tiene una definición de ese tipo, dado que:
n! = n * (n – 1)!
Asi, 4! = 4 * 3! = 4 * 3 * 2! = 4 * 3 * 2 * 1! = 4 * 3 * 2 * 1 * 0! = 4 * 3 * 2] * ] = 24
Estos son los ingredientes esenciales de una rutina recursiva: poder definir un caso "complejo" en términos de uno más "simple" y tener un caso "trivial" (no recursivo) que pueda resolverse de manera directa. Al hacerlo, puede desarrollarse una solución si se supone que se ha resuelto el caso más simple. La versión C de la función factorial supone que esta definido (n –1)! y usa esa cantidad al calcular n!.
Otra forma de aplicar estas ideas a otros ejemplos antes explicados. En la definición de a * b, es trivial el caso de b = 1, pues a * b es igual a a. En general, a + b puede definirse en términos de a * (b – 1) mediante la definición a * b = a * (b – 1) + a. De nuevo, el caso complejo se transforma en un caso mas simple al restar 1, lo que lleva, al final, al caso trivial de b = 1. Aquí la recursión se basa únicamente en el segundo parámetro, b. Con respecto al ejemplo de la función de Fibonacci, se definieron dos casos triviales: fib(0) = 0 y fib(1) = 1. Un caso complejo fib(n) se reduce entonces a dos más simples: fib(n –1) y fib(n –2). Esto se debe a la definición de fib(n) como fib(n –1) + fib(n – 2), donde se requiere de dos casos triviales definidos de
manera directa. Fib(1) no puede definirse como fib(0) + fib(-1) porque la función de Fibonacci no está definida para números negativos.
6.- Asignación estática y dinámica de memoria:
Hasta este momento solamente hemos realizado asignaciones estáticas del programa, y más concretamente estas asignaciones estáticas no eran otras que las declaraciones de variables en nuestro programa. Cuando declaramos una variable se reserva la memoria suficiente para contener la información que debe almacenar. Esta memoria permanece asignada a la variable hasta que termine la ejecución del programa (función main). Realmente las variables locales de las funciones se crean cuando éstas son llamadas pero nosotros no tenemos control sobre esa memoria, el compilador genera el código para esta operación automáticamente.

En este sentido las variables locales están asociadas a asignaciones de memoria dinámicas, puesto que se crean y destruyen durante la ejecución del programa.
Así entendemos por asignaciones de memoria dinámica, aquellas que son creadas por nuestro programa mientras se están ejecutando y que por tanto, cuya gestión debe ser realizada por el programador.
El lenguaje C dispone, como ya indicamos con anterioridad, de una serie de librerías de funciones estándar. El fichero de cabeceras stdlib.h contiene las declaraciones de dos funciones que nos permiten reservar memoria, así como otra función que nos permite liberarla.
Las dos funciones que nos permiten reservar memoria son:
o malloc (cantidad_de_memoria);
o calloc (número_de_elementos,
tamaño_de_cada_elemento).
Estas dos funciones reservan la memoria especificada y nos devuelven un puntero a la zona en cuestión. Si no se ha podido reservar el tamaño de la memoria especificado devuelve un puntero con el valor 0 o NULL. El tipo del puntero es, en principio void, es decir, un puntero a cualquier cosa. Por tanto, a la hora de ejecutar estás funciones es aconsejable realizar una operación cast (de conversión de tipo) de cara a la utilización de la aritmética de punteros a la que aludíamos anteriormente. Los compiladores modernos suelen realizar esta conversión automáticamente. Antes de indicar como deben utilizarse las susodichas funciones tenemos que comentar el operador sizeof. Este operadores imprescindible a la hora de realizar programas portables, es decir, programas que puedan ejecutarse en cualquier máquina que disponga de un compilador de C.
El operador sizeof (tipo_de_dato), nos devuelve el tamaño que ocupa en memoria un cierto tipo de dato, de esta manera, podemos escribir programas independientes del tamaño de los datos y de la longitud de palabra de la máquina. En resumen si no utilizamos este operador en conjunción con las conversiones de tipo cast probablemente nuestro programa sólo funciones en el ordenador sobre el que lo hemos programado.
Por ejemplo, el los sistemas PC, la memoria está orientada a bytes y un entero ocupa 2 posiciones de memoria, sin embargo puede que en otro sistema la máquina esté orientada a palabras (conjuntos de 2 bytes, aunque en general una máquina orientada a palabras también puede acceder a bytes) y por tanto el tamaño de un entero sería de 1 posición de memoria, suponiendo que ambas máquinas definan la misma precisión para este tipo.
Con todo lo mencionado anteriormente veamos un ejemplo de un programa que reserva dinámicamente memoria para algún dato.
#include
main()
{
int *p_int;
float *mat;
p_int = (int *) malloc(sizeof(int));
mat = (float *)calloc(20,sizeof(float));
if ((p_int==NULL)||(mat==NULL))
{
printf ("\nNo hay memoria");
exit(1);
}
/* Aquí irían las operaciones sobre los datos */
/* Aquí iría el código que libera la memoria */
}
Este programa declara dos variables que son punteros a un entero y a un float. A estos punteros se le asigna una zona de memoria, para el primero se reserva memoria para almacenar una variable entera y en el segundo se crea una matriz de veinte elementos cada uno de ellos un float. Obsérvese el uso de los operadores cast para modificar el tipo del puntero devuelto por malloc y calloc, así como la utilización del operador sizeof.
Como se puede observar no resulta rentable la declaración de una variable simple (un entero, por ejemplo, como en el programa anterior) dinámicamente,
en primer lugar por que aunque la variable sólo se utilice en una pequeña parte del programa, compensa tener menos memoria (2 bytes para un entero) que incluir todo el código de llamada a malloc y comprobación de que la asignación fue correcta (esto seguro que ocupa más de dos bytes).
En segundo lugar tenemos que trabajar con un puntero con lo cual el programa ya aparece un poco más engorroso puesto que para las lecturas y asignaciones de las variables tenemos que utilizar el operador *.
Para termina un breve comentario sobre las funciones anteriormente descritas.
Básicamente da lo mismo utilizar malloc y calloc para reservar memoria es equivalente:
mat = (float *)calloc (20,sizeof(float));
mat = (float *)malloc (20*sizeof(float));
La diferencia fundamental es que, a la hora de definir matrices dinámicas calloc es mucho más claro y además inicializa todos los elementos de la matriz a cero.
Nótese también que puesto que las matrices se referencian como un puntero la asignación dinámica de una matriz nos permite acceder a sus elementos con instrucciones de la forma:
NOTA: En realidad existen algunas diferencias al trabajar sobre máquinas con alineamiento de palabras.
mat[0] = 5;
mat[2] = mat[1]*mat[6]/67;
Con lo cual el comentario sobre lo engorroso que resultaba trabajar con un puntero a una variable simple, en el caso de las matrices dinámicas no existe diferencia alguna con una declaración normal de matrices.
La función que nos permite liberar la memoria asignada con malloc y calloc es free(puntero), donde puntero es el puntero devuelto por malloc o calloc.
En nuestro ejemplo anterior, podemos ahora escribir el código etiquetado como: /* Ahora iría el código que libera la memoria */
free (p_int);
free(mat);
Hay que tener cuidado a la hora de liberar la memoria. Tenemos que liberar todos los bloque que hemos asignado, con lo cual siempre debemos tener almacenados los punteros al principio de la zona que reservamos. Si mientras actuamos sobre los datos modificamos el valor del puntero al inicio de la zona reservada, la función free probablemente no podrá liberar el bloque de memoria.

7.- Ejemplos:
7.1.- Las Torres de Hanói:

A continuación se verá cómo pueden usarse técnicas recursivas para lograr una solución lógica y elegante de un problema que no se especifica en términos recursivos. EL problema es el de "las torres de Hanoi", cuyo planteamiento inicial se muestra en la figura a continuación...
Hay tres postes: A, B y C. En el poste A se ponen cinco discos de diámetro diferente de tal manera que un disco de diámetro mayor siempre queda debajo de uno de diámetro menor. El objetivo es mover los discos al poste C usando B como auxiliar. Sólo puede moverse el disco superior de cualquier poste a otro poste, y un disco mayor jamás puede quedar sobre uno menor. Considérese la posibilidad de encontrar una solución. En efecto, ni siquiera es claro que exista una.
Ahora se verá si se puede desarrollar una solución. En lugar de concentrar la atención en una solución para cinco discos, considérese el caso general de n discos. Supóngase que se tiene una solución para n – 1 discos y que en términos de ésta, se pueda plantear la solución para n – 1 discos. El problema se resolvería entonces. Esto sucede porque en el caso trivial de un disco (al restar 1 de n de manera sucesiva se producirá, al final, 1) la solución es simple: sólo hay
que el único disco del poste A a C. Así se habrá desarrollado una solución recursiva si se plantea una solución para n discos en términos de n – 1.
Considérese la posibilidad de encontrar tal relación. Para el caso de cinco discos en particular, supóngase que se conoce la forma de mover cuatro de ellos del poste A al otro, de acuerdo con las reglas. ¿Cómo puede completarse entonces el trabajo de mover el quinto disco? Cabe recordar que hay 3 postes disponibles.
Supóngase que se supo cómo mover cuatro discos del poste A al C. Entonces, se pondrá mover éstos exactamente igual hacia B usando el C como auxiliar. Esto da como resultado la situación los cuatro primeros discos en el poste B, el mayor en A y en C ninguno. Entonces podrá moverse el disco mayor de A a C y por último aplicarse de nuevo la solución recursiva para cuatro discos para moverlo de B a C, usando el poste A como auxilia. Por lo tanto, se puede establecer una solución recursiva de las torres de Hanoi como sigue:
Para mover n discos de A a C usando B como auxiliar:
1. Si n = = 1, mover el disco único de A a C y parar.
2. Mover el disco superior de A a B n – 1 veces, usando C como auxiliar.
3. Mover el disco restante de A a C.
4. Mover los disco n – 1 de B a C usando A como auxiliar
Con toda seguridad este algoritmo producirá una solución completa por cualquier valor de n. Si n = = , el paso 1 será la solución correcta. Si n = = 2, se
sabe entonces que hay una solución para n – 1 = = 1, de manera tal que los pasos 2 y 4 se ejecutaran en forma correcta. De manera análoga, cuando n = = 3 ya se
habrá producido una solución para n – 1 = = 2, por lo que los pasos 2 y 4 pueden ser ejecutados. De esta forma se puede mostrar que la solución funciona para n = = 1, 2, 3, 4, 5,... hasta el valor para el que se desee encontrar una solución.
Adviértase que la solución se desarrollo mediante la identificación de un caso trivial (n = = 1) y una solución para el caso general y complejo (n) en términos
de un caso mas simple (n – 1).
Ya se demostró que las transformaciones sucesivas de una simulación no recursivas de una rutina recursiva pueden conducir a un programa mas simple para resolver un problema. Ahora se simulara la recursión del problema y se intentara simplificar la simulación no recursiva.
towers (n, frompeg, topeg, auxpeg)
int n;
char auxpeg, frompeg, topeg;
{
/* si es solo un disco, mover y regresar */
if (n = = 1) {
printf (" /n%s%c%s%c%", "mover disco 1 del poste",frompeg, "al poste", topeg);
return; } /* fin del if*/
/* mover los n – 1 discos de arriba de A a B, usando como auxiliar */
towers (n – 1, frompeg, auxpeg, tpoeg);
/* move remaining disk from A to C */
printf ("/n%s%d%s%c%s%c%", "mover disco", n, "del poste" frompeg, "al poste", topeg);

/* mover n – 1 discos de B hacia C empleando a A como auxiliar */
towers (n – 1, auxpeg, topeg, frompeg);} /* fin de towers */
En esta función, hay cuatro parámetros, cada uno de los cuales esta sujeto a cambios en cada llamada recursiva. En consecuencia, el área de datos debe contener elementos que representen a los cuatro. No hay variables locales. Hay un solo valor temporal que se necesita para guardar el valor de n – 1, pero esta se puede representar por un valor temporal similar en el programa de simulación y no tiene que estar apilada. Hay tres puntos posibles a los que
regresa la función en varias llamadas: el programa de llamada y los dos puntos que siguen a las llamadas recursivas. Por lo tanto, se necesitan cuatro etiquetas.
start:
Label1:
Label2:
Label3:
La dirección de regreso se codifica como un entero (1, 2 o 3) dentro de cada área de datos.
Considérese la siguiente simulación no recursiva de towers:
struct dataarea {
int nparam;
char fromparam;
char toparam;
char auxparam;
short int retaddr;
};
struct stack {
int top struct dataarea item [MAXSTACK]; };
simtowers (m, frompeg, topeg, auxpeg)
int n;
char auspeg, frompeg, topeg; {
struct stack s;
struct dataarea currarea;
char temp;
short int i;
s.top = -1;
currarea.nparam = 0;
currarea.fromparam = ‘ ‘ ;
currarea.toparam = ‘ ‘ ;

currarea. auxparam = ‘ ‘ ;
currarea.retaddr = 0;
/* colocar en la pila un área de datos simulados */
push (&s, &currarea);
/* asignar parámetros y direcciones de regreso del área de datos actual a sus
valores apropiados */
currarea.nparam = n;
currarea,fromparam = frompeg;
currarea,toparam = topeg;
currarea.auxparam = auxpeg;
currarea.retaddr = 1;
start: /* Este es el inicio de la rutina simulada */
if (currarea.nparam = = 1) {
printf (" /n%s%c%s%c", "mover disco 1 del poste", currarea.fromparam, "al
poste", currarea.toparam) ;
i = currarea.retaddr;
pop (&s, &currarea);
switch (i) {
case 1: goto label1;
case 2: goto label2;
case 3: goto label3; } /* fin del switch */
} /* fin del if */
/* Esta es la primera llamada recursiva */
push (&s, &currarea);
-- currarea.nparam;
temp = currarea.auxparam;
currarea.auxparam = currarea.toparam;
currarea.toparam = temp;
currarea.retaddr = 2;
got start;
label2: /* se regresa a este punto desde la primera llamada recursiva */
printf ("/n%s%d%s%c%s%c", "mover disco", currarea.nparam, "del poste",
currarea.fromparam, "al poste", currarea.toparam);
/* Esta es la segunda llamada recursiva */
push (&s, &currarea);

--currarea.nparam;
temp = currarea.fromparam;
currarea.fromparam = currarea.auxparam;
currarea.auxparam = temp;
currarea.rtaddr = 3;
got start;
label3: /* se regresa a este punto desde la segunda llamada recursiva */
i = currarea.retaddr;
pop (&s, &currarea);
swicth (i) {
case 1: goto label1;
case 2: goto label2;
case 3: goto label3; } /* fin del switch */
label1: return;
} /* fin de simtowers */
Ahora se simplificará el programa. En primer lugar, debe observarse que se usan tres etiquetas para indicar direcciones de regreso; una para cada una de las dos llamadas recursivas y otra para el regreso al programa principal. Sin embargo, el regreso al programa principal puede señalarse por un subdesborde en la pila, de la misma for que en la segunda versión simfact. Esto deja dos etiquetas de regreso. Si pudiera eliminarse otra mas, sería innecesario guardar
en la pila la dirección de regreso, ya que solo restaría un punto al que se podría transferir el control si se eliminan los elementos de la pila con éxito. Ahora dirijamos nuestra atención a la segunda llamada recursiva y a la instrucción:
towers (n – 1, auxpeg, topeg, frompeg);
Las acciones que ocurren en la simulación de esta llamada son las siguientes:
1. Se coloca el área de datos vigente a 1 dentro de la pila.
2. En la nueva área de datos vigente a 2, se asignan los valores respectivos n
– 1, auxpeg, topeg, y frompeg a los parámetros.
3. En el área de datos vigente a 2, se fija la etiqueta de retorno a la dirección
de la instrucción que sigue de inmediato a la llamada.
4. Se salta hacia el principio de la rutina simulada.
5. Después de completar la rutina simulada, ésta queda lista parar regresar.
Las siguientes acciones se llevan a efecto:
6. Se salva la etiqueta de regreso, /, de área de datos vigentes a 2.
7. Se eliminan de la pila y se fija el área de datos vigente como el área de
datos eliminada de la pila, a 1.
8. Se transfiere el control a /.
Sin embrago, / es la etiqueta del final del bloque del programa ya que la segunda llamada a towers aparece en la última instrucción de la función. Por lo tanto, el siguiente paso es volver a eliminar elementos de la pila y regresar. No se volverá a hacer uso de la información del área de datos vigente a 1, ya que ésta es destruida en la eliminación de los elementos en la pila tan pronto como se vuelve a almacenar. Puesto que no hay razón para volver a usar esta área de
datos, tampoco hay razón para salvarla en la pila durante la simulación de la llamada. Los datos se deben salvar en la pila sólo si se van a usar otra vez. En
consecuencia, la seguida llamada a towers puede simularse en forma simple mediante:
1. El cambio de los parámetros en el área de datos vigente a sus valores respectivos.
2. El "salto" al principio de la rutina simulada.
Cuando la rutina simulada regresa puede hacerlo en forma directa a la rutina que llamó a la versión vigente. No hay razón para ejecutar un regreso a la versión vigente, sólo para regresar de inmediato a la versión previa. Por lo tanto, se elimina la necesidad de guardar en la pila la dirección de regreso al simular la llamada externa (ya que se puede señalar mediante subdesborde y simular la segunda llamada recursiva, ya que no hay necesidad de salvar y volver a almacenar al área de datos de la rutina que llamada en este momento). La única dirección de regreso que resta es la que sigue a la primera llamada recursiva.
Ya que sólo queda una dirección de regreso posible, no tiene caso guardarla en la pila para que se vuelva a insertar y eliminar con el resto de los datos. Siempre
se eliminan elementos de la pila con éxito, hay una solo dirección hacia la que se puede ejecutar un "salto" (la instrucción que sigue a la primera llamada). Como los nuevos valores de las variables del área de datos vigente se obtendrán a partir de los datos antiguos de área de datos vigente, es necesario declarar una variable adicional, temp, de manera que los valores sean intercambiables.

7.2.- El Problema de las Ocho Reinas:
El problema de las ocho reinas y en general de las N reinas, se basa en colocar 8 reinas en un tablero de 8´ 8 (o N en un tablero de NxN, si el problema se generaliza), de forma que en no puede haber dos piezas en la misma línea horizontal, vertical o diagonal, ver Figura 1.
Para ver el gráfico seleccione la opción "Descargar" del menú superior Figura 1 Posible solución para el problema de las ocho reinas Este programa has sido muy estudiado por los matemáticos. Se trata de un problema NP-Completo que no tiene solución para N=2 y N=3. Para N=4 tiene
una única solución. Para N=8 hay más de 80 soluciones dependiendo de las restricciones que se impongan.
Una forma de abordar el problema se lleva a cabo mediante la construcción de un predicado en Prolog del tipo siguiente: reinas (N, Solución), donde N representa las dimensiones del tablero y el número de reinas y Solución es una lista que contiene la permutación de la lista de números que resuelven el problema. Los índices de dicha lista representan la columna en la que se encuentra una reina y el número que almacena la posición o índice representa la
fila donde la reina está colocada. Así, para el ejemplo mostrado en la Figura 1, tenemos que R=[2,4,1,3].

Este problema es resuelto, de modo clásico, por el método de prueba y error, luego se adapta perfectamente a un algoritmo de backtracking. Básicamente, el problema se reduce a colocar una reina, e intentar repetir el proceso teniendo en cuenta la reina colocada. Si logramos poner todas las reinas el problema se ha resuelto, en caso contrario, deshacemos lo que llevamos hasta ahora y probamos con otra combinación. Por tanto, hemos de generar un conjunto de
permutaciones y seleccionar aquella que cumpla los requisitos impuestos por el juego.
Veamos el código que resuelve el problema:
rango(N, N, [N]).
rango(N, M, [N|Cola]):-N

Árbol de ejecución para el objetivo reina(4,Solucion)
He aquí otro ejemplo sobre el problema de las ocho reinas. Primero se mostrara un pseudocodigo sobre el mismo y luego su respectiva codificación en el lenguaje C.
(i: entero)
inicializar el conjunto de posiciones de la reina i-ésima
+-REPETIR hacer la selección siguiente
| +-SI segura ENTONCES
| | poner reina
| | +-SI i <>
Observaciones sobre el código:
1) Estudiar la función ensayar() a partir de este pseudocódigo.
2) Vectores utilizados:
int posiciones_en_columna[8]; RANGO: 1..8
BOOLEAN reina_en_fila[8]; RANGO: 1..8
BOOLEAN reina_en_diagonal_normal[15]; RANGO: -7..7
BOOLEAN reina_en_diagonal_inversa[15]; RANGO: 2..16
En C, el primer elemento de cada vector tiene índice 0, esto es fácil solucionarlo con las siguientes macros:
#define c(i) posiciones_en_columna[(i)-1]
#define f(i) reina_en_fila[(i)-1]
#define dn(i) reina_en_diagonal_normal[(i)+7]
#define di(i) reina_en_diagonal_inversa[(i)-2]
Significado de los vectores:
c(i) : la posición de la reina en la columna i
f(j) : indicativo de que no hay reina en la fila j-ésima
dn(k): indicativo de que no hay reina en la diagonal normal
(\) k-ésima
di(k): indicativo de que no hay reina en la diagonal
invertida (/) k-ésima
Dado que se sabe, por las reglas del ajedrez, que una reina actúa sobre todas las piezas situadas en la misma columna, fila o diagonal del tablero se deduce que cada columna puede contener una y sólo una reina, y que la elección de la situación de la reina i-ésima puede restringirse a los cuadros de la columna i.
Por tanto, el parámetro i se convierte en el índice de columna, y por ello el proceso de selección de posiciones queda limitado a los ocho posibles valores del índice de fila j.
A partir de estos datos, la línea poner reina del pseudocódigo es:
c (i) = j; f (j) = di (i + j) = dn (i - j) = FALSE;
y la línea quitar reina del pseudocódigo:
f (j) = di (i + j) = dn (i - j) = TRUE;
y la condición segura del pseudocódigo:
f (i) && di (i + j) && dn (i - j)
/* Ficheros a incluir: */
#include /* printf () */
#include /* getch () */
/* Macros: */
#define BOOLEAN int
#define TRUE 1
#define FALSE 0
/* Variables globales: */
BOOLEAN acertado;
int posiciones_en_columna[8];
BOOLEAN reina_en_fila[8];

BOOLEAN reina_en_diagonal_normal[15];
BOOLEAN reina_en_diagonal_inversa[15];
#define c(i) posiciones_en_columna[(i)-1]
/* rango de índice: 1..8 */
#define f(i) reina_en_fila[(i)-1]
/* rango de índice: 1..8 */
#define dn(i) reina_en_diagonal_normal[(i)+7]
/* rango de índice: -7..7 */
#define di(i) reina_en_diagonal_inversa[(i)-2]
/* rango de índice: 2..16 */
/* Prototipos de las funciones: */
void proceso (void);
void ensayar (int i);
/* Definiciones de las funciones: */
void main (void)
{
printf ("\n\nPROBLEMA DE LAS OCHO REINAS:\n ");
proceso ();
printf ("\n\nPulsa cualquier tecla para finalizar. ");
getch ();
}
void proceso (void)
{
register int i,j;
for (i = 1; i <= 8; i++) f (i) = TRUE; for (i = 2; i <= 16; i++) di (i) = TRUE; for (i = -7; i <= 7; i++) dn (i) = TRUE; ensayar (1); if (acertado) for (printf ("\n\nLA SOLUCION ES:\n\n"), i = 1; i <= 8; i++) {

or (j = 1; j <= 8; j++) printf ("%2d", c (j) == i ? 1 : 0); printf ("\n"); } else printf ("\n\nNO HAY SOLUCION.\n"); } void ensayar (int i) { int j = 0; do { j++; acertado = FALSE; if (f (j) && di (i + j) && dn (i - j)) { c (i) = j; f (j) = di (i + j) = dn (i - j) = FALSE; if (i < 8) { ensayar (i + 1); if (! acertado) f (j) = di (i + j) = dn (i - j) = TRUE; } else acertado = TRUE; } } while (! acertado && j !j 8); }

CONCLUSIÓN
Se puede decir que la recursividad es una técnica de programación bastante útil y muy interesante de estudiar. A través de los ejemplos que el individuo pueda revisar, aprenderá con más rapidez y sencillez lo que es programar recursivamente e incluir esta técnica cuando se le presente un problema como los que fueron mencionados anteriormente. La asignación de memoria, sea estática o dinámica, en realidad se tendrá que aplicar en cualquier programa al momento de su codificación; tomando en cuenta que cada programador tiene su estilo de programar. El ejemplo de las torres de Hanoi tanto como el ejemplo de las ocho reinas son problemas claves que tienen que ver directamente con lo que es la recursividad.