viernes, 29 de octubre de 2010

Persistencia Básica en Java

Cuando abordamos el desarrollo de una aplicación en Java, uno de los primeros requerimientos que debemos resolver es la integración con una base de datos para guardar, actualizar y recuperar la información que utiliza nuestra aplicación.

Se llama “persistencia” de los objetos a su capacidad para guardarse y recuperarse desde un medio de almacenamiento. La persistencia en Base de Datos relacionales se suele implementar mediante el desarrollo de funcionalidad específica utilizando la tecnología JDBC o mediante frameworks que automatizan el proceso a partir de mapeos (conocidos como Object Relational Mapping, ORM) como es el caso de Hibernate.

Si bien existen más alternativas de persistencia, en este tutorial aboraremos estas dos alternativas ya que son las más frecuentemente utilizadas.

Los código fuente que se muestran a continuación son fragmentos del Zip que se puede encontrar en PersistenciaBasicaEnJava.zip

JDBC

Java DataBase Connectivity es el API de Java que define cómo una aplicación cliente accederá a una base de datos, independientemente del motor de base de datos al que accedamos.

A continuación mostramos un ejemplo del código necesario para insertar un elemento y hacer una consulta:


// Cargar el driver

Class.forName(jdbcDriver);

// Crear una conexión

Connection con = DriverManager.getConnection(jdbcUrl, userName,

password);

// Crear un Statement para obtener el máximo id

Statement stmt = con.createStatement();

ResultSet rs = stmt.executeQuery("SELECT MAX(id) FROM " + schema

+ "DEMO_QUERIES");

int id = 0;

if (rs.next()) {

id = rs.getInt(1) + 1;

}

rs.close();

stmt.close();

// Crear un PreparedStatement para insert

PreparedStatement prepareInsert = con.prepareStatement(

"INSERT INTO " + schema + "DEMO_QUERIES (id, nombre, fecha)”

+ “VALUES (?, ?, ?)");

// Completar sus atributos

int i = 1;

prepareInsert.setInt(i++, id);

prepareInsert.setString(i++, "Ejemplo JDBC");

prepareInsert.setDate(i++, new Date((new Date()).getTime()));

// Ejecutar el insert

prepareInsert.executeUpdate();

prepareInsert.close();

// Crear un PreparedStatement para select

PreparedStatement prepareSelect = con

.prepareStatement("SELECT id, nombre, fecha FROM " + schema

+ "DEMO_QUERIES WHERE fecha < ?");

// Completar sus atributos

prepareSelect.setDate(1, new Date((new java.util.Date()).getTime()

+ DAY_IN_MILLIS));

// Ejecutar la select

rs = prepareSelect.executeQuery();

while (rs.next()) {

System.out.println("Id = " + rs.getInt(1) + " - nombre = "

+ rs.getString(2) + " - fecha = " + rs.getDate(3) + "");

}

rs.close();

prepareSelect.close();


Como vemos el código es esencialmente simple aunque si tenemos un número amplio de clases y problemáticas de maestro/detalle (como pueden ser facturas con items) o soporte multi-base de datos la implementación puede volverse muy difícil de mantener.

Una mejora a la mantenibilidad es utilizar el patrón de diseño Data Access Object (DAO, Objeto de Acceso a Datos ver http://es.wikipedia.org/wiki/Data_Access_Object) donde básicamente definimos una interfaz y una clase que concentren toda la funcionalidad de creación, lectura, actualización y borrado en la base de datos.

Hibernate

En Hibernate esta misma funcionalidad se simplifica a:


Entidad entidad = new Entidad();

entidad.setId(id);

entidad.setNombre("Ejemplo Hibernate\n");


Session session = sessionFactory.getCurrentSession();

session.beginTransaction();

session.save(entidad);

session.getTransaction().commit();


O para obtener el listado:


Session session = sessionFactory.getCurrentSession();

session.beginTransaction();

Query q = session

.createQuery("from e in class com.persistencia.hibernate.Entidad where e.fecha < :fecha");

// se inyecta el valor del parámetro utilizando el nombre

q.setParameter("fecha", new java.sql.Date(fecha.getTime()));

List entidades = q.list();


¿¡¿Pero cómo funciona la magia?!? Bueno, Entidad es un POJO (Plain Old Java Object), es decir una simple clase Java que tiene métodos get y set para cada uno de los atributos; así que ahí no está la magia.

Es en el fichero de mapeo donde ponemos la magia, que tampoco es tan complicada:


<hibernate-mapping>

<class name="com.hemasoft.demos.queries.hibernate.Entidad"

table="DEMO_QUERIES">

<id name="id" type="java.lang.Integer" />

<property name="nombre" />

<property name="fecha" type="java.sql.Date" />

class>

hibernate-mapping>


Este fichero de mapeo lo declaramos en hibernate.cfg.xml junto a la información de acceso a la base de datos de la siguiente forma:


<hibernate-configuration>


<session-factory>


<property name="connection.driver_class">oracle.jdbc.driver.OracleDriverproperty>

<property name="connection.url">jdbc:oracle:thin:@192.168.1.20:1521:qemuproperty>

<property name="connection.username">testproperty>

<property name="connection.password">testproperty>


<property name="connection.pool_size">1property>


<property name="dialect">org.hibernate.dialect.Oracle9Dialectproperty>


<mapping resource="com/hemasoft/demos/queries/hibernate/Entidad.hbm.xml"/>


session-factory>


hibernate-configuration>


Creo que el fichero es lo suficientemente intuitivo como para no necesitar mayores explicaciones.

Los costes de aprendizaje de este framework en términos de tiempo dedicado se van recompensando desde el primer día con el ahorro en tiempo de desarrollo y depuración de código JDBC. Incluso, a partir de la versión 3 de Hibernate su configuración se simplifica notablemente mediante Anotaciones (recomiendo ver http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#entity-mapping).

Además, Hibernate nos proporciona grandes beneficios como:

  • soporte a múltiples motores de base de datos

  • bajo acoplamiento entre negocio y persistencia, ya que su diseño está orientado a objetos así como el soporte a consultas y operaciones (HQL).

  • desarrollo robusto, ya que el framework ha madurado tras años de uso en decenas de miles de proyectos

  • optimizado, ya que el SQL generado contiene optimizaciones específicas para cada motor de base de datos mediante componentes especializados llamados dialectos.

  • rápido y completo, ya que con la funcionalidad estándar de Hibernate podremos cubrir el 80 - 90% de la persistencia de nuestra aplicación

    Todo esto nos permite centrar nuestros esfuerzos en desarrollar la funcionalidad de la aplicación.

viernes, 8 de octubre de 2010

Ejemplo sencillo JTREE

En este tutorial vamos a ver un ejemplo sencillo de cómo usar el JTree en java.


El JTree es el componente java visual (como los botoncitos, listas, menús, etc) que nos permite visualizar un árbol. En él podemos ver el típico árbol de datos en el que podemos abrir cada uno de los nodos para ver qué tiene dentro, cerrarlos, etc. Similar al árbol de directorios que nos muestran algunas aplicaciones para elegir un fichero.


Aunque el JTree es muy configurable, en este tutorial sólo veremos como usarlo de una forma sencilla, usando las clases por defecto que java nos ofrece para ello.



Clases Java implicadas


Como en casi todos los componentes visuales de java, hay dos clases importantes implicadas.


Por un lado tenemos "la vista", que es la clase java que se ve. Esta clase es el JTree y es lo que se ve en la pantalla, en nuestra ventana.


Por otro lado tenemos el "modelo de datos". Esta clase de java puede ser cualquier clase que implemente la interface TreeModel, pero java nos ofrece ya implementada la clase DefaultTreeModel. Esta clase es la que contiene los datos que queremos visualizar en "la vista". Contiene los datos que visualizaremos en el JTree.


¿Qué datos admite el DefaultTreeModel?. Puesto que vamos a hacer un árbol, admite datos que se puedan asociar entre sí como padres e hijos. No valen datos cualesquiera. Esos datos deben implementar la interface TreeNode. Cualquier clase que implemente esta interface, tendrá métodos para interrogarle sobre quién es su padre, si tiene hijos, etc. Estos métodos será los que acabe usando JTree para saber qué debe pintar, quién es hijo de quién y quién es padre de quién.


Existe otro tipo de dato también importante, el MutableTreeNode. Este es igual que el anterior, pero además tiene métodos para modificar las asociaciones entre padres e hijos. Permite añadir nuevos hiijos a los padres, cambiar el padre de los hijos y cualquier otro tipo de indecencia que se nos ocurra. Si nuestro árbol va a cambiar sobre la marcha, nos interesa usar datos (nodos) que implementen esta interface.


Java nuevamente nos ofrece una clase que ya implementa MutableTreeNode y por tanto tiene todos los métodos necesarios para saber quién es hijo de quién y los métodos necesarios para cambiar estas asociaciones. Esta clase es DefaultMutableTreeNode. Tiene además un método intereseante, que es setUserObject(). Este método nos permite guardar dentro la información que queramos. Esta información será nuestro dato real, lo que realmente nos interesa. DefaultMutableTreeNode únicamente nos ahorrará escribir el código necesario para mantener asociaciones entre padres e hijos, además de hacer de almacén de nuestro dato.


Código de ejemplo


Vamos a ir haciendo código para ver cómo usar todas estas clases. Trataremos de construir y construiremos el árbol del dibujo


imagen jtree


Primero instanciamos nuestro modelo de datos, el DefaultTreeModel y la parte visual, el JTree. Metemos el primero dentro del segundo.


La clase DefaultTreeModel necesita en su constructor el nodo raíz del árbol, es decir, el dato que hace de padre de todos los demás, el de más alto nivel. Por ello, debemos instanciar este primer dato para poder construir el DefaultTreeModel.


Ese primer dato será un DefaultMutableTreeNode. A este DefaultMutableTreeNode podemos pasarle el dato que queramos bien a través del método que comentamos setUserObject(), bien a través del constructor. Nuestro dato será un simple String que diga "abuelo" y lo meteremos en el constructor.


El código quedaría así


DefaultMutableTreeNode abuelo = new DefaultMutableTreeNode("abuelo");

modelo = new DefaultTreeModel(abuelo);

JTree tree = new JTree(modelo);


En el árbol se mostrará el resultado de llamar a toString() de nuestro "user object". Como en nuestro caso es un simple String "abuelo", el método toString() de String devuelve "abuelo" y eso es lo que se verá como raíz del árbol.


Ahora sólo nos queda ir añadiendo el resto de los datos del árbol. Lo único que tenemos que hacer es ir creando los nodos, como DefaultMutableTreeNode. A cada uno de ellos meterle el dato que queramos, bien en el constructor, bien con el método setUserObject(). En nuestro caso usaremos un simple String con el texto que queremos que se muestre. Finalmente, hay que ir asociando estos datos.


El abuelo ya lo tenemos creado, así que el código de creación de los demás nodos puede ser este


DefaultMutableTreeNode padre = new DefaultMutableTreeNode("padre");

DefaultMutableTreeNode tio = new DefaultMutableTreeNode("tio");

DefaultMutableTreeNode hijo=new DefaultMutableTreeNode("hijo");

DefaultMutableTreeNode hija=new DefaultMutableTreeNode("hija");


Para asociar estos datos tenemos dos opciones.



  • Usar los métodos add(), insert() y setParent() de DefaultMutableTreeNode para ir añadiendo unos nodos a otros.

  • Usar el método insertNodeInto() de DefaultTreeModel. A este método le pasamos nodo padre e hijo que queremos asociar y el se encarga de hacer la asociación.


La diferencia de hacerlo de una manera u otra es que JTree se entera automáticamente de cambios de DefaultTreeModel y los refleja automáticamente en pantalla, pero no se entera de los cambios en los DefaultMutableTreeNode y por tanto no los refresca en pantalla.


Si queremos refresco inmediato, debemos usar métodos de DefaultTreeModel. Si queremos hacer varios cambios sin ver como se van haciendo en pantalla, podemos usar los métodos de DefaultMutableTreeNode, pero debemos tener en cuenta que al final hay que provocar desde código el refresco del JTree, bien con un repaint(), bien con uno de los métodos fire...() de DefaultTreeModel.


Puesto que estamos haciendo un ejemplo simple y es más simple, usaremos el método insertNodeInto() para hacer la asociación. Este método lleva tres parámetros:



  • Nodo que queremos que sea hijo.

  • Nodo que queremos que sea padre.

  • En qué posición queremos que esté el hijo respecto a otros hijos. Dicho de otra forma, cuando despleguemos un padre que tiene por ejemplo cuatro hijos, en qué posición queremos que esté este nuevo hijo: el primero, en medio, el último...


El código para estas asociaciones es sencillo:


modelo.insertNodeInto(padre,abuelo,0);

modelo.insertNodeInto(tio, abuelo, 1);

modelo.insertNodeInto(hijo, padre, 0);

modelo.insertNodeInto(hija, padre, 1);


Ya está. Esto construye el árbol de la figura inicial. En PruebaJTree.java puedes ver el ejemplo completo.


El siguiente paso es cambiar esos iconos tan feos que salen en el árbol por otros más horribles, pero que al menos sean de nuestra propia cosecha.


Codigo


---------------------------------------------------------------------------------------------------


/*

* Fichero: PruebaJTree.java

*

* Fecha: 27/02/07 22:19

*/





import javax.swing.JFrame;

import javax.swing.JScrollPane;

import javax.swing.JTree;

import javax.swing.WindowConstants;

import javax.swing.tree.DefaultMutableTreeNode;

import javax.swing.tree.DefaultTreeModel;





/**

* Clase de ejemplo sencillo de uso del JTree

*

*

*/

public class PruebaJTree

{

/**

* Ejemplo sencillo de uso de JTree

*

* @param args Argumentos de linea de comandos. Se ignoran.

*/

public static void main(String[] args)

{

// Construccion del arbol

DefaultMutableTreeNode abuelo = new DefaultMutableTreeNode("abuelo");

DefaultTreeModel modelo = new DefaultTreeModel(abuelo);

JTree tree = new JTree(modelo);



// Construccion de los datos del arbol

DefaultMutableTreeNode padre = new DefaultMutableTreeNode("padre");

DefaultMutableTreeNode tio = new DefaultMutableTreeNode("tio");

modelo.insertNodeInto(padre, abuelo, 0);

modelo.insertNodeInto(tio, abuelo, 1);



DefaultMutableTreeNode hijo = new DefaultMutableTreeNode("hijo");

DefaultMutableTreeNode hija = new DefaultMutableTreeNode("hija");

modelo.insertNodeInto(hijo, padre, 0);

modelo.insertNodeInto(hija, padre, 1);



// Construccion y visualizacion de la ventana

JFrame v = new JFrame();

JScrollPane scroll = new JScrollPane(tree);

v.getContentPane().add(scroll);

v.pack();

v.setVisible(true);

v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

}

}

jueves, 7 de octubre de 2010

Arboles

Introducción

El siguiente trabajo trata sobre la estructura de datos no lineales llamada árbol. Esta estructura se usa principalmente para representar datos con una relación jerárquica entre sus elementos, como por ejemplo registros, árboles genealógicos, y tablas de contenidos. Vamos a profundizar en un tipo especial de árbol llamado árbol binario, la cual puede ser implementado fácilmente en la computadora; aunque en un árbol puede parecer muy restrictivo. También se va a ampliar sobre árboles más generales y puntos con relación a los árboles binarios; entre estos tenemos a la terminología, los árboles binarios complementos, árboles binarios de búsqueda, búsqueda e inserción en árboles binarios de búsqueda, árboles generales, representación de árboles generales en la computadora y correspondencia entre los árboles generales y árboles binarios.

Concepto de Árboles.

En ciencias de la computación, un árbol es una estructura de datos ampliamente usada que emula la forma de un árbol (un conjunto de nodos conectados). Un nodo es la unidad sobre la que se construye el árbol y puede tener cero o mas nodos hijos conectados a él. Se dice que un nodo a es padre de un nodo b, si existe un enlace desde a hasta b (en ese caso, también decimos que b es hijo de a). Sólo puede haber un único nodo sin padres, que llamaremos raíz. Un nodo que no tiene hijos se conoce como hoja.

El árbol También se define como una estructura de datos no lineal. Esta estructura se usa principalmente para representar datos con una relación jerárquica entre sus elementos, como por ejemplo registros, árboles genealógicos y tablas de contenidos. Entre otros tenemos un tipo especial de de árbol que es, llamado árbol binario, que puede ser implementado fácilmente en la computadora.

Árboles Binarios

Un árbol binario T se define como un conjunto finito de elementos, llamados nodos, de forma que:


  1. T es vacío ( en cuyo caso se llama árbol nulo o árbol vació) o
  2. T contiene un nodo distinguido R, llamado raíz de T, y los restantes nodos de T forman un par ordenado de árboles binarios disjuntos T1 y T2.

Si T contiene una raíz R, los dos árboles T1 y T2 se llaman, respectivamente, subárboles izquierdo y derecho de la raíz R. Si T1 no es vació , entonces su raíz se llama sucesor izquierdo de R; y análogamente, si T2 no es vació, su raíz se llama sucesor derecho de R.

Observe que :

  1. B es un sucesor izquierdo y C un sucesor derecho del nodo A.
  2. El subárbol izquierdo de la raíz A consiste en los nodos B, D, E y F, y el subárbol derecho de A consiste en los nodos C , G, H, J, K y L.

Figura (1)

Cualquier nodo N de un árbol binario T tiene 0, 1 ó 2 sucesores. Los nodos A,B,C y H tienen dos sucesores, los nodos R y J sólo tienen un sucesor , y los nodos D,F, G,L y K no tienen sucesores. Los nodos sin sucesores se llaman nodos terminales.

La definición anterior del árbol binario T es recursiva, ya que T se define en términos de los subárboles binarios T1 y T2. Esto significa, en particular, que cada nodo N de T contiene un subárbol izquierdo y uno derecho. Más aun, si N es un nodo terminal, ambos árboles están vacíos.

Dos árboles binarios T y T’ se dicen que son similares si tienen la misma estructura o, en otras palabras, si tienen la misma forma. Los árboles se dice que son copias si son similares y tienen los mismos contenidos en sus correspondientes nodos.

Terminología

Frecuentemente se usa una terminología de relaciones familiares para describir las relaciones entre los nodos de un árbol T. En particular, suponga que N es un nodo de T con un sucesor izquierdo S1 y un sucesor derecho S2. Entonces N se llama padre de S1 y S2. Análogamente, S1 se llama el hijo izquierdo de N y S2 el hijo derecho de N. Es mas, S1 y S2 se dice que son hermanos. Cada nodo N de un árbol binario T, excepto la raíz, tiene un único padre, llamado predecesor de N.

Los términos descendientes y antecesor tienen su significado usual. Así, un nodo L se dice descendiente de un nodo N ( y N se dice antecesor de L) si existe una sucesión de hijos desde N hasta L. En particular, L se dice descendiente izquierdo o derecho de N dependiendo de si pertenece al subárbol izquierdo o al derecho de N.

También se usa esa terminología de teoría de grafos y de horticultura para un árbol binario T. específicamente, la línea dibujada entre un nodo N de T y un sucesor suyo se llama ariste, y una secuencia de aristas consecutivas se denomina camino. Un nodo terminal se llama hoja y un camino que termina en una hoja se llama rama.

Cada nodo de un árbol binario T tiene asignado un número de nivel, de la forma que sigue. A la raíz R del árbol T se le asigna el numero de nivel 0, y al resto de los nodos se le asigna un numero de nivel que es mayor en 1 que el numero de nivel de su padre. Más aun, aquellos nodos con el mismo número de nivel se dice que pertenecen a la misma generación.

La profundidad o altura (o altura) de un árbol T es el número máximo de nodos de una rama de T. Equivale a 1 más que el mayor numero de nivel de T.

Dos árboles binarios T y T’ se dice que son similares si tienen la misma estructura o , en otras palabras, si tienen la misma forma. Los árboles se dice que son copias si son similares y tienen los mismos contenidos en sus correspondientes nodos.

La terminología de relaciones familiares, de teoría de grafos y horticultura se usa para los árboles generales de la misma forma que para los árboles binarios. En particular, si N es un nodo con sucesores S 1, S 2,…, S m, se dice que N es el padre de los S i , los S i son hijos de N y los S i son hermanos unos de otros.

El termino "árbol" aparece, con significados ligeramente diferentes, en muchas áreas diferentes de las matemáticas y de la informática. Aquí asumimos que nuestro árbol general T esta enraizado, es decir, que T tiene un nodo distinguido R llamado raíz de T; y que T esta ordenado, ósea, que los hijos de cada nodo N de T tienen un orden especifico. Estas dos propiedades no se requieren siempre para definir un árbol.

Ejemplo:

La figura muestra un árbol general T con 13 nodos,

A,B,C,D,E,F,G,H,J,K,L,M,N

A menos de que se indique lo contrario, la raíz de un árbol T es el nodo en lo alto del diagrama, y los hijos de un nodo están ordenados de izquierda a derecha. Así, A es la raíz de T y A tiene tres hijos; el primer hijo B, el segundo C y el tercero D. se observa que:

  1. El nodo C tiene tres hijos.
  2. Cada uno de los nodos B y K tienen dos hijos.
  3. Cada uno de los nodos D y H tiene un hijo.
  4. Los nodos E,F,G,L,J,M y N no tienen hijos.

El último grupo de nodos, los que no tienen hijos, se llaman nodos terminales.

Un árbol binario T’ no es un caso especial de un árbol general T: los árboles binarios y los árboles generales son dos cosas distintas. Las dos diferencias básicas son:


  1. un árbol binario T’ puede estar vació, pero un árbol general T no es vació.
  2. Suponga que un nodo N tiene un solo hijo. Entonces el hijo se distingue por ser el izquierdo o el derecho en un árbol binario T’, mientras que no existe esa distinción en un árbol general T.

Figura (2)

Árboles binarios Completos.

Considere un árbol binario T. El árbol binario T se dice que es completo si todos sus niveles, excepto posiblemente el ultimo, tienen el máximo numero de nodos posibles y si todos lo9s nodos del ultimo nivel están situados. Lo más posible a la izquierda. Así, solo existe un único árbol completo Tn con exactamente n nodos.

Representación de los árboles generales en la computadora.

Suponga que T es un árbol general. A menos que se diga lo contrario, T se mantendrá en memoria en términos de una representación enlazada que usa tres arrays paralelos, INFO, HIJO, (o ABAJO) Y HERM (u HORIZ), y una variable puntero RAIZ, tal como sigue. En primer lugar, cada nodo N de T corresponderá a una posición K tal que:


  1. INFO [ K ] contiene los datos del nodo N.
  2. HIJO [ K ] contiene la posición del primer hijo de N. La condición HIJO [ K ]= NULO indica que N no tiene hijos.
  3. HERM [ K ] contiene la posición del siguiente hermano de N. La condición HERM [ K ] = NULO indica que N es el ultimo hijo de su padre.

Ejemplo:

Considere el árbol general T de la figura (2) , suponga que los datos de los nodos de T se guardan en un Array INFO como en la figura (3) las relaciones estructurales de T se obtienen asignando valores al puntero RAIZ y a los Arrays HIJO y HERM tal y como sigue:


  1. como la raíz A de T se guarda en INFO [ 2 ], se y hace RAIZ:= 2.
  2. Como el primer hijo de A es el nodo B, guardado en INFO [3 ], se hace HIJO [ 2 ]:= 3. como A no tiene hermanos, se hace HERM [ 2 ]= NULO.
  3. Como el primer hijo de B es el nodo E, guardado en INFO [ 15 ], se hace HIJO [3]:= 15. como el nodo C es el siguiente hermano de B y C se guarda en INFO [ 4 ], se hace HERM [3]:=4.

Y así sucesivamente. La figura (3) da los valores finales de HIJO y HERM. Observe que la lista DISP de nodos vacos se mantiene en el primer array, hijo, donde DISP = 1.

Figura (3)

Árboles Generales.

Un árbol general ( a veces es llamado árbol ) se define como un conjunto, finito no vació T de elementos, llamados nodos, tales que:


  1. T contiene un elemento distinguido R, llamado raíz de T.
  2. Los restantes elementos de T forman una colección ordenada de cero o mas árboles disjuntos T1, T2,.., Tm..

Figura (4)

Árboles Binarios de búsqueda.

Esta sección discute una de las estructuras de datos más importantes de la informática, el árbol binario de búsqueda. Esta estructura permite buscar y encontrar un elemento con una media de tiempo de ejecución f (n) = 0 ( log2 n), también permite insertar y borrar elementos fácilmente. Esta estructura contrasta con las siguientes estructuras:


  1. Array lineal ordenado. Aquí se puede buscar y encontrar un elemento con un tiempo de ejecución f(n) = (log2n), pero es costoso el insertar y borrar elementos.
  2. Lista enlazada. Aquí se puede insertar y borrar elementos fácilmente, pero es costoso el buscar y encontrar un elemento, ya que se debe usar una búsqueda secuencial.

Aunque cada nodo de un árbol binario de búsqueda puede contener un registro entero de datos, la definición del árbol binario depende de un campo dado cuyos valores son distintos y deben estar ordenados.

Supongamos que T es un árbol binario. Entonces T se dice que es un árbol binario de búsqueda ( o árbol binario ordenado) si cada nodo N de T tiene la siguiente propiedad: el valor de N es mayor que cualquier valor del subárbol izquierdo de N y es menor que cualquier valor del subárbol derecho de N. ( no es difícil ver que esta propiedad garantiza el recorrido inorden de T dará una lista ordenada de los elementos de T) .

Conclusión.

De este trabajo se podría decir que un árbol binario se define como un conjunto finito de elementos llamados nodos. En estos casos se puede usar terminología de relaciones familiares para descubrir las relaciones entre los nodos de un árbol; y que un árbol puede ser implementado fácilmente en una computadora.

Es bueno hacer énfasis en esto ya que se puede saber mucho sobre lo que tiene que ver con los árboles; entre las cosas que podemos mencionar se encuentra la raíz, los nodos de un árbol y la diferencia entre nodos sucesores y nodos terminales, como se muestran en el contenido del trabajo.



viernes, 1 de octubre de 2010

Lista enlazada con LinkedList

package Linked;

import javax.swing.*;
import java.util.*;
class ListaEnlazada
{
public static void main (String[] args)
{
LinkedList myList=new LinkedList();
Integer menu;

do{
menu = Integer.parseInt(JOptionPane.showInputDialog("Menu

1 Insertar ala izquierda
2 Insertar a la derecha
3 Eliminar a la izquierda
4 Eliminar a la derecha
5 Borrar toda la lista
6 Salir"));
switch (menu)
{
case 1:
myList.addFirst(JOptionPane.showInputDialog("introduce el valor a agregar"));
JOptionPane.showMessageDialog(null,""+myList);
break;
case 2:
myList.addLast(JOptionPane.showInputDialog("introduce el valor a agregar"));
JOptionPane.showMessageDialog(null,""+myList);
break;
case 3:
myList.removeFirst();
JOptionPane.showMessageDialog(null,""+myList);
break;
case 4:
myList.removeLast();
JOptionPane.showMessageDialog(null,""+myList);
break;
case 5:
myList.clear();
JOptionPane.showMessageDialog(null,""+myList+"Lista Vacia");
//System.exit(0);
}

} while(menu!=6);
System.exit(0);
}
}

Ejercicio LinkedList para practicar

package linked;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;


public class inked {

@SuppressWarnings("unchecked")
public static void main (String args[]) {
Scanner leer = new Scanner(System.in);

int num;
int op;

LinkedList lista = new LinkedList();
do{
System.out.println( "\t Menú \t" );
System.out.println( "Operaciones con listas" );
System.out.println( "1.- Insertar al principio" );
System.out.println( "2.- Insertar al final" );
System.out.println( "3.- Borrar al principio" );
System.out.println( "4.- Borrar al final" );
System.out.println( "5.- Mostrar la lista" );
System.out.println( "6.- Borrar toda la lista" );
System.out.println( "7.- Salir" );
System.out.println( "\n" );
System.out.println( "Elija la operación que desee" );

op = leer.nextInt();

switch(op){
case 1:
System.out.println( "Inserte numero" );
num = leer.nextInt();
lista.addFirst(num);
break;
case 2:
System.out.println( "Inserte numero" );
num = leer.nextInt();
lista.addLast(num);
break;
case 3:
System.out.println( "Se borrara el primer nodo" );
lista.removeFirst();
break;
case 4:
System.out.println( "Se borrara el nodo final" );
lista.removeLast();
break;
case 5:
System.out.println( "La lista es la siguiente" );
List lista2 = new ArrayList(lista);
Iterator it = lista2.iterator();
while (it.hasNext()){
System.out.println(it.next()+"");
}
break;
case 6:
System.out.println( "Se borraran todos los elementos de la lista" );
lista.clear();
break;
case 7:
System.out.println( "Al rato" );
break;
}
}

while( op != 7 );
}
}

jueves, 5 de agosto de 2010

ArrayList en Java

ArrayList
• Un ArrayList es un array dinámico. No tiene restricciones de
capacidad. Su tamaño se ajusta de forma dinámica.
• Constructor por defecto: new ArrayList(). Inicialmente, la
capacidad de un ArrayList creado así es 0.
• Los elementos dentro de un ArrayList son Objetos. No pueden ser
de tipo básico, pero pueden ser de cualquier tipo de objeto.
• La clase ArrayList forma parte del paquete java.util
• Para poner un elemento dentro de esta estructura, usamos el
método add y para recoger un elemento usamos el método get.




Ejemplo:
import java.util.*;
public class ArrayListExample1 {
public static void main(String[ ] args) {
ArrayList thisArrayList = new ArrayList();
thisArrayList.add("hello");
thisArrayList.add(",");
thisArrayList.add("are");
thisArrayList.add("you");
thisArrayList.add("?");
for (int i=0;i<"thisArrayList.size()";i++)
System.out.print(thisArrayList.get(i)+" ");
}
}

Métodos de ArrayList

• int size() -- El tamaño actual (puede ser 0)

• void add(obj) -- Añade un objeto al final del ArrayList, incrementando su tamaño de
1. obj es un objeto.

• Object get(N) -- Devuelve el elemento almacenado a la posición N en el ArrayList.
N tiene que ser un entero entre 0 y size()-1.

– En ArrrayListInteger.java, se convierte el objeto devuelto por get() a un Integer
con casting.

– En ArrayListString.java, se convierte el objeto devuelto por get() a un String
llamando al método toString() de Object.

-----Analizar
import java.util.ArrayList;
public class ArrayListInteger {
public static void main(String[] args) {
ArrayList numeros = new ArrayList();
Integer num1 = new Integer(10);
Integer num2 = new Integer(20);
Integer num3 = new Integer(30);
Integer num4 = new Integer(40);
numeros.add(num1);
numeros.add(num2);
numeros.add(num3);
numeros.add(num4);
int suma=0;
for (int i=0;i<"numeros.size()";i++) {
Integer thisNumero = (Integer)numeros.get(i);
suma = suma + thisNumero.intValue();
System.out.print(thisNumero);
if (i<"numeros.size()"-1)
System.out.print("+");
else
System.out.print("=");
}
System.out.println(suma);
}
}

Otro ejemplo


6
import java.util.*;
public class ArrayListString {
public static void main(String[] args) {
ArrayList cadenas = new ArrayList();
cadenas.add("hello");
cadenas.add(",");
cadenas.add("are");
cadenas.add("you");
cadenas.add("?");
for (int i=0;i
Object object = cadenas.get(i);
String cadena = object.toString();
cadena = cadena.toUpperCase();
System.out.print(cadena+" ");
}
}
}

Ejercicios

• Escribir los siguientes métodos:
– void eliminarTodos(ArrayList cadenas,String cadena)
Elimina todas las copias de cadena dentro de cadenas
– int min(ArrayList numeros)
Devuelve el número más pequeño del array dinámico
– void toUpperCase(ArrayList cadenas)
Sustituye cada cadena (String) del arrayList por la su versión
máyuscula.
– int veces(ArrayList cadenas,String cadena)
Devuelve el número de veces que aparece la cadena en el array
dinámico de cadenas.

viernes, 30 de julio de 2010

Bienvenidos!!!

Matrices, arrays o vectores en java.

Java posee la capacidad de definir un conjunto de variables del mismo tipo agrupadas todas ellas bajo un mismo nombre, y distinguiéndolas mediante un índice numérico.

Para definir un array en java es como definir una variable o atributo, pero al especificar el tipo lo que hacemos es colocar un par de corchetes [] para indicar que lo que estamos definiendo es un array. Por ejemplo:

public int [] losValores;

en la que definimos un array de enteros llamado losValores. Vamos a intentar realizar un ejemplo para ver como funciona:

Práctica:

Crear el fichero Array.java

Agregar el siguiente código en el fichero:

public class Array

{

public static void main(String arg[])

{

int [] losValores = null;

losValores[4] = 100;

System.out.println(losValores[4]);

}

}


...Compilamos el código, ejecutemos y...error!!! Parece extraño que el error sea NullPointerException, pero tiene sentido, recordemos que una variable java, que no sea de tipo básico es una referencia que puede apuntar a objetos y por tanto losValores también es una referencia y debe de apuntar a objetos de tipo array de enteros. Es decir, el código de la función main es necesario modificarlo:

int [] losValores = new int[10];