KDE 4.4 SC released.
A new big release of KDE Software Compilation has been made. Thanks to everybody involved in KDE for making this happen.and give us great software.
In case you don’t have it installed watch the videos in Youtube..
QGraphicsView
Una introducción a QGraphicsView, ampliamente usado en aplicaciones Qt.
QGraphicsView es el framework dentro de Qt que permite la creación e interacción de elementos gráficos 2D y que usa el método de programación modelo/vista.
De manera simple, varias vistas pueden observar una misma escena y una escena puede contener elementos (items) de diferentes formas geométricas.
El framework está compuesto de 3 elementos:
- QGraphicsScene (La Escena): Representa una escena con items. Es la clase que se encarga de almacenar los widgets, así como manejar propagar eventos a cada item.
Además esta clase se encarga de manejar los estados de un item. Un objeto QGraphicsScene es muy flexible como para incluir cualquier número de objetos QGraphicsItem.
- QGraphicsView (La Vista): La clase que se encarga de proporcionar los widgets que visualizan el contenido de una escena.
La vista recibe eventos de entrada del teclado/mouse, y los traslada a la escena.
- QGraphicsItem (El Item): Representa un grupo de items. Es una clase para el manejo de items gráficos en la escena y proporciona varios items estándar para formas típicas como rectángulos, elipses y textos. También soporta eventos del mouse como mover, soltar, presionar, doble click, sobre y eventos del teclado.
QGraphicsItem, además soporta dos características importantes en elementos gráficos: Drag and Drop (Soltar y arrastrar) y collision detection.
Cada objeto QGraphicsItem en la escena soporta rotación, zooming, traslado y el poder cortarlo.
Hagamos un ejemplo sencillo de como crear un escena, un item y como visualizarlos:
// Incluimos las clases de la escena, vista y el tipo de item
#include <QtGui/QApplication>
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QGraphicsView>
int main( int argc, char **argv )
{
QApplication app(argc, argv);
// Iniciamos la escena y definimos su tamaño
QGraphicsScene scene;
scene.setSceneRect(-100, -100, 200, 200);
// Color y estilo
scene.setForegroundBrush(QBrush(Qt::lightGray, Qt::CrossPattern));
// Creamos y agregamos nuestro item (rectángulo) a la escena
QGraphicsRectItem *item = new QGraphicsRectItem( 0, &scene );
// izquierda, arriba, ancho y alto
item->setRect(-60, -30, 140, 60);
// Línea: Ancho y estilo
item->setPen(QPen(Qt::blue,4,Qt::SolidLine));
// Relleno: Color y estilo.
item->setBrush(QBrush(Qt::green,Qt::SolidPattern));
// Creamos una vista para visualizar la escena
QGraphicsView view( &scene );
view.setRenderHints( QPainter::Antialiasing );
view.show();
return app.exec();
}
Y el resultado:
Como ser desarrollador de KDE
Bueno ya que hace poco empecé a involucrarme en el desarrollo de KDE y ya me está yendo bien, quisiera compartir con los programadores latinos, gente de Perú e interesados en general, cómo es el proceso para convertirse en desarrollador de KDE.
Es importante aclarar que estoy en camino de ser desarrollador de KDE, simplemente deseo trasmitir mi experiencia y lo aprendido hasta el momento. Cualquier mejora o aporte a esta guía es bienvenido.
Hay distintos caminos para llegar a este objetivo, y es más, hay gente que ha escrito al respecto como:
The Road to KDE Devland (6 series)
The Road to KDE and Qt Development
y de la web oficial:
Hay muchas cosas en común en esos caminos y básicamente la idea es la misma.
He tratado de ser lo más breve posible y decidido escribir mi pequeña guía “Como ser desarrollador de KDE” en español, pues se que, como yo alguna vez, hay muchos hispano hablantes que desean contribuir a KDE y no tienen alguna idea de cómo empezar. Espero profundizar y continuar esta guía más adelante.
Ojo, hay muchas maneras de contribuir a kDE como arte, documentación, traducción, promoción, reportando fallos, etc. Ahora me voy a enfocar sólo en el desarrollo, ahí vamos:
Cómo ser desarrollador de KDE
Contribuir con el desarrollo de KDE, es uno de los aportes principales a la comunidad y al proyecto. Es una experiencia enriquecedora que te va a permitir compartir, extender tus conocimientos y aprender a trabajar en equipo.
Si eres un estudiante o profesional de la computación, te gusta la programación y el desarrollo de software, deseas participar en proyectos reales y pertenecer a una comunidad internacional de desarrolladores y gente creativa, si es así, entonces estás en el sitio correcto.
Para ser un desarrollador de KDE necesitas aprender lo siguiente:
Está demás decir que debes de tener un nivel aceptable de Inglés, pues la comunicación se realiza en este idioma.
C++
C++ es un potente lenguaje de programación orientado a objetos, diseñado para muchos propósitos, muy usado en la computación gráfica y desarrollo de juegos.
KDE está mayormente escrito en C++. Entonces si no sabes C++, tienes que aprenderlo. Hay muchos libros y excelentes recursos en internet sobre C++. Un gran libro es “Pensando en C++” de Bruce Eckel que también está disponible como libre descarga en castellano. Es imprescindible que aprendas todos los fundamentos de C++ antes que empieces con KDE.
Qt
Para ser un desarrollador de KDE, debes aprender Qt. Qt es una biblioteca multiplataforma escrita en C++ para desarrollar aplicaciones gráficas y también para desarrollar programas sin interfaz gráfica como herramientas de consola y servidores.
Si no estás familiarizado con Qt, puedes ver la documentación oficial de Qt y desarrollar los tutoriales incluidos ahí.
Si prefieres aprender Qt mediante la lectura de un libro tradicional, mira la página de libros acerca de Qt. Algo importantísimo es que aprendas el concepto y la aplicación de Signals and Slots, es fundamental en todas las aplicaciones construidas con Qt.. Básicamente, es un mecanismo de comunicación entre objetos.
KDE
Un punto de partida para empezar a desarrollar en KDE son los tutoriales del sitio oficial. Lo primero que debes revisar es la sección Introducción a la programación en KDE4.. Empiezas con un Hola Mundo, luego a crear ventanas, después añadir acciones, barras, menús y así vas desarrollando paso a paso.
También encontrarás información útil sobre el desarrollo de KDE en la sección de Preguntas Frecuentes.
Otro recurso valioso para desarrollar es la API (Interfaz de programación de aplicaciones) de KDE. Allí encontrarás excelente documentación de clases, métodos y funciones de las librerías y aplicaciones de KDE.
Después que tengas una base de conocimientos en C++, QT y KDE, entonces ya puedes empezar a desarrollar para KDE, pero antes necesitas aprender lo siguiente:
- Cómo obtener el código de KDE4 con subversion.
- Cómo compilar la versión de desarrollo de KDE4.
- Cómo configurar KDE4 para el desarrollo.
- Entender la arquitectura de KDE4.
- Seguir el estilo de código de las librerías de KDE.
Una vez que hayas compilado la última versión en desarrollo, configurado tu ambiente de desarrollo y realizado tus primeros tutoriales de programación en KDE, quiere decir que ya estás preparado para dar los primeros pasos.
Tienes que tener paciencia, automotivarte y sentir pasión por lo que haces. La comunidad KDE es sensacional y el software que produce es de alta calidad. No todo cae de la noche a la mañana, entonces con trabajo constante, poco a poco verás los frutos de tu esfuerzo.
Bueno, entonces llegó la hora que empieces a escribir código para algún proyecto dentro de KDE. Claro que puedes desarrollar tu propia aplicación, pero se recomienda que antes intentes involucrarte con uno ya existente para que entiendas mejor como funcionan las cosas internamente, aprendas del código de otros, veas como es la organización y el trabajo en equipo.
Puedes ver todo el código de KDE directamente desde el navegador en WebSVN para que explores las aplicaciones y/o librerías que forman parte de KDE.
Puedes descargarte el código de una aplicación/librería con el usuario anónimo de subversion. Obviamente haz tenido que instalar antes subversion. Por ejemplo, con el siguiente comando me descargo kdelibs, que son las librerías básicas de KDE.
svn co svn://anonsvn.kde.org/home/kde/trunk/KDE/kdelibs
Una breve explicación de los directorios y subdirectorios principales:
Branches: Es donde están las distintas versiones de KDE, incluyendo lo que será la próxima revisión de la versión actual de KDE.
Trunk: Es donde se lleva a cabo el desarrollo de la rama principal de KDE, es decir, lo que será la próxima versión de KDE.
-KDE
——kdelibs: Librerías críticas de KDE.
——kdebase: Dividido en 3 partes.
———apps: Aplicaciones que forman parte de la distribución principal de KDE como Dolphin, Kate, Konqueror.
———runtime: Cosas necesarias para todas las aplicaciones KDE en tiempo de ejecución y una dependencia requerida.
———workspace: Cosas específicas de KDE, como Plasma o el gestor de ventanas.
——kdeartwork: Trabajo artístico, diseño gráfico, íconos, sonidos, temas, fondos de pantalla.
——kdeedu: Aplicaciones educativas.
——kdegames: Juegos.
——kdegraphics: Aplicaciones gráficas.
——kdemultimedia: Reproductores de audio y video.
——kdepim: Aplicaciones de manejo de información personal.
——kdepimlibs: Librerías usadas por las aplicaciones kdepim
——kdeplasma-addons: Aplicaciones, tecnologías de Plasma como applets, dataengines, runners.
——kdeutils: Utilitarios para KDE.
——kdewebdev: Aplicaciones para desarrollo web.
-extragear: Aplicaciones que usan las librerías y estásn relacionadas con KDE, pero no forman parte de la distribución principal de KDE.
-koffice: Suite Ofimática de KDE. Tienen sus propias fechas de liberaciones.
-playground: Aplicaciones en estado alpha. Pueden compilar, pero carecen de estabilidad, robustez, internacionalización, usabilidad, arte, en fin, no están maduras para el usuario final.
-kdereview: Cuando una aplicación de playground alcanza cierta madurez y estabilidad, se mueve a kdereview para darle los toques finales y sea revisada profundamente por los desarrolladores para que alcanze un nivel óptimo. Después de kdereview pasan a formar parte de la rama principal de KDE.
-kdesupport: Librerías/software necesario para compilar KDE.
-l10n-kde4: Archivos de traducción de KDE a muchos idiomas.
-www: Aquí se encuentran los archivos, imágenes que pertenecen a las páginas web de KDE.
Elige una aplicación de tu agrado que te gustaría hacerle algún cambio, agregarle una nueva funcionalidad.
Normalmente los desarrolladores dentro del directorio de su proyecto tienen un archivo llamado TODO, donde está la lista de tareas por hacer, un README con la descripción de la aplicación y un archivo HACKING que explica los lineamientos para desarrollar en ese proyecto.
Aparte de agregar una característica a una aplicación, también puedes corregir un fallo. Los fallos se reportan en el Sistema de búsqueda de fallos de KDE, llamado bugs.kde.org.
Desde bugs.kde.org puedes filtrar los fallos existentes en la aplicación que escogiste y ver cuales aún no están resueltos. Escoge uno y trata de resolverlo.
Otra opción para empezar con el desarrollo en KDE, es realizar algún Junior Job, (Tarea o trabajo pequeño). Los Juniors Job son trabajos muy sencillos que necesitan realizarse en las aplicaciones. Normalmente los desarrolladores suben Juniors Jobs a bugs.kde.org para obtener nuevas contribuciones e involucrar a la gente recién iniciada en el desarrollo de KDE. Puedes ver la lista de Junios Jobs aquí.
Sea que haz corregido un fallo, haz agregado una nueva característica, funcionalidad o haz hecho un Junior Job, debes de enviarles tus cambios al desarrollador(es). O mejor dicho, tienes que enviar tus parches.
Un parche consta de cambios que se aplican a un programa, para corregir errores, agregarle funcionalidad, actualizarlo, etc.
La mayoría de proyectos en KDE usan un sistema web llamado Review Board que permite manejar los parches de manera mucho más eficiente. Te registras y envias tu(s) parche(s) a la aplicación que escogiste.
En caso, la aplicación que estás modificando no use Review Board, tienes que enviar tus parches por email al desarrollador o a la lista de correo del proyecto. Debes de enviar tus archivos en un formato que el desarrollador vea los cambios que haz realizado de manera rápida. Para ello existen dos comandos Unix/Linux que te van a ser muy útiles: diff y patch.
Un ejemplo sencillo, imagina que tienes 2 archivos (original.cpp y nuevo.cpp), deseas ver la diferencia entre ambos y generar otro archivo. El comando sería:
diff -u original.cpp nuevo.cpp > miparche.patch
Enviándole el archivo miparche.patch al desarrollador le haces la vida más facil porque puede ver y aplicar tus cambios rápidamente. No importa el tamaño de tu parche, así solucione algo pequeño, pero útil será bienvenido, de lo contrario será rechazado por diversas razones. Entre ellas que quizá no sigues los estándares del código de la aplicación, no resuelves el problema o te faltan pequeños detalles que corregir. Si hay algún problema con tu parche, el desarrollador te lo hará saber y te dirá que le falta para que sea aplicable.
No tengas miedo, los desarrolladores de KDE, son seres humanos y muy buenas personas que muestran mucho respeto por el trabajo de otros y están dispuestos a ayudarte a resolver problemas o guiarte con la solución.
Pero, sea cual sea la respuesta del desarrollador, igualmente muestra respeto y sigue investigando cómo puedes mejorar.
Hay maneras y maneras de decir las cosas. Por eso, es importantísimo que sigas el Código de Conducta de la comunidad KDE.
Bien ya enviaste tus cambios, fueron aceptados, ya te sientes parte de la comunidad y crees que haz cambiado el mundo.
Ahora tienes que solicitar una cuenta subversion en KDE (KDE SVN account). Subversion es el sistema de control de versiones con el cúal trabaja actualmente KDE, posteriormente se cambiará a Git.
Cualquiera que ya haya hecho algún trabajo en KDE puede aplicar a una cuenta svn. Con una cuenta svn podrás aplicar los cambios tú mismo al proyecto, en vez de estar enviando parches y quitarle tiempo a los desarrolladores.
Lee esta guía de como solicitar una cuenta svn. Si tu solicitud fue aceptada, entonces lo siguientes es leer Los primeros pasos con tu cuenta KDE svn.
Una vez que tengas tu cuenta svn y haz leído lo primero que debes de hacer con ella, bien ya puedes trabajar directamente en el proyecto con subversion.
Para descargarte el código de un proyecto y tener una copia local del mismo (checkout), ssh es lo más óptimo:
svn co svn+ssh://tuusuario@svn.kde.org/home/kde/ruta/a/la/aplicacion
En mi caso cuando descargué el juego que empecé a modificar:
svn co svn+ssh://ronnyy@svn.kde.org/home/kde/trunk/playground/games/pege/
Ahora, ingresa al directorio del proyecto que te bajaste:
cd proyecto_kde
Para ver el estado del proyecto, los archivos que han sido agregados, modificados, eliminados:
svn status
Realiza tus cambios y haz tu primer commit:
svn ci -m “My new feature / Fixed bug description.”
Para ver todos los cambios que hiciste dentro de un directorio y generar un archivo .diff
svn diff –diff-cmd diff -x -uw > ~/patch.diff
Para estar al día y actualizado con los últimos cambios que se hicieron al código.
svn up
Son algunos comandos básicos de subversion, puedes encontrar muchos tutoriales y how-tos en la web donde encontrarás mucha más información.
Finalmente, si haces commits a menudo, participas activamente y das un aporte significativo a algún proyecto, la comunidad te tratará como un desarrollador de KDE, si eso pasa, ya podrás llamarte desarrollador de KDE.
Como ves, ser desarrollador de KDE es un proceso que toma su tiempo. Seguramente en el camino encontrarás obstáculos y te estancarás en alguna parte, pero depende de ti poder superar esas barreras.
Contribuir a KDE te va a dar un prestigio y elevar tu karma en la comunidad Open Source/Software Libre. A la larga, todo esto te dará muchos beneficios sociales, técnicos y probablemente puede cambiar tu vida.
Diviértete, comunica, comparte, aprende, enseña y todo se hará más fácil.
Sitio principal para desarrolladores de KDE
http://techbase.kde.org/Development_(es)
Lista de correo
Si estás interesado en el desarrollo de KDE, estás creando tu propia aplicación y quieres hablar con alguien que hace o está interesado en el desarrollo de KDE en general.
Visita: https://mail.kde.org/mailman/listinfo/kde-devel y subscríbete a la lista.
Canal IRC
#kde-devel en irc.freenode.net
Otros lenguajes de programación
Si te gustaría desarrollar para KDE en otros lenguajes de programación, también tienes otras alternativas.
KDE Y Qt disponen de una serie de bindings y tecnologías para diversos lenguajes de programación, entre los principales tenemos a Python, Ruby y Javascript:
Python
Ruby
Javascript
KDE se cambia a Git
Como muchos otros proyectos Open Source, (Kernel Linux, Perl, Ruby on Rails, Wine, X.org, Android, VLC, FreeBSD, OpenSuse…) KDE ha iniciado el cambio de sistema de control de versiones de Subversion a Git.
En subversion, que es un sistema centralizado, todos los desarrolladores de determinado proyecto deben de conectarse a un servidor central y los cambios que se realizan afectan a todos. Otro de las desventajas de un sistema centralizado es que muchos contribuyentes o personas que desean contribuir tienen muchas limitaciones de escritura debido a las políticas de acceso. Pero claro Subversion se ajusta a algunos tipos de proyectos y también tiene sus ventajas.
Por el contrario, Git es un sistema de control de versiones distribuido, es decir, que no depende de un repositorio central. Git permite administrar varios tipos de proyectos, especialmente de gran envergadura, de manera rápida y eficiente.
Una de las ventajas de Git, es que abre las puertas a más contribuyentes. Tú puedes tener tu propia rama dentro del proyecto, experimentar, realizar cambios sin afectar a los demás y cuando pienses que tu código es estable y funcional puedes fusionar tus cambios con otra rama.
Git tiene otras características cool, entre ellas, que puedes realizar ciertas cosas estando desconectado de la red.
Probablemente este va a ser un cambio impactante en la comunidad, debido al tamaño de KDE y el número de aplicaciones/desarrolladores/contribuyentes. Pero ya existen proyectos de KDE que han migrado exitósamente a Git como Amarok, Phonon, Konversation y Gluon.
Todo el código de las librerías y aplicaciones de KDE, van a ser movidos a Gitorious, excepto los archivos de traducción y documentación.
Gitorious es un servicio para alojar proyectos Open Source, donde también está alejado Qt y existe una buena relación/comunicación con desarrolladores de Qt en Nokia.
Aaron Seigo, KDE Hacker, explica , más a fondo, en su blog los motivos del cambio.
Si tienes conocimientos en git, esta una gran oportunidad para contribuir a KDE y unirte al KDE Git Team. Entra al canal #kde-git en Freenode.
¿Cómo aprender Git?
Hay mucha información, tutoriales y libros en la web. Yo te recomiendo Git Magic de Ben Lynn empleado de Google.
Gracias a esta guía, tengo una base en Git. Está todo muy bien explicado con palabras sencillas, directo al grano y con todo lo que necesias para empezar a usar Git.
Git en la web de KDE
KDE Latinoamérica
No tuve mucho tiempo de postear estas últimas semanas, pero más vale tarde que nunca.
El día 10 de noviembre de 2009 tuve la suerte de asistir a la reunión de comunidades de KDE en latinoamérica, canal #kde-cl en freenode, gracias a la invitación de Christian González de la comunidad KDE Chile. Christian ha escrito una carta dirigida a todas las comunidades de KDE en Lationamérica y España donde resume los puntos tratados en la reunión.
Transcribo la carta para que más personas puedan unirse a esta iniciativa:
Carta abierta a las comunidades de KDE de Latinoamérica y España
El día martes 10 de noviembre de 2009 se efectuó la segunda reunión por IRC [1] de la recientemente formada comunidad KDE Chile, en la cual participaron representantes de varias comunidades latinoamericanas. En dicha reunión se planteó la posibilidad de aunar esfuerzos en pos de construir una comunidad KDE Latinoamérica-España, potenciando así la difusión y el apoyo al proyecto KDE en nuestros países y evitando la duplicación de esfuerzos.
Después de una larga discusión, los representantes de las distintas comunidades establecieron los siguientes acuerdos:
- Cada comunidad individual seguirá teniendo plena autonomía para trabajar en sus proyectos locales, así como para administrar sus propios portales web. Se propone tener una plantilla genérica que pueda ser usada por las comunidades que así lo deseen.
- Se solicitará la creación de un subforo en idioma español dentro del foro oficial de KDE (disponible en http://forum.kde.org), en el cual puedan participar todos los miembros de las distintas comunidades respondiendo consultas técnicas de los usuarios de habla hispana. Se evaluará la posibilidad de tener una sección por cada país para temas como organización, política interna, actividades locales, etc.
- Se apoyarán los esfuerzos de documentación de KDE (especialmente las traducciones) en los wikis oficiales del proyecto: http://techbase.kde.org (para desarrolladores) y http://userbase.kde.org (para usuarios).
- Se creará un “Planeta KDE en español” que agrupe los blogs personales de los miembros de las distintas comunidades.
- Se decidió crear el canal IRC #kde-latam en el servidor Freenode (irc.freenode.org:6667) como un lugar de coordinación transversal para las distintas comunidades.
Para lograr estos objetivos, se ha establecido contacto con Helio Chissini de Castro, contacto oficial de KDE para Latinoamérica. Estamos bastante confiados en que su intermediación será de mucho provecho para lograr los objetivos antes mencionados.
Por todo lo anterior, queremos extender esta invitación a todas las comunidades de KDE en España y Latinoamérica. Si están interesados en participar de esta iniciativa, por favor publiquen esta carta en los medios de comunicación de su comunidad (portal web, lista de correo, etc.) y envíen un aviso a la lista de correos de KDE Chile (http://www.kde.cl/group), o comuníquense a través del canal IRC #kde-latam.
Esperamos que más comunidades puedan unirse y podamos difundir y apoyar al proyecto KDE en nuestros países.
Desde Perú, nos unimos a esta iniciativa de agrupar a las todas las comunidades de KDE en Lationamérica y España.
Se ha creado hace poco la lista oficial kde-latam, así que se invita a usuarios y desarrolladores de KDE para que participen.
My KDE life started
KDE is the community and the Open Source/Free Software project that I always wanted to be part of. I am a KDE user for about 3 years and enjoy using KDE applications everyday. I use Kate for web development, can’t live without Amarok, Dolphin, Kaffeine, digiKam, Kopete, Konversation and Konsole obviously.
Unfortunately, I haven’t had enough time to contribute to KDE in a real way due to other responsibilities. I just blogged a little about KDE, shared Kubuntu and OpenSuse CDs with some friends and adapted a small script to add Peruvian radios in Amarok. No more.
But, I am following the KDE development since the 4.0 times reading the dot.kde.org and planet.kde.org and all articles around the web about KDE development. I think is time to give KDE a real contribution. Why?
Simple, I love the KDE community. These people have fun creating things and software, really smart, creative, friendly and with great passion for what they do. That is really encouraging for me.
In my case, I want to develop and promote KDE. I think is better to start contributing to an existing project to see how all this works, have a good understanding of the KDE platform and then write your own application.
I have some knowledge of C++, learned the principles of QT and checked the KDE examples at Techbase. Also, I set up my KDE development environment. So, I felt ready to start and took a look at many KDE apps/projects and see where I can get involved. Finally, I decided to start with KDE games. I enjoy playing KSudoku, Palapelli and KPat. (Didn’t try the others yet).
Well, I picked up a game from playground called Peg-E, an implementation of the game Peg solitaire (also known as Hi-Q). The game consists of jumping over pieces in order to remove them from the board. The goal is to remove all pegs but one. Peg solitaire at Wikipedia:
Playground is the section in the KDE source code repository where live KDE applications in alpha version. Many of those applications compile, but they lack of stability, international support, artwork and are not ready to use for the masses.
This game was abandoned for about 8 months. I compiled, become addicted and started hacking on it. I had to study libkdegames which is a library used for games in KDE. The first thing I did was to add difficulty levels, a timer, highscores and follow the KDE coding style. After that, I sent the patches to the developer (Graeme Gott) and requested him the maintainership of the game. The developer answered me that KDE is not a good fit for him, and accepted me to be the maintainer (Thanks a lot Graeme), but I have to change the name of the game because he has a pure QT version called Peg-E and users can be confused. The game name probably will be KPeg.
Then, I applied for my KDE svn account attaching the patches and happily, after some hours, my svn account was created and I made my first commit. Now, if everything goes fine this game will be part of KDE games for the KDE SC 4.5 release. I’ll work hard on it and sure I’ll learn much more about programming and games development.
I am impressed about the interesting algorithms and math behind the Peg Solitaire. That’s why I choose it. The game looks relatively simple, but it is very difficult to leave only one peg. There are many competitions around the world and papers about how fast and efficient you can be to solve a Peg solitaire. Well, I created my TODO list and currently reading some technical articles about the game.
That’s how my KDE life started and now I am happy of being part of the KDE community. Of course, I will write all my progress about the development of the game and my new adventures in the KDE devland.
Wait, wait, wait I forgot to tell you something. There is another KDE user in my family: Celeste, my daughter. I showed her the game KTurbeling and she loved it. I promised her to write a Lazy Town theme. She is a real fan and crazy about that program.
I am preparing more posts about KDE and have a surprise for you: Peruvian KDE users/developers.
So, Stay tuned.
La Última Lección de Randy Pausch
Ayer fue uno de esos días duros que uno tiene, fue el día más triste y doloroso de mi vida, estaba completamente destrozado, desmotivado y con una depresión inmensa por ciertas situaciones.
Derramé muchas lágrimas (Sí también los programadores tienen emociones), pero lo bueno es que tuve la compañía de mi hija en todo momento, estuvo a mi lado y me decía no llores papito, sentí todo su amor y su cariño. Igual necesitaba algo más como comprenderán.
Hasta que encontré el video de La Última Lección (Last Lecture) que dio Randy Pausch meses antes de morir de cáncer al páncreas. Simplemente despuès de ver el video completo me sentí mejor por lo educativo, divertido, inspirador y motivante que es. Esta es una lección de humanidad que la voy a compartir con mis amigos y familia. Después de ver el video me descargué el libro entero sobre su última lección, donde cuenta detalles que no dijo en el auditorio.
Simplemente brillante. En mi opinión Randy es un genio de la manera como transmitir emociones y sabiduría.
Randy no necesita presentación, fue un profesor y gran científico de la Ciencia de la computación y más que eso un ejemplo para millones de personas en el mundo. Hay miles de artículos y homenajes hacia el y bastante información sobre su vida en la web, así que prefiero no hablar mucho de su vida, mas si sobre su libro.
Una de las cosas que me impactó del libro es la manera como Randy sabiendo que iba a morir, tenía tanto sentido del humor para hablar acerca de la vida y además la manera como expresa cada una de sus historias.
Este libro, es sin duda, uno de los mejores que he leìdo y que dejaron huella en mi vida. Considero que hay mucho, mucho de que aprender de Randy y es un must-have en la cabecera de tu cama, en tu escritorio o en tu oficina.
Hay 2 capítulos que me marcaron:
Cumple tus sueños de la infancia.. Aquí Randy explica todos los sueños que tuvo de niño y como los fue cumpliendo todos. Sumamente entretenida la historia.
Uno de esos sueños y con el que me identifico es como llegó a ser un creativo de Disney y todo lo que luchó para llegar ahí y que lo resume muy bien en dos palabras: Trabajo duro. Claro que mi sueño no es exactamene igual al de Randy, pero si estoy luchando duro para llegar a un lugar que para mí es el trabajo con el que siempre he soñado.
Y el otro sueño que me hizo reír y acordar de mi infancia es “Ganar animales de peluche”, me acuerdo como jugaba y de la manera como lo hacía con tanta pasión para llevarle un peluche a mi madre y hermanita. Nunca me olvidaré esos sueños de niño. Simplemente sensacional este capítulo, me di cuenta lo importante que es siempre llevar ese niño adentro, para no dejar de soñar y usar la imaginación.
El otro capìtulo que nunca olvidaré:
La cuestión es como vivir tu vida está llena de emociones y lecciones de Randy. Aún seguía con un vacío inmenso y después de leer este capìtulo, me sentí mas reconfortado, fue cuando realmente desperté y me di cuenta que tenía una vida por delante, que debo vivir cada segundo como si fuera el último y no debo perder el optimismo y emplear mi tiempo correctamente.
Y sobre todo lo que aprendí de “La cuestión es como vivir tu vida” es que leí una frase que a partir de ahora estará en mi vida para siempre:
«Los muros existen por alguna razón. No están para dejarnos afuera, sino para darnos la oportunidad de mostrar hasta qué punto deseamos algo. Están para detener a los que no lo desean lo suficiente.»
Si así es la vida, la cuestión es como vivir tu vida y tú decides si quieres vivir quejándote de la vida, de tu suerte y de tu entorno o si quieres vivir con alegrìa, con pasíón, con humildad y ver siempre el lado bueno de las personas.
No se como agradecerle a Randy por todo lo que sus enseñanzas me dejaron y sobre todo por ayudarme en este momento tan difícil en mi vida. Se que cumpliendo mis sueños el estaría conforme, pero he decidido darle un pequeño homenaje: Voy a hacer feliz, muy feliz a las personas que tanto amo, como lo hizo Randy. Voy a trabajar y ser constante para llegar lejos. Y el día que llegue donde me he trazado, ese día, Randy va a estar en la lista de invitados a la celebración y va a recibir un reconocimiento especial.
Randy, estés donde estés, gracias eternamente.
Disfruten aquí el video en Inglés,prefiero verlo así para aprende más, pero también lo pueden encontrar en partes con subtítulos en español. Dura 1:16, ya tiene billones de visitas y es un fenómeno en Internet.
Peruvian Radios in Amarok
Estimados KDEeros peruanos y usuarios de Linux en general:
Acabo de publicar un script que agrega algunas radios online de nuestro querido Perú en el excelente reproductor Amarok versión 2.0+. Lo pueden descargar desde aquí
Para instalar el script se van al Menú Tools->Script Manager->Install Script seleccionan el script que descargaron, presionan OK y listo.
Otra forma es en vez de hacer click en “Install script” presionan “Get More Scripts”, y hacen click en “Install” a lado de “Peruvian Radio Stations” y listo. Cierran y vuelven a abrir Amarok y tendrán una pantalla como esta:

Peruvian Radio Stations in Amarok
Hacen click en Peruvian Radio Stations y les aparecerá:

Peruvian Radio Stations in Amarok
He agregado todas las radios que pude encontrar en la web. Disfruten escuchando la música de su preferencia, así como noticias, deportes, etc. Normalmente cuando cambias de una radio a otra, demora de 1 a 5 segundos.
Las siguientes radios fueron testeadas una y otra vez y funcionan correctamente:
Lima:
Callao 1400 KHZ AM
Capital 96.7 FM
Corazon 96.7 FM
CPN Radio 90.5 FM
Doble Nueve 99.1 FM
Felicidad 88.9 FM
La Unión 103.3 FM
Miraflores 96.1 FM
Moda 97.3 FM
Panamericana 101.1 FM
Planeta 107.7 FM
Ritmo Romántica 93.1 FM
RPP 89.7 FM
San Borja 91.1 FM
Secretos al corazón 93.1 FM
Studio92 92.5 FM
Telestereo 88 FM
Arequipa:
La Mega 94.3 FM
Las Vegas 99.3 FM
Melodia 104.3 FM
Panorama 96.5 FM
Super Stereo 105.5 FM
Yaravi 106.3 FM
Tacna:
Power 98.1 FM
Super Stereo 103.5 FM
Uno 93.7 FM
Cusco:
TV Color 98.1 FM
Willkamayu 940 AM
Trujillo:
La Grande 96.1 FM
Libertad Mundo 1160 Kcs AM
Ica:
Sonica 92.1 FM
Este pequeño script está basado en el script de Radio France con ciertas modificaciones. Gracias al desarrollador y a este tutorial que encontré en la web de Kubuntu que me permitió entender mejor como funcionan los scripts en Amarok..
Si desean que una radio sea agregada, por favor, simplemente envíen un mail a ronnycontacto(at)gmail.com indicando la stream url de la radio o simplemente la dirección del sitio web y gustosamente agregaré la radio en la brevedad posible..
Congratulations KDE team for Caizen (KDE 4.3)
kde 4.3 (Caisen) was released today. Please read the announcement, see the improvements, applications, the platform and give this desktop a try and you will see the difference.
Congratulations and thanks to all the KDE team for the hard work..

KDE 4.3
I love KDE and now that I am doing more c++ and QT I hope to be part of the team for 4.4.
Upgrade to Django 1.1
Developing or considering Django to create your cool 2.0 web applications/sites?
Please, try the new version of Django (1.1) which comes with interesting new features.
If you already have Django installed, you must remove the old version directory before upgrading. The path to the directory depends of your system, but it is usually located at:
/usr/local/lib/python$version/dist-packages/
/usr/local/lib/python$version/site-packages/
or
/usr/lib/python$version/dist-packages/
/usr/lib/python$version/site-packages/
One of the new features I recently tried is the possibility to create admin actions that allow for bulk updates to many objects at once.
Example:
Imagine you have a field called status which is a boolean field and you want to change the status of many elements at the same time. It’s annoying to select an object one by one to change the status. Here come “admin actions”, they are really useful.
In this short example, I want to make some objects published/unpublished. I will define two methods in my admin.py to achieve this.
def published(modeladmin, request, queryset):
queryset.update(status=1)
published.short_description = 'Published stores'
def unpublished(modeladmin, request, queryset):
queryset.update(status=0)
unpublished.short_description = 'Unpublished stores'
As you can see, in this case, the actions take an argument: queryset, which contains the action to perform and the fields that will be affected.
Then, you add these actions to your model admin:
class StoreAdmin(admin.ModelAdmin): ... actions = [published,unpublished]
And your admin interface will look like this:

Django admin actions
Now you can select Published/Unpublished and press “Go” to test the actions.
I selected some elements to make them unpublished and in a second I got the following:

After performing admin actions in Django
Simple right?. KISS is always important. But, there are some things to consider before finishing:
Those actions(published, unpublished) are placed outside the class ModelAdmin. (StoreAdmin in this example). But, we also can define these actions as methods of the ModelAdmin.
The advantage is that defining actions as methods gives the action a more direct access to the ModelAdmin (Performance) and the possibility to call any of the methods provided by the admin.
So, I am going to define the actions as methods of StoreAdmin and rename modeladmin parameter to self.
And finally I put the strings ‘published’,'unpublished’ in actions to tell the ModelAdmin to see those actions as methods instead of direct references to functions:
class StoreAdmin(admin.ModelAdmin):
...
actions = ['published','unpublished']
def published(self, request, queryset):
queryset.update(status=1)
published.short_description = 'Published stores'
def unpublished(self, request, queryset):
queryset.update(status=0)
unpublished.short_description = 'Unpublished stores'
And that’s it. If you want to know more about admin actions or implement advanced action techniques, take a look at the excellent Django documentation.
Another feature I tried in Django 1.1 was the option: list_editable which allow edit and save multiple rows at once from the change list page. This option has the same format that list_display, but you have two restrictions:
class StoreAdmin(admin.ModelAdmin):
...
list_display = ('customer', 'state','city','phone','status')
list_editable = ['phone']
A screenshot of the list_editable option for the field phone of my Store model.

Django - list_editable option
Well, I’ll continue exploring the new features in Django 1.1. If you have something to share, don’ t hesitate to post a comment or blog about that.
Búsqueda lineal y búsqueda binaria
Los algoritmos de búsqueda lineal y binaria son 2 de los algoritmos más usados para encontrar elementos en una estructura de datos.
La búsqueda lineal probablemente es sencilla de implementar e intuitiva. Básicamente consiste en buscar de manera secuencial un elemento, es decir, preguntar si el elemento buscado es igual al primero, segundo, tercero y así sucesivamente hasta encontrar el deseado. Entonces este algoritmo tiene una complejidad de O(n).
La búsqueda binaria al igual que otros algoritmos como el quicksort utiliza la técnica divide y vencerás. Uno de los requisitos antes de ejecutar la búsqueda binaria, es que el conjunto de elementos debe de estar ordenado. Supongamos que tenemos el siguiente array.
57 53 21 37 17 36 22 3 44 97 89 26 31 47 8 17
Debemos ordenarlo
3 8 17 17 21 22 26 31 36 37 44 47 53 57 89 97
¿Como funciona la búsqueda binaria?
Necesitamos una seria de datos para realizar la búsqueda: El elemento en la posición inicio, fin, medio. Y porsupuesto el tamaño del vector y elemento que queremos buscar.
inicio = 0;
fin = tam – 1;
medio = (inicio + fin) / 2;
Preguntamos si el elemento buscado es igual al elemento que se encuentra en la posicion medio del array, si es afirmativo ya encontramos el elemento y no hay nada más que hacer.
if(buscado == array[medio]){
cout << "Se encuentra en la posicion " << medio + 1 << endl;
return array[medio];
}
Si no es así. Preguntamos si el elemento que se encuentra en la posición medio es mayor al elemento buscado, si es afirmativo y como el array está ordenado, quiere decir que elemento buscado es menor al del medio. Entonces ahora solo buscaríamos en esa división del array,
por lo tanto, el fin ahora sería el elemento anterior al medio.
if(array[medio] > buscado){
fin = medio - 1;
}
De lo contrario quiere decir que elemento buscado es mayor al del medio, entonces debemos buscar en la otra división del array, por lo tanto el inicio sería el elemento posterior al medio.
else {
inicio = medio + 1;
}
Con cualquiera de estas 2 operaciones descartamos la otra mitad del array y por lo tanto reducimos notablemente el número de iteraciones.
Por lo tanto, en cada iteración, la búsqueda se reduce a la mitad del array. Realizamos esto en un bucle mientras el inicio sea menor o igual al fin.
El algoritmo de búsqueda binaria tiene una complejidad de O(log n).
Veamos la implementación de la búsqueda lineal y binaria en C++.
Nota: Para realizar la búsqueda binaria, estoy incluyendo el archivo que contiene el algoritmo de ordenamiento quicksort, para no volver a escribirlo y así reutilizar código.
#include “quicksort.h”
Aquí tienen el código del algoritmo y una breve explicación. Retiren el main para utilizarlo en otros programas.
#include <iostream>
#include "quicksort.h"
using namespace std;
int busqueda_lineal(int *array,int buscado,int tam)
{
for(int i=0;i<tam;i++){
if(buscado==array[i]){
cout << "Se encuentra en la posicion " << i+1 << endl;
}
}
}
int busqueda_binaria(int *array, int buscado, int tam)
{
int medio, inicio, fin;
inicio = 0;
fin = tam-1;
while(inicio <= fin){
medio = (inicio + fin) / 2;
if(buscado == array[medio]){
cout << "Se encuentra en la posicion " << medio + 1 << endl;
return array[medio];
} else{
if(array[medio] > buscado){
fin = medio - 1;
} else {
inicio = medio + 1;
}
}
}
return -1;
}
void imprimir(int *array,int tam)
{
for(int i=0;i<tam;i++){
cout << array[i] << " ";
}
cout << endl << endl;
}
int main()
{
int tam;
int buscado;
cout << "Ingresa el tamanyo del array" << endl;
cin >> tam;
int array[tam];
srand(time(NULL));
for(int i=0;i<tam;i++){
array[i] = rand() % 100;
}
cout << endl;
cout << "Array al inicio " << endl;
imprimir(array,tam);
cout << "Ingresa el elemento a buscar (Busqueda lineal) ";
cin >>buscado;
busqueda_lineal(array,buscado,tam);
cout << "Array ordenado " << endl;
quicksort(array,0,tam);
imprimir(array,tam);
cout << "Ingresa el elemento a buscar (Busqueda binaria) ";
cin >>buscado;
busqueda_binaria(array,buscado,tam);
return 0;
}
Ejemplo de la salida del programa:
Ingresa el tamanyo del array 16 Array al inicio 57 53 21 37 17 36 22 3 44 97 89 26 31 47 8 17 Ingresa el elemento a buscar (Busqueda lineal) 36 El elemento se encuentra en la posicion 6 Array ordenado 3 8 17 17 21 22 26 31 36 37 44 47 53 57 89 97 Ingresa el elemento a buscar (Busqueda binaria) 89 El elemento se encuentra en la posicion 15
Listas enlazadas – Clase Lista,Nodo en c++
Una lista es una estructura de datos que nos permite agrupar elementos de una manera organizada. Las listas al igual que los algoritmos son importantísimas en la computación y críticas en muchos programas informáticos.
Las listas están compuestas por nodos, estos nodos tienen un dato o valor y un puntero a otro(s) nodo(s).
Existen varios tipos de listas: Simplemente enlazada, doblemente enlazada, circular simplemente enlazada, circular doblemente enlazada.
Vamos a revisar las listas enlazadas simples, por ser el punto de partida y fundamentales para poder entender las otras.
Una lista enlazada tiene un conjunto de nodos, los cuales almacenan 2 tipos de información: El dato que contienen y un puntero al siguiente nodo en la lista. El último nodo de la lista tiene como siguiente nodo el valor NULL. Entonces las listas enlazadas simples solo pueden ser recorridas en una dirección, apuntando al nodo siguiente, mas no a un nodo anterior.
Aquí una ejemplo de un lista enlazada simple.
En cristiano: 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL Internamente: Nodo-> Dato: 55 Direcion: 0x3d2c00 Siguiente: 0x3d2c80 Nodo-> Dato: 60 Direcion: 0x3d2c80 Siguiente: 0x3d2c90 Nodo-> Dato: 31 Direcion: 0x3d2c90 Siguiente: 0x3d2ca0 Nodo-> Dato: 5 Direcion: 0x3d2ca0 Siguiente: 0x3d2cb0 Nodo-> Dato: 4 Direcion: 0x3d2cb0 Siguiente: 0x3d2cc0 Nodo-> Dato: 51 Direcion: 0x3d2cc0 Siguiente: 0x3d3ab8 Nodo-> Dato: 9 Direcion: 0x3d3ab8 Siguiente: 0x3d3ac8 Nodo-> Dato: 27 Direcion: 0x3d3ac8 Siguiente: 0x3d3ad8 Nodo-> Dato: 68 Direcion: 0x3d3ad8 Siguiente: 0x3d3ae8 Nodo-> Dato: 62 Direcion: 0x3d3ae8 Siguiente: 0
Obviamente, internamente no existen las palabras nodo, dato,dirección y siguiente, es solo una representación.
Como una lista es una estructura de datos dinámica, el tamaño de la misma puede cambiar durante la ejecución del programa.
Como vimos en post anteriores, se puede generar memoria dinámicamente para un array, pero un array es una estructura estática pues su tamaño tiene un limite y así creáramos array dinámicos hay que redimensionar el tamaño si es necesario, lo cual ya implica un costo de volver a generar memoria dinámica.
Entonces podemos ver una ventaja de la listas sobre los arrays: No tener que redimensionar la estructura y poder agregar elemento tras elemento indefinidamente.
Cuando uno ya ha trabajado con arrays (vectores y matrices) y empieza a estudiar las listas, se da cuenta que una restricción de las listas es el acceso a los elementos. En un vector podíamos hacer algo como v[50] y nos estábamos refiriendo al índice 50 del vector v. A esto se le conoce como acceso aleatorio.
En el caso de las listas el acceso es secuencial, es decir, para acceder a un elemento del conjunto debemos de recorrer uno por uno los elementos hasta llegar al solicitado. Rápidamente se puede concluir que el tiempo de acceso a los elementos de un array es muchísimo más rápido que en una lista. Esta es una gran desventaja de las listas, por lo que buscar elementos por índice sería muy costoso. Esto no quiere decir que trabajar con arrays sea mejor que con listas. Las listas son muy flexibles y para muchos casos son imprescindibles.
Bueno, aquí va la primera práctica que hice sobre listas enlazadas. Implementación de una clase Lista, clase Nodo y los siguientes métodos:
- Añadir un elemento al inicio.
- Añadir un elemento al final
- Añadir un elemento de manera ordenada
- Llenar la lista por teclado
- Llenar la lista aleatoriamente
- Imprimir la lista
- Buscar un elemento
- Eliminar un elemento por dato
- Eliminar un elemento por posicion o índice
- Eliminar toda la lista
- Invertir una lista
- Ordernar una lista
- Cargar una lista desde archivo
- Guardar la lista en un archivo
- Concatenar una lista a otra
- Intersección entre 2 listas
Podrán ver la variable *temp en casi todos los métodos , este es el puntero de tipo Nodo que me va a permitir moverme a través de la lista y que inicialmente es igual a la cabeza (head). Mientras exista algo en la lista, voy avanzado el puntero para que apunte al siguiente. Esto se consigue en casi todos los casos con un while.
While(temp)
temp = temp->gte
Otra operación común en los métodos es preguntar si inicialmente la lista está vacía, es decir, si la cabeza no contiene algo o es igual a Null.
if(!head) o if(head==NULL)
Apliqué mis limitados conocimientos de templates para tener una lista genérica y así pueda funcionar con varios tipos de datos y de verdad funciona.
Ahí la definición e implementación de la clase, lista, clase nodo y el main para ver el funcionamiento. Cualquier crítica, sugerencia o comentarios son bienvenidos siempre.
Nodo.h
#ifndef NODO_H
#define NODO_H
#include <iostream>
using namespace std;
template <class T>
class Nodo
{
public:
T dato;
Nodo *sgte;
Nodo();
Nodo(T);
~Nodo();
void print();
void eliminar();
};
#endif // NODO_H
Nodo.cpp
#include "Nodo.h"
//constructor por defecto
template<typename T>
Nodo<T>::Nodo()
{
dato = NULL;
sgte = NULL;
}
//constructor por parametro
template<typename T>
Nodo<T>::Nodo(T dato_)
{
dato = dato_;
sgte = NULL;
}
//imprimir un nodo
template<typename T>
void Nodo<T>::print()
{
//cout << "Nodo-> " << "Dato: " << dato << " Direcion: " << this << " Siguiente: " << sgte << endl;
cout << dato << "-> ";
}
//eliminar todos los nodos
template<typename T>
void Nodo<T>::eliminar()
{
if(sgte)
sgte->eliminar();
delete this;
}
template<typename T>
Nodo<T>::~Nodo(){}
Lista.h
#ifndef LISTA_H
#define LISTA_H
#include <iostream>
#include "time.h"
#include <fstream>
#include <string>
#include "Nodo.h"
#include "Nodo.cpp"
using namespace std;
template <class T>
class Lista
{
private:
int dim,num_nodos;
T line;
string archivo;
public:
T ele;
Nodo<T> *head;
Lista();
~Lista();
void llenar_teclado(int);
void llenar_aleatorio(int);
void print();
void add_end(T);
void add_head(T);
void add_sort(T);
void search(T);
void del_dato(T);
void del_pos(int);
void del_all();
void invertir();
void sort();
void load(string);
void save(string);
void concat(Lista);
void interseccion(Lista);
};
#endif // LISTA_H
Lista.cpp
#include "Lista.h"
using namespace std;
//constructor por defecto
template<typename T>
Lista<T>::Lista()
{
num_nodos = 0;
head = NULL;
}
//llenar la lista por teclado
template<typename T>
void Lista<T>::llenar_teclado(int dim)
{
for(int i=0;i<dim;i++){
cout << "Ingresa el elemento " << i + 1 << endl;
cin >> ele;
add_end(ele);
}
}
//llenar la lista aleatoriamente para enteros
template<typename T>
void Lista<T>::llenar_aleatorio(int dim)
{
srand(time(NULL));
for(int i=0;i<dim;i++){
add_end(rand() % 100);
}
}
//imprimir la lista
template<typename T>
void Lista<T>::print()
{
Nodo<T> *temp = head;
if(!head){
cout << "La lista esta vacia " << endl;
} else{
while(temp){
temp->print();
if(!temp->sgte) cout << "NULL";
temp = temp->sgte;
}
}
cout << endl << endl;
}
//insertar al final
template<typename T>
void Lista<T>::add_end(T dato_)
{
Nodo<T> *temp = head;
Nodo<T> *nuevo = new Nodo<T> (dato_);
if(!head){
head = nuevo;
} else{
while(temp->sgte !=NULL){
temp = temp->sgte;
}
temp->sgte = nuevo;
}
num_nodos++;
}
//insertar al inicio
template<typename T>
void Lista<T>::add_head(T dato_)
{
Nodo<T> *temp = head;
Nodo<T> *nuevo = new Nodo<T> (dato_);
if(!head){
head = nuevo;
} else{
nuevo->sgte = head;
head = nuevo;
while(temp){
temp = temp->sgte;
}
}
num_nodos++;
}
//insertar de manera ordenada
template<typename T>
void Lista<T>::add_sort(T dato_)
{
Nodo<T> *nuevo = new Nodo<T> (dato_);
Nodo<T> *temp = head;
if(!head){
head = nuevo;
} else{
if(head->dato > dato_){
nuevo->sgte = head;
head = nuevo;
} else{
while((temp->sgte != NULL) && (temp->sgte->dato < dato_)){
temp = temp->sgte;
}
nuevo->sgte = temp->sgte;
temp->sgte = nuevo;
}
}
num_nodos++;
}
//buscar el dato de un nodo
template<typename T>
void Lista<T>::search(T dato_)
{
Nodo<T> *temp = head;
int cont = 1;
int cont2=0;
while(temp){
if(temp->dato == dato_){
cout << "El dato se encuentra en la posicion: " << cont << " (Para seres humanos)" << endl;
cont2++;
}
temp = temp->sgte;
cont++;
}
if(cont2 == 0){
cout << "No existe el dato " << endl;
}
cout << endl << endl;
}
//eliminar por dato del nodo
template<typename T>
void Lista<T>::del_dato(T dato_)
{
Nodo<T> *temp = head;
Nodo<T> *temp1 = head->sgte;
int cont=0;
if(head->dato == dato_){
head = temp->sgte;
} else {
while(temp1){
if(temp1->dato == dato_){
Nodo<T> *aux = temp1;
temp->sgte = temp1->sgte;
delete aux;
cont++;
num_nodos--;
}
temp = temp->sgte;
temp1 = temp1->sgte;
}
}
if(cont == 0){
cout << "No existe el dato " << endl;
}
}
//eliminar por posicion del nodo
template<typename T>
void Lista<T>::del_pos(int pos)
{
Nodo<T> *temp = head;
Nodo<T> *temp1 = temp->sgte;
if(pos < 1 || pos > num_nodos){
cout << "Fuera de rango " << endl;
} else if(pos==1){
head = temp->sgte;
} else{
for(int i=2;i<=pos;i++){
if(i==pos){
Nodo<T> *aux = temp1;
temp->sgte = temp1->sgte;
delete aux;
num_nodos--;
}
temp = temp->sgte;
temp1 = temp1->sgte;
}
}
}
//eliminar todos los nodos
template<typename T>
void Lista<T>::del_all()
{
head->eliminar();
head = 0;
}
//invertir la lista
template<typename T>
void Lista<T>::invertir()
{
Nodo<T> *temp = head;
Nodo<T> *prev = NULL;
Nodo<T> *next = NULL;
while(temp){
next = temp->sgte;
temp->sgte = prev;
prev = temp;
temp = next;
}
head = prev;
}
//ordenar de manera ascendente
template<typename T>
void Lista<T>::sort()
{
T aux2;
Nodo<T> *aux = head;
Nodo<T> *temp = aux;
while(aux){
temp=aux;
while(temp->sgte){
temp=temp->sgte;
if(aux->dato>temp->dato){
aux2=aux->dato;
aux->dato=temp->dato;
temp->dato=aux2;
}
}
aux=aux->sgte;
}
}
//cargar una lista de un archivo
template<typename T>
void Lista<T>::load(string archivo)
{
ifstream in;
in.open(archivo.c_str());
if(!in.is_open()){
cout << "No se puede abrir el archivo: " << archivo << endl << endl;
} else{
while(in >> line){
add_end(line);
}
}
in.close();
}
//guardar una lista en un archivo
template<typename T>
void Lista<T>::save(string archivo)
{
Nodo<T> *temp = head;
ofstream out;
out.open(archivo.c_str());
if(!out.is_open()){
cout << "No se puede guardar el archivo " << endl;
} else{
while(temp){
out << temp->dato;
out << " ";
temp = temp->sgte;
}
}
out.close();
}
//concatenar a otra lista
template<typename T>
void Lista<T>::concat(Lista Lista2)
{
Nodo<T> *temp2 = Lista2.head;
while(temp2){
add_end(temp2->dato);
temp2 = temp2->sgte;
}
}
//numeros que coinciden en 2 listas
template<typename T>
void Lista<T>::interseccion(Lista Lista2)
{
Nodo<T> *temp = head;
Nodo<T> *temp2 = Lista2.head;//cabeza de la segunda lista
Lista lista_interseccion;//creo otra lista
int num_nodos2 = Lista2.num_nodos;//nodos de la segunda lista
int num_inter=0;//numero de coincidencias
//creo 2 vectores dinamicos
T *v1 = new T[num_nodos];
T *v2 = new T[num_nodos2];
//lleno los vectores v1 y v2 con los datos de la lista original y segunda lista respectivamente
int i=0;
while(temp){
v1[i] = temp->dato;
temp = temp->sgte;
i++;
}
int j=0;
while(temp2){
v2[j] = temp2->dato;
temp2 = temp2->sgte;
j++;
}
//ordeno los vectores
insert_sort(v1,num_nodos);
insert_sort(v2,num_nodos2);
int v1_i= 0;//indice del 1er vector (v1)
int v2_i= 0;//indice del 2do vector (v2)
//mientras no haya terminado de recorrer ambas listas
while (v1_i < num_nodos && v2_i < num_nodos2) {
if(v1[v1_i] == v2[v2_i]){//cuando los datos de ambas sean iguales
lista_interseccion.add_end(v1[v1_i]);//utilizo mi metodo add_end para llenar la lista de intersecciones
v1_i++;
v2_i++;
num_inter++;
} else if(v1[v1_i] < v2[v2_i]){
v1_i++;
} else{
v2_i++;
}
}
//Solo si hay alguna interseccion imprimo la nueva lista creada
if(num_inter > 0) {
cout << "Existen " << num_inter << " intersecciones " << endl;
lista_interseccion.print();
} else {
cout << "No hay interseccion en ambas listas" << endl;
}
}
//usado por el metodo interseccion
template<typename T>
void insert_sort(T a[],int tam)
{
T temp;
for(int i=0;i<tam;i++){
for(int j=i-1;j >=0 && a[j+1] < a[j];j--){
temp = a[j+1];
a[j+1] = a[j];
a[j] = temp;
}
}
}
template<typename T>
Lista<T>::~Lista(){}
main.cpp
#include <iostream>
#include "Lista.h"
#include "Lista.cpp" //por errores de linking de tipo "undefined reference to" (estudiando)
using namespace std;
int main()
{
Lista<int> l1;
Lista<int> l2;
int dim,pos;
string archivo;
cout << "Ingresa la dimension de la lista " << endl;
cin >>dim;
l1.llenar_aleatorio(dim);//llenar_teclado para otros tipos
cout << "Lista A al inicio " << endl;
l1.print();
cout << "Agrega un elemento por la cabeza" << endl;
cin >>l1.ele;
l1.add_head(l1.ele);
l1.print();
cout << "Lista invertida " << endl;
l1.invertir();
l1.print();
cout << "Lista ordenada " << endl;
l1.sort();
l1.print();
cout << "Agrega un elemento (Sera ordenado)" << endl;
cin >>l1.ele;
l1.add_sort(l1.ele);
l1.print();
cout << "Busca un elemento" << endl;
cin >>l1.ele;
l1.search(l1.ele);
cout << "Elimina un elemento por dato" << endl;
cin >>l1.ele;
l1.del_dato(l1.ele);
l1.print();
cout << "Elimina un elemento por posicion" << endl;
cin >>pos;
l1.del_pos(pos);
l1.print();
cout << "Cargar una lista desde archivo - Ingresa el nombre" << endl;
cin >> archivo;//debe estar en el mismo directorio que este programa
l2.load(archivo);
cout << "Lista B" << endl;
l2.print();
cout << "Guardar la lista en un archivo - Ingresa el nombre" << endl;
cin >> archivo;//ingresa un nombre cualquiera *.*
l2.save(archivo);
cout << "Interseccion entre las listas A y B " << endl;
l1.interseccion(l2);
cout << "Listas A y B concatenadas " << endl;
l1.concat(l2);
l1.print();
l1.del_all();
l1.print();
return 0;
}
Un ejemplo de la salida del programa:
Ingresa la dimension de la lista 10 Lista A al inicio 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL Agrega un elemento por la cabeza 18 18-> 55-> 60-> 31-> 5-> 4-> 51-> 9-> 27-> 68-> 62-> NULL Lista invertida 62-> 68-> 27-> 9-> 51-> 4-> 5-> 31-> 60-> 55-> 18-> NULL Lista ordenada 4-> 5-> 9-> 18-> 27-> 31-> 51-> 55-> 60-> 62-> 68-> NULL Agrega un elemento (Sera ordenado) 45 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 60-> 62-> 68-> NULL Busca un elemento 51 El dato se encuentra en la posicion: 8 (Para seres humanos) Elimina un elemento por dato 60 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> 68-> NULL Elimina un elemento por posicion: 11 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> NULL Cargar una lista desde archivo - Ingresa el nombre prueba.txt // mi archivito prueba.txt tenia estos datos Lista B 8-> 59-> 23-> 15-> 94-> 63-> 9-> 17-> 62-> 33-> NULL Guardar la lista en un archivo - Ingresa el nombre otralista.txt // abre tu archivo y mira el contenido Interseccion entre las listas A y B Existen 2 intersecciones 9-> 62-> NULL Listas A y B concatenadas 4-> 5-> 9-> 18-> 27-> 31-> 45-> 51-> 55-> 62-> 8-> 59-> 23-> 15-> 94-> 63-> 9->17-> 62-> 33-> NULL La lista esta vacia.
Hasta pronto
Operaciones con matrices – Clase Matriz en c++
El siguiente es el primer ejercicio que hice con matrices. Quizás alguno de estos ejercicios te puedan servir como una base. Puedes leer el post anterior sobre vectores, matrices y punteros si aún no haz trabajo con ellos.
Recomiendo que intentes y practiques mucho antes de copiar y pegar. Si te sientes estancado en algún problema recién trata de buscar una guía para llegar a la solución.
Esta clase matriz tendrá 3 atributos: Matriz,número de filas y número de columnas. Tiene un constructor por defecto,constructor copiador y un constructor por parámetro que recibe el número de filas y columnas.
Las siguientes funciones fueron implementadas:
- Generar una matriz dinámicamente
- LLenar la matriz desde teclado:
- Llenar la matriz aleatoriamente:
- Imprimir la matriz
- Hallar el mayor elemento.
- Hallar el menor elemento.
- Hallar la moda.
- Intercambiar filas.
- Intercambiar columnas.
- Sumar otra matriz: Sumar 2 objetos de tipo matriz retornar otra matriz. Ejem: c = a + b.
- Restar otra matriz: Igual que la suma. Ejem: c= a – b
- Multiplicar por otra matriz: Ejem: c = a * b. El nro de filas de a debe ser igual al nro de columnas de b
- Multiplicar por un escalar: Ingreso un número y todos los elementos de la matriz se multiplican por ese número.
- Hallar matriz transpuesta: matr[m][n] su transpuesta es matr[n][m]. Se obtiene cambiando filas por columnas. Donde los elementos de la fila m ahora pertenecen a la columna m de la transpuesta.
- Verificar si es simétrica: Una matriz es simétrica si es cuadrada(filas=columnas) y cuando su transpuesta es igual a su matriz original.
- Verificar si es identidad: Es identidad si tiene todos sus elementos nulos excepto los de la diagonal principal que son iguales a 1.
NOTA: He aplicado un poco de templates para manejar la matriz con varios tipos de datos (int, float, char,double) y sobrecarga de operadores para la suma, resta y multiplicación de matrices.
Recien estoy aprendiendo a usar estas 2 características importantes del lenguaje (templates y sobrecarga de operadores) por lo tanto, estos temas serán tratados a profundidad el proximo año.
En breve:
Un template es una manera de que funciones, clases métodos puedan ser usados con varios tipos de datos. Imagínense crear una lista de datos y tener que crear funciones insertar, eliminar, buscar, concatenar, etc para cada tipo de dato. Si los métodos y la clase tienen la misma lógica para que reescribir código si podemos reutilizar.
La sobrecarga de operadores es una manera de realizar las mismas operaciones que solemos hacer con tipos de datos comunes con tipos abstractos de datos. Por ejemplo, la sobrecarga me permitió sumar 2 objetos de tipo Matriz y almacenar el resultado en otro objeto Matriz, del modo c = a + b
Al grano:
Definición de la clase Matriz (La cabecera o header):
matriz.h
#ifndef MATRIZ_H
#define MATRIZ_H
#include <iostream>
#include <time.h>
using namespace std;
template <class T>
class Matriz
{
private:
T mayor_,menor_,moda_,ele,**matr1;
int dim_matriz;
public:
int fils,cols;
T escalar;
Matriz();
Matriz(int,int);
Matriz(const Matriz &m);//constructor copia
void llenar_teclado();
void llenar_aleatorio();
void imprimir();
T mayor();
T menor();
T moda();
void inter_filas(int,int);
void inter_cols(int,int);
bool esSimetrica();
bool esIdentidad();
void multi_escalar(T);
void transpuesta();
Matriz<T> operator+ (const Matriz &matr2);
Matriz<T> operator- (const Matriz &matr2);
Matriz<T> operator* (const Matriz &matr2);
void eliminar();
~Matriz();
protected:
};
#endif // MATRIZ_H
Implemetanción de la clase:
matriz.cpp
#include "Matriz.h"
//Constructor por defecto
template<typename T>
Matriz<T>::Matriz()
{
fils=4;
cols=4;
}
//Constructor copia
template<typename T>
Matriz<T>::Matriz(const Matriz &m)
{
*this = m;
}
//Constructor por parametro
template<typename T>
Matriz<T>::Matriz(int fils_ , int cols_)
{
fils = fils_;
cols = cols_;
matr1 = new T*[fils];
for(int i=0;i<fils;i++){
matr1[i] = new T[cols];
}
}
//Llenar aleatoriamente una matriz
template<typename T>
void Matriz<T>::llenar_aleatorio()
{
//srand(time(NULL));
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
matr1[i][j] = rand() % 30;
}
}
mayor_= matr1[0][0];
menor_= matr1[0][0];
srand(time(NULL));
}
//Llenar una matriz desde teclado
template<typename T>
void Matriz<T>::llenar_teclado()
{
for(int i=0;i<fils;i++){
cout << "Fila " << i+1 << endl;
for(int j=0;j<cols;j++){
cout << "Ingresa el elemento " << j+1 << endl;
cin >>ele;
matr1[i][j] = ele;
}
cout << endl;
}
mayor_= matr1[0][0];
menor_= matr1[0][0];
}
//Imprimir matriz
template<typename T>
void Matriz<T>::imprimir()
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
cout << matr1[i][j] << " ";
}
cout << endl << endl;
}
cout << endl << endl;
}
//Obtener el mayor de la matriz
template<typename T>
T Matriz<T>::mayor()
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if(matr1[i][j] > mayor_){
mayor_ = matr1[i][j];
}
}
}
return mayor_;
}
//Obtener el menor de la matriz
template<typename T>
T Matriz<T>::menor()
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if(matr1[i][j] < menor_){
menor_ = matr1[i][j];
}
}
}
return menor_;
}
//Obtener la moda de la matriz
template<typename T>
T Matriz<T>::moda()
{
//creo una matriz auxiliar
Matriz maux(fils,cols);
//lleno la matriz con ceros
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
maux.matr1[i][j] = 0;
}
}
dim_matriz = fils * cols;
int y=0;//para retener una fila n veces
int z=0;//para retener una columna n veces
//empiezo a comparar cada elemento n veces
for(int x=0;x<dim_matriz;x++){
for (int i = 0; i < fils; i++){
for (int j = 0; j < cols; j++){
if(matr1[y][z] == matr1[i][j]){
maux.matr1[i][j]++;//incremento en 1 el valor de la matriz aux en esa posicion
}
}
}
//pasar a la siguiente columna despues de n comparaciones
z++;
if(z==cols){//empiezo a comparar con la siguiente fila
z=0;//empiezo nuevamente en la 1era columna
y++;//paso a la siguiente fila
}
}
//obtengo el valor mayor de la matriz
mayor_ = maux.mayor();
if(mayor_==1){//si ningun valor se ha repetido mas de una vez no hay moda
return -1;
} else {
for(int i=0; i<fils;i++){
for(int j=0;j<cols;j++){
if(maux.matr1[i][j] == mayor_) {
moda_ = matr1[i][j];
}
}
}
}
return moda_;
}
//Intercambiar dos filas en una matriz
template<typename T>
void Matriz<T>::inter_filas(int fil1, int fil2)
{
if(fil1 > fils || fil2 > fils){
cout << "Por favor, hasta cuando " << endl;
} else {
T temp;
fil1--;
fil2--;
for(int i=0;i<cols;i++){
temp = matr1[fil1][i];
matr1[fil1][i] = matr1[fil2][i];
matr1[fil2][i] = temp;
}
cout << "Se intercambio la fila " << fil1 + 1 << " por la " << fil2 + 1 << endl;
imprimir();
}
}
//Intercambiar dos columnas en una matriz
template<typename T>
void Matriz<T>::inter_cols(int col1, int col2)
{
if(col1 > cols || col2 > cols){
cout << "Por favor, hasta cuando " << endl;
} else{
T temp;
col1--;
col2--;
for(int i=0;i<fils;i++){
temp = matr1[i][col1];
matr1[i][col1] = matr1[i][col2];
matr1[i][col2] = temp;
}
cout << "Se intercambio la columna " << col1 + 1 << " por la " << col2 + 1 << endl;
imprimir();
}
}
//Verificar si una matriz es simetrica
template<typename T>
bool Matriz<T>::esSimetrica()
{
if(fils!=cols) {
return false;
}
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if (matr1[i][j]!=matr1[j][i]){
return false;
}
}
}
return true;
}
//Verificar si una matriz es identidad
template<typename T>
bool Matriz<T>::esIdentidad()
{
if(fils!=cols) {
return false;
}
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if (i == j) {
if (matr1[i][j] != 1)
return false;
} else {
if (matr1[i][j] != 0)
return false;
}
}
}
return true;
}
//Multiplicar a una matriz por un escalar
template<typename T>
void Matriz<T>::multi_escalar(T escalar)
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
matr1[i][j] = matr1[i][j] * escalar;
}
}
cout << "Se multiplico a la matriz por el escalar " << escalar << endl;
imprimir();
}
//Obtener la transpuesta de una matriz
template<typename T>
void Matriz<T>::transpuesta()
{
Matriz matresult(cols,fils);
for(int i=0;i<cols;i++){
for(int j=0;j<fils;j++){
matresult.matr1[i][j]= matr1[j][i];
}
}
matresult.imprimir();
}
//Suma de matrices con sobrecarga de operadores
template<typename T>
Matriz<T> Matriz<T>::operator+ (const Matriz &matr2)
{
Matriz matresult(fils,cols);
for (int i=0;i<fils;i++){
for (int j=0;j<cols;j++){
matresult.matr1[i][j] = matr1[i][j] + matr2.matr1[i][j];
}
}
return matresult;
}
//Resta de matrices con sobrecarga de operadores
template<typename T>
Matriz<T> Matriz<T>::operator- (const Matriz &matr2)
{
Matriz matresult(fils,cols);
for (int i=0;i<fils;i++){
for (int j=0;j<cols;j++){
matresult.matr1[i][j] = matr1[i][j] - matr2.matr1[i][j];
}
}
return matresult;
}
//Multiplicacion de matrices con sobrecarga de operadores
template<typename T>
Matriz<T> Matriz<T>::operator* (const Matriz &matr2)
{
Matriz matresult(fils,matr2.cols);
T total;
for (int i=0;i<fils;i++){
for (int j=0;j<matr2.cols;j++){
for(int k=0;k<cols;k++){
total += (matr1[i][k] * matr2.matr1[k][j]);
//para mostrar lo que pasa
/*cout << "(" << matr1[i][k] << " * " << matr2.matr1[k][j] << ")";
if(k<cols-1){
cout << " + ";
} else {
cout << " = " << total;//despues del ultimo muestro la suma
}*/
}
//cout << endl;
matresult.matr1[i][j] = total;
total = 0;//para limpiar el total sumado arriba
}
cout << endl;
}
return matresult;
}
template<typename T>
void Matriz<T>::eliminar()
{
for(int i=0;i<fils;i++){
delete[] matr1[i];
}
delete[] matr1;
}
template<typename T>
Matriz<T>::~Matriz(){}
main.cpp
#include <iostream>
#include "Matriz.h"
#include "Matriz.cpp"
using namespace std;
int main()
{
srand(time(NULL));//para no generar los mismos numeros aleatorios
int fils,cols,fil1,col1,fil2,col2;
cout << "Ingresa nro de filas " << endl;
cin >> fils;
cout << "Ingresa nro de columnas " << endl;
cin >> cols;
cout << endl;
Matriz<int> a(fils,cols);
Matriz<int> b(fils,cols);
Matriz<int> c(fils,cols);//matriz para almacenar el resultado de las operaciones
a.llenar_aleatorio();//existe el metodo llenar_teclado() para otros tipos
b.llenar_aleatorio();
cout << "Operaciones con matrices " << endl;
cout << "Matriz A " << endl;
a.imprimir();
cout << "Matriz B " << endl;
b.imprimir();
cout << "Matriz A + B " << endl;
c = a + b;
c.imprimir();
cout << "Matriz A - B " << endl;
c = a - b;
c.imprimir();
cout << "Matriz A * B " << endl;
c = a * b;
c.imprimir();
cout << "Operaciones basicas con la matriz A" << endl;
cout << "Matriz A " << endl;
a.imprimir();
cout << "El mayor de la matriz es: " << a.mayor() << endl;
cout << "El menor de la matriz es: " << a.menor() << endl;
cout << "La moda de la matriz es: " << a.moda() << endl;
cout << (a.esSimetrica() ? "" : "No") << " Es simetrica." << endl;
cout << (a.esIdentidad() ? "" : "No") << " Es identidad." << endl;
cout << endl;
cout << "Ingresa el escalar " << endl;
cin >>a.escalar;
a.multi_escalar(a.escalar);
cout << "Intercambio: Ingresa dos filas del 1 al " << fils << endl;
cin >>fil1;
cin >>fil2;
a.inter_filas(fil1,fil2);
cout << "Intercambio: Ingresa dos columnas del 1 al " << cols << endl;
cin >>col1;
cin >>col2;
a.inter_cols(col1,col2);
cout << "Transpuesta de A " << endl;
a.transpuesta();
a.eliminar();
b.eliminar();
c.eliminar();
return 0;
}
Particularmente, todos los ejercicios no son nada difíciles de resolver, pero yo me estanqué en la moda y creo que fue el problema que me hizo pensar un rato.
Lo resolví, pero sinceramente no me siento bien con la solución. No me gustó porque tiene una complejidad de O(n2) y con una matriz muy grande puede tarda mucho debido al número de recorridos y comparaciones.
La solución consistió en:
- Crear otra matriz auxiliar con el mismo nro de filas columas y llenarla con ceros.
- Recorrer la matriz original e ir comparando el primer elemento con todos los otros elementos de la matriz y contar sus repeticiones y así sucesivamente con los demás elementos.
- Si encuentro una repetición, incremento en uno el valor en esa posición de la matriz auxiliar.
- Luego hallar el mayor elemento de la matriz auxiliar.
- Y finalmente recorrer la matriz auxiliar, cuando algún elemento de esta matriz sea igual al mayor elemento, quiere decir, que ese fue el elemento que más se repitió en la matriz original. Por lo tanto la moda se encuentra en esa posición.
Matriz original 17 16 10 26 10 3 9 19 29 7 1 6 6 20 0 10 Matriz auxiliar al inicio 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Matriz auxiliar despues de las comparaciones con el nro de repeticiones de los valores 1 1 3 1 3 1 1 1 1 1 1 2 2 1 1 3
La moda de la matriz es: 10,
3 es el valor maximo que se repite en la matriz
Y en las posiciones en que se encuentra 3 se encuentra 10 en la matriz original.
Un tip que me dió el profe es reducir el nro de comparaciones creando una matriz booleana e ir poniendo unos y ceros a los números que ya comparé para luego no volver a comparar con los números que comparé anteriormente. Voy a seguir resolviendo el problema,si alguien tiene otra solución y puede explicarla fantástico.
Si yu
Vectores, Matrices y Punteros en c++
Estimados lectores y fans, les pido disculpas por este humilde y sencillo post, se que este mini-tutorial super básico es una humillación a su inteligencia y profesionalismo, pero comprendan que esto va dedicado a personas que como yo recién empiezan con sus primeros pininos en C++. Espero de verdad le sea útil a alguien.
Escribir todo esto, me costó una noche entera y mucho café. Parte de los conceptos aquí los aprendí en clases de la U y mucho también lo aprendí por cuenta propia. Así que agradecimientos al teacher Patricio del cual aprendí muchísimo. Una vez más a ustedes y a los tantos miles de seguidores que me leen a diario las disculpas del caso.
Vamos ir avanzando de a pocos así que no se preocupen y desesperen porfavor, paciencia. La idea es que esta sección crezca con su ayuda, feedback y motivación. Luego vamos a ver ejemplos con objetos, clases, sobrecarga de operadores, métodos de búsqueda, màs ordenación, punteros, listas, pilas, colas, templates… por ahora sigo practicando y haciendo simples cosas con este lenguaje. Los códigos los compilé con g++, el compilador de GNU.
VECTORES
Un vector, también llamado array(arreglo) unidimensional, es una estructura de datos que permite agrupar elementos del mismo tipo y almacenarlos en un solo bloque de memoria juntos, uno despues de otro. A este grupo de elementos se les identifica por un mismo nombre y la posición en la que se encuentran. La primera posición del array es la posición 0.
Podríamos agrupar en un array una serie de elementos de tipo enteros, flotantes, caracteres, objetos, etc. Crear un vector en c++ es sencillo, seguimos la siguiente sintaxix: Tipo nombre[tamanyo];
Ejm:
int a[5];//Vector de 5 enteros float b[5];//vector de 5 flotantes Producto product[5];//vector de 5 objetos de tipo Producto
Podríamos también inicializar el vector en la declaración:
int a[] = {5,15,20,25,30};
float b[] = {10.5,20.5,30.5,12.5,50.5}
Producto product[] = {celular,calculadora,camara,ipod,usb}
Como hay 5 elementos en cada array, automáticamente se le asignará 5 espacios de memoria a cada vector.Pero si trato de crear el vector de la forma int a[]; el compilador mostrará un error, porque no indiqué el tamaño del vector ni tampoco inicializé sus elementos.
Asigno valores a los elementos de un vector indicando su posición:
int a[4] = 30; // le asigno el valor 30 a la posición 4 del vector, es decir, al 5to elemento. product[2].setPrecio(300) // le asigno un precio de 300 al producto en la posicion 2, o sea al tercer elemento.
Obviamente el método setPrecio() debe de estar implementado.
Para llenar, recorrer e imprimir un vector podemos utilizar un bucle for:
#include <iostream>
using namespace std;
int main()
{
int dim;
cout << "Ingresa la dimension del vector" << endl;
cin >> dim; // Supongamos que ingrese 10
int vector[dim]; // mi vector es de tamanyo 10
for(int i=0;i < dim;i++){
vector[i] = i * 10;
cout << vector[i] << " ";
}
return 0;
}
La salida del programa mostrará: 0 10 20 30 40 50 60 70 80 90
Fàcil verdad? Bien ahora creen 2 o más vectores y empiecen a hacer funciones básicas como sumar, restar, buscar, ordenar, moda, etc que ayudan mucho a ir desarrollando la lógica. No vale copiar y pegar, mejor es practicar, practicar y practicar.
Aquí una función simple para sumar 2 vectores a y b y poner el resultado en un tercer vector c
#include <iostream>
using namespace std;
void sumar(int a[], int b[], int c[],int dim){
for (int i=0; i<dim; i++) {
c[i]=a[i] + b[i];
}
}
void imprimir(int v[],int dim)
{
for(int i=0;i<dim;i++){
cout << v[i] << " ";
}
cout << endl << endl;
}
int main()
{
int dim;
cout << "Ingresa la dimension" << endl;
cin >> dim;
int a[dim];
int b[dim];
int c[dim];
for(int i=0;i<dim;i++){
a[i] = i * 10;
b[i] = i * 5;
}
cout << "Vector A " << endl;
imprimir(a,dim);
cout << "Vector B " << endl;
imprimir(b,dim);
sumar(a,b,c,dim);
cout << "Vector C " << endl;
imprimir(c,dim);
return 0;
}
Este programa me botaría (si ingreso una dimensión de 10):
Vector A
0 10 20 30 40 50 60 70 80 90
VECTOR B
0 5 10 15 20 25 30 35 40 45
VECTOR C
0 15 30 45 60 75 90 105 120 135
Entonces para tomar en cuenta:
Todo vector debe tener definido un tipo de dato.
Todo vector necesita de una dimensión o tamanyo.
El código de arriba se puede mejorar muchísimo con objetos y clases, este es solo un pequeño ejemplo.
MATRICES
Una matriz es un vector de vectores o un también llamado array bidimensional. La manera de declarar una matriz es c++ es similar a un vector:
int matriz[fils][cols];
int es el tipo de dato, matriz es el nombre del todo el conjunto de datos y debo de especificar el numero de filas y columnas. Las matrices también pueden ser de distintos tipos de datos como char, float, double,etc.
Las matrices en c++ se almacenan al igual que los vectores en posiciones consecutivas de memoria. Usualmente uno se hace la idea que una matriz es como un tablero. Pero internamente el manejo es como su definicion lo indica, un vector de vectores, es decir, los vectores estan uno detras del otro juntos.
La forma de acceder a los elementos de la matriz es utilizando su nombre e indicando los 2 subindices que van en los corchetes. Si Coloco int matriz[2][3]=10; //estoy asignando al cuarto elemento de la tercera fila el valor 10. No olvidar que tanto filas como columnas se enumeran a partir de 0.
Bueno y para recorrer una matriz podemos usar igualmente un bucle. En este caso 2 for
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
matriz[i][j] = i % j;
}
}
PUNTEROS
El valor de todas las variales que manejamos en nuestros programas se almacenan en memoria y tienen una dirección. Un puntero es una variable especial que apunta a la dirección de memoria de una variable. El puntero tiene a su vez su propia dirección. Todas estas direcciones tienen un formato hexadecimal.
Los punteros son herramientas muy poderosas con muchas utilidades y enormes ventajas como veremos más adelante. A grandes rasgos, un puntero me permite desplazarme en la memoria, apuntar, redireccionar a ciertas variables, funciones, métodos, objetos sin necesidad de mover grandes bloques de datos, lo cual nos ahorra muchísimo el consumo de memoria en los programas.
Un puntero se debe declarar de acuerdo al tipo de dato al que apunta. Ejem:
int *var; //Un puntero llamado var que podra apuntar a cualquier variable de tipo entero. char *u;//puntero de tipo char Persona *per;//puntero de tipo persona
Para determinar,asignar la dirección de una variable en c++, se usa el operador & y para obtener el contenido de un puntero utilizamos el operador * Ejem:
int a;//entero int *b;//puntero a entero a = 20;//a tiene 20 b=&a;//asigno la direccion de a al puntero b cout << b << endl; // imprira la direccion de memoria de a; cout << *b;// imprimira 20, osea el contenido de a
Ahora analicemos las siguientes instrucciones y veamos como las variables van cambiando de valor en tiempo de ejecución:
#include <iostream>
using namespace std;
int main () {
int a=10;
int b=20;
int *p,*p2;//punteros de tipo entero
cout << "ANTES" << endl;
cout << "Variable a = " << a << endl;
cout << "Direccion de a = " << &a << endl << endl;
cout << "Variable b = " << b << endl;
cout << "Direccion de b = " << &b << endl << endl;
cout << "Contenido de p (BASURA)= " << *p << endl;//tiene basura al principio, podria inicializar con *p=0
cout << "Direccion de p = " << &p << endl << endl;
cout << "DESPUES" << endl;
a++;//incremento a
p= &a; //p ahora tiene a la direccion de a
cout << "Contenido de p = " << *p << endl;
p = &b;//p ahora tiene la direccion de b
*p +=20; // le sumo 20 al contenido de p, es decir, estoy incrementando el valor de b
cout << "Variable a = " << a << endl;
cout << "Variable b = " << b << endl << endl;
p=&a;//p ahora tiene la direccion de a
*p = a * 5;//contenido de p es igual al contenido de a * 5
cout << "Contenido de p = " << *p << endl;
cout << "Variable a = " << a << endl << endl;
cout << "Contenido de p2 (BASURA) = " << *p2 << endl;//tiene basura al principio, podria inicializar con *p2=0
cout << "Direccion de p2 = " << &p2 << endl << endl;
p2 = p;//el contenido de p es asignado al contenido de p2
*p2 +=15;//incremento 15 al contenido de p2
cout << "Contenido de p2 = " << *p2 << endl;//igual al contenido de p
p++;//p apunta a otra direccion de memoria,se desplaza 4 bytes en memoria
cout << "Contenido de p (BASURA) = " << *p << endl;//el contenido de esa nueva direccion
return 0;
}
La salida del programa:
ANTES
Variable a = 10
Direccion de a = 0×22ff74
Variable b = 2
Direccion de b = 0×22ff70
Contenido de p (BASURA)= -1017291943
Direccion de p = 0×22ff6c
DESPUES
Contenido de p = 11
Variable a = 11
Variable b = 40
Contenido de p = 55
Variable a = 55
Contenido de p2 (BASURA) = 2293680
Direccion de p2 = 0×22ff68
Contenido de p2 = 70
Contenido de p (BASURA) = 2293680
El contenido de p y p2 al principio es basura porque no tienen ningun valor asignado aun. Podriamos asignar el valor NULL a un puntero para luego posteriormente en algun problema que se me presente saber el estado del puntero y saber si contiene algo o no, así:
int *p= NULL;
ARITMÉTICA DE PUNTEROS
En las ultimas sentencias del programa anterior:
p++;
cout << *p;
Pueden visualizar que estoy incrementando el puntero p en 1. Esto quiere decir que el puntero se desplazara 4 bytes en memoria (en este caso por ser entero) y entonces apuntara a otra direccion. Por eso es que el nuevo contenido de p es basura o bueno el contenido de lo que tiene esa nueva direccion a la que apunta.
Supongamos que definir un entero y puntero de tipo char:
char c; char *d; d= &c;//asigno la direccion de c a d c='u';//asigno el valor u a mi variable c c--;//desplazo una posicion a c cout << *d;//
No Imprimira ‘u’ porque fijense que desplazé c en sentido negativo 1 byte (los char ocupan a 1 byte). Es decir, que si d estaba apuntado a una direccion como por ejemplo 0×22ff99, despues del c– estara apuntando a algo como 0×22ff98
Para tomar en cuenta cosas que no puedo hacer con punteros:
int a=15; int *p; double *q; void *r; p = a; //No puedo hacer esto porque estoy asignando una variable a un puntero y un puntero es una direccion. p = &50; // 50 es un valor constante en este caso y no una variable,por lo tanto no tiene direccion p = &(a+1); //una expresion no tiene direccion p = 30;//igual que el primer error, 30 es un entero. &a = p;//no puedo cambiar la direccion de una variable p = q;//p es puntero de tipo entero y q de tipo double
Un puntero de tipo void, es un puntero al cual le podemos asignar cualquier tipo de puntero. Por lo tanto si podriamos hacer esto:
r = p;
VECTORES Y PUNTEROS
Cuando declaramos un vector int v[10];El nombre del vector, o sea v, es un puntero al primer elemento del vector, es decir a v[0].Entonces como un vector es un puntero al primer elemento del mismo, también podríamos hacer aritmética de punteros con el vector.
(v+1) ;//apuntara a v[1]; *(v+5);//me refiero al contenido de v[5] //Y también a los punteros les puedo poner índices: int *p; //puntero de tipo entero p = &v[0];//p apunta a la direccion del vector v[0] o tambien a v. p = v p[8] = 80; //le asigno el valor 80 al puntero en la posicion 8, es decir a v[8]
VECTORES DINÁMICOS
Lo que vimos en el inicio de este post, son vectores estáticos, puesto que tienen una cantidad fija de memoria asignada y tamaño definido que no podemos modificarlo. Sin embargo, un vector podría tener una cantidad variable de datos, a este se le llama un vector dinámico.
Para usar vectores dinámicos necesitamos gestionar memoria dinámica. Si bien es cierto que es trae enormes ventajas, el hacer un mal uso de la memoria dinámica nos podría traer problemas desastrozos. Por eso es importante que que cuando creemos vectores dinámicos también liberemos la memoria utilizada. Obviamente eliminaremos la memoria utilizada cuando ya no necesitamos más usar, en este caso, un determinadao vector.
El operador new sirve para reservar memoria dinámica.
El operador delete se usa para liberar la memoria dinámica reservada con new.
Para liberar memoria de un array dinámico usamos delete[]
El espacio de memoria que hemos reservado con new tendrá vida hasta que finalize la ejecución del programa o cuando liberemos ese espacio con delete. Siempre es recomendable liberar memoria para posteriormente no tener problemas con excesivo consumo de memoria.
Un simple ejem:
#include <iostream>
using namespace std;
int main()
{
int *pv;
int dim;
cout << "Ingresa el tamanyo del vector" << endl;
cin >>dim;
pv = new int[dim];
for(int i=0;i<dim;i++){
pv[i] = i * i;
cout << pv[i] << " ";
}
delete[] pv;
return 0;
}
MATRICES Y PUNTEROS
Supongamos que se declaró una matriz int m[5][5]
Como dijimos anteriormente, el nombre o identificador de un vector es un puntero al primer elemento del vector. En el caso de matrices el nombre de la matriz, en este ejemplo v, es un puntero que apunta al primer elemento del primer vector de la matriz. Entonces m es un doble puntero.m es igual a &m[0] que es igual a la direccion de &m[0][0].
Si declaramos un puntero int *pm y luego igualamos pm = m, p ahora puede desplazarse por los valores de m.
*p;//contenido de m[0],el cual apunta al primer elemento de ese vector, es decir, m[0][0]
También puedo referirme a los contenidos con aritmética de punteros
*(p+1);//Desplazo una posicion a p,se refiere al contenido de m[1],el cual apunta al primer elemento de ese vector, es decir, m[1][0] *(*(p+1)+1);//desplazo una posición en el vector principal y este a su vez se desplaza una posicion en ese vector. es decir,me refiero al contenido de m[1][1]; p[2][4] = 20;//asigno el valor 20 a la posicion 2,4 de la matriz *(*(p+2)+4) = 20 // es lo mismo que la asignacion anterior *(pm[2]+4) = 20 // tambien los mismo //En conclusión: p[i][j] = *(*(p+i)+j) = *(pm[i]+j)
MATRICES DINÁMICAS
Para crear una matriz dinámica debemos de crear un doble puntero int **pm y samos al igual que los vectores el operador new para reservar memoria y delete para liberar.
Primero tenemos que crear el vector que contendrá a otros vectores especificando el numero de vectores que tendra este vector principal. Ejem:
pm = new int* [fils];//creo el vector de punteros principal
for(int i=0;i<fils;i++){
pm[i] = new int [cols];//para crear los vectores dentro del vector principal
}
Ahora sí vamos al grano y veamos un simple programa que crea una matriz dinámica, asigna valores, muestra el contenido de cada uno de los elementos los elementos así como sus direcciones de memoria.
También mostramos la matriz usando aritmética de punteros,ahí va:
#include <iostream>
using namespace std;
int main()
{
int **pm;//puntero a una matriz
int fils,cols;
cout << "Ingresa el nro de filas: ";
cin >>fils;
cout << endl;
cout << "Ingresa el nro de columnas: ";
cin >>cols;
pm = new int* [fils];
for(int i=0;i<fils;i++){
pm[i] = new int [cols];
}
cout << "Elementos de la Matriz con sus direcciones" << endl;
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
pm[i][j] = i + j;
cout << pm[i][j] << "--> ";
cout << &pm[i][j] << " ";
}
cout << endl;
}
cout << endl;
cout << "La matriz con aritmetica de punteros" << endl;
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
*(*(pm+i)+j) = i + j;//aritmetica de punteros
cout << *(*(pm+i)+j) << "-->";
cout << &pm[i][j] << " ";
}
cout << endl;
}
for(int i=0;i<fils;i++){
delete[] pm[i];//elimino cada vector de la matriz
}
delete[] pm;//elimino el vector principal
return 0;
}
La salida del programa:
Ingresa el nro de filas: 6
Ingresa el nro de columnas: 4
//Elementos de la Matriz con sus direcciones 0–> 0×3d2c90 1–> 0×3d2c94 2–> 0×3d2c98 3–> 0×3d2c9c 1–> 0×3d2ca8 2–> 0×3d2cac 3–> 0×3d2cb0 4–> 0×3d2cb4 2–> 0×3d2cc0 3–> 0×3d2cc4 4–> 0×3d2cc8 5–> 0×3d2ccc 3–> 0×3d3ab8 4–> 0×3d3abc 5–> 0×3d3ac0 6–> 0×3d3ac4 4–> 0×3d3ad0 5–> 0×3d3ad4 6–> 0×3d3ad8 7–> 0×3d3adc 5–> 0×3d3ae8 6–> 0×3d3aec 7–> 0×3d3af0 8–> 0×3d3af4 //La matriz con aritmetica de punteros 0–> 0×3d2c90 1–> 0×3d2c94 2–> 0×3d2c98 3–> 0×3d2c9c 1–> 0×3d2ca8 2–> 0×3d2cac 3–> 0×3d2cb0 4–> 0×3d2cb4 2–> 0×3d2cc0 3–> 0×3d2cc4 4–> 0×3d2cc8 5–> 0×3d2ccc 3–> 0×3d3ab8 4–> 0×3d3abc 5–> 0×3d3ac0 6–> 0×3d3ac4 4–> 0×3d3ad0 5–> 0×3d3ad4 6–> 0×3d3ad8 7–> 0×3d3adc
En mi caso esa son las direcciones de memoria. Bueno ya que hemos revisado conceptos básicos a continuación veamos la Clase Matriz, su definición, algunos métodos y su implementación.
Tail recursion
La recursividad es una técnica de programación que consiste en que una serie de instrucciones se repiten como una subtarea de la tarea principal, es decir, las funciones, procesos o rutinas se llaman a sí mismos cada vez que lo requieran y se ejecutan repetidas veces hasta que se satisface una condición específica.
Sin embargo, la recursividad en algunos casos, tiene un costo computacional alto, debido a las constantes llamadas a la misma función, rutina y muchas veces estas llamadas consumen demasiada memoria.
En algunos algoritmos recursivos, se puede implementar un caso de recursividad especial llamado Tail Recursion (recursividad por cola), la cual es una técnica para optimizar la recursividad eliminando las constantes llamadas recursivas. Tail recursion es cuando la llamada recursiva es la última instrucción de la función.
Sin embargo, las funciones tail recursive deben cumplir la condición que en la parte que realiza la llamada a la función, no debe existir ninguna otra sentencia.
Una ventaja de la recursividad por cola es que podemos evitar la sobrecarga de cada llamada a la función y nos evitamos el gasto de memoria de pila. Con una función tail recursive se puede evitar lo que se conoce como stack overflow, que ocurre cuando la pila de llamadas (call stack) consume mucha memoria.
Veamos esta técnica con un ejemplo muy conocido que es encontrar el factorial de un número.
Esta simple función obtiene el factorial de un número de la manera recursiva convencional: La explicación es sencilla, llamamos a la misma función fact hasta que n sea igual a 1, en ese momento la recursividad se detiene.
int fact_recursivo(int n)
{
if(n == 1)
return n;
else
return n * fact_recursivo(n-1);
}
int main() {
int num=0;
cout << "Ingresa un nro " << endl; cin >> num;
cout << "Su factorial es " << fact_recursivo(num);
return 0;
}
Digamos que ingresé 15, si compilamos el programa la función me daría 2004310016, lo cual es correcto, pero hay que tener en cuenta todas las llamadas recursivas que hizo la función fact_recursivo, es decir, la función tiene que calcular el factorial de 14 y este el fact de 13, y este el fact de 12… sucesivamente hasta 1. Tenemos un crecimiento del número de llamadas recursivas.
Ahora vamos a realizar la misma función usando tail recursion. En este caso no se necesita guardar un marco de pila para cada llamada recursiva, y el algoritmo se comporta como si fuera iterativo.
Para conseguir esto usamos un parámetro adicional que actúa como acumulador.
Esta sería la función factorial con tail recursion:
//function factorial con tail recursion
int fact_tail_sum(int n, int sum) {
if(n == 1) {
return sum;
} else {
return fact_tail_sum(n - 1, sum*n);
}
}
//para mantener la sintaxis original de como se llama a la función factorial
int fact_tail(int n) {
return fact_tail_sum(n, 1);
}
int main() {
int num=0;
cout << "Ingresa un nro " << endl; cin >> num;
cout << "Su factorial es " << fact_tail(num);
return 0;
}
El resultado igualmente sería 2004310016, pero el costo computacional baja drásticamente debido a que cuando se hace la llamada return fact_tail_sum(n – 1, sum*n) ambos parámetros son inmediatamente resueltos. Con esta llamada podemos calcular sin esperar una llamada a una función recursiva para que nos devuelva un valor.
En este caso el compilador reduce drásticamente el uso de la pila y la cantidad de información que debe ser almacenada, el valor de n y sum es independiente del número de llamadas recursivas.
Una función recursiva normal se puede convertir a tail recursive usando en la función original un parámetro adicional, usado para ir guardando un resultado de tal manera que la llamada recursiva ya no tiene una operación pendiente.
También se usa una función adicional para mantener la sintaxis de como llamamos normalmente a la función. En el caso del factorial, para seguir llamando a la función de la forma fact(n).
En conclusión:
• Una llamada es tail recursive (recursiva por cola) si no tiene que hacer nada más después de la llamada de retorno.
• Tail recursion es cuando la llamada recursiva es la última instrucción en la función.
• Usar tail recursion es muy ventajoso, porque la cantidad de información que debe ser almacenada durante el cálculo es independiente del número de llamadas recursivas.
• El compilador trata una función tail recursive como si fuera una función iterativa.
Quicksort en C++
Me pareció una buena manera de practicar programación y C++ y hacer una explicación que permite entender este algoritmo , bueno al menos eso intenté. Hace año y medio también publiqué unos ejemplos de ordenación en Haskell.
Voy a explicar el funcionamiento del quicksort brevemente y después veremos su implementación en C++.
Se tiene una array de n elementos, tomamos un valor del array como pibote(usualmente el primero), separamos los elementos menor a este pibote a laizquierda y los mayores a la derecha, es decir, dividimos el array en 2 subarrays.
Con estos subarrays se repite el mismo proceso de forma recursiva hasta que estos tengan más de 1 elemento. Por lo tanto la función quicksort quedaría de la siguiente manera:
void quicksort(int *array, int inicio, int fin)
{
int pivote;
if (inicio < fin) {
pivote = dividir(array, inicio, fin );
quicksort( array, inicio, pivote - 1 ); //ordeno la lista de los menores
quicksort( array, pivote + 1, fin ); //ordeno la lista de los mayores
}
}
La magia está en la función dividir que es la que voy a explicar a
continuación:
Empezamos creando o generando un array de n elementos, por ejemplo yo use la función rand() de c++ para generar aleatorios del 1 al 15, mi arreglo quedó así:
a[] = {8, 1, 5, 14, 4, 15, 12, 6, 2, 11, 10, 7, 9};
izq der
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
| 8 | 1 | 5 | 14 | 4 | 15 | 12 | 6 | 2 | 11 | 10 | 7 | 9 |
Tomamos como pibote el 8 y usamos 2 índices que me indiquen la posición del array:
Uno que vaya de izquierda a derecha buscando los elementos mayores al pibote. a[izq]
Y un índice que busque de derecha a izquierda los elementos menores al pibote. a[der]
El índice izquierdo irá aumentando en 1 mientras el array en la posición
izquierda sea menor o igual al pibote:
while ((izq < der) && (array[izq] <= pibote)){
izq++;
}
El índice derecho irá reduciéndose en 1 mientras el array en la posición
derecha sea mayor al pibote.
while (array[der] > pibote){
der--;
}
Si al final de estas 2 operaciones, el índice izquierdo es menor al derecho se intercambian las posiciones a[izq] con a[der], usando una variable temporal:
En este caso, en la primer recorrido el índice izquierdo encuentra al 14 (mayor al pibote) y el índice derecho al 7 (menor al pibote), y
se intercambian los índices:
| 8 | 1 | 5 | 14 | 4 | 15 | 12 | 6 | 2 | 11 | 10 | 7 | 9 |
| 8 | 1 | 5 | 7 | 4 | 15 | 12 | 6 | 2 | 11 | 10 | 14 | 9 |
Segundo recorrido: El índice izquierdo encuentra al 15 (mayor al
pibote) y el índice derecho al 2 (menor al pibote), se intercambian:
| 8 | 1 | 5 | 7 | 4 | 15 | 12 | 6 | 2 | 11 | 10 | 14 | 9 |
| 8 | 1 | 5 | 7 | 4 | 2 | 12 | 6 | 15 | 11 | 10 | 14 | 9 |
Tercer recorrido: El índice izquierdo encuentra al 12 (mayor al
pibote) y el índice derecho al 6 (menor al pibote), se intercambian:
| 8 | 1 | 5 | 7 | 4 | 2 | 12 | 6 | 15 | 11 | 10 | 14 | 9 |
| 8 | 1 | 5 | 7 | 4 | 2 | 6 | 12 | 15 | 11 | 10 | 14 | 9 |
Cuando los índices se juntan o se cruzan ponemos el pibote en el lugar que le corresponde en el array:
temp = array[der]; array[der] = array[inicio]; // el pibote está en el inicio del array array[inicio] = temp;
Se intercambian el 8 con el 6 y el array quedaría así:
| 6 | 1 | 5 | 7 | 4 | 2 | 8 | 12 | 15 | 11 | 10 | 14 | 9 |
Ahora la función quicksort se llamaría 2 veces recursivamente para los 2 subarray que tenemos:
quicksort(a,0,5) // el pibote está en la posición 6 quicksort(a,7,12) // el pibote está en la posición 6
Se repite el mismo proceso con este primer subarray quicksort(a, 0, 5)
El pibote es 6, se encuentra por la izquierda al 7 y por la derecha al 2. Se intercambian y como se cruzaron los índices movemos el pibote a su lugar:
| 6 | 1 | 5 | 7 | 4 | 2 |
| 6 | 1 | 5 | 2 | 4 | 7 |
| 4 | 1 | 5 | 2 | 6 | 7 |
Otra vez tenemos 2 subarrays. Entonces se vuelve a llamar la función
quicksort(a,0,3) // la posición del pibote es 4 quicksort(a,5,5) // No se ejecuta nada, el inicio no es menor al final
El mismo proceso. Se ejecutar quicksort (a, 0, 3). El pibote ahora es 4, se encuentra por el índice izquierdo al 5 y por el derecho a 2. Se intercambian y como se juntaron los índices se mueve el pivote a su lugar.
| 4 | 1 | 5 | 2 |
| 4 | 1 | 2 | 5 |
| 2 | 1 | 4 | 5 |
quicksort (a,0,1) // la posición del pibote es 2 quicksort (a,3, 3) // No se ejecuta nada, el inicio no es menor al final
Cuando se ejecuta quicksort (a, 0, 1) se intercambia los índices otra vez.
| 2 | 1 |
| 1 | 2 |
Ahora se llamaría a quicksort(a, 0,0), se divide en 2 elementos el subarray
y no hay nada más que hacer por que solo tienen 1 elemento.
Ahora se ejecuta el mismo proceso con el segundo subarray del array original. Quicksort (a, 7,12)
Se encuentra el 15 y el 9, se intercambian y como luego se juntan los índices, se coloca el pibote a su lugar:
| 12 | 15 | 11 | 10 | 14 | 9 |
| 12 | 9 | 11 | 10 | 14 | 15 |
| 10 | 9 | 11 | 12 | 14 | 15 |
Tenemos otros 2 subarrays y se vuelve a llamar la función quicksort
quicksort(a,7,10) // posición del pibote es 10 y la 1era 7 quicksort(a,11,12) //posición del pibote es 10 y la ultima 12
Se intercambian los índices y nos quedan otros 2 subarrays de 1 solo elemento entonces no se ejecuta nada.
| 10 | 9 | 11 |
| 9 | 10 | 11 |
Con el anterior subarray (14, 15) se llama a quicksort(a, 11,12).
| 14 | 15 |
Se divide en 2 elementos este subarray y no hay nada más que hacer por que los array que contienen al 14 y al 15 solo tienen 1 elemento.
De manera que el árbol recursivo de ordenación queda más o menos así:

Quick Sort
Complejidad computacional del Quicksort:
En el mejor de los casos tiene un costo de O(n*log (n)). Que es cuando el pibote siempre queda al medio del arreglo.

Quicksort Mejor caso
En el peor de los casos tiene un costo de O(n^2). Cuando el pibote siempre se inclina hacia a un lado, es decir, genera una array de sólo 1 elemento y una segunda con el resto de elementos.

Quicksort peor caso
En el caso promedio también tiene un costo de O(n*log (n)). Se produce cuando el pibote se inclina más hacia un lado y los 2 subarrays tienen distinto tamaño de elementos.

Quicksort caso promedio
Para calcular el tiempo de ejecución estoy usando la función clock() que determina el tiempo usado por el procesador. En este caso defino 3 variables ini, final y total.
ini=clock(); // Antes del quicksort: final = clock(); //Después que se ejecuta el quicksort total =((double)(final – ini)) / CLOCKS_PER_SEC; // El valor retornado por clock() debe ser dividido por el valor de la macro CLOCKS_PER_SEC
He leído en varios sitios de c++ que la función clock no tiene mucha precisión. Si alguien sabe un mejor método para calcular el tiempo de ejecución, algún comentario, sugerencia o aporte para optimizar al algoritmo, bienvenido.
Queda pendiente para otro post calcular con exactitud tiempos de ejecución e implementar el código del número de comparaciones e intercambios.
Bueno, aquí está la implementación del algoritmo en C++ disfrutenlo.
#include <iostream>
#include <time.h>
#include <stdio.h>
using namespace std;
//funcion para dividir el array y hacer los intercambios
int dividir (int *array, int inicio, int fin){
int izq;
int der;
int pibote;
int temp;
pibote = array[inicio];
izq = inicio;
der = fin;
//Mientras no se cruzen los índices
while (izq < der){
while (array[der] > pibote){
der--;
}
while ((izq < der) && (array[izq] <= pibote)){
izq++;
}
// Si todavia no se cruzan los indices seguimos intercambiando
if(izq < der){
temp= array[izq];
array[izq] = array[der];
array[der] = temp;
}
}
//Los indices ya se han cruzado, ponemos el pivote en el lugar que le corresponde
temp = array[der];
array[der] = array[inicio];
array[inicio] = temp;
//La nueva posición del pivote
return der;
}
//funcion recursiva para hacer el ordenamiento
void quicksort( int *array, int inicio, int fin)
{
int pivote;
if(inicio < fin){
pivote = dividir(array, inicio, fin );
quicksort( array, inicio, pivote - 1 );//ordeno la lista de los menores
quicksort( array, pivote + 1, fin );//ordeno la lista de los mayores
}
}
int main()
{
int const max = 100;
int tamanyo;
clock_t ini, final;
double total;
ini=clock();
cout << "Ingresa tamanyo " << endl;
cin >> tamanyo;
int a[tamanyo];
srand(time(0));//para que el rand no genere siempre los mismos numeros, utilizando la hora del sistema
for (int i = 0; i < tamanyo; i++){
a[i] = rand() % max;//rand para generar enteros aleatorios
}
cout << "Array antes de ordenarse: " << endl;
for (int i=0; i < tamanyo; i++){
cout << a[i] << " ";
}
cout << endl << endl;
quicksort(a, 0, tamanyo - 1 );
final=clock();
total=((double)(final - ini)) / CLOCKS_PER_SEC;
printf("Tiempo de ejecucion : %lf segundos \n",total);
cout << "Array ordenado " << endl;
for (int i=0; i < tamanyo; i++ ){
cout << a[i] << "-";
}
cout << endl << endl;
return 0;
}
Cuentos Chinos de Andrés Oppenheimer
Oppenheimer, es uno de los mejores periodistas de América Latina con muchas distinciones y premios internacionales. A mí me gusta su análisis crítico, constructivo siempre acompañado con un buen fundamento. Aquí en Perú se emite su programa, Oppenheimer Presenta, los domingos a las 8pm por Canal N.
He visto programas y entrevistas muy interesantes, muchas veces sus programas tienen bastante carga política, pero otras veces se habla mucho de trabajo, tecnología, oportunidades de mejora, estudios, cultura, problemas y educación en latinoamérica.
Una de las entrevistas que más disfrute, fue la que le hizo a Bill Gates (No fui, ni soy fan de este hombre por sus malas prácticas, acciones y actitudes malévolas) y no porque sea un hombre ligado a la computación, sino porque Bill, tiene una visión muy clara en cuanto al tema de innovación, investigación y desarrollo.
En la entrevista, dejó muy en claro, la relación inmensa que existe en EE.UU. entre empresa-universidad-mercado. Habló de las mejores universidades del mundo, de como se realizan exitosamente grandes proyectos de investigación, de la fuerte inversión por parte del gobierno americano en cuanto a desarrollo tecnológico-científico y también tocó el tema de como la India y China están haciendo enormes esfuerzos por ser las futuras potenciales mundiales.
Bueno, el libro que voy a comentar, Cuentos Chinos, tiene mucho que ver con el tema de educación, ciencia y tecnología. Básicamente, lo que plantea Oppenheimer es una seria de falsas creencias, ideas y modos de ver el desarrollo y crecimiento de un país que tienen muchas personas influyentes en latinoamérica. Por esas razones es que estamos distanciados de EE.UU, Europa y varios países de Asia en temas de educación, trabajo, calidad de vida, niveles de pobreza, infraestructura, salud, etc.
Entonces en varios capítulos habla concretamente de algunos países latinoamericanos, de sus presidentes, políticos y como sus ideas obsoletas, equivocadas han llevado a varios años de retraso. No hay que ser genio, para suponer que toco el tema de Venezuela-Hugo Chávez y todo el daño que este hombre le hace a la región y específicamente a Venezuela.
Un ejemplo pequeño que pone es que mientras en China recibieron con alfombra a un alto ejecutivo de McDonald’s para que esa enorme empresa se instale e invierta millones de dolares en China, Hugo Chávez amenaza violentamente a la misma empresa si intenta poner un solo pie en sus país, y seguramente ustedes ya conocen su discurso anti-americano.
Es decir, que mientras en China con esa inversión, se crean miles puestos de trabajo y su economía se sigue moviendo, Huguito hace que en su país muchas personas sigan pasando hambre, tan solo por un sentimiento nacionalista. Yo lo veo de este modo, es como que grandes empresas de tecnología (Google, Nokia, Apple, …) quieran instalarse en Perú, contratar a peruanos para desarrollar tecnología de punta y salga por ahí un idiota que diga que está desacuerdo porque es una multinacional y va a frenar a los emprendedores e innovadores en Perú.
Ese pensamiento, de buscar frenar a toda costa la inversión extranjera, se repite muchas veces en los países subdesarrollados y eso obviamente estanca el desarrollo y crecimiento económico, social.
Oppenheimer dedica un capítulo a Brasil, uno a Argentina y uno a México. Sinceramente estos capítulos no me gustaron mucho, no por las ideas planteadas, sino porque a pesar que son historias distintas, en sí, la misma idea se repite: Decisiones e ideas erróneas de presidentes y políticos de esos países. Muchas anécdotas y entrevistas, que sinceramente no quisiera mencionar.
Mejor, para mi gusto, son los otros capítulos, en ellos realmente es donde disfruto el libro de Oppenheimer, pues muestra el enorme crecimiento del continente asiático, como países muy pobres de Europa años atrás, ahora son los países más ricos del mundo.
China
El capítulo 2 del libro, es sumamente interesante por todo lo que cuenta Oppenheimer en su visita a China. Cómo desde el primer día que llegó se sentía un extraño en un país de extraterrestres por las gigantescas construcciones ultra modernas: rascacielos, aeropuertos, centros comerciales, etc.
En China, están los centros comerciales más grandes del mundo y Beijing es como Nueva York a inicios del siglo XX, una ciudad que crece cada minuto y se está convirtiendo en el centro del mundo.
Se dio cuenta al instante que estaba en un país en auge económico, creciendo en varios factores, lleno de tecnología y sobretodo mucho optimismo y deseos de superación por parte de sus pobladores. Según el Consejo Nacional de Inteligencia (CNI), centro de estudios a largo plazo de la CIA, China se está convirtiendo en una gran potencia mundial y será el principal rival económico, político y militar de EE.UU.
El CNI, también pronostica que las economías de China e India tendrán un fuerte impacto a nivel mundial y que las compañías multinacionales tendrán una orientación más asiática y menos occidental.
¿Por qué esta creciendo tanto China?
Entre otros factores, específicamente desde 1978, es que dieron la bienvenida al capitalismo y desde ese año no han parado de recibir inversiones extranjeras y nacionales. Por todas esas miles de inversiones, en China aproximadamente más de 250 millones de personas han dejado de ser pobres y pasado a la clase media y se estima que ya hay más de 10 mil ricos con fortunas que superan los 10 millones de dólares cada uno.
La nueva consigna de China es privatizar. En una de sus principales entrevistas a funcionarios chinos, Oppenheimer cuenta su conversación con Zhou Xi-an del Ministerio Nacional de Desarrollo y Reforma y le pregunta ¿Que porcentaje de la economía China esta en manos privadas? La respuesta no es sorprendente: “El estado chino actualmente controla menos del 30% del producto bruto nacional, mientras que un 60% está en manos privadas y un 10% en colectivas.
En China ya hay mas de 3,8 millones de empresas privadas que son las que mueven el desarrollo de la economía del país y gracias a ellas existen miles de puestos de trabajo que además no dejan de crecer rápidamente”.
Otra de las cosas que me sorprendió al leer este capítulo, es que la salud y la educación en China, ya han dejado de ser gratuitas, claro excepto para los becados. Pero en sí, la gente paga por esos servicios.
Y aquí me acordé de algo interesante que dijo Bill en la entrevista que les comente anteriormente. La educación no debería ser gratuita, pues una institución educativa al recaudar dinero podría financiar fuertes proyectos de investigación, mejorar su infraestructura y seguir creciendo, eso a largo plazo haría más grande aún a esa institución y los estudiantes tendrían una educación de mejor calidad.
Y aunque China sigue en un crecimiento económico acelerado, también se toca , en este capítulo, el tema de la democracia en China, la falta de libertad de prensa, la desigualdad y la censura. Por ejemplo, la censura en Internet, es imposible visitar varios sitios web que hablan de derechos humanos, igualdad, Tibet y cualquier otro tema que critique o hable algo en contra de China.
Según estimaciones, hay unos 30 mil informáticos trabajando a toda hora controlando el acceso a Internet en China. Si aparece alguna página web, artículo, noticia o algún contenido que hable tan solo algo mal de China, desaparece a los 5 minutos por arte de magia, realmente impresionante.
Irlanda: El milagro Irlandés
Capítulo 3. Cuenta Oppenheimer que cuando visitó Dublin, la capital de Irlanda, se sentía como en casa porque los irlandeses siempre han tenido mucho en común con los latinoamericanos. Bebedores, poetas, músicos y porsupuesto impuntuales, llenos de excusas, en fin rasgos típicos de los latinos.
Al igual que muchos países latinoamericanos Irlanda se ha caracterizado, a lo largo de los años, por sobresalir en las artes y letras más no en las ciencias, la tecnología o el mundo empresarial.
Pero, si los irlandeses han tenido mucho de los latinos, muchos se preguntan, ¿Cómo es que Irlanda en tan poco tiempo (12 años), ha pasado de ser un país pobre, típico agrícola, a ser uno de los países más ricos del mundo, con un gran crecimiento económico y lleno de tecnología de punta? Y no solo eso, sino un país con los mejores niveles de calidad de vida.
Uno de los puntos claves del éxito de Irlanda, es que antes estaba aislado de los países ricos de Europa, en contra del libre comercio y rechazando el capitalismo. Se dieron del cuenta del error que estaban cometiendo por años, hasta que se unieron a la Unión Europea.
Irlanda, en la década de los 90 tuvo uno de los mayores crecimientos económicos del mundo, con un promedio de 9% anual, disminuyo sus índices de pobreza a 5%. Irlanda pasó a convertirse en uno de los mayores centros tecnológicos de la industria farmacéutica y uno de los mayores exportadores de software a grandes empresas informáticas como Intel, Microsoft, Oracle e IBM.
En los últimos años, se instalaron unas 1100 empresas multinacionales. Gran parte del progreso de Irlanda, se debe al acuerdo que tuvieron empresarios y obreros para dar paso a una apertura económica. Los sindicatos en vez de reclamar y generar más problemas llegaron a un gran acuerdo de cooperación con empresarios y el gobierno.
Pero, ¿Por qué en tan poco tiempo Irlanda progresó? Además del acuerdo que hubo entre empresarios y trabajadores, se eliminó las trabas para la generación de nuevas empresas y al igual que muchos países desarrollados, las inversiones extranjeras fueron siempre bienvenidas.
En Irlanda para formar una empresa, bastan solo tres procedimientos legales que se realizan en aproximadamente 12 días. ¿Alguien sabe cuántos trámites hay que hacer y cuánto demora formar una empresa en los países latinos?.
Irlanda, se propuso como política de estado, atraer a las mejores empresas de computación del mundo e incentivar el estudio de carreras relacionadas a la ciencia y tecnología. Desde la década del 70, cuando Irlanda se unió a la Unión Europea ha destinado muchos recursos a las escuelas de ciencia e ingeniería creando nuevas universidades que se dediquen exclusivamente a ese tipo de carreras. El gobierno irlandés, apoyaba fuertemente las investigaciones científicas y técnicas con posibilidades comerciales.
En las escuelas irlandesas se incentiva mucho el estudio de carreras técnicas y el gobierno ha dado máxima prioridad a la educación en los últimos años, lo cual ha generado un gran impacto cultural. Los principales periódicos de Irlanda, se dedican a difundir noticias educativas, de, por ejemplo, los estudios y trabajos de niños en las escuelas, proyectos de investigación que se vienen desarrollando en las universidades, cosa que no pasa muy a menudo en países de latinoamérica.
A mi me da mucha pena ver como diarios de mi país, según ellos prestigiosos, tienen un alto porcentaje de noticias relacionadas a la farándula y cosas irrelevantes que solo ayudan a frenar el nivel educativo, tan solo por vender.
Oppenheimer, finalizando el capítulo del milagro irlandés, cita una frase de un académico Mexicano, Luis Rubio: “Irlanda demuestra que las limitantes no son económicas, sino mentales y políticas”. Es decir, que los irlandeses se dieron cuenta de sus graves errores e ideas obsoletas, que tenían el potencial para ser una gran nación, no les faltaba oportunidades de inversión o exportación, sino un cambio de mentalidad, reformas políticas y mucha más organización.
América Latina en el siglo del conocimiento
Este es el ultimo capitulo del libro, en mi opinión, el más importante por las conclusiones a las que llega el autor.
Para nadie es un secreto que las más grandes empresas de latinoamérica se dedican a las materias primas y que muchos empresarios y políticos latinos enfocan sus esfuerzos e inversiones en materias primas como el petróleo, gas, minerales, alimentos, etc.
En los países desarrollados, la clave de sus riquezas, es la generación de conocimiento, el capital intelectual, la fuerte investigación en educación, ciencia y tecnología. Estamos en una era donde lo agrícola e industrial no son los mayores generadores de riquezas. Oppenheimer pone ejemplos claros de que los países con mayores recursos naturales aún no salen de la pobreza y también menciona como Singapur con cero recursos naturales ha tenido un enorme progreso en los últimos años.
En latinoamérica, muchos todavía siguen pensando que los alimentos, los grandes minerales, en fin, la explotación de recursos naturales, es lo que nos va a traer el máximo progreso y desarrollo.
Una parte a destacar es como Holanda produce y exporta más flores que cualquier país latinoamericano. América latina debería ser el primer productor mundial de flores por sus grandes recursos, excelente clima, gran territorio, reservas de agua, etc. Sin embargo, Holanda, con mano de obra mucho más cara, menos recursos naturales, menos sol y teniendo un territorio más pequeño es el primer productor mundial de flores. Michael Porter, profesor de Harvard concluye: En la industria de las flores, lo que importa es la ingeniería genética, la capacidad de distribución y el marketing.
Como ejemplo de que el negocio de la materia prima no es lo que está triunfando, también se menciona a Starbucks, la empresa de locales de café más grande del mundo y cómo, por cada taza de café que se vende en EE.UU, apenas 3 centavos son para el productor del café latino.
En latinoamérica, los gobiernos centran sus esfuerzos en exportar productos agrícolas o materias primas en lugar de productos de mayor valor agregado.
Algo sumamente interesante de este capitulo es la historia de Nokia, el mayor fabricante de teléfonos celulares con origen en Finlandia, uno de los países más desarrollados del mundo, que años atrás exportaba materia prima y hoy por hoy se concentra en la tecnología.
Nokia, que se formó en el siglo pasado, pasó de ser una empresa maderera, después a fabricar muebles y varios diseños industriales, hasta dedicarse por completo a las telecomunicaciones y ahora al software, lo cual la ha convertido en una enorme empresa con miles de empleados, con millonarias ganancias anuales y es una de las marcas más caras que existen.
Otro ejemplo de empresas que pasaron del negocio de la materia prima a productos intangibles es Wipro, de la India, que se dedicaba a la venta de aceites de cocina y ahora es una de las mayores empresas de software de la India y del mundo. Hoy Wipro es una empresa innovadora con ingresos anuales de millones de dólares.
Como lo menciona en muchas partes del libro, en todos los países que han progresado y siguen creciendo, hay un alto porcentaje de estudiantes y profesionales dedicados a las ingenierías, la investigación y desarrollo.
En China, se siguen instalando empresas de telecomunicaciones, donde contratan a miles de ingenieros y técnicos al año para producir aparatos modernos y exportarlos a los países más ricos.
Otro de los puntos que se toca en este capítulo fue una pequeña comparativa entre las universidades latinoamericanas con las del resto del mundo. Según un ranking publicado por The Times, solo una universidad latina aparece en las 200 primeras del mundo, en el puesto 195, La UNAM.
Oppenheimer resalta de una manera como celebraron y publicaron ese logro los líderes de esa universidad por estar entre las mejores 200 del mundo, mientras que universidades europeas que se ubicaron entre las 60 primeras se sentían preocupadas por los resultados y empezaron a investigar fuertemente cómo mejorar el nivel educativo.
También menciona a la UBA, una prestigiosa universidad de Argentina y similar a lo que pasa con la UNAM, reciben millones de dólares de parte del gobierno y se niegan a ser evaluados por organizaciones internacionales porque según ellos, son tan prestigiosas y de tan alta calidad que no merecen ser evaluadas. Según este estudio, de 20 de las mejores universidades del mundo, 11 son de EE.UU, las demás de Europa, India, China, Japón y Australia.
Oppenheimer critica duramente, a las universidades latinas, por los bajos sueldos a los profesores, la falta de infraestructura y los obsoletos que son sus métodos de enseñanza.
Pero lo más importante y como lo mencioné al principio, es que la educación no debería ser gratuita, que eso da paso al retraso, puesto que se podría juntar grandes cantidades de dinero que sirvan para mejorar la calidad de las universidades y ayudar a estudiar a los que son muy pobres. Hay estudiantes, que realmente si pueden pagar su educación, pero que rechazan hacerlo porque el sistema así lo permite.
Estoy completamente de acuerdo con esto, la educación, no puede ser gratuita y se debería identificar a aquellos que pueden realizar un pago y aportar a la económia de las instituciones educativas. Con gran dinero recaudado, ¿Cuántos proyectos de cualquier tipo se podrían financiar?
Otro punto, imagínate que un amigo/familiar/colega se va a estudiar o trabajar al extranjero, si le preguntas a un latino que piensa sobre la partida de ese profesional, la respuesta típica es que se siente contento por el logro, pero pasa una segundo y te menciona la famosa “Fuga de cerebros”, idea que es completamente alejada de la realidad.
Los chinos e indios están creando ejércitos de ingenieros, técnicos y científicos totalmente competitivos en cualquier parte del mundo porque muchos de ellos están estudiando en las mejores universidades de EE.UU. y Europa, regresan a su país con más conocimiento, experiencia, invierten en sus países, crean empresas o sucursales, tienen más conexiones y relaciones con profesionales, empresarios de otros países y generan a su vez más crecimiento, conocimiento.
En los países latinos hay miles de graduados al año en artes, letras y faltan personas con formación científica, tecnológica. Otra de las diferencias con los países en crecimiento es su alta exigencia por aprender y hablar muy bien el inglés, idioma universal, indispensable para la comunicación, negociación con profesionales y empresas internacionales.
En una de las últimas partes de este capítulo, se menciona, porqué los estudiantes asiáticos estudian más que en cualquier otra parte del mundo, cómo no solo los chinos, sino casi todos los países de Asia están obsesionados por el estudio y los padres colaboran diariamente para que sus hijos refuercen sus estudios cotidianos con clases privadas y como les limitan ver la televisión a solo un par de horas a ala semana. De repente, para nosotros puede parecernos trágico esta situación por una cuestión cultural, pero para los niños asiáticos, en estos tiempos, el estudio forma parte del día a día durante muchas muchas horas.
Mis conclusiones
Ha sido divertida la lectura, por la forma en como Oppenheimer cuenta sus vivencias, anécdotas en sus viajes a muchas partes del mundo. Gran parte del libro son las entrevistas a personas y políticos influyentes de los países que lograron salir de la pobreza y también de los que están estancados.
Algunos opinan que no te puedes basar solamente en entrevistas para dar un fundamento acerca de cómo crece un país. Claro, pero yo pienso, que seguramente, estar en el mismo lugar, conversar con la gente, los líderes y ver con tus propios ojos todo lo que está pasando, te hace generar ciertas opiniones, como en este caso, que nuestros políticos latinos nos paran contando cuentos chinos.
Básicamente, Cuentos Chinos, te da un panorama global de lo que está pasando en el mundo, se habla mucho de la economía y no se profundiza mucho en ciertos temas como el de la educación, pero permite abrir una discusión al futuro de América Latina en sus factores más importantes: Reducción de la pobreza, el bienestar, calidad de vida, trabajo, creación de empresas innovadoras, como frenar la delincuencia, corrupción, como mejorar los niveles educativos, generar un clima de entusiasmo y superación constante de cada uno de los habitantes.
Particularmente, me hubiera gustado que Oppenheimer profundice más en el tema de la educación, que se dirija hasta el fondo del asunto. es decir, algo así como un reportaje en una universidad que ha pasado de ser una mas del montón a ser una institución exitosa.
Entrevistas a los estudiantes, ver en qué están trabajando, como lo hacen, para quien, que métodos usan, que empresas contratan a estudiantes de esa universidad, en que criterios se basan, el número de publicaciones internacionales y como esas publicaciones o investigaciones se han aplicado en un caso práctico, de la vida real. Quienes son los profesores de esas universidades, donde estudiaron, como enseñan, la relación con sus alumnos. Las escuelas más activas de esa universidad, donde están los estudiantes con mayores calificaciones, cuantos han generado empresas de servicios o intangibles. Los sueldos a los profesores, como son las prácticas profesionales, como califican a los estudiantes, si hay concursos internos, cuantas horas estudian al día, cuánto pagan por estudiar en esa universidad, los niveles económicos de los estudiantes, etc, etc, etc.
En fin, un reportaje extremo de un caso particular de institución educativa que paso de la mediocridad al éxito, algo así me gustaría leer algún día.
Realmente si me gustó el libro, por eso lo compartí en este breve resumen y lo recomiendo a todo aquel estudiante o profesional de latinoamérica que desea conocer un poco mas de lo que pasa en el resto del mundo y en que nos estamos quedando.
Install KDE 4.2 in debian
This is how looked my desktop some minutes after the kde 4.2 installation.
Runner, Leave note, Twitter, RSS, NowPlay, Dictionary, Clock -> Widgets in KDE 4.2Y
You need Debian unstable (Sid) and enable the experimental branches to install kde 4.2 version.Have in mind that this Debian branches come with lots of bugs and sometimes your system doesn’t respond as you like. Well, going to the whole point.
Add this to your /etc/apt/sources.list
deb http://ftp.de.debian.org/debian/ sid main
deb-src http://ftp.de.debian.org/debian/ sid main
Enable the experimental branch by adding this to your /etc/apt/sources.list
deb http://ftp.de.debian.org/debian/ experimental main
deb-src http://ftp.de.debian.org/debian/ experimental main
Update your system:
sudo apt-get update
Install the KDE packages from experimental with the command:
sudo aptitude -t experimental install kde4-minimal
kde4-minimal includes:
kdebase-runtime: Essential runtime components
kdebase-workspace: Desktop environment
kdebase: Core applications
If you want a complete installation, run:
sudo aptitude -t experimental install kde4
This command will install all packages of KDE 4.2 and could take some time. But, I recommend you install just the packages you need like: kdepim, kdemultimedia, kdenetwork, kdeplasma-addon, etc. Look at the Debian/KDE website for more information.
¡Enjoy your KDE Desktop!
Here are some screnshots of my desktop when playing with KDE 4.2.

Calendar, Folder view, Picture widgests in Plasma

Blue Curl Picture

Iceweasel

Dolphin

Kickoff Menu, Twitter widget, Folder View

Konsole, RSS, Runner, Dictionary
KDE 4.2 “The answer”
First of all: I always prefer and love KDE for his elegance, customization, easy-usage, great applications and now because is really interesting for programming. I use KDE in my everyday work: Konqueror (now Dolphin), konsole, k3b, Amarok, kate, Konversation, Kopete and other ones.
When KDE 4.0 was published many people criticize it very hard: A lot of bugs, different look and concept of desktop, different panels, new applications menu, widgets, etc, etc were some features that made most KDE users unhappy. However, KDE developers always said in the announcement page, blogs and mailing lists that KDE 4 is a work in progress and they will be working, coding hard to release new versions of KDE (4.1, 4.2… ) with a lot of improvements.
KDE 4.1 was much better than KDE 4.0(many bugs killed and improvements,more stability, applications,speed), but KDE 4.2, in my opinion, is a version, that give us a stable desktop with cool, interesting, features not only for users but also for developers. This KDE version was named: “The answer” because it minimize negative, destructive. comments and people who didn’t believe in the KDE community and team. I consider these people don’t know appreciate the innovation and great effort.
Congratulations to the all KDE Team for the hard-work they made. I am really impressed about how can you customize your desktop, add new features and the KDE 4 development way.
In this video you can see the KDE 4 presentation in Google Campus where Aaron Seigo a famous KDE hacker member of the core-team talk about the KDE 4 technology and how KDE innovation can make current desktops obsolete.
Nepomuk, Decibel, Plasma, Oxygen, Solid, Phonon, Akonadi are some parts of KDE 4 that introduce new behaviours and will make a big change in KDE. I am particularly interested in Plasma and Nepomuk for development and deciding in which project participate for this Google Summer of Code. But I need more reading and practicing about how these work. If you make a Gsoc proposal without researching, reading, practicing and talking to mentors you probably will fail. In this page, you can see the initial process to start your KDE 4 development environment.
In general KDE 4 has as main goals: Improve the desktop user experience, have better applications and development platform and make our desktop a central place to be more productive. That is my impression and for now on I will continue researching and folowing the KDE development process.
Blogging once again
Wow. Almost 4 months since my last post, sometimes it’s too hard to update my blog. I’m married, have a beautiful baby, study and work and believe me that is a little bit difficult to manage.
However, I continue exploring and learning new technologies about my passion: Open Source/Free Software.
Here are some things that happened in the last months.
I started learning Python and Django and I have to admit that since the first moment I tried them that I like it very much. On the other hand, I got tired about how slow rails is and the fucking error messages whenever you upgrade some gems and plugins. Conclusion: I switched to Python-Django for web development. Now I am re-writing an application, written in Rails, with Django.
My boss acquired a dedicated server hosting to run a lot of web services for his company use and proposed me to manage it. Now I am maintaining the server and it was fun to learn SSH and Fedora commands (I use Debian). SSH takes part of my everyday freelance work.
Last week, I finished the development of an e-commerce site for an American company called Misti International. I used the Magento e-commerce platform to develop it. Which at the beginning seems beautiful with a lot of cool features, but you need some patience to understand it deeply, because has a complex structure with too many folder and files and it is kind of difficult to customize it. But, I worked hard on this site and my client is really happy about it. I strongly recommend to learn PHP5 and take a look at the Zend Framework to learn more about the Magento code.
I installed KDE 4.2 in my Debian machine. (Here is a quick tutorial ). The only thing I want to say is: THANKS to all the KDE team for give us this great technology that is so well created and designed. But I will talk about KDE in other posts, because I am really interested in developing for KDE.
Google Summer of Code 2009 was announced and I am going to apply this year again. I already got in contact with a mentor to work in his proposal and received good feedback about it.
That’s it. Well , I forgot to mention that with Maritza and Celeste (wife and daughter) visited many tourist places here in Arequipa and had great moments. I love spend and enjoy time with my 2 girls.
Debian GNU/Linux 5.0 – Lenny released
Esta es la nota de publicación de esta nueva versión de este gran sistema operativo..
El Proyecto Debian se complace en anunciar la publicación oficial de la versión 5.0 de Debian GNU/Linux, nombre en clave lenny, tras 22 meses de desarrollo constante. Debian GNU/Linux es un sistema operativo libre que soporta un total de doce arquitecturas de procesador e incluye los entornos de escritorio KDE, GNOME, Xfce y LXDE. También ofrece compatibilidad con el estándar FHS v2.3 y software desarrollado para la versión 3.2 de LSB.
(para descargar Lenny ahora mismo, visita la página de descargas de Debian)
Debian GNU/Linux se ejecuta en ordenadores que van desde agendas hasta supercomputadoras, pasando por prácticamente cualquier sistema intermedio. Se da soporte a un total de doce arquitecturas: Sun SPARC (sparc), HP Alpha (alpha), Motorola/IBM PowerPC (powerpc), Intel IA-32 (i386), IA-64 (ia64), HP PA-RISC (hppa), MIPS (mips, mipsel), ARM (arm, armel), IBM S/390 (s390), y AMD64 de AMD y EM64T de Intel (amd64).
What I learned from Gsoc?
Google Summer of Code was a wonderful experience for me, I’ll never forget it. I finished my project and that gave me a lot of satisfaction. Getting opinions and feedback from the open source community was really special. In general, this is what I learned:
Community:
Improve my communication skills: Doing a project that involves other people means that you have to be clear in your words, be brief but efficient, and most important, make people understand what you are trying to say.
English:
I wrote a lot in English. (My project, IRC meetings, asking in the list, answering questions, etc). Although, English is not my first language I enjoyed having to be clear with my mentor, my organization and the Google group of summer of coders.
Technology
Ruby and Ruby on Rails: This Ruby user’s guide helped me a lot. I haven’t finished it, but I learned a lot about this great language (regular expressions, strings, arrays, iterators, control structures, OOP, classes, methods). And I also do a lot of programing with the ruby on rails framework. I learned how to manage and modified some plugins.
Actually working with views is not my favorite part of a project. However, CSS work at the end of the project was really fun. What CSS make is impressive.
Solr: I never ever have worked with a search server. Solr is just amazing – Full-Text Search Capabilities- . t I learned how to integrate Solr and the act_as_solr plugin to my Rails application.
Subversion: I learned how to work with this collaboration tool which I consider make you more productive. However, I had to deal with so many error messages, strange problems, I need to learn more commands apart from the common ones.
Vulnerability and Patch concepts.
I believe that be an expert in these fields takes his time. I never did a security system and didn’t work with a security team before. But I learned key concepts related to patches and vulnerabilities that helped me a lot to write the code. For example:
- Vulns classification (Location, Attack Type , Impact, Solution, Exploits).
- Vulns technical description and how to test a vulnerability.
- Patch severity (Critical, Severe,important, Minor, Pointless )
- Security Products: Nikto, Snort and Nessus.
- What CVE means.
- How to associate a vuln-patch with a Vendor/Product/Version
Many lessons learned in these months let me think what I did wrong and what I did well. I feel that I’m not always as productive as I might like to, my effort changes with the tasks I’m doing.
Once I read some Linus interview in which he said that if you are completely present in a situation and totally focused on something then that something *becomes* interesting, whatever it may be.
So, I think that making your job interesting and fun and get really concentrated on the problem are the keys to your project success.
I would like to participate for Gsoc 2009 again.
¡Happy Hacking!
La teoría del todo de Hawking.

Estoy contento, hace una semana compré mi espectacular libro “La teoría del todo” cuyo autor es uno de los científicos, en mi opinión, más grandes de todos los tiempos: Stephen Hawking.
Siempre he tenido dudas y mucho interés en leer sobre el origen, evolución del universo y del hombre. Leí varios artículos acerca de esto, pero siempre me quedaba con interrogantes por la diversidad de teorías. Sin embargo, creo que Hawking es uno de los investigadores científicos, que más ha hablado y escrito acerca del universo en los últimos años, por eso tenía una deuda conmigo mismo: Leer un libro del tío Hawking.
Me parece atrevido decir que Dios creo al universo y no tener algún sustento de ello. Bueno y yo que soy agnóstico con mucha más razón no puedo afirmar ni negar dicha teoría. Por eso los invito a leer este libro.
Estoy en el capítulo 5: El origen y el destino del universo. La lectura no ha sido muy difícil, aunque sinceramente ciertos párrafos los he leído un par de veces para entenderlos mejor porque contenían un vocabulario complejo. Quizá si fuera físico y no programador, sería mucho más sencillo.
Lo interesante del libro es que Hawking hace un resumen de ideas antiguas del universoy también habla de teorías de la gravedad y relatividad de Einstein y Newton, habla del big bang los agujeros negros, y nuestra época actual, bueno eso es hasta donde leí.
Voy a hacer un breve resumen del libro cuando acabe de leerlo. Se los recomiendo muchísimo, sumamente interesante.
¿Porqué perdemos el tiempo?
Es impresionante como los medios de comunicación le dan semejante relevancia a la captura de un personaje de televisión. Que por más famoso o popular que sea, es solo eso, un personaje.
Amo a mi país, y me da tristeza ver como la gente se llena la boca, todos los días, hablando de temas que no tienen absolutamente relación alguna con los problemas reales por los que atraviesa el país: Pobreza, Corrupción, educación, desempleo, etc.
¿Porqué perdemos el tiempo?, porqué no invertir ese tiempo en cosas más productivas. porqué no en vez de ver televisión y hablar de Magaly Medina o su programa mediocre, pensamos en aportar ese granito de arena para hacer un Perú mejor o hablar de proyectos educativos, de generación de empleos.
Porque no existen medios de comunicación peruanos que hablen de esos 3 puntos vitales hoy en día de los que tanto habla Oppenheimer: Ciencia, Tecnología y Educación. Cuando tengo la remota oportunidad de ver algo en TV o leer algún periódico siempre mantengo la esperanza viva de encontrar algo que eduque, algo interesante, pero siempre me quedo con las manos vacías y siempre me pregunto ¿porqué perdemos el tiempo?.
Cada vez estoy más convencido que la TV es una basura. Y si no fuera por el Discovery, Animal Planet, National Geography, History Channel y afines sería aún más basura.
No perdamos el tiempo, en lugar de ello, dediquemos tiempo a nuestras familias, mejor dedicarse a estudiar , trabajar, escribir o leer algo, en fin realizar algo educativo o que nos divierta. En fin, tantas cosas más productivas podríamos hacer.
Bueno es solo una opinión, ojalá a alguien le sirva o ayude algo.
De vuelta al GYM
Hip, hip urra. Después de un duro año sin tiempo para nada, regresé al gym. Ya era tiempo de un relax, salud mental y mucho ejercicio. Me da mucha satisfacción, aunque levantarse a las 6:30am todos los días si me trasnocho no va a ser fácil, pero le voy a poner huevos. Y lo bueno que tendré todos los días la companía de mi hermanita Nadia.
El plan a corto plazo es octubre, noviembre y diciembre, bien trabajados, para llegar en formar al verano 2009. Una buena alimentación, creatina para las fuerzas y energías, dormir al menos 6 horas diarias, un breve descanso en la tarde, investigaré respecto a que es lo mejor para mí.
Antes del ingreso
No pongo los nombres de las máquinas porque no me las se todas. Mi rutina es básica, en sí, para todos los ejercicios estoy haciendo 4 series de 12 c/u. Casi todo fue recomendación del chato. (El instructor)
Lunes: Pecho y espalda + Abdominales y pantorrillas.
Martes: Biceps y Triceps + Abdominales y pantorrillas.
Miércoles: Hombros y piernas + Abdominales y pantorrillas.
Continúa sucesivamente para el jueves, viernes y sábado. Porfavor si alguien tiene un consejo, sugerencia opinión será bienvenido.
A la salida
Rails 2.2 will be thread safe
Reading the rubyonrails blog I read that Rails 2.2 will be thread safe and that this hard work comes from a Google Summer of Coder. Josh Peek who will join the rails core.
This is a great advance for the framework, because many people were looking for merb for this rails weak, but this improvement will attract new developers to join the rails community.
Congratulations Josh.
Finishing my project for the Gsoc
These are the latest changes on the project. Before that, it is important to know all the work made before and the information we can submit for a patch.
Basic Information:
Dates(Disclosure, Creation)
Description
Classification
Severity
Ratings
Association with:
Products
Vulnerabilities
Files
Documentation Links
Credits (Authors, Companies)
User Interaction:
Comments:
Stats (views, percent complete).
Updates:
* Allow users select patches based on the watchlist.
* Patches were incorporated into the solr search engine.Main fields were indexed(id, title,short and technical description,dates,vendors and products). For the moment, the search for patches is separated from the search for vulnerabilities.
* An advanced search for patches (For severity, for classification, for products)
* When adding vulnerabilities to a patch, users can auto complete vulns based on the their identifiers..
* I made some CSS work changing the style for the show page on the patches, that way users can distinguish immediately an information page for a patch from a vulnerability.
* However I will need one or maybe two more days to finish all my presentation styles and user alerts when a patch is released and goes into the portal.
I am really glad to see that everything is coming fine and all work made in these months is having sense for me.
Passed GSoC Mid-Term Evaluation
I am really happy. I passed the Google Summer of Code 2008 mid-term evaluation! This means that I get to finish my project patch management portal. I want to thank Dave, my mentor for give me the opportunity to continue working on the project.
This is a quick report of all the work made until this point.
May 26 – June 1: Tables used on the project were created and integrated into the OSVDB schema. Use cases were defined.
June 1-18:
I created an MVC to manage patches. So the base_patches_controller.rb allow us to manage all the actions related to patch submission. I was testing the code and submitting my first patches and all their relevant information and things are going quite well.
So, principal functions were created. You can submit general information about a patch, also associate it with a vendor/product/version, associate it with an author, vulnerability and add a patch rating.
These are the principal actions (methods). However, more actions will be created this week, specially for ratings and vulnerabilities.
General: create edit update destroy
Ratings: addpatchrating updatepatchrating
Products: addvendor showversions
Credits: adduthor update_author deleteauth
Vulnerabilities addvuln deletevuln
I also created and MVC for base_patch_rating_levels. So, it is possible to CRUD patch_rating_levels.
I just worked in models creating maping objects (Has many, belongs_to, has_and_belongs_to), but didn’t work on validations yet. I expect to work in views at the end of this week. (This is HTML and CSS work).
June 18-30: We have the core of Patch Management Portal written. Patches are linked to vulnerabilities and shown in the home page.
-Main views for patches were created.
-Optimization in the database tables.(indexes)
-Active and fragmet caching in some pages and methods.And a patch sweeper created.
-Moderator nav modified to submit a patch and to C,R,U,D rating levels with Active scaffold.
-Home page modified to show “Latest OSVDB Patches” (similar functionality to vulns) with Printer,normal and popup views.
-Validations added to models.
July 01-07: Working on file submission.
This is really important because users can submit a file for everybody to download. So, it is more easy for mostly users to apply the patch just by reading the short-technical description and downloading the file(code).
my my
July 13: File Submission finished. Users can add/delete files related to patches.
You can see my work in progress here in the project wiki and also take a look at my mid-term evaluation. Later on I will be publishing the source code.
I expect to finish the project successfully and be part of the development team.
Rdoc – Generating documentation for ruby and rails
Rdoc is a program for creating documentation for ruby source code. Rdoc generates HTML documentation, using syntactic information from the source and text in comment blocks.
You can check documentation about ruby libraries if you have ruby property installed by running the ri command. For example, if we want to know what the capitalize method does, just type in your terminal:
ri String.capitalize ---------------------------------------------------String#capitalize str.capitalize => new_str -------------------------------------------------------------------- Returns a copy of str with the first character converted to uppercase and the remainder to lowercase "hello".capitalize #=> "Hello" "HELLO".capitalize #=> "Hello" "123ABC".capitalize #=> "123abc"
Rdoc is very useful to look for information about programs, methods and examples.
If you want to see the rails api documentation type in your terminal: gem server and then go to your browser at the url http://localhost:8808
You will get an HTML page “RubyGems Documentation Index” with a summary of all ruby gems installed on your system.
Click on the gem you want to see the documentation and you will see an HTML page with 3 columns: (Files, Classes, Methods) and everything documented in detail.
If you installed rails with rubygems you can access the rails api.
Also the rake app:doc command creates the HTML documentation for your Rails project and stores this documentation in the doc/app directory.
Run the file doc/app/index.html and you will see of the documentation of your rails project.
Query analyzer for Rails
I found an interesting and very useful plugin for rails called Query analyzer that allows us check for tables not optimized in our database. It really helps a lot to optimize tables and queries and put indexes on our conditions columns and primary/foreign keys. Sometimes, we forget to do things so simple like this. Here is a great explanation of what the plugin does.
How to use it?
Just install the plugin with:
script/plugin install http://svn.nfectio.us/plugins/query_analyzer
and then check your logs. You can see your console as well. Once you have the plugin installed you will see all queries your application does and how they are currently managed.
For example:
I have a table called form_help_divs. It is a table to show some messages in forms around my application. I usually make a call to the database to get a form_help_div record. The query generated is like this:
SELECT * FROM `form_help_divs` WHERE (`form_help_divs`.`name` = 'patch_vuln') LIMIT 1
So in theory. The query should check for only one row, but that is not true because the name column doesn’t have an index. And how I realized that?. I just checked my log and saw this:
Analyzing FormHelpDiv Load select_type | key_len | type | Extra | id | possible_keys | rows | table | ref | key --------------------------------------------------------------------------------------------------- SIMPLE | | ALL | Using where | 1 | | 33 | form_help_divs | |
As you see the query is looking for all records (in this case 33) in the database searching for the name ‘patch_vuln’. That is not good guys. Let us optimize our queries by adding and index to that table. We can add it by hand in our mysql interface, but is better to create migrations.
class AddFormHelpDivIndexes < ActiveRecord::Migration def self.up add_index :form_help_divs, :name end def self.down remove_index :form_help_divs, :name end end
Type rake db:migrate in your console and your migration will be executed.Now run your application again and you will see the difference in your logs and console. This is the result:
FormHelpDiv Load (0.001585) SELECT * FROM `form_help_divs` WHERE (`form_help_divs`.`name` = 'patch_vuln') LIMIT 1 Analyzing FormHelpDiv Load select_type | key_len | type | Extra | id | possible_keys | rows |table | ref | key ------------------------------------------------------------------------------------------------- SIMPLE |768|ref|Using where|1|name,index_form_help_divs_on_name|1|form_help_divs | const | name
¡What a big difference!. Now the query is looking just for one row in the database and that will increase the query speed significantly.
There are other ways to make our applications running faster with rails. Adding indexes is one of those ways and let us gain a lot of optimization specially if we are working with big applications and tables with so many records.
I strongly recommend you to optimize tables and use the query analyzer.
Rake
Rake is a ruby program that builds other ruby programs. Each time you execute rake, it knows how to build those programs by reading a file called Rakefile which has a set of tasks. Those tasks allows us to do some project needs in a very easy and efficient way.
When you generate a rails project you automatically get a Rakefile and it is in the root of your project.
You can see all rake tasks and their descriptions by running a simple command in your main directory:
rake –tasks
And this should be shown:
rake backgroundrb:remove # Remove backgroundrb from your rails …
rake backgroundrb:restart # Restart backgroundrb server (default…
rake backgroundrb:setup # Setup backgroundrb in your rails app…
rake backgroundrb:start # Start backgroundrb server (default v…
rake backgroundrb:stop # Stop backgroundrb server (default va…
rake db:abort_if_pending_migrations # Raises an error if there are pending…
rake db:charset # Retrieves the charset for the curren…
rake db:collation # Retrieves the collation for the curr…
rake db:create # Create the database defined in confi…
rake db:create:all # Create all the local databases defin…
rake db:drop # Drops the database for the current R…
rake db:drop:all # Drops all the local databases define…
rake db:fixtures:identify # Search for a fixture given a LABEL o…
rake db:fixtures:load # Load fixtures into the current envir…
rake db:migrate # Migrate the database through scripts…
rake db:migrate:redo # Rollbacks the database one migration…
rake db:migrate:reset # Resets your database using your migr…
rake db:reset # Drops and recreates the database fro…
rake db:rollback # Rolls the schema back to the previou…
rake db:schema:dump # Create a db/schema.rb file that can …
rake db:schema:load # Load a schema.rb file into the database
rake db:sessions:clear # Clear the sessions table
rake db:sessions:create # Creates a sessions migration for use…
rake db:structure:dump # Dump the database structure to a SQL…
rake db:test:clone # Recreate the test database from the …
rake db:test:clone_structure # Recreate the test databases from the…
rake db:test:prepare # Prepare the test database and load t…
rake db:test:purge # Empty the test database
rake db:version # Retrieves the current schema version…
rake doc:app # Build the app HTML Files
rake doc:clobber_app # Remove rdoc products
rake doc:clobber_plugins # Remove plugin documentation
rake doc:clobber_rails # Remove rdoc products
rake doc:plugins # Generate documentation for all insta…
rake doc:rails # Build the rails HTML Files
rake doc:reapp # Force a rebuild of the RDOC files
rake doc:rerails # Force a rebuild of the RDOC files
rake log:clear # Truncates all *.log files in log/ to…
rake notes # Enumerate all annotations
rake notes:fixme # Enumerate all FIXME annotations
rake notes:optimize # Enumerate all OPTIMIZE annotations
rake notes:todo # Enumerate all TODO annotations
rake rails:freeze:edge # Lock to latest Edge Rails or a speci…
rake rails:freeze:gems # Lock this application to the current…
rake rails:unfreeze # Unlock this application from freeze …
rake rails:update # Update both configs, scripts and pub…
rake rails:update:configs # Update config/boot.rb from your curr…
rake rails:update:javascripts # Update your javascripts from your cu…
rake rails:update:scripts # Add new scripts to the application s…
rake remove_simple_captcha_files # Remove unuseful captcha images and s…
rake routes # Print out all defined routes in matc…
rake secret # Generate a crytographically secure s…
rake solr:destroy_index # Remove Solr index
rake solr:start # Starts Solr.
rake solr:stop # Stops Solr.
rake stats # Report code statistics (KLOCs, etc) …
rake test # Test all units and functionals
rake test:functionals # Run tests for functionalsdb:test:pre…
rake test:integration # Run tests for integrationdb:test:pre…
rake test:plugins # Run tests for pluginsenvironment / R…
rake test:recent # Run tests for recentdb:test:prepare …
rake test:uncommitted # Run tests for uncommitteddb:test:pre…
rake test:units # Run tests for unitsdb:test:prepare /…
rake tmp:cache:clear # Clears all files and directories in …
rake tmp:clear # Clear session, cache, and socket fil…
rake tmp:create # Creates tmp directories for sessions…
rake tmp:pids:clear # Clears all files in tmp/pids
rake tmp:sessions:clear # Clears all files in tmp/sessions
rake tmp:sockets:clear # Clears all files in tmp/sockets
rake uml:schema # Generate an XMI db/schema.xml file d…
Those rake tasks will be used many times when developing your rails application.
For example there is an interesting task rake stats which generates detailed statistics about your application code and provides a dashboard of information. This is what I get:
+----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 6080 | 5241 | 54 | 369 | 6 | 12 | | Helpers | 552 | 501 | 0 | 25 | 0 | 18 | | Models | 3855 | 3274 | 157 | 326 | 2 | 8 | | Libraries | 3068 | 2806 | 18 | 71 | 3 | 37 | | APIs | 9 | 9 | 1 | 0 | 0 | 0 | | Components | 0 | 0 | 0 | 0 | 0 | 0 | | Integration tests | 0 | 0 | 0 | 0 | 0 | 0 | | Functional tests | 1261 | 942 | 97 | 200 | 2 | 2 | | Unit tests | 1246 | 884 | 117 | 129 | 1 | 4 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 16071 | 13657 | 444 | 1120 | 2 | 10 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 11831 Test LOC: 1826 Code to Test Ratio: 1:0.2
Many other rake commands are very useful for rails development.
Summer of Code started
Hey. Today Summer of Code started and I feel pretty well at this point.
I had a good chat with my mentor David Shettler (Leader software developer of the OSVDB team). I consider him a complete professional and better mentor because of his support, humility and his advices.
I remember perfectly the first words he told me today: “Oh Ronny. Fun starts today”.
We discuss many things , mainly about the current OSVDB database schema wich is really big. This let me get a better understanding of the project and making an initial design of my work and use cases.
I got subversion access and I am now looking the source code and running this great software project (OSVDB 2.0). This is a real web application written in ruby on rails used to manage vulnerabilities and all the osvdb website. It is just amazing.
I really enjoyed this day and think this will be a great experience for me and other summer of coders. I am going to inform of my work progress in the OSVDB gsoc 2008 wiki.
Good luck to everyone. Enjoy the summer.
Hpricot installation problem
Hpricot is a fast, flexible HTML parser written in C.Hpricot can be handy for reading broken XML files, since many of the same techniques can be used. If a quote is missing, Hpricot tries to figure it out.
I was really having problems to install hpricot, the newest version is 0.6. Whenever I executed
$ sudo gem install hpricot Select which gem to install for your platform (arm-linux) 1. hpricot 0.6 (mswin32) 2. hpricot 0.6 (jruby) 3. hpricot 0.6 (ruby) 4. hpricot 0.5 (ruby) 5. hpricot 0.5 (mswin32) 6. Skip this gem 7. Cancel installation > 3 I received the following message: Building native extensions. This could take a while... ERROR: While executing gem ... (Gem::Installer::ExtensionBuildError) ERROR: Failed to build gem native extension. I Typed this to see what is going on: ruby extconf.rb install hpricot and the error continued. extconf.rb:1:in `require': no such file to load -- mkmf (LoadError) from extconf.rb:1 Gem files will remain installed in /var/lib/gems/1.8/gems/hpricot-0.6 for inspection. Results logged to /var/lib/gems/1.8/gems/hpricot-0.6/ext/hpricot_scan/gem_make.out $
Googling for a while I found a good solution in the hpricot project wiki. The main problem is that I had ruby 1.8 and 1.9 installed, Ruby 1.8.5 was the version I was using, but I didn’t have development libraries installed. So, gem couldn’t install correctly hpricot.
You can check your version for ruby, rails, gem and everything else by typing -m after the program name.
$ ruby -v ruby 1.8.5 (2006-08-25) [i486-linux] $ gem -v 1.1.1
The solution:
There is a file we need called mkmf.rb that has connection with ruby libraries, so let’s search it.
$ auto-apt search mkmf.rb usr/lib/ruby/1.9/mkmf.rb devel/ruby1.9-dev As you can see, we don't have it in ruby1.8 directory, so let us install ruby1.8 development libraries. $ sudo apt-get install ruby1.8-dev and now, we have the mkmf.rb in ruby1.8 $ auto-apt search mkmf.rb usr/lib/ruby/1.9/mkmf.rb devel/ruby1.9-dev usr/lib/ruby/1.8/mkmf.rb devel/ruby1.8-dev
There is no documentation in the wiki, but I assume that you have to install another gem called mechanize which has as a dependency hpricot. By doing:
$ sudo gem install mechanize Install required dependency hpricot? [Yn] Select which gem to install for your platform (arm-linux) 1. hpricot 0.6 (mswin32) 2. hpricot 0.6 (jruby) 3. hpricot 0.6 (ruby) 4. hpricot 0.6 (jruby) 5. hpricot 0.6 (ruby) 6. hpricot 0.6 (mswin32) 7. Skip this gem 8. Cancel installation > 3 Building native extensions. This could take a while... Successfully installed mechanize-0.6.9 Successfully installed hpricot-0.6 Installing ri documentation for mechanize-0.6.9... Installing ri documentation for hpricot-0.6... Installing RDoc documentation for mechanize-0.6.9... Installing RDoc documentation for hpricot-0.6...
you will get hpricot successfully installed and now you can use this great gem.









