Anda di halaman 1dari 85

programacionparajava.blogspot.

com


1


ndice
Estructuras lineales estticas ................................................................. 1
Pilas .................................................................................................... 1
Colas simples ...................................................................................... 5
Cola circular ....................................................................................... 8
Colas dobles...................................................................................... 11
Estructuras lineales dinmicas ............................................................ 12
Listas ligadas simples ........................................................................ 12
Listas de doble ligadura..................................................................... 16
Listas ligadas circulares .................................................................... 19
Estructuras no lineales dinamicas ....................................................... 24
Arboles binarios ................................................................................ 24
Arboles binarios balanceados ............................................................ 28
Arboles b .......................................................................................... 38
Arboles b+ ........................................................................................ 51
Teora de grafos ................................................................................... 55
Operaciones en grafos ....................................................................... 55
Tablas de hash ...................................................................................... 76
Referencias bibliograficas: .................................................................. 84

Estructuras lineales estticas

Pilas
Una pila (stack en ingls) es una lista ordinal o estructura de datos en la que el modo de
acceso a sus elementos es de tipo LIFO (del ingls Last In First Out, ltimo en entrar,
primero en salir) que permite almacenar y recuperar datos. Esta estructura se aplica en
multitud de ocasiones en el rea de informtica debido a su simplicidad y ordenacin
implcita de la propia estructura.
Para el manejo de los datos se cuenta con dos operaciones bsicas: apilar (push), que coloca
un objeto en la pila, y su operacin inversa, retirar (o desapilar, pop), que retira el ltimo
elemento apilado.
programacionparajava.blogspot.com


2

En cada momento slo se tiene acceso a la parte superior de la pila, es decir, al ltimo
objeto apilado (denominado TOS, Top of Stack en ingls). La operacin retirar permite la
obtencin de este elemento, que es retirado de la pila permitiendo el acceso al siguiente
(apilado con anterioridad), que pasa a ser el nuevo TOS.
Por analoga con objetos cotidianos, una operacin apilar equivaldra a colocar un plato
sobre una pila de platos, y una operacin retirar a retirarlo.
Las pilas suelen emplearse en los siguientes contextos:
Evaluacin de expresiones en notacin postfija (notacin polaca inversa).
Reconocedores sintcticos de lenguajes independientes del contexto
Implementacin de recursividad.
A continuacin se muestra un ejemplo de pila:

import java.io.*;

public class principal {
public static class ClasePila { // Declaracion de la clase de la Pila
private int max=10; // Tamano maximo de la pila
private int pila[] = new int [max]; // Arreglo para almacenar la pila
private int top; // Indica la cantidad de datos en la pila

public ClasePila() { // Constructor
top=0;
System.out.println("Pila creada !!!");
}

public void Push(int dato) {
if(top==max) // Esta llena la Pila?
{
System.out.println("Pila llena !!!");
return;
}
for(int i=0; i<top; i++) {
if(pila[i]==dato) { // Ya existe el dato?
System.out.println("Duplicado !!!");
return;
}
if(dato<pila[i]) { // Alta al principio o intermedia
for(int j=top;j>i;j--)
pila[j]=pila[j-1];
pila[i]=dato;
top++;
System.out.println("Dato insertado al principio o intermedio !!!");
return;
}
}
pila[top++]=dato; // Alta al final
System.out.println("Dato insertado al final !!!");
programacionparajava.blogspot.com


3

return;
}

public void Pop(int dato) {
if(top==0) { // Esta vacia la Pila?
System.out.println("Pila vacia !!!");
return;
}
for(int i=0;i<top;i++) {
if(pila[i]==dato) {
for(int j=i; j<top-1; j++)
pila[j]=pila[j+1];
top--;
System.out.println("Dato eliminado !!!");
return;
}
}
System.out.println("Dato inexistente !!!");
}

public void Mostrar() {
System.out.println("\n\n<<< MOSTRAR LA PILA >>>");
if(top==0) System.out.println("Pila vacia !!!");
for(int i=0;i<top;i++)
System.out.println("pila["+i+"]="+pila[i]);
System.out.println("top="+top);
System.out.println("max="+max);
}
}


static ClasePila Pila=new ClasePila(); // Declaracion del objeto Pila

// Funcion principal
public static void main(String args[]) throws IOException {
int op=0;
do {
op=0;
System.out.println("\n\n<<< PILAS >>>");
System.out.println("1.-Push");
System.out.println("2.-Pop");
System.out.println("3.-Mostrar Pila");
System.out.println("0.-Salir");

//op=Integer.parseInt(JOptionPane.showInputDialog("Opcion? "));
System.out.print("Opcion? ---> ");
op=getInt();

switch(op) {
case 1 : Altas(); break;
case 2 : Bajas(); break;
case 3 : Pila.Mostrar(); break;
}
}while(op!=0);
programacionparajava.blogspot.com


4

}

public static void Altas() throws IOException {
int dato=0;
System.out.println("\n\n<<< ALTAS >>>");
System.out.print("\nAnote el dato que desea insertar ---> ");
dato=getInt();
Pila.Push(dato); // Invocar el metodo Push del objeto Pila
}

public static void Bajas() throws IOException {
int dato=0;
System.out.println("\n\n<<< BAJAS >>>");
System.out.print("\nAnote el dato que desea eliminar ---> ");
dato=getInt();
Pila.Pop(dato); // Invocar el metodo Pop del objeto Pila
}

// Funcion para capturar una cadena desde el teclado
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}

// Funcion para capturar un entero desde el teclado
public static int getInt() throws IOException {
String s = getString();
return Integer.parseInt(s);
}
}
Asi se ejecuta en eclipse como se muestra abajo:
programacionparajava.blogspot.com


5




Colas simples

Una cola (tambin llamada fila) es una estructura de datos, caracterizada por ser una
secuencia de elementos en la que la operacin de insercin pushse realiza por un extremo y
la operacin de extraccin pop por el otro. Tambin se le llama estructura FIFO (del
ingls First In First Out), debido a que el primer elemento en entrar ser tambin el primero
en salir.
Las colas se utilizan en sistemas informticos, transportes y operaciones
de investigacin (entre otros), dnde los objetos, personas o eventos son tomados como
datos que se almacenan y se guardan mediante colas para su posterior procesamiento. Este
tipo de estructura de datos abstracta se implementa en lenguajes orientados a
objetos mediante clases, en forma de listas enlazadas.
Ejemplo de cola en java:
import java.io.*;

public class Colas {
public static class ClaseColas { // Declaracion de la clase de Colas
static int max=10; // Tamano maximo de la Cola
static int cola[]= new int[max]; // Declaracion del arreglo
static int frente, fin; // Indicadores de inicio y fin de la Cola

programacionparajava.blogspot.com


6

ClaseColas() { // Constructor que inicializa el frente y el final de la
Cola
frente=0; fin=0;
System.out.println("Cola inicializada !!!");
}

public static void Insertar(int dato) {
if(fin==max) { // Esta llena la Cola?
System.out.println("\nCola llena !!!");
return;
}
cola[fin++]=dato;
System.out.println("Dato insertado !!!");
}

public static void Eliminar() {
System.out.println("\n\n<<< ELIMINAR >>>");
if(frente==fin) { // Esta vacia la Cola?
System.out.println("\nCola vacia !!!");
return;
}
System.out.println("Elemento eliminado: "+cola[frente++]);
}

public static void Mostrar() {
int i=0;
System.out.println("\n\n<<< MOSTRAR >>>");
if(frente==fin) System.out.println("\nCola vacia !!!");
for(i=frente; i<fin; i++) {
System.out.println("cola["+i+"]="+" "+cola[i]);
}
System.out.println("\nFrente= "+frente);
System.out.println("Final = "+fin);
System.out.println("Max = "+max);
}
}

static ClaseColas Cola=new ClaseColas(); // Declaracion del objeto Cola

// Funcion principal
public static void main(String args[]) throws IOException {
int op=0;
do {
System.out.println("\n\n<<< COLAS >>>");
System.out.println("1.- Altas");
System.out.println("2.- Eliminar");
System.out.println("3.- Mostrar");
System.out.println("0.- Salir");
System.out.print("Opcion? ---> ");
op=getInt();

switch(op) {
case 1 : Altas(); break;
case 2 : Cola.Eliminar(); break;
programacionparajava.blogspot.com


7

case 3 : Cola.Mostrar(); break;
}
}while(op!=0);
}

public static void Altas() throws IOException {
int elemento=0;
System.out.println("\n\n<<< ALTAS >>>");
System.out.print("Elemento a insertar? ---> ");
elemento=getInt();
Cola.Insertar(elemento); // Invocar el metodo Insertar del objeto Cola
}

// Funcion para capturar una cadena desde el teclado
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}

// Funcion para capturar un entero desde el teclado
public static int getInt() throws IOException {
String s = getString();
return Integer.parseInt(s);
}
}
Asi quedara corriendo el programa en eclipse:



programacionparajava.blogspot.com


8

Cola circular
http://es.scribd.com/doc/41076913/Colas-Dobles-y-Circulares
Una cola circular o anillo es una estructura de datos en la que los elementos estnde forma
circular y cada elemento tiene un sucesor y un predecesor. Loselementos pueden
consultarse, aadirse y eliminarse nicamente desde la cabezadel anillo que es una posicin
distinguida. Existen dos operaciones de rotaciones,una en cada sentido, de manera que la
cabeza del anillo pasa a ser el elementosucesor, o el predecesor, respectivamente, de la
cabeza actual.Las colas lineales tienen un grave problema, como las extracciones slo
puedenrealizarse por un extremo, puede llegar un momento en que el apuntador A seaigual
al mximo nmero de elementos en la cola, siendo que al frente de la mismaexistan lugares
vacos, y al insertar un nuevo elemento nos mandar un error deoverflow (cola llena).Para
solucionar el problema de desperdicio de memoria se implementaron lascolas circulares, en
las cuales existe un apuntador desde el ltimo elemento alprimero de la cola.
Ejemplo de cola circular:

import java.io.*;

public class ColaCircular {
public static class ClaseColaCircular { // Declaracion de la clase de la Cola
Circular
static int max=5; // Tamano maximo de la Cola Circular
static int colacirc[]=new int[max]; // Declaracion del arreglo para
almacenar la Cola Circular
static int frente, fin; // Inidicadores del inicio y final de la Cola
Circular

ClaseColaCircular() { // Constructor que inicializa el frente y el final de
la Cola Circular
frente=-1; fin=-1;
System.out.println("Cola circular inicializada !!!");
}

public static void Mostrar() {
int i=0;
System.out.println("\n\n<<< MOSTRAR COLA CIRCULAR >>>");
if(frente==-1) {
System.out.println("\nCola Circular vacia !!!");
}
else {
i=frente;
do {
System.out.println("colacircssss["+i+"]="+colacirc[i]);
i++;
if(i==max && frente>fin) i=0; // Reiniciar en cero (dar la vuelta)
}while(i!=fin+1);
}
programacionparajava.blogspot.com


9


System.out.println("frente="+frente);
System.out.println("fin="+fin);


System.out.println("max="+max);
}

public static void Insertar(int dato) {
if((fin==max-1 && frente==0) || (fin+1==frente)) {
System.out.println("\nCola Circular llena !!!");
return;
}
if(fin==max-1 && frente!=0) fin=0; else fin++;
colacirc[fin]=dato;
if(frente==-1) frente=0;
}

public static void Eliminar() {
System.out.println("\n\n<<< ELIMINAR DATO >>>");

if(frente==-1) {
System.out.println("Cola Circular vacia !!!");
return;
}
System.out.println("Dato eliminado = "+colacirc[frente]);//elimina en el
vector
if(frente==fin) { //el primer fuente
frente=-1; fin=-1; //si frente igual a fin vacios mostrar -1
return;
}
if(frente==max) frente=0; else frente++;
}
}

// Declaracion del objeto ColaCircular
static ClaseColaCircular ColaCircular=new ClaseColaCircular();

// Funcion principal
public static void main(String args[]) throws IOException {
int op=0;
do {
System.out.println("\n\n<<< COLAS CIRCULARES >>>");
System.out.println("1.- Insertar");
System.out.println("2.- Eliminar");
System.out.println("3.- Mostrar");
System.out.println("0.- Salir");

System.out.print("Opcion? ---> ");
op=getInt();
switch(op) {
case 1 : Altas(); break;
case 2 : ColaCircular.Eliminar(); break;
case 3 : ColaCircular.Mostrar(); break;
programacionparajava.blogspot.com


10

}
}while(op!=0);
}

public static void Altas() throws IOException {
int dato;
System.out.println("\n\n<<< ALTAS >>>");
System.out.print("Dato a insertar? ---> ");
dato=getInt();
ColaCircular.Insertar(dato); //Invocar el metodo Insertar del objeto
ColaCircular
}

// Funcion para capturar una cadena desde el teclado
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}

// Funcion para capturar un entero desde el teclado
public static int getInt() throws IOException {
String s = getString();
return Integer.parseInt(s);
}
}


programacionparajava.blogspot.com


11

Colas dobles
La bicola o doble cola es un tipo de cola especial que permiten la insercin y eliminacin
de elementos de ambos extremos de la cola.
Puede representarse a partir de un vector y dos ndices, siendo su representacin ms
frecuente una lista circular doblemente enlazada.
Todas las operaciones de este tipo de datos tienen coste constante.
Esta es la estructura de una cola doble:
// ArrayCircularQueue.java

package com.javajeff.cds;

public class ArrayCircularQueue implements Queue {
private int front = 0, rear = 0;
private Object [] queue;

public ArrayCircularQueue (int maxElements) {
queue = new Object [maxElements];
}

public void insert (Object o) {
int temp = rear;
rear = (rear + 1) % queue.length;
if (front == rear) {
rear = temp;
throw new FullQueueException ();
}
queue [rear] = o;
}

public boolean isEmpty () {
return front == rear;
}

public boolean isFull () {
return ((rear + 1) % queue.length) == front;
}

public Object remove () {
if (front == rear)
throw new EmptyQueueException ();
front = (front + 1) % queue.length;
return queue [front];
programacionparajava.blogspot.com


12

}
}




Estructuras lineales dinmicas

Listas ligadas simples

La lista enlazada bsica es la lista enlazada simple la cual tiene un enlace por nodo. Este
enlace apunta al siguiente nodo (o indica que tiene la direccin en memoria del siguiente
nodo) en la lista, o al valor NULL o a la lista vaca, si es el ltimo nodo.
Ejemplo de lista hecha en java con eclipse:
import java.io.*;

public class Listas_Objetos {
public static class ClaseLista {
public static class ClaseNodo {
char dato; // Dato del nodo (NO debe declararse "static")
ClaseNodo sn; // Apuntador al siguiente nodo (NO debe declararse
"static")
}

static ClaseNodo inicial;

public static void Inicializar() {
inicial=new ClaseNodo();
inicial=null;
}

public static void Eliminar(char d) throws IOException {
ClaseNodo i=inicial, anterior=i;
if(i==null) {
System.out.println("Lista vacia !!!");
getch();
return;
}
while(i!=null) {
if(d==i.dato) {
if(i==inicial) {
inicial=i.sn;
System.out.println("\nBaja al principio...");
programacionparajava.blogspot.com


13

getch();
return;
}
anterior.sn=i.sn;
System.out.println("\nBaja intermedia o al final ...");
getch();
return;
}
anterior=i;
i=i.sn;
}
System.out.println("\nNo existe ese dato !!!");
getch();
return;
}

public static void Insertar(char d) throws IOException {
ClaseNodo i=inicial, nuevo_nodo, anterior=i;

if(i==null) {
nuevo_nodo=new ClaseNodo();
nuevo_nodo.dato=d;
nuevo_nodo.sn=null;
inicial=nuevo_nodo;
System.out.println("\nAlta a lista vacia...");
getch();
return;
}
while(i!=null) {
if(d==i.dato) {
System.out.println("\nDuplicado !!!");
getch();
return;
}
if(d<i.dato) {
if(i==inicial) {
nuevo_nodo=new ClaseNodo();
nuevo_nodo.dato=d;
nuevo_nodo.sn=inicial;
inicial=nuevo_nodo;
System.out.println("\nAlta al principio...");
getch();
return;
}
nuevo_nodo=new ClaseNodo();
nuevo_nodo.dato=d;
nuevo_nodo.sn=anterior.sn;
anterior.sn=nuevo_nodo;
System.out.println("\nAlta intermedia...");
getch();
return;
}
anterior=i;
i=i.sn;
programacionparajava.blogspot.com


14

}
nuevo_nodo=new ClaseNodo();
nuevo_nodo.dato=d;
nuevo_nodo.sn=null;
anterior.sn=nuevo_nodo;
System.out.println("\nAlta al final...");
getch();
return;
}

public static void Recorrido() throws IOException {
ClaseNodo i=inicial;
clrscr();
System.out.println("\n<<< RECORRIDO DE UNA LISTA ENCADENADA >>>\n\n");
if(i==null) {
System.out.println("\nLista vacia");
}
while(i!=null) {
System.out.print(i.dato+"->");
i = i.sn;
}
System.out.println("null");
getch();
}
}

static ClaseLista Lista=new ClaseLista(); // Declaracion global del objeto
Lista

public static void main(String args[]) throws IOException {
int op=0;
Lista.Inicializar(); // Inicializar la Lista Enlazada
do {
clrscr();
System.out.println("\n\n<<< LISTAS ENCADENADAS CON OBJETOS >>>");
System.out.print("\n1.- Altas");
System.out.print("\n2.- Bajas");
System.out.print("\n3.- Recorrido");
System.out.print("\n0.- Salir");
System.out.print("\nOpcion? ---> ");
op=getInt();

switch(op) {
case 1 : Altas(); break;
case 2 : Bajas(); break;
case 3 : Lista.Recorrido(); break;
}

}while(op!=0);
}

public static void Bajas() throws IOException {
char dato;
clrscr();
programacionparajava.blogspot.com


15

System.out.println("\n<<< BAJAS >>>");
System.out.print("\nAnote el dato a eliminar ---> ");
dato=getChar();
Lista.Eliminar(dato);
}

public static void Altas() throws IOException {
char dato;
clrscr();
System.out.println("\n\n<<< ALTAS >>>");
System.out.print("\nAnote el dato a insertar ---> ");
dato=getChar();
Lista.Insertar(dato);
}

public static void clrscr() {
for(int i=0;i<26;i++)
System.out.println(" ");
}

//Funcion para capturar una cadena desde el teclado
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}

// Funcion para capturar un entero desde el teclado
public static int getInt() throws IOException {
String s = getString();
return Integer.parseInt(s);
}

//Funcion para capturar un caracter desde el teclado
public static char getChar() throws IOException {
String s=getString();
return s.charAt(0);
}

// Rutina para hacer una pausa
public static void getch() throws IOException {
String s;
System.out.print("\n<<< Oprima cualquier tecla para continuar >>>");
s=getString();
return;
}
} asi quedara en eclipse como la imagen de abajo:
programacionparajava.blogspot.com


16



Listas de doble ligadura
http://decsai.ugr.es/~jfv/ed1/tedi/cdrom/docs/ldoble.html
La ventaja de las listas doblemente enlazadas es que podemos usar un puntero a la celda
que contiene el i-simo elemento de una lista para representar la posicin i, mejor que usar
el puntero a la celda anterior aunque lgicamente, tambin es posible la implementacin
similar a la expuesta en las listas simples haciendo uso de la cabecera. El nico precio que
pagamos por estas caractersticas es la presencia de un puntero adicional en cada celda y
consecuentemente procedimientos algo ms largos para algunas de las operaciones bsicas
de listas.


Dentro del tipo abstracto de listas doblemente enlazadas podemos proponer las siguientes
primitivas:
tLista crear ()
void destruir (tLista l)
tPosicion primero (tLista l)
tPosicion fin (tLista l)
void insertar (tElemento x, tPosicion p, tLista l)
void borrar (tPosicion *p, tLista l)
programacionparajava.blogspot.com


17

tElemento elemento(tPosicion p, tLista l)
tPosicion siguiente (tPosicion p, tLista l)
tPosicion anterior (tPosicion p, tLista l)
tPosicion posicion (tElemento x, tLista l)

Ejemplo de cdigo de una lista de doble ligadura, su estructura es la siguiente:

public class Listas {
private Object dato;
private Listas sig;
private Listas ant;

public Listas() {
dato = null;
sig = null;
ant = null;

}
public void InsertarFinal(Object x) {
int tamanio=tamao();
if(tamanio<=0){
dato = x;
sig = new Listas();
sig.ant=null;
}else
if (vacia()) {
dato = x;
sig.ant =sig.sig ;
sig = new Listas();
} else {
sig.InsertarFinal(x);
}
}
public boolean vacia() {
return dato == null && sig == null;
}
public String toString() {
String res = "[" + restosig() + "]";
return res;
}
private String restosig() {
String res = "";
if (!vacia()) {
res = dato.toString();
if (!sig.vacia()) {
res = res + ", " + sig.restosig();
}
}
System.out.println(ant);
return res;
}
private String restoant() {
String res = "";
programacionparajava.blogspot.com


18

if (!vacia()) {
res = dato.toString();
if (!ant.vacia()) {
res = res + "," + sig.ant.restoant();

}

}
return res;
}
public int tamao() {
if (vacia()) {
return 0;
}
return 1 + sig.tamao();
}
public boolean buscar(Object x) {
if (vacia()) {
return false;
}
if (dato.equals(x)) {
return true;
}
return sig.buscar(x);
}
public Object obtener(int pos) {
if (vacia()) {
return null;
}
if (pos == 0) {
return dato;
}
return sig.obtener(pos - 1);
}
public void modificar(int pos, Object x) {
if (vacia() || pos < 0) {
return;
}
if (pos == 0) {
dato = x;
} else {
sig.modificar(pos - 1, x);
}
}
public Object eliminar(Object x) {
Object res = null;
if (!vacia()) {
if (dato.equals(x)) {
res = dato;
dato = sig.dato;
sig = sig.sig;
} else {
res = sig.eliminar(x);
}
}
return res;
programacionparajava.blogspot.com


19

}
}







Listas ligadas circulares
http://ingenierasdesiyvane.blogspot.es/
Cada nodo tiene un enlace, similar al de las listas enlazadas simples, excepto que el
siguiente nodo del ltimo apunta al primero. Como en una lista enlazada simple, los nuevos
nodos pueden ser solo eficientemente insertados despus de uno que ya tengamos
referenciado. Por esta razn, es usual quedarse con una referencia solamente al ltimo
elemento en una lista enlazada circular simple, esto nos permite rpida sinserciones al
principio, y tambin permite accesos al primer nodo desde el puntero del ltimo nodo.

Operaciones bsicas con listas circulares:
A todos los efectos, las listas circulares son como las listas abiertas en cuanto a las
operaciones que se pueden realizar sobre ellas:
" Aadir o insertar elementos.
" Buscar o localizar elementos.
" Borrar elementos.
" Moverse a travs de la lista, siguiente.
Cada una de stas operaciones podr tener varios casos especiales, por ejemplo, tendremos
que tener en cuenta cuando se inserte un nodo en una lista vaca, o cuando se elimina el
nico nodo de una lista.
Un ejemplo sencillo seria el siguiente:

//Definicion de la clase NodosListaCircular
class NodosListaCircular{
//datos amigables para que la clase lista tenga un acceso directo
programacionparajava.blogspot.com


20

Object datos;
NodosListaCircular siguiente;
//Constructor crea un nodo de tipo Object
NodosListaCircular(Object valor){
datos=valor;
siguiente=null;
}
//Constructor Crea un nodo de tipo Object y al siguiente nodo de la lista
NodosListaCircular (Object valor,NodosListaCircular signodo){
datos=valor;
siguiente=signodo; //siguiente se refiere al siguiente nodo
}
//Retorna el dato que se encuentra en ese nodo
Object getObject(){
return datos;
}
//Retorna el siguiente nodo
NodosListaCircular getnext(){
return siguiente;
}
}

//Definicion de la clase ListaCircular
class ListaCircular{
NodosListaCircular PrimerNodo;
String Nombre;

//Constructor construye una lista vacia con un nombre s
public boolean VaciaLista(){
return PrimerNodo==null;
}

//Imprime el contenido de la lista
public void Imprimir(){
if (VaciaLista()){
System.out.println("Vacia" + Nombre);
}
else{
System.out.print("La "+Nombre + " es: ");
NodosListaCircular Actual=PrimerNodo.siguiente;
System.out.print(PrimerNodo.datos.toString()+" ");
while(Actual != PrimerNodo){
System.out.print(Actual.datos.toString()+" ");
Actual=Actual.siguiente;
}
System.out.println();
System.out.println();
}
}

//Constructor
public ListaCircular(String s){
Nombre=s;
PrimerNodo=null;
programacionparajava.blogspot.com


21

}

//Constructor
public ListaCircular(){
this ("Lista");
}

//Inserta un elemento al frente de la lista
void InsertaInicio(Object ElemInser){
if(VaciaLista()){
PrimerNodo=new NodosListaCircular(ElemInser);
PrimerNodo.siguiente=PrimerNodo;
}
else{
NodosListaCircular aux=PrimerNodo;
while(aux.siguiente != PrimerNodo)
aux=aux.siguiente;
NodosListaCircular tempo=new NodosListaCircular (ElemInser);
aux.siguiente=tempo;
tempo.siguiente=PrimerNodo;
PrimerNodo=tempo;
}
}

//Inserta al final de la lista
public void InsertaFinal(Object ElemInser){
if(VaciaLista()){
PrimerNodo=new NodosListaCircular (ElemInser);
PrimerNodo.siguiente=PrimerNodo;
}
else{
NodosListaCircular aux=PrimerNodo;
while(aux.siguiente != PrimerNodo)
aux=aux.siguiente;
NodosListaCircular tempo=new NodosListaCircular(ElemInser);
aux.siguiente=tempo;
tempo.siguiente=PrimerNodo;
}
}

//Inserta elemento en posicion dada
public void InsertaMedio(Object ElemInser,int Posicion){
if(VaciaLista()){
PrimerNodo=new NodosListaCircular (ElemInser);
PrimerNodo.siguiente=PrimerNodo;
}
else{
if(Posicion<=1){
NodosListaCircular Nuevo=new
NodosListaCircular(ElemInser);
Nuevo.siguiente=PrimerNodo;
PrimerNodo=Nuevo;
}
else{
programacionparajava.blogspot.com


22

NodosListaCircular Aux=PrimerNodo;
int i=2;
while((i != Posicion) & (Aux.siguiente !=
PrimerNodo)){
i++;
Aux=Aux.siguiente;
}
NodosListaCircular Nuevo=new
NodosListaCircular(ElemInser);
Nuevo.siguiente=Aux.siguiente;
Aux.siguiente=Nuevo;
}
}
}

//Elimina al Inicio
public void EliminaInicio(){
if(VaciaLista())
System.out.println("No hay elementos");
else{
NodosListaCircular aux=PrimerNodo;
while(aux.siguiente != PrimerNodo)
aux=aux.siguiente;
PrimerNodo=PrimerNodo.siguiente;
aux.siguiente=PrimerNodo;
}
}

//Elimina al Final
public void EliminaFinal(){
if(VaciaLista())
System.out.println("No hay elementos");
else{
NodosListaCircular aux=PrimerNodo;
NodosListaCircular ac=null;
if(PrimerNodo==PrimerNodo.siguiente){
PrimerNodo=null;
}
else{
while(aux.siguiente != PrimerNodo){
ac=aux;
aux=aux.siguiente;
}
ac.siguiente=PrimerNodo;
}
}
}

//Retorna si un elemento es miembro
public boolean Miembro(Object ele){
boolean enc=false;
if(!VaciaLista()){
NodosListaCircular aux=PrimerNodo.siguiente;
if(ele.equals(PrimerNodo.datos))
programacionparajava.blogspot.com


23

enc=true;
else{
while((aux != PrimerNodo) && (enc==false)){
if(ele.equals(aux.datos)){
enc=true;
}
else{
aux=aux.siguiente;
}
}
}
}
return enc;
}
}

class ListaCircularA{
public static void main (String [] args){
ListaCircular l=new ListaCircular();
//Crea la lista
l.InsertaInicio("7");
l.InsertaInicio("3");
l.InsertaInicio("16");
l.InsertaInicio("2");
l.InsertaInicio("5");
l.InsertaInicio("8");
l.InsertaInicio("10");
l.InsertaInicio("15");
l.InsertaInicio("1");
l.EliminaFinal();
l.Imprimir();
}
}

Ejemplo de ejecucin del programa:
programacionparajava.blogspot.com


24



Estructuras no lineales dinamicas

Arboles binarios
http://cosasparafuturosingenieros.blogspot.mx/2012/11/codigo-fuente-java-programa-arbol.html
Un rbol binario es una estructura de datos en la cual cada nodo siempre tiene un hijo
izquierdo y un hijo derecho. No pueden tener ms de dos hijos (de ah el nombre "binario").
Si algn hijo tiene como referencia a null, es decir que no almacena ningn dato, entonces
este es llamado un nodo externo. En el caso contrario el hijo es llamado un nodo interno.
Usos comunes de los rboles binarios son los rboles binarios de bsqueda, los montculos
binarios y Codificacin de Huffman

El programa esta construido de la siguiente manera: consta de 3 clases, una llamada nodo
donde alojamos la estructura de nuestro arbol, otra llamada arbol donde escribimos
los mtodos que manipulan a este, y una ultima llamada Main que alojara al mtodo
principal de nuestro programa que se encargara de controlar todo el programa.

Ejemplo de rbol bimario en cdigo java:

PRIMERO LA CLASE:

//definicion de la clase NodoArbol
class NodoArbol {
programacionparajava.blogspot.com


25


//miembros de acceso
NodoArbol nodoizquierdo;
int datos;
NodoArbol nododerecho;

//iniciar dato y hacer de este nodo un nodo hoja
public NodoArbol(int datosNodo)
{
datos = datosNodo;
nodoizquierdo = nododerecho = null; //el nodo no tiene hijos
}

//buscar punto de insercion e insertar nodo nuevo
public synchronized void insertar(int valorInsertar)
{
//insertar en subarbol izquierdo
if (valorInsertar < datos){

//inserta nuevo nodoarbol
if (nodoizquierdo == null)
nodoizquierdo = new NodoArbol(valorInsertar);
else //continua recorriendo subarbol izquierdo
nodoizquierdo.insertar(valorInsertar);
}

//insertar nodo derecho
else if(valorInsertar > datos){

//insertar nuevo nodoarbol
if (nododerecho == null)
nododerecho = new NodoArbol(valorInsertar);
else //continua recorriendo subarbol derecho
nododerecho.insertar(valorInsertar);
}
} //fin del metodo insertar

} //fin clase nodoarbol


SEGUNDA CLASE :
class Arbol{
private NodoArbol raiz;

//contruir un arbol vacio
public Arbol()
{
raiz = null;
}

//insertar un nuevo nodo en el arbol de busqueda binaria
public synchronized void insertarNodo(int valorInsertar)
{
if(raiz == null)
programacionparajava.blogspot.com


26

raiz = new NodoArbol(valorInsertar); //crea nodo raiz

else
raiz.insertar(valorInsertar); // llama al metodo insertar
}

//--------------- EMPESAR EL RECORRIDO EN PREORDEN-----------------------
public synchronized void recorridoPreorden()
{
ayudantePreorden(raiz);
}
//metodo recursivo para recorrido en preorden

private void ayudantePreorden(NodoArbol nodo)
{
if (nodo == null)
return;

System.out.print(nodo.datos + " "); // mostrar datos del nodo
ayudantePreorden(nodo.nodoizquierdo); //recorre subarbol izquierdo
ayudantePreorden(nodo.nododerecho); //recorre subarbol derecho
}

//--------------EMPEZAR RECORRIDO INORDEN--------------------------------
---
public synchronized void recorridoInorden()
{
ayudanteInorden(raiz);
}

// metodo recursivo para recorrido inorden

private void ayudanteInorden(NodoArbol nodo)
{
if (nodo == null)
return;

ayudanteInorden(nodo.nodoizquierdo);
System.out.print(nodo.datos + " ");
ayudanteInorden(nodo.nododerecho);
}

//-----------------------------EMPEZAR RECORRIDO POSORDEN----------------
-----------------
public synchronized void recorridoPosorden()
{
ayudantePosorden(raiz);
}

//metodo recursivo para recorrido posorden

private void ayudantePosorden(NodoArbol nodo)
{
if (nodo == null)
programacionparajava.blogspot.com


27

return;

ayudantePosorden(nodo.nodoizquierdo);
ayudantePosorden(nodo.nododerecho);
System.out.print(nodo.datos + " ");
}

}//fin clase rbol


POR ULTIMO LA CLASE PRINCIPAL
public class PruebaArbol {
public static void main(String args[])
{
Arbol arbol = new Arbol();
int valor;

System.out.println( "Insertando los siguientes valores: ");

//insertando 10 numeros aleatorios del 0 al 99 en el arbol
for (int i = 1; i<=10 ; i++)
{
valor = (int) (Math.random() * 100);
System.out.print(valor + " ");
arbol.insertarNodo(valor);
}

System.out.println("\n\nRecorrido preorden");
arbol.recorridoPreorden();

System.out.println("\n\nRecorrido inorden");
arbol.recorridoInorden();

System.out.println("\n\nRecorrido posorden");
arbol.recorridoPosorden();
}
}



A continuacion se muestra la ejecucion del programa



programacionparajava.blogspot.com


28



Arboles binarios balanceados
http://estructura-de-datos-itsav.blogspot.mx/2012/03/525-balanceo-arboles-binarios.html
Cuando se estudiaron los arboles binarios de bsqueda se menciono que es una estructura
sobre la cual se pueden realizar eficientemente las operaciones de bsqueda, insercin y
eliminacin. Sin embargo, si el rbol crece o decrece descontroladme, el rendimiento puede
disminuir considerablemente. El caso ms desfavorable se produce cuando se inserta un
conjunto de claves ordenadas en forma ascendente o descendente.
Es de notar que el nmero promedio de comparaciones que se deben realizar para localizar
una determinada clave en un rbol binario de bsqueda con crecimiento descontrolado
es N/2, cifra que muestra un rendimiento muy pobre en la estructura.
Con el objeto de mantener la eficiencia en la operacin de bsqueda surgen los arboles
balanceados.La principal caracterstica de estos es la de realizar reacomodos o balanceos,
despus de inserciones o eliminaciones de elementos. Estos arboles reciben el nombre
de AVL en honor a sus inventores, dos matemticos rusos, G. M. Adelson-Velskii y E. M.
Landis.


Formalmente se define un rbol balanceado como un rbol binario de bsqueda, en el cual
se debe cumplir la siguiente condicin: Para todo nodo T del rbol, la altura de los
subrbols izquierdo y derecho no deben diferir en ms de una unidad.

Donde HRI es la altura de la rama o subrbol izquierdo y HRD es la altura de la rama o
subrbol derecho.
programacionparajava.blogspot.com


29

Los arboles balanceados se parecen mucho, en su mecanismo de formacin, a los nmeros
Fibonacci. El rbol de altura 0 es vaco, el rbol de altura 1 tiene un nico nodo y, en
general, el nmero de nodos del rbol con altura h > 1 se calcula aplicando la siguiente
formula recursiva:

donde K indica el nmero de nodos del rbol y hla altura.
Por otra parte, algunos estudios demuestran que la altura de un rbol balanceado de n nodos
nunca exceder de 1.44 * log n.

Insercin en rboles balanceados

Al insertar un elemento en un rbol balanceado se deben distinguir los siguientes casos:

1. Las ramas izquierda (RI) y derecha (RD) del rbol tienen la misma altura (HRI = HRD)
por lo tanto:
1.1 Si se inserta un elemento en RI, entonces HRI ser mayor en una unidad.
1.2 Si se inserta un elemento en RD, entonces HRD ser mayor en una unidad.
Observe que en cualquiera de los dos casos mencionados (1.1 y 1.2), no se viola el
criterio de equilibrio del rbol.

2. Las ramas izquierda (RI) y derecha (RD) del rbol tienen altura diferente
2.1 Supongamos que HRI < HRD :
2.1.1 Si se inserta un elemento en RI, entonces HRI ser igual a HRD . las ramas
tienen la misma altura, por lo que se mejora el equilibrio de y no es necesario estructurarlo
2.1.2 Si se inserta un elemento en RD, entonces se rompe el criterio de equilibrio
del rbol y es necesario reestructurarlo.
2.2 Supongamos que HRI > HRD:
2.2.1 Si se inserta un elemento en RI, entonces se rompe el criterio de equilibrio
del rbol y es necesario reestructurarlo.
2.2.2 Si se inserta un elemento en RD, entonces HRD ser igual a HRI Las
ramas tienen la misma altura, por lo que se mejora el equilibrio del rbol
Ahora bien, para poder determinar si un rbol esta balanceado o no, se debe manejar
informacin relativa al equilibrio de cada nodo del rbol. Surge as el concepto de factor de
equilibrio de un nodo(FE) que se define como la altura del subrbol derecho menos la
altura del subrbol izquierdo.

A continuacin se presenta la definicin de un rbol balanceado en lenguaje algortmico.
ENLACE = ^NODO
NODO = REGISTRO
IZQ, DER: tipo ENLACE
programacionparajava.blogspot.com


30

INFO: tipo de dato
FE: -1 1
Fin de la definicin

Reestructuracin del rbol balanceado
El proceso de insercin en un rbol balanceado es sencillo, sin embargo requiere
operaciones auxiliares que complican parcialmente el proceso. Primero se debe seguir el
camino de bsqueda del rbol, hasta localizar el lugar donde hay que insertar el elemento.
Luego se calcula su FE, que obviamente ser 0, y regresamos por el camino de bsqueda
calculando el FE de los distintos nodos visitados. Si en alguno de los nodos viola el criterio
de equilibrio entonces se debe reestructurar el rbol. El proceso termina al llegar a la raz
del rbol, o cuando se realiza la reestructuracin del mismo, en cuyo caso no es necesario
determinar el FE de los nodos restantes.
Reestructurar el rbol significa rotar los nodos del mismo para llevarlo a un estado de
equilibrio. La rotacin puede ser simple o compuesta. El primer caso involucra dos nodos y
el segundo caso afecta a tres. Si la rotacin es simple se puede realizar por las ramas
derechas (DD) o por las ramas izquierdas (IT). Si por otra parte la rotacin es compuesta se
puede realizar por las ramas derecha e izquierda (DI) o por las ramas izquierda y
derecha (ID).

Inserta_balanceado(NODO, BO, INFOR)
El algoritmo inserta un elemento en un rbol balanceado. NODO es un parmetro de tipo
puntero, por referencia. BO es un parmetro de tipo booleano, por referencia. BO se utiliza
para indicar que la altura del rbol ha crecido, su valor inicial es FALSO. INFOR es un
parametro de tipo entero que contiene la informacin del elemento que queremos insertar
OTRO, NODOl y NODO2 son variables auxiliares de tipo puntero
1. Si (NODO NULO)
entonces
1.1 Si (INFOR < NODO^.INFO)
entonces
Regresar a Inserta_balanceado con NODO^.IZQ, BO e INFOR
Llamada recursiva
1.1.1 Si (BO = VERDADERO)
entonces
1.1.1.1 Si (NODO^.
FE) = 1: Hacer NODO^.FE <- 0 y BO <-
FALSO = 0: Hacer NODO^.FE <- -1
= -1: Hacer NODO1 <- NODO^.IZQ Reestructuracin del rbol
1.1.1.1.1 Si (NODO^.FE 0)
entonces Rotacin II
programacionparajava.blogspot.com


31

Hacer NODO^.IZQ <- NODO1^.DER,
NODO1^.DER <- NODO,
NODO^.FE <-0 y NODO <-NODOl Termina la rotacin II
si no Rotacin ID
Hacer NODO2 <- NODO1^.DER,
NODO^.IZQ <- NODO2^.DER,
NODO2^.DER <- NODO,
NODO1^.DER <- NODO2^.IZQ y
NODO2^.IZQ <- NODOl
1.1.1.1.1.A Si(NODO2^.FE = -l)
entonces
Hacer NODO^.FE <- -1
si no
Hacer NODO^.FE <- 0
1.1.1.1.1.B. Fin del condicional del paso 1.1.1.1.1.A
1.1.1.1.1.C Si(NODO2^.FE = l)
entonces
Hacer NODO1^. FE <- -1
si no
Hacer NODOl^. FE <- 0
1.1.1.1.1.D. Fin del condicional del paso 1.1.1.1.1.C
Hacer NODO <- NOD02
Termina la rotacin ID
1.1.1.1.2 Fin del condicional del paso 1.1.1.1.1
Hacer NODO^.FE <- 0 y BO <- FALSO
1.1.1.2 Fin del condicional del paso 1.1.1.1
1.1.2 Fin del condicional del paso 1.1.1
si no
1.1.3 Si (INFOR > NODO^.INFO)
entonces
Regresar a Inserta_balanceado con NODO^.DER, BO e INFOR
Llamada recursiva
1.1.3.1 Si (BO = VERDADERO)
entonces
1.1.3.1.1 Si (NODO^.FE)
= -1: Hacer NODO^.FE <- 0 y BO <- FALSO
= 0: Hacer NODO1^.FE <- 1
= 1: Hacer NODOl <-NODO^.DER
Reestructuracin del rbol
1.1.3.1.1.A S (NODOl^.FE 0)
programacionparajava.blogspot.com


32

entonces Rotacin DD
Hacer NODO^.DER <- NODOl^.IZQ,
NODO1^.IZQ <- NODO,
NODO^.FE <- 0 y NODO <- NODOl
Termina la rotacin DD
si no Rotacin DI
Hacer NODO2 <- NODO1^.IZQ,
NODO^.DER <- NODO2^.IZQ,
NODO2^.IZQ <- NODO,
NODO1^.IZQ <- NODO2^.DER y
NODO2^.DER <- NODOl
(NODO2^.FE = 1)
entonces
Hacer NODO^.FE <- 1
si no
Hacer NODO^.FE <- 0
Fin del condicional interno
S (NOD02^.FE = -l)
entonces
Hacer NODO1^. FE <- -1
si no
Hacer NODO1^.FE <- 0
Fin del condicional interno
Hacer NODO <- NODO2
Termina la rotacin DI
1.1.3.1.1.B Fin del condicional del paso 1.1.3.1.1.A
Hacer NODO^.FE <- 0 y BO <- FALSO
1.1.3.1.2 Fin del condicional del paso 1.1.3.1.1
1.1.3.2 Fin del condicional del paso 1.1.3.1
si no
Escribir La informacin ya se encuentra en el rbol
1.1.4 Fin del condicional del paso 1.1.3
1.2 Fin del condicionante del paso 1.1
Si no
Crear(NODO)
Hacer NODO^.INFO <- INFOR, NODO^.IZQ <- NULO, NODO^.DER <-
NULO, NODO^.FE <- 0 y
BO <- VERDADERO
2. Fin del condicional del paso 1
Eliminacin en rboles balanceados
programacionparajava.blogspot.com


33


La operacin de eliminacin en rboles balanceados es un poco ms compleja que la
operacin de insercin, como normalmente ocurre en casi todas las estructuras de datos.
Esta consiste en quitar un nodo del rbol sin violar los principios que definen un rbol
balanceado. Recuerde que se defini como una estructura en la cual, para todo nodo del
rbol, se debe cumplir que: la altura del subrbol izquierdo y la altura del subrbol derecho
no deben diferir en ms de una unidad.
Eliminar nodos en un rbol balanceado resulta difcil a pesar de que se utiliza mismo
algoritmo de eliminacin, idntico en lgica pero diferente en implementacin que en los
rboles binarios de bsqueda y las mismas operaciones de reacomodo que se utilizan en el
algoritmo de insercin en arboles balanceados.
En la operacin de eliminacin en arboles balanceados se deben distinguir los siguientes
casos:
1. Si el elemento a eliminar es terminal u hoja, simplemente se suprime.
2. Si el elemento a eliminar tiene un solo descendiente, entonces se tiene que sustituir por ese
descendiente.
3. Si el elemento a eliminar tiene los dos descendientes, entonces se tiene que sustituir por el
nodo que se encuentra ms a la izquierda en el subrbol derecho o por el que se encuentra
ms a la derecha en el subrbol izquierdo.
Para eliminar un nodo en un rbol balanceado lo primero que se debe hacer es localizar su
position en el rbol. Se elimina siguiendo los criterios establecidos anteriormente y se
regresa por el camino de bsqueda calculando el FE de los nodos visitados. Si en alguno de
los nodos se viola el criterio de equilibrio, entonces se debe reestructurar el rbol. El
proceso termina cuando se llega a la raz del rbol. Cabe aclarar que mientras que en el
algoritmo de insercin una vez efectuada una rotacin se poda detener el proceso, en este
algoritmo se debe continuar puesto que se puede producir ms de unarotacin en el camino
hacia atrs.

Con el fin de darle mayor modularidad al algoritmo de eliminacin en arboles balanceados,
se estudiaran dos algoritmos auxiliares. El primero, Reestructura_izq, se utiliza cuando la
altura de la rama izquierda ha disminuido. El segundo, Reestructura_der, se emplea cuando
la altura de la rama derecha ha disminuido.

Reestructura_izq (NODO, BO)

Este algoritmo reestructura el rbol cuando la altura de la rama izquierda ha disminuido y
el FE de NODO es igual a 1. NODO es un parmetro por referencia de tipo puntero. BO es
un parmetro de tipo booleano, tambin por referencia. BO se utiliza para indicar que la
altura de la rama izquierda ha disminuido) NODOl y NODO2 son variables auxiliares de
tipo puntero
programacionparajava.blogspot.com


34

1. S(BO = VERDADERO)
entonces
1.1 Si (NODO^.FE)
= -1: Hacer NODO^.FE <- 0
= -0: Hacer NODO^.FE <- 1 y BO <- FALSO
= -1: Restructuracin del rbol
Hacer NODOl <- NODO^.DER
1.1.1 S (NODO1^.FE 0)
entonces Rotacin DD
Hacer NODO^.DER <- NODO1^.IZQ y
NODO1^.IZQ <-NODO
1.1.1.1 S NODO1^.FE
= 0: Hacer NODO^.FE <- 1, NODO1^.FE
<- -1 y BO <-FALSO
= 1: Hacer NODO^.FE <- 0 y NODO1^.FE
<- 0
1.1.1.2 Fin del condicional 1.1.1.1
Hacer NODO <- NODOl
Termina la rotacin DD
si no Rotacin DI
Hacer NODO2 <- NODO1^.IZQ,
NODO^.DER <- NODO2^.IZQ,
NODO2^.IZQ <- NODO,
NODO1^.IZQ <- NODO2^.DER y
NODO2^.DER <- NODO1
1.1.1.3 S(NODO2^.FE = l)
entonces
Hacer NODO^.FE <- 1
si no
Hacer NODO^.FE <- 0
1.1.1.4 {Fin del condicional 1.1.1.3}
1.1.1.5 Si (NODO2^.FE = -1)
entonces
Hacer NODO1^.FE <-- 1
si no
Hacer NODOl^.FE <- 0
1.1.1.6 Fin del condicional 1.1.1.5
Hacer NODO <- NODO2 y NODO2^.FE <- 0
Termina la rotacin DI
1.1.2. Fin del condicional del paso 1.1.1
programacionparajava.blogspot.com


35

1.2 Fin del condicional del paso 1.1
2. Fin del condicional del paso 1
Reestructura der (NODO, BO)

Este algoritmo reestructura el rbol cuando la altura de la rama derecha ha disminuido y
el FE de NODO es igual a -1. NODO es un parmetro por referencia, de tipo puntero. BO
es un parmetro de tipo booleano, tambin por referencia. BO se utiliza para indicar que la
altura de la rama derecha ha disminuido NODOl y NODO2 son variables auxiliares de tipo
puntero
1.S (BO = VERDADERO)
entonces
1.1 S NODO^.FE
= 1 : Hacer NODO^.FE <- 0
= 0 : Hacer NODO^.FE <- -1 y BO <- FALSO
= -1: Reestructuracin del rbol
Hacer NODOl <- NODO^.IZQ
1.1.1 Si (NODO1^.FE 0)
entonces Rotacin II
Hacer NODO^.IZQ <- NODO1^.DER y
NODO1^.DER <- NODO
1.1.1.1 Si NODO1^.FE
= -0: Hacer NODO^.FE <- -1,
NODO1^.FE <-1 y BO <- FALSO
= -1: Hacer NODO^.FE <- 0 y
NODOl^.FE<-0
1.1.1.2 Fin del condicional del paso 1.1.1.1
Hacer NODO <- NODOl
Termina la rotacin II
si no Rotacin ID)
Hacer NODO2 <- NODOl^.DER,
NODO^.IZQ <- NODO2^.DER
NODO2^.DER <- NODO,
NODO1^.DER <- NODO2^.IZQ
NODO2^.IZQ <-NODOl
1.1.1.3 S(NODO2^.FE = -l)
entonces
Hacer NODO^.FE <- 1
si no
Hacer NODO^.FE <- 0
1.1.1.4 Fin del condicional del paso 1.1.1.3
programacionparajava.blogspot.com


36

1.1.1.5 S(NODO2^.FE = l)
entonces
Hacer NODO1^.FE <- -1
Hacer NODO1^.FE <- 0
1.1.1.6 Fin del condicional del paso 1.1.1.5
Hacer NODO <- NODO2 y NODO2^.FE <- 0
Termina la rotacin ID
1.1.2 Fin del condicional del paso 1.1.1
1.2 Fin del condicional del paso 1.1
2. Fin del condicional del paso 1

A continuacin se presenta el algoritmo de eliminacin en arboles balanceados, el cual har
uso de los previamente explicados.

Elimina_balanceado (NODO, BO, INFOR)

El algoritmo elimina un elemento en un rbol balanceado. Utiliza dos algoritmos auxiliares
Reestructura izq y Reestructura der. NODO es un parmetro por referencia de tipo puntero.
BO es un parmetro de tipo booleano, tambin por referencia, y se utiliza para indicar que
si la altura del rbol ha disminuido, su valor inicial es FALSO. INFOR es un parmetro de
tipo entero que contiene la informacin del elemento que se quiere eliminar OTRO, AUX,
AUX1 son variables auxiliares de tipo puntero. BOOL es una variable de tipo booleano
1. Si (NODO NIL)
entonces
1.1 Si (INFOR < NODO^.INFO)
entonces
Regresar a Elimina_balanceado con NODO^.IZQ, BO e INFOR
Llamar al algoritmo Reestructura_izq con NODO y BO
si no
1.1.1 Si (INFOR > NODOMNFO)
entonces
Regresar a Elimina_balanceado con NODO^.DER, BO e INFOR
Llamar al algoritmo Reestructura_der con NODO y BO
si no
Hacer OTRO <- NODO y BO <- VERDADERO
1.1.1.1 Si (OTRO^.DER = NULO)
entonces
Hacer NODO <- OTRO^.IZQ
si no
1.1.1.1.1 Si (OTRO^.IZQ = NULO)
programacionparajava.blogspot.com


37

entonces
Hacer NODO <-OTRO^.DER
Hacer AUX <- NODO^.IZQ y BOOL <- FALSO
1.1.1.1.1.A Mientras (AUX^.DER NULO) Repetir

Hacer AUX1 <- AUX,

AUX <- AUX^.DER y

BOOL <- VERDADERO
1.1.1.1.1.B {Fin del ciclo del paso 1.1.1.1.1.A }
Hacer NODO^.INFO <- AUX^.INFO y
OTRO <-AUX
1.1.1.1.1.C Si (BOOL = VERDADERO)

entonces

Hacer AUX1^.DER <- AUX^.IZQ

si no

Hacer NODO^.IZQ <- AUX^.IZQ
1.1.1.1.1.D Fin del condicional del paso 1.1.1.1.1.C
Llamar al algoritmo Reestructura_der con NODO^.IZQ y BO
1.1.1.1.2 Fin del condicional del paso 1.1.1.1.1
1.1.1.2 Fin del condicional del paso 1.1.1.1
Quitar (OTRO) Libera la memoria del nodo
1.1.2. Fin del condicional del paso 1.1.1
1.2. Fin del condicional del paso 1.1
si no
Escribir "La informacin no se encuentra en el rbol"
2. Fin del condicional del paso 1


El anlisis matemtico de los algoritmos de insercin Inserta balanceado y eliminacin
demuestra que es posible buscar, insertar y minar un elemento en un rbol balanceado
de n nodos en O(log n)unidades de tiempo. Por otra parte, diversos anlisis demuestran que
son ms frecuentes las rotaciones en las operaciones de insercin que en las de eliminacin,
ya que mientras se produce aproximadamente una rotacin por cada dos inserciones, se
produce una rotacin por cada cinco eliminaciones.
programacionparajava.blogspot.com


38




Arboles b
http://ertereg.galeon.com/
http://es.wikipedia.org/wiki/%C3%81rbol-B
En las ciencias de la computacin, los rboles-B o B-rboles son estructuras de datos de
rbol que se encuentran comnmente en las implementaciones de bases de datos y sistemas
de archivos. Son rboles balanceados de bsqueda en los cuales cada nodo puede poseer
ms de dos hijos.
1
Los rboles B mantienen los datos ordenados y las inserciones y
eliminaciones se realizan en tiempo logartmico amortizado.
La idea tras los rboles-B es que los nodos internos deben tener un nmero variable de
nodos hijo dentro de un rango predefinido. Cuando se inserta o se elimina un dato de la
estructura, la cantidad de nodos hijo vara dentro de un nodo. Para que siga mantenindose
el nmero de nodos dentro del rango predefinido, los nodos internos se juntan o se parten.
Dado que se permite un rango variable de nodos hijo, los rboles-B no necesitan
rebalancearse tan frecuentemente como los rboles binarios de bsqueda auto-balanceables,
pero por otro lado pueden desperdiciar memoria, porque los nodos no permanecen
totalmente ocupados. Los lmites una superior e inferior en el nmero de nodos hijo son
definidos para cada implementacin en particular. Por ejemplo, en un rbol-B 2-3 (A
menudo simplemente llamado rbol 2-3 ), cada nodo slo puede tener 2 3 nodos hijo.
Un rbol-B se mantiene balanceado porque requiere que todos los nodos hoja se encuentren
a la misma altura.
Los rboles B tienen ventajas sustanciales sobre otras implementaciones cuando el tiempo
de acceso a los nodos excede al tiempo de acceso entre nodos. Este caso se da usualmente
cuando los nodos se encuentran en dispositivos de almacenamiento secundario como
los discos rgidos. Al maximizar el nmero de nodos hijo de cada nodo interno, la altura del
rbol decrece, las operaciones para balancearlo se reducen, y aumenta la eficiencia.
Usualmente este valor se coloca de forma tal que cada nodo ocupe un bloque de disco, o un
tamao anlogo en el dispositivo. Mientras que los rboles B 2-3 pueden ser tiles en la
memoria principal, y adems ms fciles de explicar, si el tamao de los nodos se ajustan
para caber en un bloque de disco, el resultado puede ser un rbol B 129-513.
Los creadores del rbol B, Rudolf Bayer y Ed McCreight, no han explicado el significado
de la letra B de su nombre. Se cree que la B es de balanceado, dado que todos los nodos
hoja se mantienen al mismo nivel en el rbol. La B tambin puede referirse a Bayer, o
a Boeing, porque sus creadores trabajaban en los Boeing Scientific Research Labs por ese
entonces.
programacionparajava.blogspot.com


39


Definicin tcnica
B-rbol es un rbol de bsqueda que puede estar vaco o aquel cuyos nodos pueden tener
varios hijos, existiendo una relacin de orden entre ellos, tal como muestra el dibujo.
Un rbol-B de orden M (el mximo nmero de hijos que puede tener cada nodo) es un rbol
que satisface las siguientes propiedades:
1. Cada nodo tiene como mximo M hijos.
2. Cada nodo (excepto raz y hojas) tiene como mnimo (M+1)/2 claves.
3. La raz tiene al menos 2 hijos si no es un nodo hoja.
4. Todos los nodos hoja aparecen al mismo nivel.
5. Un nodo no hoja con k hijos contiene k-1 elementos almacenados.
6. Los hijos que cuelgan de la raz (r1, , rm) tienen que cumplir ciertas condiciones:
1. El primero tiene valor menor que r1.
2. El segundo tiene valor mayor que r1 y menor que r2, etc.
3. El ltimo hijo tiene valor mayor que rm.

A continuacin se muestra un ejemplo de rbol binario y utilizamos 2 clases:
La primera clase ListaSimpleEst:
//Definicion de la clase lista
class ListaSimpleEst{
String impresor="";
NodosListaEst PrimerNodo;
NodosListaEst UltimoNodo;
//Retorna True si lista Vacia
public boolean VaciaLista(){
return PrimerNodo ==null;
}
//Inserta al final de la lista (solo prestamos)
public void InsertaFinal(int ide,int cod,String nom,NodosListaEstCursos
a){
if(VaciaLista()){
PrimerNodo= UltimoNodo = new NodosListaEst (ide,cod,nom,a);
System.out.println("Se inserto estudiante "+ide+nom);
}
else{
UltimoNodo=UltimoNodo.siguiente=new NodosListaEst
(ide,cod,nom,a);
System.out.println("Se inserto estudiante "+ide+" "+nom);
}
}

//elimina el ultimo elemento
programacionparajava.blogspot.com


40

public void EliminaFinal (){
if(!VaciaLista()){
if(PrimerNodo.equals(UltimoNodo))
PrimerNodo = UltimoNodo = null;
else{
NodosListaEst Actual=PrimerNodo;
while(Actual.siguiente != UltimoNodo)
Actual = Actual.siguiente;
UltimoNodo =Actual;
Actual.siguiente = null;
}
}
}
//Miembro
public boolean Miembro (int ele){
boolean enc=false;
NodosListaEst aux=PrimerNodo;
while((aux != null) && (enc==false)){
if(ele==aux.ident){
enc=true;
}
else{
aux=aux.siguiente;
}
}
return enc;
}
//Nombre
public String CualNombre (int ele){
String x="";
boolean enc=false;
NodosListaEst aux=PrimerNodo;
while((aux != null) && (enc==false)){
if(ele==aux.ident){
enc=true;
x=aux.Nombre;
}
else{
aux=aux.siguiente;
}
}
return x;
}
//imprime
public void Imprimir(){
if (VaciaLista()){
impresor="error";
}
else{
NodosListaEst Actual = PrimerNodo;
while (Actual != null){
impresor=impresor+"Id: "+Actual.ident+"\nNombre:
"+Actual.Nombre+"\nCod Carrera: "+Actual.Codcar+"\nCursos: ";
NodosListaEstCursos aa=Actual.cursos;
programacionparajava.blogspot.com


41

while(aa!=null){
impresor=impresor+aa.curso+" ";
aa=aa.siguiente;
}
impresor=impresor+"\n--------------------------\n";
Actual=Actual.siguiente;
}
}
}
// Largo
public void Largo(){
NodosListaEst aux=PrimerNodo;
int Lar =0;
while (aux!= null){
Lar++;
aux =aux.siguiente;
}
System.out.println ( "El largo de la Lista es: "+ Lar);
}
}
//Nodo de lista simple
class NodosListaEst{
int ident;
int Codcar;
String Nombre;
NodosListaEstCursos cursos;
NodosListaEst siguiente;
NodosListaEst (int ide,int cod,String nom,NodosListaEstCursos a){
ident=ide;
Codcar=cod;
Nombre=nom;
cursos=a;
siguiente=null;
}
NodosListaEst(){}
}
//lista de cursos
class NodosListaEstCursos{
int curso;
NodosListaEstCursos siguiente;
NodosListaEstCursos (int cur){
curso=cur;
siguiente=null;
}
NodosListaEstCursos(){}
}


Y la clase principal llamada Btree :

programacionparajava.blogspot.com


42

import javax.swing.*;
import java.io.*;
//Arboles Btree
class Btree{
Bnodo p=new Bnodo();
Bnodo Xder = new Bnodo();
Bnodo Xizq = new Bnodo();
NodoPr X;
Bnodo Xr;
String salida="",imps="";
boolean EmpA = false,Esta=false;
//***************************************
//*****Inserta un nodo en un arbol b*****
//***************************************
void Inserta(NodoPr clave){
Insertaa(clave,p);
}
//auxiliar de inserta nodo
public void Insertaa(NodoPr clave, Bnodo raiz){
Empujar(clave,raiz);
if(EmpA){
p=new Bnodo();
p.Cuentas= 1;
p.Claves[0]=X;
p.Ramas[0]=raiz;
p.Ramas[1]=Xr;
}
JOptionPane.showMessageDialog(null,"Insercion Completa");
}
//Empuja los elementos del arbol
public void Empujar(NodoPr clave, Bnodo raiz){
int k=0;
Esta=false;
if(Vacio(raiz)){
EmpA=true;
X=clave;
Xr=null;
}
else{
k=BuscarNodo(clave, raiz);
if(Esta){
JOptionPane.showMessageDialog(null,"No hay claves
repetidas");
EmpA=false;
}
else{
Empujar(clave, raiz.Ramas[k]);
if(EmpA){
if(raiz.Cuentas < 4){
EmpA = false;
MeterHoja(X, raiz, k);
}
else{
EmpA = true;
programacionparajava.blogspot.com


43

DividirN(X, raiz, k);
}
}
}
}
}
//Meter hoja
public void MeterHoja(NodoPr clave, Bnodo raiz, int k){
int i = raiz.Cuentas;
while (i != k){
raiz.Claves[i] = raiz.Claves[i-1];
raiz.Ramas[i+1] = raiz.Ramas[i];
--i;
}
raiz.Claves[k] = clave;
raiz.Ramas[k+1] = Xr;
raiz.Cuentas = ++raiz.Cuentas;
}
//Dividir nodo
public void DividirN(NodoPr Clave, Bnodo Raiz, int k){
int pos=0;
int Posmda=0;
if (k <= 2)
Posmda = 2;
else{
Posmda = 3;
}
Bnodo Mder = new Bnodo();
pos = Posmda+1;
while (pos != 5){
Mder.Claves [(pos - Posmda)-1] = Raiz.Claves[pos-1];
Mder.Ramas [pos - Posmda] = Raiz.Ramas[pos];
++pos;
}
Mder.Cuentas = 4 - Posmda;
Raiz.Cuentas = Posmda;
if (k <= 2)
MeterHoja(Clave, Raiz, k);
else{
MeterHoja(Clave, Mder, (k - Posmda));
}
X = Raiz.Claves[Raiz.Cuentas-1];
Mder.Ramas[0] = Raiz.Ramas[Raiz.Cuentas];
Raiz.Cuentas = --Raiz.Cuentas;
Xr=Mder;
}
//****************************************
//*****Borrar un elemento del arbol b*****
//****************************************
void Eliminar(NodoPr clave){
if(Vacio(p)){
JOptionPane.showMessageDialog(null,"No hay elementos");
}
else
programacionparajava.blogspot.com


44

Eliminara(p,clave);
}
public void Eliminara(Bnodo Raiz, NodoPr clave){
try{
EliminarRegistro(Raiz, clave);
}
catch(Exception e){
Esta=false;
}
if (!Esta)
JOptionPane.showMessageDialog(null,"No se encontro el
elemento");
else{
if (Raiz.Cuentas == 0)
Raiz = Raiz.Ramas[0];
p=Raiz;
JOptionPane.showMessageDialog(null,"Eliminacion completa");
}
}
//Elimina el registro
public void EliminarRegistro(Bnodo raiz, NodoPr c){
int pos = 0;
NodoPr sucesor;
if (Vacio(raiz))
Esta = false;
else{
pos = BuscarNodo(c, raiz);
if (Esta){
if (Vacio(raiz.Ramas[pos-1]))
Quitar(raiz, pos);
else{
Sucesor(raiz, pos);
EliminarRegistro (raiz.Ramas[pos],
raiz.Claves[pos-1]);
}
}
else{
EliminarRegistro(raiz.Ramas[pos], c);
if ((raiz.Ramas[pos] != null) &&
(raiz.Ramas[pos].Cuentas < 2))
Restablecer(raiz, pos);
}
}
}
//Busca el sucesor
public void Sucesor (Bnodo raiz, int k){
Bnodo q=raiz.Ramas[k];
while(!Vacio(q.Ramas[0]))
q=q.Ramas[0];
raiz.Claves[k-1]=q.Claves[0];
}
//Combina para formar un nodo
public void Combina(Bnodo raiz, int pos){
int j;
programacionparajava.blogspot.com


45

Xder = raiz.Ramas[pos];
Xizq = raiz.Ramas[pos-1];
Xizq.Cuentas++;
Xizq.Claves[Xizq.Cuentas-1] = raiz.Claves[pos-1];
Xizq.Ramas[Xizq.Cuentas] = Xder.Ramas[0];
j = 1;
while (j != Xder.Cuentas+1){
Xizq.Cuentas++;
Xizq.Claves[Xizq.Cuentas-1] = Xder.Claves[j-1];
Xizq.Ramas[Xizq.Cuentas] = Xder.Ramas[j];
j++;
}
Quitar(raiz, pos);
}
//Mueve a la derecha
public void MoverDer(Bnodo raiz, int pos){
int i = raiz.Ramas[pos].Cuentas;
while (i != 0){
raiz.Ramas[pos].Claves[i] = raiz.Ramas[pos].Claves[i-1];
raiz.Ramas[pos].Ramas[i+1] = raiz.Ramas[pos].Ramas[i];
--i;
}
raiz.Ramas[pos].Cuentas++;
raiz.Ramas[pos].Ramas[1] = raiz.Ramas[pos].Ramas[0];
raiz.Ramas[pos].Claves[0] = raiz.Claves[pos-1];
raiz.Claves[pos-1] = raiz.Ramas[pos-1].Claves[raiz.Ramas[pos-
1].Cuentas-1];
raiz.Ramas[pos].Ramas[0] = raiz.Ramas[pos-1].Ramas[raiz.Ramas[pos-
1].Cuentas];
raiz.Ramas[pos-1].Cuentas--;
}
//Mover a la izquierda
public void MoverIzq(Bnodo raiz, int pos){
int i;
raiz.Ramas[pos-1].Cuentas++;
raiz.Ramas[pos-1].Claves[raiz.Ramas[pos-1].Cuentas-1] =
raiz.Claves[pos-1];
raiz.Ramas[pos-1].Ramas[raiz.Ramas[pos-1].Cuentas] =
raiz.Ramas[pos].Ramas[0];
raiz.Claves[pos-1] = raiz.Ramas[pos].Claves[0];
raiz.Ramas[pos].Ramas[0] = raiz.Ramas[pos].Ramas[1];
raiz.Ramas[pos].Cuentas--;
i = 1;
while (i != raiz.Ramas[pos].Cuentas+1){
raiz.Ramas[pos].Claves[i-1] = raiz.Ramas[pos].Claves[i];
raiz.Ramas[pos].Ramas[i] = raiz.Ramas[pos].Ramas[i+1];
i++;
}
}
//Quita el elemento
public void Quitar (Bnodo raiz, int pos){
int j = pos + 1;
while (j != raiz.Cuentas+1){
raiz.Claves [j-2] = raiz.Claves[j-1];
programacionparajava.blogspot.com


46

raiz.Ramas [j-1] = raiz.Ramas[j];
j++;
}
raiz.Cuentas--;
}
//Restablece el nodo
public void Restablecer(Bnodo raiz, int pos){
if (pos>0){
if (raiz.Ramas[pos-1].Cuentas > 2)
MoverDer(raiz, pos);
else
Combina(raiz, pos);
}
else{
if (raiz.Ramas[1].Cuentas > 2)
MoverIzq(raiz, 1);
else
Combina(raiz, 1);
}
}
//***************************
//*****Metodos Generales*****
//***************************
//muestra los temas por estudiante
public void temasestudiante(ListaSimpleEst idents,Bnodo Raiz){
NodosListaEst m=idents.PrimerNodo;
imps="";
while(m!=null){
imps=imps+"IDENTIFICACION: "+m.ident;
temasestudianteaux(m.ident,Raiz);
imps=imps+"\n---------------------------------------\n";
m=m.siguiente;
}
}
public void temasestudianteaux(int id,Bnodo Raiz){
int i;
if(!Vacio(Raiz)){
temasestudianteaux(id,Raiz.Ramas[0]);
i=1;
while (i != Raiz.Cuentas+1){
if(id==Raiz.Claves[i-1].ident){
imps=imps+"\n***** Tema: "+Raiz.Claves[i-
1].codtem+" *****"+"\n -Num Prestamo: "+Raiz.Claves[i-1].nump+"\n
-Libro: "+Raiz.Claves[i-1].codlib+"\n -Cod Autor: "+Raiz.Claves[i-
1].codaut+"\n -Fecha/Hora: "+Raiz.Claves[i-1].fecha;
}
temasestudianteaux(id,Raiz.Ramas[i]);
++i;
}
}
}
//Retorna true si el arbol esta vacio
public boolean Vacio(Bnodo raiz){
return (raiz==null || raiz.Cuentas==0);
programacionparajava.blogspot.com


47

}
//Buscar retorna true si lo encuentra y la posicion
public int BuscarNodo(NodoPr clave, Bnodo raiz){
int j=0;
if(clave.nump < raiz.Claves[0].nump){
Esta = false;
j=0;
}
else{
j = raiz.Cuentas;
while (clave.nump < raiz.Claves[j-1].nump && j>1)
--j;
Esta = (clave.nump == raiz.Claves[j-1].nump);
}
return j;
}
//miembro
public boolean Miembro(NodoPr clave, Bnodo raiz){
boolean si=false;
int j=0;
if(!Vacio(p)){
if(clave.nump < raiz.Claves[0].nump){
si = false;
j=0;
}
else{
j = raiz.Cuentas;
while (clave.nump < raiz.Claves[j-1].nump && j>1)
--j;
si = (clave.nump == raiz.Claves[j-1].nump);
}
}
return si;
}
//Recorrido InOrden Iterativo
void InordenIT(){
int i=0;
Bnodo nodo=p;
ListaSimpleB Pila = new ListaSimpleB();
do{
i=0;
while (!Vacio(nodo)){
Pila.InsertaFinal(nodo, i);
nodo=nodo.Ramas[i];
}
if (!Pila.VaciaLista()){
i=Pila.UltimoNodo.indice;
nodo=Pila.UltimoNodo.datos;
Pila.EliminaFinal();
i++;
if (i <= nodo.Cuentas){
salida=salida+"Num Prestamo: "+nodo.Claves[i-
1].nump+"\n -Id: "+nodo.Claves[i-1].ident;
programacionparajava.blogspot.com


48

salida=salida+"\n -Cod Tema:
"+nodo.Claves[i-1].codtem+"\n -Cod Libro: "+nodo.Claves[i-
1].codlib+"\n -Cod Autor: "+nodo.Claves[i-1].codaut+"\n
-Fecha/hora: "+nodo.Claves[i-1].fecha+"\n";
salida=salida+"-------------------------------
\n";
if (i < nodo.Cuentas)
Pila.InsertaFinal(nodo, i);
nodo=nodo.Ramas[i];
}
}
}
while (!Pila.VaciaLista() || !Vacio(nodo));
}
}
//Nodo de arbol b
class Bnodo{
Bnodo[]Ramas = new Bnodo[5];
NodoPr[]Claves = new NodoPr[4];
int Cuentas = 0;
Bnodo(NodoPr clave){
Claves[0] = clave;
}
Bnodo(){
}
}

//Definicion de la clase lista
class ListaSimpleB{
NodosLista PrimerNodo;
NodosLista UltimoNodo;
//Retorna True si lista Vacia
public boolean VaciaLista(){
return PrimerNodo ==null;
}
public ListaSimpleB(String s){
PrimerNodo=UltimoNodo=null;
}
public ListaSimpleB(){
this ("Lista");
}
//Inserta un elemento al frente de la lista (solo prestamos)
void InsertaInicio(Bnodo ElemInser,int ind){
if(VaciaLista())
PrimerNodo=UltimoNodo=new NodosLista(ElemInser,ind);
else
PrimerNodo=new NodosLista(ElemInser, PrimerNodo,ind);
}
//Inserta al final de la lista (solo prestamos)
public void InsertaFinal(Bnodo ElemInser,int ind){
if(VaciaLista()){
PrimerNodo= UltimoNodo = new NodosLista (ElemInser,ind);
}
else{
programacionparajava.blogspot.com


49

UltimoNodo=UltimoNodo.siguiente=new
NodosLista(ElemInser,ind);
}
}
//Elimina al final (todos)
public void EliminaFinal(){
if (VaciaLista())
System.out.println ("No hay elementos");
if (PrimerNodo.equals (UltimoNodo))
PrimerNodo = UltimoNodo = null;
else{
NodosLista Actual =PrimerNodo;
while (Actual.siguiente != UltimoNodo)
Actual = Actual.siguiente;
UltimoNodo =Actual;
Actual.siguiente = null;
}
}
//Inserta al final de la lista (normal)
public void InsertaFinal(String ElemInser){
if(VaciaLista()){
PrimerNodo= UltimoNodo = new NodosLista (ElemInser);
}
else{
UltimoNodo=UltimoNodo.siguiente=new NodosLista(ElemInser);
}
}
//Elimina al Inicio (todos)
public void EliminaInicio(){
if(VaciaLista())
System.out.println("No hay elementos");
else
if(PrimerNodo.equals(UltimoNodo))
PrimerNodo=UltimoNodo=null;
else
PrimerNodo=PrimerNodo.siguiente;
}
// Largo
public void Largo(){
NodosLista aux=PrimerNodo;
int Lar =0;
while (aux!= null){
Lar++;
aux =aux.siguiente;
}
System.out.println ( "El largo de la Lista es: "+ Lar);
}
//Imprimir
void Imprimir(){
NodosLista m=PrimerNodo;
String k;
while(m!=null){
k=String.valueOf(m.letra);
if(k.equals("#"))
programacionparajava.blogspot.com


50

System.out.print(" ");
else{
System.out.print(m.letra);
}
m=m.siguiente;
}
System.out.println("");
}
}
//Nodo de lista simple
class NodosLista{
Bnodo datos;
String letra;
int indice;
NodosLista siguiente;
NodosLista(Bnodo valor,int ind){
datos=valor;
indice=ind;
siguiente=null;
}
NodosLista (Bnodo valor,NodosLista signodo,int ind){
datos=valor;
indice=ind;
siguiente=signodo;
}
NodosLista(String valor){
letra=valor;
siguiente=null;
}
NodosLista (String valor,NodosLista signodo){
letra=valor;
siguiente=signodo;
}
}
//Nodo de prestamos
class NodoPr{
int nump;
int ident;
int codlib;
int codtem;
int codaut;
String fecha;
NodoPr(int val){
nump=val;
}
NodoPr(){
}
}

class Aas{
public static void main(String a[]){
Btree m=new
Btree();

programacionparajava.blogspot.com


51

NodoPr fa;

for(int i=0;i<14;i++){
fa=new NodoPr(i);
m.Inserta(fa);
}
fa=new NodoPr(4);
m.Eliminar(fa);
m.InordenIT();
System.out.println(m.salida);
//getchar();
}
}

Corrida del programa:


Arboles b+
En ciencias de la computacin, un rbol B+ es un tipo de estructura de datos de rbol,
representa una coleccin de datos ordenados de manera que se permite una insercin y
borrado eficientes de elementos. Es un ndice, multinivel, dinmico, con un lmite mximo
y mnimo en el nmero de claves por nodo. Un rbol B+ es una variacin de un rbol B.
En un rbol B+, toda la informacin se guarda en las hojas. Los nodos internos slo
contienen claves y punteros. Todas las hojas se encuentran en el mismo nivel, que
corresponde al ms bajo. Los nodos hoja se encuentran unidos entre s como una lista
enlazada para permitir bsqueda secuencial.
programacionparajava.blogspot.com


52


Caractersticas
Las estructuras de rbol B+ renen las siguientes caractersticas:
El nmero mximo de claves en un registro es llamado el orden del rbol B+.
El mnimo nmero de claves por registro es la mitad del mximo nmero de claves. Por
ejemplo, si el orden de un rbol B+ es n, cada nodo (exceptuando la raz) debe tener
entre n/2 y n claves.
El nmero de claves que pueden ser indexadas usando un rbol B+ est en funcin del
orden del rbol y su altura.

Altura: El mejor y el peor caso
Dado un M, el cual corresponde al nmero mximo de hijos que un nodo puede contener se
define por:
La altura h de un rbol B+ (El peor caso):

La altura h de un rbol B+ (Mejor caso) :

Este caso se debe a que si guardamos menos hijos en los nodos, se necesitarn ms
niveles para almacenar todo.

Cantidad de claves
Para un rbol B+ de orden n, con una altura h:
El nmero mximo de claves es:
El nmero mnimo de claves es:

Ejemplo de rbol b+ en java :
La primera clase :

public class BTree {
private BTree izquierda= null;
private BTree derecha= null;
programacionparajava.blogspot.com


53

private Object elemento;
public static int LADO_IZDO= 1;
public static int LADO_DRCHO= 2;
public BTree(Object elemento) {
this.elemento = elemento ;
}
public Object getElement() {
return elemento;
}
public BTree getIzquierda() {
return izquierda;
}
public BTree getDerecha() {
return derecha;
}
public void insertar(BTree tree, int lado) throws BTreeException {
if (lado==LADO_IZDO) {
if (izquierda==null) izquierda= tree;
else throw new BTreeException("Ya hay un ?rbol enlazado");
}
else if (lado==LADO_DRCHO) {
if (derecha==null) derecha= tree;
else throw new BTreeException("Ya hay un ?rbol enlazado");
}
else throw new BTreeException("Lado incorrecto");
}
public BTree extraer(int lado) throws BTreeException {
BTree subarbol;if (lado==LADO_IZDO) {
subarbol= izquierda;
izquierda= null;
}
else if (lado==LADO_DRCHO) {
subarbol= derecha;
derecha= null;
}
else
throw new BTreeException("Lado incorrecto");
return subarbol;
}
public void imprimePreOrden() {
System.out.println(elemento);
if (izquierda!=null) izquierda.imprimePreOrden();
if (derecha!=null) derecha.imprimePreOrden();
}
public void imprimePostOrden() {
if (izquierda!=null) izquierda.imprimePostOrden();if (derecha!=null)
derecha.imprimePostOrden();System.out.println(elemento); } public void
imprimeEnOrden() {if (izquierda!=null)
izquierda.imprimeEnOrden();System.out.println(elemento);if (derecha!=null)
derecha.imprimeEnOrden(); }}



programacionparajava.blogspot.com


54


la segunda clase:

public class BTreeException extends Exception { public BTreeException (String
mensaje) {super(mensaje); }}


y la principal:


public class Trabalenguas { public static void main(String args[]) {BTree
trabalenguas, subarbol, temporal;try { trabalenguas= new BTree("Tres");
subarbol= new BTree("tristes"); trabalenguas.insertar(subarbol,
BTree.LADO_IZDO); temporal= new BTree("tigres"); trabalenguas.insertar(temporal,
BTree.LADO_DRCHO); temporal= new BTree("com?an"); subarbol.insertar(temporal,
BTree.LADO_IZDO); temporal= new BTree("trigo"); subarbol.insertar(temporal,
BTree.LADO_DRCHO);} catch (BTreeException ex) {
System.out.println(ex.getMessage());
return;}trabalenguas.imprimePreOrden();System.out.println("------------------
");trabalenguas.imprimeEnOrden();System.out.println("------------------
");trabalenguas.imprimePostOrden();System.out.println("------------------
");System.out.println("------------------");try { subarbol=
trabalenguas.extraer(BTree.LADO_IZDO);} catch (BTreeException ex) {
System.out.println(ex.getMessage()); return;}trabalenguas.imprimePreOrden(); }}

Y asi quedara la corrida del programa:


programacionparajava.blogspot.com


55

Teora de grafos

Operaciones en grafos

En los grafos, como en todas las estructuras de datos, las dos operaciones bsicas son
insertar y borrar. En este caso, cada una de ellas se desdobla en dos, para insertar/eliminar
vrtices e insertar/eliminar aristas.
Insertar vrtice
La operacin de insercin de un nuevo vrtice es una operacin muy sencilla, nicamente
consiste en aadir una nueva entrada en la tabla de vrtices (estructura de datos que
almacena los vrtices) para el nuevo nodo. A partir de ese momento el grafo tendr un
vrtice ms, inicialmente aislado, ya que ningna arista llegar a l.
Insertar arista
Esta operacin es tambin muy sencilla. Cuando se inserte una nueva arista en el grafo,
habr que aadir un nuevo nodo a la lista de adyacencia (lista que almacena los nodos a los
que un vrtice puede acceder mediante una arista) del nodo origen, as si se aade la arista
(A,C), se deber incluir en la lista de adyacencia de A el vrtice C como nuevo destino.
Eliminar vrtice
Esta operacin es inversa a la insercin de vrtice. En este caso el procedimiento a realizar
es la eliminacin de la tabla de vrtices del vrtice en s. A continuacin habr que eliminar
las aristas que tuviesen al vrtice borrado como origen o destino.
Eliminar arista
Mediante esta operacin se borra un arco del grafo. Para llevar a cabo esta accin es
necesario eliminar de la lista de adyacencia del nodo origen el nodo correspondiente al
nodo destino.
Otras operaciones
Las operaciones adicionales que puede incluir un grafo son muy variadas. Adems de las
clsicas de bsqueda de un elemento o recorrido del grafo, tambin podemos encontrarnos
con ejecucin de algoritmos que busquen caminos ms cortos entre dos vrtices, o
programacionparajava.blogspot.com


56

recorridos del grafo que ejecuten alguna operacin sobre todos los vrtices visitados, por
citar algunas operaciones de las ms usuales.
1. ///////////////////////////////////////////////////////////////////
/////////////////////////////////////////
2. /*
3. *
4. *



5. *
6. *
7. * Dado un grafo no dirigido G con el conjunto de vrtices
{0,1,..,V-1} y con E aristas. Denotamos con (i,j) la
8. * conexin entre el vrtice i y el vrtice j y con d(i) el grado
del vrtice i.
9. *
10. * Definimos las siguientes operaciones:
11. * - borrarArista(i,j): borrar de G la arista (i,j).
12. * - borrarAristasIncidentes(i): borrar de G todas las d(i) aristas
incidentes en el referido vrtice.
13. *
14. * Implemente ambas funciones en el cdigo fuente de libro de Weiss
y mencione un preciso anlisis del costo de
15. * ejecucin de ambos mtodos. El cdigo fuente estar disponible
en Educa
16. *
17. * Incluya todos los archivos necesarios para las pruebas de
funcionamiento.
18. *
19. * Para tener una mejor idea de cmo est almacenado el grafo y su
diseo * consultar el libro Algoritmos y Estructuras de Datos
en Java, Mark A. Weiss *Pag. 357 Addison Wesley
20. *
21. */
22.
23.
24.
25.
26.
27. //////////////////////////////////////////////////////////////////
//////////////////////////////////////////
28.
29.
30.
31.
32.
33. import DataStructures.*;
34. import Supporting.*;
programacionparajava.blogspot.com


57

35. import Exceptions.*;
36.
37. import java.util.StringTokenizer;
38. import Supporting.Comparable;
39. import java.io.*;
40.
41. // Graph class interface: evaluate shortest paths
42. //
43. // CONSTRUCTION: with no initializer
44. //
45. // ******************PUBLIC OPERATIONS**********************
46. // void addEdges( String source, String dest, int cost )
47. // --> Add additional edge
48. // boolean processRequest( BufferedReader in )
49. // --> Run a bunch of shortest path algs
50. // ******************ERRORS*********************************
51. // Some error checking is performed to make sure graph is ok,
52. // parameters to processRequest represent vertices in the graph,
53. // and to make sure graph satisfies properties needed by each
algorithm
54.
55. /**
56. * This class represents the basic
57. * item in the adjacency list.
58. */
59. class Edge
60. {
61. // First vertex in edge is implicit
62. public int dest; // Second vertex in edge
63. public int cost; // Edge cost
64.
65. public Edge( int d, int c )
66. {
67. dest = d;
68. cost = c;
69. }
70. }
71.
72.
73. /**
74. * This class represents the basic item
75. * stored for each vertex.
76. */
77. class Vertex
78. {
79. String name; // The real name
80. List adj; // The adjacency list
81.
82. int dist; // Cost (after running algorithm)
83. int prev; // Previous vertex on shortest path
84. int scratch; // Extra variable for use in algorithm
85. int grado; //El grado de entrada del nodo.
86. Vertex( String nm )
87. {
88. name = nm; // Share name in hash table
89. adj = new LinkedList( ); // Make a new list
programacionparajava.blogspot.com


58

90. }
91. }
92.
93.
94. /**
95. * This class represents the basic entry
96. * in the vertex dictionary.
97. * It implements the Hashable interface by providing
98. * hash and equals.
99. */
100. class HashItem implements Hashable
101. {
102. public String name; /* The real name */
103. public int rank; /* The assigned number */
104.
105. public HashItem( )
106. {
107. this( null );
108. }
109.
110. public HashItem( String nm )
111. {
112. name = nm;
113. }
114.
115. public int hash( int tableSize )
116. {
117. return ProbingHashTable.hash( name, tableSize );
118. }
119.
120. public boolean equals( Object rhs )
121. {
122. return name.equals( ((HashItem) rhs).name );
123. }
124. }
125.
126.
127. /**
128. * Object stored in the priority queue
129. * for Dijkstra's algorithm
130. */
131. class Path implements Comparable
132. {
133. int dest; // W
134. int cost; // D(W)
135.
136. static Path negInf = new Path( ); // Sentinel
137.
138. Path( )
139. {
140. this( 0 );
141. }
142.
143. Path( int d )
144. {
145. this( d, 0 );
programacionparajava.blogspot.com


59

146. }
147.
148. Path( int d, int c )
149. {
150. dest = d;
151. cost = c;
152. }
153.
154. public boolean lessThan( Comparable rhs )
155. {
156. return cost < ( (Path) rhs ).cost;
157. }
158.
159. public int compares( Comparable rhs )
160. {
161. return cost < ( (Path) rhs ).cost ? -1 :
162. cost > ( (Path) rhs ).cost ? 1 : 0;
163. }
164. }
165.
166. /**
167. * Graph class: evaluate shortest paths.
168. */
169. public class Graph
170. {
171. public Graph( )
172. {
173. numVertices = 0;
174. table = new Vertex[ INIT_TABLE_SIZE ];
175. vertexMap = new QuadraticProbingTable( );
176. }
177.
178. /**
179. * Add the edge ( source, dest, cost ) to the graph.
180. */
181. public void addEdge( String source, String dest, int cost )
182. {
183. addInternalEdge( addNode( source ), addNode( dest ), cost
);
184. }
185.
186. /**
187. * Process a request; return false if end of file.
188. */
189. public boolean processRequest( BufferedReader in )
190. {
191. String sourceName, destName;
192. HashItem source = new HashItem( );
193. HashItem dest = new HashItem( );
194.
195. try
196. {
197. System.out.println( "Enter start node:" );
198. if( ( sourceName = in.readLine( ) ) == null )
199. return false;
200. System.out.println( "Enter destination node:" );
programacionparajava.blogspot.com


60

201. if( ( destName = in.readLine( ) ) == null )
202. return false;
203. }
204. catch( IOException e )
205. {
206. System.out.println( "Error: " + e );
207. return false;
208. }
209.
210. try
211. {
212. source.name = sourceName;
213. source = (HashItem) ( vertexMap.find( source ) );
214. dest.name = destName;
215. dest = (HashItem) ( vertexMap.find( dest ) );
216.
217. unweighted( source.rank );
218. printPath( dest.rank );
219.
220. if( dijkstra( source.rank ) )
221. printPath( dest.rank );
222. else
223. System.out.println( "Dijkstra fails - neg edge" );
224.
225. if( dijkstraPair( source.rank ) )
226. printPath( dest.rank );
227. else
228. System.out.println( "Dijkstra fails - neg edge" );
229.
230. if( negative( source.rank ) )
231. printPath( dest.rank );
232. else
233. System.out.println( "Negative fails - neg cycle"
);
234.
235. if( acyclic( source.rank ) )
236. printPath( dest.rank );
237. else
238. System.out.println( "Acyclic fails - cycle" );
239. }
240. catch( ItemNotFound e )
241. { System.err.println( "Vertex not in graph" ); }
242. return true;
243. }
244.
245.
246. /**
247. * Metodo para imprimir la est. de datos tabla que se utiliza
248. * para representar el grafo.
249. * Muestra el nodo de la tabla y sus adyacentes.
250. */
251. public void imprimirGrafoTabla(){
252. int i = 0;
253. ListItr theList;
254. Edge theEdge;
255.
programacionparajava.blogspot.com


61

256. System.out.println( "Nodo\tAdyacentes");
257.
258. //Recorremos la tabla mientras que no sea null
259. while( this.table[ i ] != null ) //Analizamos cada
nodo en la tabla
260. {
261.
262. System.out.print( " " + this.table[ i ].name + " --
> "); //Imprimimos el nodo actual
263.
264. //Una vez impreso el nodo actual, tenemos que revisar
su lista de adyacencias
265. theList = new LinkedListItr( this.table[ i ].adj );
266. theList.first();
267. theEdge = (Edge)theList.retrieve();
268. while( theEdge != null )
269. {
270. System.out.print( this.table[ theEdge.dest ].name
+ " "); //Imprimimos
271. theList.advance(); //Avanzamos la lista
272.
273. theEdge = (Edge)theList.retrieve();
274. }
275.
276. System.out.print("\n");
277.
278. i++;
279. }
280. }
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298. /**
299. * Metodo para borrar una arista de un nodo X a un nodo Y
300. * La idea es ir hasta X luego ver si existe Y en la lista de
X,
301. * si existe ir hasta Y y remover en la lista de Y la
ocurrencia de X,
302. * por ultimo remover de la lista de X la ocurrencia de Y
303. * @param X
304. * @param Y
305. * Costo:
programacionparajava.blogspot.com


62

306. * -Encontrar los vertices por sus nombres: O(1) gracias a la
tabla hash
307. * -Encontrar arista en la lista de adyacencia (2 veces):
O(|E|)
308. * -Borrar las aristas de las listas de adyacencia: O(1)
309. * -Costo total: O(|E|)
310. * @throws ItemNotFound
311. */
312.
313. private void borrarArista(String X, String Y) throws
ItemNotFound{
314. LinkedListItr AdjX = new
LinkedListItr(table[addNode(X)].adj);
315. AdjX.first();
316. LinkedListItr AdjY = new
LinkedListItr(table[addNode(Y)].adj);
317. AdjY.first();
318. for( ;AdjX.isInList(); AdjX.advance() ) {
319. Edge actual = ((Edge)(AdjX.retrieve()));
320. if( actual.dest == addNode(Y) ) {
321. AdjX.remove(actual);
322. }
323. }
324. for( ;AdjY.isInList(); AdjY.advance() ) {
325. Edge actual = ((Edge)(AdjY.retrieve()));
326. if( actual.dest == addNode(X) ) {
327. AdjY.remove(actual);
328. }
329. }
330. }
331. public void borrarAristaviejo(String X, String Y) throws
ItemNotFound{
332. int i = 0;
333. int j = 0;
334. ListItr theListi;
335. Edge theEdge;
336. ListItr theListj;
337. Edge theEdge2;
338. boolean continuar=true;
339.
340.
341.
342. //Recorremos la tabla
343. while( this.table[ i ] != null && !continuar ){
//Analizamos secuencialmente cada nodo en la tabla
344. if (this.table[i].name.equals(X)) { //Comparamos hasta encontrar X
345.
346. //Una vez encontrado el nodo X, tenemos que
revisar su lista de adyacencias e ir hasta Y
347. theListi = new LinkedListItr( this.table[ i ].adj
);
348. theListi.first();
349. theEdge = (Edge)theListi.retrieve();
350. // continuar = true;
351.
programacionparajava.blogspot.com


63

352. while( theEdge != null ) { //Recorremos para
buscar Y en la lista de X
353.
354. //Buscamos en la lista de X el nodo Y para
desconectar
355. if (
this.table[theEdge.dest].name.equals(Y) ){ //Verificamos si Y
figura en la lista de adyacencias de X
356. theListi.remove(theEdge);
357. continuar=false;
358. break;}
359. else{
360. theListi.advance();
361. theEdge =
(Edge)theListi.retrieve();}
362.
363.
364. }
365.
366. }
367. i++;
368. }
369.
370. int posY=findPosEdge(Y);
371. theListj = new LinkedListItr(table[posY].adj);
372. theListj.first();
373. for( ;theListj.retrieve()==null;
theListj.advance()){
374. Edge actual =
((Edge)(theListj.retrieve()));
375. if( actual.dest == (posY))
376. theListj.remove(actual);

377. }
378. }
379.
380.
381. private int findPosEdge(String edgeName){
382. for(int i=0; i<numVertices; i++){
383. if(table[i].name.equals(edgeName))
384. return i;
385. }
386. return -1;
387. }
388.
389.
390.
391. /**
392. * Metodo para borrar las aristas incidentes en un nodo Z
393. * @param Z
394. * La idea es ir hasta Z en la tabla[], luego ver sus
adyacentes
395. * primero ir sucesivamente a cada nodo adyacentes en la
tabla[] del nodo Z y desconectar en donde figure Z
396. * por ultimo eliminar todos los enlaces que figuran en la
lista de adyacencia del nodo Z
programacionparajava.blogspot.com


64

397. * Costo:
398. * -Encontrar Z: O(|V|)
399. * -Recorrer la lista de adyacencia, por cada elemento
recorrer la otra lista de adyacencia, buscar
400. * la arista adyacente y eliminar: O(|E|^2)
401. * -Costo total: O(|V| + |E|^2)
402. * @throws ItemNotFound
403. */
404. /* Z es el nodo que queremos dejar libre, o sea borrar todas
sus incidencias
405. * J llamamos al nodo adyacente a Z */
406. public void borrarAristasIncidentes(String Z) throws
ItemNotFound {
407. int i = 0;
408. int j = 0;
409. boolean continuar;
410. ListItr theList;
411. ListItr theList2;
412. Edge theEdge;
413. Edge theEdge2;
414.
415. //Recorremos la tabla
416. while( this.table[ i ] != null ){ //Analizamos
secuencialmente cada nodo en la tabla
417.
418.
419. if (this.table[i].name.equals(Z)) { //Comparamos hasta encontrar
420.
421. System.out.println ("Nodo " + Z + "
encontrado " + "en indice: " + i);
422.
423. //Una vez encontrado el nodo Z, tenemos que
revisar su lista de adyacencias
424. theList = new LinkedListItr( this.table[ i ].adj
);
425. theList.first();
426. theEdge = (Edge)theList.retrieve();
427. while( theEdge != null )
428. {
429. System.out.print( this.table[ theEdge.dest
].name + " "); //Imprimimos nombre del adyacente a Z
430.
431. j = 0;
432. while (this.table[j] != null) {
433. if (this.table[j].name.equals(this.table[
theEdge.dest ].name)) { //Buscamos la posicion del adyacente a Z
434.
435. System.out.println (" Adyacente encontrado
en indice " + j); //j contiene la posicion del
adyacente a Z
436.
437.
438. //Como el grafo es no dirigido, ahora
tenemos que buscar en la posicion del nodo J y eliminar la
referencia al nodo Z
programacionparajava.blogspot.com


65

439. //Una vez encontrado el nodo J, tenemos que
revisar su lista de adyacencias y desconectar Z
440. theList2 = new LinkedListItr( this.table[
j ].adj );
441. theList2.first();
442. theEdge2 = (Edge)theList2.retrieve();
443. continuar = true;
444. while( theEdge2 != null && continuar ==
true) { //Recorremos la lista del nodo J, la idea es buscar el nodo
Z y desconectarlo
445. //Buscamos en la lista de J el nodo
Z para desconectar
446. if (
this.table[i].name.equals(this.table[theEdge2.dest].name) ){ //Si
Z figura en la lista de adyacencias de J eliminamos la referencia a
Z
447. continuar = false;
448. theList2.remove(theEdge2); //Eliminamos Z de la lista de J
449. }
450.
451.
452. theList2.advance(); //Avanzamos la lista
453. theEdge2 = (Edge)theList2.retrieve();
454. }
455.
456. }
457.
458. j++;
459. }
460.
461.
462.
463. theList.advance(); //Avanzamos la lista
464.
465. theEdge = (Edge)theList.retrieve();
466. }
467.
468. System.out.print("\n");
469.
470. //Una vez que se ha desconectado todos los nodos
que apuntaban a Z, ahora limpiar la lista de Z para que Z apunte a
ninguno
471. theList.first(); //Nos colocamos nuevamente en la
posicion primera de la lista de Z
472. theEdge = (Edge)theList.retrieve();
473. while( theEdge != null ) { //Avanzamos y vamos limpiando la lista de Z
474. theList.remove(theEdge); //Eliminamos el nodo
475. theList.advance(); //Avanzamos la lista
476. theEdge = (Edge)theList.retrieve();
477. }
478. }
479.
480.
481. i++;
482.
483. }
programacionparajava.blogspot.com


66

484. }
485.
486. private LinkedList findCycle () throws ItemNotFound {
487. boolean hay_ciclo = false;
488. LinkedList Cycle = new LinkedList();
489. for( int i=0; i<this.numVertices && !hay_ciclo; i++ ) {
490. ListItr adyacentes = new LinkedListItr(table[i].adj);
491. for( ;adyacentes.isInList(); adyacentes.advance() ) {
492. this.unweighted(i);
493. //Si hay un camino entre un vertice adyacente y el
propio vertice
494. if( table[i].dist != INFINITY ) {
495. //entonces hay un ciclo
496. hay_ciclo=true;
497. //System.out.println("Hay un ciclo: ");
498. pathToList(
((Edge)(adyacentes.retrieve())).dest, Cycle);
499. LinkedListItr aux = new LinkedListItr(Cycle);
500. aux.first();
501. aux.insert(
table[((Edge)(adyacentes.retrieve())).dest].name );
502. break;
503. }
504. }
505. }
506. return Cycle;
507. }
508.
509. private LinkedList pathToList(int destino, LinkedList Path)
throws ItemNotFound {
510. Path.makeEmpty();
511. LinkedListItr Itr = new LinkedListItr(Path);
512. Itr.zeroth();
513. int actual = destino;
514. while( actual!=NULL_VERTEX ) {
515. Itr.insert(table[actual].name);
516. actual = table[actual].prev;
517. }
518. return Path;
519. }
520.
521.
522.
523.
524.
525.
526.
527.
528.
529. /**
530. * Main modificado con llamada a los metodos de impresion,
borrado de aristas y borrado de incidentes
531. * A main routine that:
532. * 1. Prompts for a file containing edges;
533. * 2. Forms the graph;
534. * 3. Repeatedly prompts for two vertices and
programacionparajava.blogspot.com


67

535. * runs shortest path algorithms.
536. * The data file is a sequence of lines of the format
537. * source destination cost.
538. * @throws ItemNotFound
539. */
540. public static void main( String [ ] args ) throws ItemNotFound
541. {
542. System.out.println( "ALGORITMOS Y EST. DE DATOS III -
TAREA 7 - GRAFOS" );
543. System.out.println( "Ingrese la ruta completa y el nombre
del archivo graph1.txt:" );
544. System.out.println( "Ejemplo -> C:\\graph1.txt" );
545. System.out.println();
546.
547. // Get the file
548. BufferedReader in = new BufferedReader( new
InputStreamReader( System.in ) );
549. FileReader fin;
550. String fileName= "";
551.
552. try
553. {
554. fileName = in.readLine( );
555. fin = new FileReader( fileName );
556. }
557. catch( Exception e )
558. {
559. System.err.println( e );
560. return;
561. }
562.
563.
564. BufferedReader graphFile = new BufferedReader( fin );
565. Graph g = new Graph( );
566.
567. // Read the edges and insert
568. try
569. {
570. String line;
571. while( ( line = graphFile.readLine( ) ) != null )
572. {
573. StringTokenizer st = new StringTokenizer( line );
574.
575. try
576. {
577. if( st.countTokens( ) != 3 )
578. throw new Exception( );
579. String source = st.nextToken( );
580. String dest = st.nextToken( );
581. int cost = Integer.parseInt( st.nextToken( )
);
582. g.addEdge( source, dest, cost );
583. }
584. catch( Exception e )
585. { System.err.println( "Error: " + line ); }
586. }
programacionparajava.blogspot.com


68

587. }
588. catch( Exception e )
589. { System.err.println( "Error: " + e ); }
590.
591. /*Llamada original
592. while( g.processRequest( in ) )
593. ;
594. */
595.
596. /////////////////////////////// METODOS AGREGADOS y
PRUEBAS //////////////////////////////////
597. /* OJO: Ya que es un grafo no dirigido, en el archivo
donde estan los nodos y sus costos deben estar
598. * en ambos sentidos Ejemplo, para un Edge con costo 10
entre A y B:
599. * A B 10
600. * B A 10
601. * Se podria optimizar agregando metodos, pero como WEISS
ya implementa este tipo de caso, simplemente
602. * modificar como el ejemplo hara que funcione bien para
un grafo no dirigido.
603. */
604. System.out.println( "\n---------------------\n" );
605. System.out.println( "\nEstado de la tabla:\n" );
606. g.imprimirGrafoTabla(); //Imprimimos el estado actual
607. System.out.println( "\n---------------------\n" );
608. LinkedList ciclo = g.findCycle();
609. LinkedListItr cicloITR = new LinkedListItr(ciclo);
610. if(ciclo.isEmpty())
611. System.out.println("El grafo es acclico");
612. else{
613. System.out.println("El grafo tiene un ciclo:");

614. for( ;cicloITR.isInList(); cicloITR.advance()){
615. System.out.print(
(String)(cicloITR.retrieve()) + " " );
616. }
617. System.out.println();
618. }
619.
620. System.out.println( "\nBorramos la arista A-D a modo de
ejemplo:\n" );
621. g.borrarArista( "A", "D"); //Borramos la arista de A a D
622.
623. System.out.println( "\nEstado de la tabla despues de
borrar la arista A-D:\n" );
624. g.imprimirGrafoTabla(); //Imprimimos el estado actual
625.
626. System.out.println( "\nBorramos las aristas incidentes en
un nodo A a modo de ejemplo:\n" );
627. g.borrarAristasIncidentes( "A" );
//Borramos las aristas incidentes
628.
629. System.out.println( "\nEstado de la tabla despues de los
metodos llamados:\n" );
630. g.imprimirGrafoTabla(); //Imprimimos nuevamente el estado
programacionparajava.blogspot.com


69

631.
632. System.out.println( "\nLista de sitios web ordenados
segun la cantidad de enlaces que llegan a l:\n" );
633. g.imprimirOrdenado();
634.
///////////////////////////////////////////////////////////////////
////////////////////////////
635.
636.
637.
638.
639.
640.
641.
642.
643.
644.
645.
646.
647. }
648.
649. private static final int INIT_TABLE_SIZE = 50;
650. private static final int NULL_VERTEX = -1;
651. private static final int INFINITY = 2147483647 / 3;
652.
653. private HashTable vertexMap; // Gets internal #
654. private Vertex [ ] table; // The table array
655. private int numVertices; // Current # vertices read
656.
657. /**
658. * Double the table array; usual stuff.
659. */
660. private void doubleTableArray( )
661. {
662. Vertex[ ] oldArray = table;
663. table = new Vertex[ oldArray.length * 2 ];
664. for( int i = 0; i < oldArray.length; i++ )
665. table[ i ] = oldArray[ i ];
666. }
667.
668. /**
669. * If vertexName is an already seen vertex, return its
670. * internal number. Otherwise add it as a new vertex,
671. * and return its new internal number.
672. */
673. private int addNode( String vertexName )
674. {
675. HashItem hashV = new HashItem( vertexName );
676. HashItem result;
677.
678. try
679. {
680. result = (HashItem) vertexMap.find( hashV );
681. return result.rank;
682. }
683. catch( ItemNotFound e )
programacionparajava.blogspot.com


70

684. {
685. // Newly seen vertex
686. hashV.rank = numVertices;
687. hashV.name = new String( vertexName );
688. vertexMap.insert( hashV );
689.
690. if( numVertices == table.length )
691. doubleTableArray( );
692. table[ numVertices ] = new Vertex( hashV.name );
693. return numVertices++;
694. }
695. }
696.
697. /**
698. * Add an edge given internal numbers of its vertices.
699. */
700. private void addInternalEdge( int source, int dest, int cost )
701. {
702. ListItr p = new LinkedListItr( table[ source ].adj );
703. try
704. { p.insert( new Edge( dest, cost ) );
705. table[dest].grado ++;}
706. catch( ItemNotFound e ) { } // Cannot happen
707. }
708.
709. /**
710. * Initialize the table.
711. */
712. private void clearData( )
713. {
714. for( int i = 0; i < numVertices; i++ )
715. {
716. table[ i ].dist = INFINITY;
717. table[ i ].prev = NULL_VERTEX;
718. table[ i ].scratch = 0;
719. }
720. }
721.
722. /**
723. * Recursively print the shortest path to DestNode
724. * (specified by its internal number)
725. * printPath is the driver routine
726. */
727. private void printPathRec( int destNode )
728. {
729. if( table[ destNode ].prev != NULL_VERTEX )
730. {
731. printPathRec( table[ destNode ].prev );
732. System.out.print( " to " );
733. }
734. System.out.print( table[ destNode ].name );
735. }
736.
737. /**
738. * Driver routine to handle unreachables and print total
739. * cost. It calls recursive routine to print shortest path
programacionparajava.blogspot.com


71

740. * to destNode after a shortest path algorithm has run.
741. */
742. private void printPath( int destNode )
743. {
744. if( table[ destNode ].dist == INFINITY )
745. System.out.println( table[ destNode ].name +
746. " is unreachable" );
747. else
748. {
749. printPathRec( destNode );
750. System.out.println( " (cost is " +
751. table[ destNode ].dist + ")" );
752. }
753. System.out.println( );
754. }
755.
756.
757. // Various short)est path algorithms that
758. // require an internal number for start-up
759.
760. /**
761. * Compute the unweighted shortest path.
762. */
763. private void unweighted( int startNode )
764. {
765. int v, w;
766. Queue q = new QueueAr( );
767.
768. clearData( );
769. table[ startNode ].dist = 0;
770. q.enqueue( new Integer( startNode ) );
771.
772. try
773. {
774. while( !q.isEmpty( ) )
775. {
776. v = ( (Integer) q.dequeue( ) ).intValue( );
777. ListItr p = new LinkedListItr( table[ v ].adj );
778. for( ; p.isInList( ); p.advance( ) )
779. {
780. w = ( (Edge) p.retrieve( ) ).dest;
781. if( table[ w ].dist == INFINITY )
782. {
783. table[ w ].dist = table[ v ].dist + 1;
784. table[ w ].prev = v;
785. q.enqueue( new Integer( w ) );
786. }
787. }
788. }
789. }
790. catch( Underflow e ) { } // Cannot happen
791. }
792.
793. /**
794. * Dijkstra's Algorithm using binary heap.
795. * Return false if negative edge detected.
programacionparajava.blogspot.com


72

796. */
797. private boolean dijkstra( int startNode )
798. {
799. int v, w;
800. PriorityQueue pq = new BinaryHeap( Path.negInf );
801. Path vrec;
802.
803. clearData( );
804. table[ startNode ].dist = 0;
805. pq.insert( new Path( startNode, 0 ) );
806.
807. try
808. {
809. for( int nodesSeen = 0; nodesSeen < numVertices;
nodesSeen++ )
810. {
811. do
812. {
813. if( pq.isEmpty( ) )
814. return true;
815. vrec = (Path) pq.deleteMin( );
816. } while( table[ vrec.dest ].scratch != 0 );
817.
818. v = vrec.dest;
819. table[ v ].scratch = 1;
820.
821. ListItr p = new LinkedListItr( table[ v ].adj );
822. for( ; p.isInList( ); p.advance( ) )
823. {
824. w = ( (Edge) p.retrieve( ) ).dest;
825. int cvw = ( (Edge) p.retrieve( ) ).cost;
826.
827. if( cvw < 0 )
828. return false;
829.
830. if( table[ w ].dist > table[ v ].dist + cvw )
831. {
832. table[ w ].dist = table[ v ].dist + cvw;
833. table[ w ].prev = v;
834. pq.insert( new Path( w, table[ w ].dist )
);
835. }
836. }
837. }
838. }
839. catch( Underflow e ) { } // This cannot happen
840.
841. return true;
842. }
843.
844. /**
845. * Dijkstra's Algorithm using pairing heap
846. * Return false if negative edges detected.
847. */
848. private boolean dijkstraPair( int startNode )
849. {
programacionparajava.blogspot.com


73

850. int v, w;
851. PairHeap pq = new PairHeap( );
852. Path vrec;
853. PairNode [ ] heapPositions = new PairNode[ numVertices ];
854.
855. clearData( );
856. for( int i = 0; i < numVertices; i++ )
857. heapPositions[ i ] = null;
858.
859. table[ startNode ].dist = 0;
860. pq.insert( new Path( startNode, 0 ) );
861.
862. try
863. {
864. while( !pq.isEmpty( ) )
865. {
866. vrec = (Path) pq.deleteMin( );
867. v = vrec.dest;
868.
869. ListItr p = new LinkedListItr( table[ v ].adj );
870. for( ; p.isInList( ); p.advance( ) )
871. {
872. w = ( (Edge) p.retrieve( ) ).dest;
873. int cvw = ( (Edge) p.retrieve( ) ).cost;
874.
875. if( cvw < 0 )
876. return false;
877.
878. if( table[ w ].dist > table[ v ].dist + cvw )
879. {
880. table[ w ].dist = table[ v ].dist + cvw;
881. table[ w ].prev = v;
882.
883. Path newVal = new Path( w, table[ w ].dist
);
884. if( heapPositions[ w ] == null )
885. heapPositions[ w ] = pq.addItem(
newVal );
886. else
887. pq.decreaseKey( heapPositions[ w ],
newVal );
888. }
889. }
890. }
891. }
892. catch( Exception e ) { } // This cannot happen
893.
894. return true;
895. }
896.
897. /**
898. * Run shortest path algorithm;
899. * Negative edge weights are allowed.
900. * Return false if negative cycle is detected
901. */
902. private boolean negative( int startNode )
programacionparajava.blogspot.com


74

903. {
904. int v, w;
905. Queue q = new QueueAr( );
906. int cvw;
907.
908. clearData( );
909. table[ startNode ].dist = 0;
910. q.enqueue( new Integer( startNode ) );
911. table[ startNode ].scratch++;
912.
913. try
914. {
915. while( !q.isEmpty( ) )
916. {
917. v = ( (Integer) q.dequeue( ) ).intValue( );
918.
919. if( table[ v ].scratch++ > 2 * numVertices )
920. return false;
921.
922. ListItr p = new LinkedListItr( table[ v ].adj );
923. for( ; p.isInList( ); p.advance( ) )
924. {
925. w = ( (Edge) p.retrieve( ) ).dest;
926. cvw = ( (Edge) p.retrieve( ) ).cost;
927. if( table[ w ].dist > table[ v ].dist + cvw )
928. {
929. table[ w ].dist = table[ v ].dist + cvw;
930. table[ w ].prev = v;
931.
932. // Enqueue only if not already on queue
933. if( table[ w ].scratch++ % 2 == 0 )
934. q.enqueue( new Integer( w ) );
935. else
936. table[ w ].scratch++; // In effect,
adds 2
937. }
938. }
939. }
940. }
941. catch( Underflow e ) { } // Cannot happen
942.
943. return true;
944. }
945.
946.
947. /**
948. * Run shortest path algorithm;
949. * Linear-time algorithm, works only for acyclic graphs.
950. * Return false if cycle is detected
951. */
952. private boolean acyclic( int startNode )
953. {
954. int v, w, iterations = 0;
955. Queue q = new QueueAr( );
956.
957. clearData( );
programacionparajava.blogspot.com


75

958. table[ startNode ].dist = 0;
959.
960. try
961. {
962. // Compute the indegrees
963. for( v = 0; v < numVertices; v++ )
964. {
965. ListItr p = new LinkedListItr( table[ v ].adj );
966. for( ; p.isInList( ); p.advance( ) )
967. table[ ( (Edge) p.retrieve( ) ).dest
].scratch++;
968. }
969.
970. // Enqueue vertices of indegree zero
971. for( v = 0; v < numVertices; v++ )
972. if( table[ v ].scratch == 0 )
973. q.enqueue( new Integer( v ) );
974.
975. for( iterations = 0; !q.isEmpty( ); iterations++ )
976. {
977. v = ( (Integer) q.dequeue( ) ).intValue( );
978.
979. ListItr p = new LinkedListItr( table[ v ].adj );
980. for( ; p.isInList( ); p.advance( ) )
981. {
982. w = ( (Edge) p.retrieve( ) ).dest;
983. if( --table[ w ].scratch == 0 )
984. q.enqueue( new Integer( w ) );
985.
986. if( table[ v ].dist == INFINITY )
987. continue;
988.
989. int cvw = ( (Edge) p.retrieve( ) ).cost;
990. if( table[ w ].dist > table[ v ].dist + cvw )
991. {
992. table[ w ].dist = table[ v ].dist + cvw;
993. table[ w ].prev = v;
994. }
995. }
996. }
997. }
998. catch( Underflow e ) { } // Cannot happen
999.
1000. return iterations == numVertices;
1001. }
1002. private void imprimirOrdenado (){
1003. clearData();
1004. int posMayor;
1005. int mayor;
1006. for( int i=0; i<this.numVertices; i++){
1007. int j;
1008. for(j=0; j<this.numVertices; j++){
1009. if( table[j].scratch == 0 ){
1010. break;
1011. }
1012. }
programacionparajava.blogspot.com


76

1013. mayor=table[j].grado;
1014. posMayor=j;
1015. for(; j<numVertices; j++) {
1016. if(table[j].scratch==0 &&
table[j].grado>mayor ){
1017. posMayor = j;
1018. mayor = table[j].grado;
1019. }
1020. }
1021. table[posMayor].scratch = 1;
1022. System.out.println(table[posMayor].name +
"\t" + table[posMayor].grado);
1023. }
1024. }
1025. }


Tablas de hash

Una tabla hash, mapa hash, tabla de dispersin o tabla fragmentada es una estructura de
datos que asocia llaves o claves con valores. La operacin principal que soporta de manera
eficiente es la bsqueda: permite el acceso a los elementos (telfono y direccin, por
ejemplo) almacenados a partir de una clave generada (usando el nombre o nmero de
cuenta, por ejemplo). Funciona transformando la clave con una funcin hash en un hash, un
nmero que identifica la posicin (casilla o cubeta) donde la tabla hash localiza el valor
deseado.
Un ejemplo prctico para ilustrar que es una tabla hash es el siguiente: Se necesita
organizar los periodicos que llegan diariamente de tal forma que se puedan ubicar de forma
rpida, entoces se hace de la siguiente forma - se hace una gran caja para guardar todos los
periodicos (una tabla), y se divide en 31 contenedores (ahora es una "hash table" o tabla
fragmentada), y la clave para guardar los periodicos es el da de publicacin (ndice).
Cuando se requiere buscar un periodico se busca por el da que fue publicado y as se sabe
en que zcalo (bucket) est. Varios peridicos quedarn guardados en el mismo zcalo (es
decir colisionan al ser almacenados), lo que implica buscar en la sub-lista que se guarda en
cada zcalo. De esta forma se reduce el tamao de las bsquedas de O(n) a - En el mejor de
los casos O(1) y en el peor de los casos O(log(n)).

Las tablas hash se suelen implementar sobre vectores de una dimensin, aunque se pueden
hacer implementaciones multi-dimensionales basadas en varias claves. Como en el caso de
programacionparajava.blogspot.com


77

los arrays, las tablas hash proveen tiempo constante de bsqueda promedio O(1),
1
sin
importar el nmero de elementos en la tabla. Sin embargo, en casos particularmente malos
el tiempo de bsqueda puede llegar a O(n), es decir, en funcin del nmero de elementos.
Comparada con otras estructuras de arrays asociadas, las tablas hash son ms tiles cuando
se almacenan grandes cantidades de informacin.
Las tablas hash almacenan la informacin en posiciones pseudo-aleatorias, as que el
acceso ordenado a su contenido es bastante lento. Otras estructuras como rboles binarios
auto-balanceables tienen un tiempo promedio de bsqueda mayor (tiempo de bsqueda
O(log n)), pero la informacin est ordenada en todo momento.

Funcionamiento:
Las operaciones bsicas implementadas en las tablas hash son:
insercin(llave, valor)
bsqueda(llave) que devuelve valor
La mayora de las implementaciones tambin incluyen borrar(llave). Tambin se
pueden ofrecer funciones como iteracin en la tabla, crecimiento y vaciado.
Algunas tablas hash permiten almacenar mltiples valores bajo la misma clave.
Para usar una tabla hash se necesita:
Una estructura de acceso directo (normalmente un array).
Una estructura de datos con una clave
Una funcin resumen (hash) cuyo dominio sea el espacio de claves y su imagen
(o rango) los nmeros naturales.
Insercin:
1. Para almacenar un elemento en la tabla hash se ha de convertir su clave a
un nmero. Esto se consigue aplicando la funcin resumen (hash) a la clave
del elemento.
2. El resultado de la funcin resumen ha de mapearse al espacio de
direcciones del vector que se emplea como soporte, lo cual se consigue con
la funcin mdulo. Tras este paso se obtiene un ndice vlido para la tabla.
3. El elemento se almacena en la posicin de la tabla obtenido en el paso
anterior.
1. Si en la posicin de la tabla ya haba otro elemento, se ha producido
una colisin. Este problema se puede solucionar asociando
una lista a cada posicin de la tabla, aplicando otra funcin o
programacionparajava.blogspot.com


78

buscando el siguiente elemento libre. Estas posibilidades han de
considerarse a la hora de recuperar los datos.
Bsqueda:
1. Para recuperar los datos, es necesario nicamente conocer la clave del
elemento, a la cual se le aplica la funcin resumen.
2. El valor obtenido se mapea al espacio de direcciones de la tabla.
3. Si el elemento existente en la posicin indicada en el paso anterior tiene la
misma clave que la empleada en la bsqueda, entonces es el deseado. Si la
clave es distinta, se ha de buscar el elemento segn la tcnica empleada
para resolver el problema de las colisiones al almacenar el elemento.

Prcticas recomendadas para las funciones hash
Una buena funcin hash es esencial para el buen rendimiento de una tabla hash. Las
colisiones son generalmente resueltas por algn tipo de bsqueda lineal, as que si la
funcin tiende a generar valores similares, las bsquedas resultantes se vuelven lentas.
En una funcin hash ideal, el cambio de un simple bit en la llave (incluyendo el hacer la
llave ms larga o ms corta) debera cambiar la mitad de los bits del hash, y este cambio
debera ser independiente de los cambios provocados por otros bits de la llave. Como una
funcin hash puede ser difcil de disear, o computacionalmente cara de ejecucin, se han
invertido muchos esfuerzos en el desarrollo de estrategias para la resolucin de colisiones
que mitiguen el mal rendimiento del hasheo. Sin embargo, ninguna de estas estrategias es
tan efectiva como el desarrollo de una buena funcin hash de principio.
Es deseable utilizar la misma funcin hash para arrays de cualquier tamao concebible.
Para esto, el ndice de su ubicacin en el array de la tabla hash se calcula generalmente en
dos pasos:
1. Un valor hash genrico es calculado, llenando un entero natural de mquina.
2. Este valor es reducido a un ndice vlido en el vector encontrando su mdulo con
respecto al tamao del array.
El tamao del vector de las tablas hash es con frecuencia un nmero primo. Esto se
hace con el objetivo de evitar la tendencia de que los hash de enteros grandes
tengan divisores comunes con el tamao de la tabla hash, lo que provocara
colisiones tras el clculo del mdulo. Sin embargo, el uso de una tabla de tamao
primo no es un sustituto a una buena funcin hash.
Un problema bastante comn que ocurre con las funciones hash es
el aglomeramiento. El aglomeramiento ocurre cuando la estructura de la funcin
hash provoca que llaves usadas comnmente tiendan a caer muy cerca unas de otras
programacionparajava.blogspot.com


79

o incluso consecutivamente en la tabla hash. Esto puede degradar el rendimiento de
manera significativa, cuando la tabla se llena usando ciertas estrategias de
resolucin de colisiones, como el sondeo lineal.
Cuando se depura el manejo de las colisiones en una tabla hash, suele ser til usar
una funcin hash que devuelva siempre un valor constante, como 1, que cause
colisin en cada insercin.

Funciones Hash ms usadas:
1. Hash de Divisin:
Dado un diccionario D, se fija un nmero m >= |D| (m mayor o igual al tamao
del diccionario) y que sea primo no cercano a potencia de 2 o de 10. Siendo k la
clave a buscar y h(k) la funcin hash, se tiene h(k)=k%m (Resto de la divisin
k/m).
2. Hash de Multiplicacin
Si por alguna razn, se necesita una tabla hash con tantos elementos o
punteros como una potencia de 2 o de 10, ser mejor usar una funcin hash
de multiplicacin, independiente del tamao de la tabla. Se escoge un
tamao de tabla m >= |D| (m mayor o igual al tamao del diccionario) y un
cierto nmero irracional (normalmente se usa 1+5^(1/2)/2 o 1-5^(1/2)/2).
De este modo se define h(k)= Suelo(m*Parte fraccionaria(k*))
Resolucin de colisiones:
Si dos llaves generan un hash apuntando al mismo ndice, los registros correspondientes no
pueden ser almacenados en la misma posicin. En estos casos, cuando una casilla ya est
ocupada, debemos encontrar otra ubicacin donde almacenar el nuevo registro, y hacerlo de
tal manera que podamos encontrarlo cuando se requiera.
Para dar una idea de la importancia de una buena estrategia de resolucin de colisiones,
considerese el siguiente resultado, derivado de la paradoja de las fechas de nacimiento. Aun
cuando supongamos que el resultado de nuestra funcin hash genera ndices aleatorios
distribuidos uniformemente en todo el vector, e incluso para vectores de 1 milln de
entradas, hay un 95% de posibilidades de que al menos una colisin ocurra antes de
alcanzar los 2.500 registros.
Hay varias tcnicas de resolucin de colisiones, pero las ms populares
son encadenamiento y direccionamiento abierto.

Direccionamiento Cerrado, Encadenamiento separado o Hashing abierto
programacionparajava.blogspot.com


80

En la tcnica ms simple de encadenamiento, cada casilla en el array referencia una lista de
los registros insertados que colisionan en la misma casilla. La insercin consiste en
encontrar la casilla correcta y agregar al final de la lista correspondiente. El borrado
consiste en buscar y quitar de la lista.
La tcnica de encadenamiento tiene ventajas sobre direccionamiento abierto. Primero el
borrado es simple y segundo el crecimiento de la tabla puede ser pospuesto durante mucho
ms tiempo dado que el rendimiento disminuye mucho ms lentamente incluso cuando
todas las casillas ya estn ocupadas. De hecho, muchas tablas hash encadenadas pueden no
requerir crecimiento nunca, dado que la degradacin de rendimiento es lineal en la medida
que se va llenando la tabla. Por ejemplo, una tabla hash encadenada con dos veces el
nmero de elementos recomendados, ser dos veces ms lenta en promedio que la misma
tabla a su capacidad recomendada.
Las tablas hash encadenadas heredan las desventajas de las listas ligadas. Cuando se
almacenan cantidades de informacin pequeas, el gasto extra de las listas ligadas puede
ser significativo. Tambin los viajes a travs de las listas tienen un rendimiento
de cach muy pobre.
Otras estructuras de datos pueden ser utilizadas para el encadenamiento en lugar de las
listas ligadas. Al usar rboles auto-balanceables, por ejemplo, el tiempo terico del peor de
los casos disminuye de O(n) a O(log n). Sin embargo, dado que se supone que cada lista
debe ser pequea, esta estrategia es normalmente ineficiente a menos que la tabla hash sea
diseada para correr a mxima capacidad o existan ndices de colisin particularmente
grandes. Tambin se pueden utilizar vectores dinmicos para disminuir el espacio extra
requerido y mejorar el rendimiento del cach cuando los registros son pequeos.



Direccionamiento abierto o Hashing cerrado:
Las tablas hash de direccionamiento abierto pueden almacenar los registros directamente en
el array. Las colisiones se resuelven mediante un sondeo del array, en el que se buscan
diferentes localidades del array (secuencia de sondeo) hasta que el registro es encontrado o
se llega a una casilla vaca, indicando que no existe esa llave en la tabla.
Las secuencias de sondeo ms socorridas incluyen:
sondeo lineal:
en el que el intervalo entre cada intento es constante (frecuentemente 1).
sondeo cuadrtico:
programacionparajava.blogspot.com


81

en el que el intervalo entre los intentos aumenta linealmente (por lo que los ndices son
descritos por una funcin cuadrtica).
doble hasheo:
en el que el intervalo entre intentos es constante para cada registro pero es calculado por
otra funcin hash.
El sondeo lineal ofrece el mejor rendimiento del cach, pero es ms sensible al
aglomeramiento, en tanto que el doble hasheo tiene pobre rendimiento en el cach pero
elimina el problema de aglomeramiento. El sondeo cuadrtico se sita en medio. El doble
hasheo tambin puede requerir ms clculos que las otras formas de sondeo.
Una influencia crtica en el rendimiento de una tabla hash de direccionamiento abierto es el
porcentaje de casillas usadas en el array. Conforme el array se acerca al 100% de su
capacidad, el nmero de saltos requeridos por el sondeo puede aumentar
considerablemente. Una vez que se llena la tabla, los algoritmos de sondeo pueden incluso
caer en un crculo sin fin. Incluso utilizando buenas funciones hash, el lmite aceptable de
capacidad es normalmente 80%. Con funciones hash pobremente diseadas el rendimiento
puede degradarse incluso con poca informacin, al provocar aglomeramiento significativo.
No se sabe a ciencia cierta qu provoca que las funciones hash generen aglomeramiento, y
es muy fcil escribir una funcin hash que, sin querer, provoque un nivel muy elevado de
aglomeramiento.
Ventajas e inconvenientes de las tablas hash :
Una tabla hash tiene como principal ventaja que el acceso a los datos suele ser muy rpido
si se cumplen las siguientes condiciones:
Una razn de ocupacin no muy elevada (a partir del 75% de ocupacin se producen
demasiadas colisiones y la tabla se vuelve ineficiente).
Una funcin resumen que distribuya uniformemente las claves. Si la funcin est mal
diseada, se producirn muchas colisiones.
Los inconvenientes de las tablas hash son:
Necesidad de ampliar el espacio de la tabla si el volumen de datos almacenados crece.
Se trata de una operacin costosa.
Dificultad para recorrer todos los elementos. Se suelen emplear listas para procesar la
totalidad de los elementos.
Desaprovechamiento de la memoria. Si se reserva espacio para todos los posibles
elementos, se consume ms memoria de la necesaria; se suele resolver reservando
espacio nicamente para punteros a los elementos.
A continuacin se muestra un ejemplo sencillo de tablas hasht:
programacionparajava.blogspot.com


82

import java.util.*;


public class diccionario{

Hashtable dic;


public diccionario(){
dic = new Hashtable();
}


public static void main (String args[]){

diccionario d = new diccionario();
Scanner s = new Scanner(System.in);
int op = 0;

System.out.println(" \n Ejemplo de uso de la clase Hashtable de
la api java\n "+
" \n\n Elige una opcin a ejecutar\n"+
" 1.- Vaciar el hash\n"+
" 2.- Cuantos elementos tiene\n"+
" 3.- Verificar si el hash esta vaco\n"+
" 4.- Imprimir el hash\n"+
" 5.- Insertar numeros de ejemplo\n"+
" 6.- Insertar strings de ejemplo\n"+
" 0.- Salir\n\n\n\n"

);

while(true){
System.out.println("\n\nTeclea una opcion de menu: ");
op = s.nextInt();

if( op == 1 ){
d.limpiar();
System.out.println("Diccionario vacio");
}
if( op == 2 ){
System.out.println("El Diccionario posee
"+d.cantElementos()+" elementos");
}
if( op == 3 ){
System.out.println("El Diccionario se encuentra
vacio ? R: "+ d.isVacio() );
}
if( op == 4 ){
d.imprimir( d.dic );
}
if( op == 5 ){
d.insertarNums();
programacionparajava.blogspot.com


83

System.out.println("Se insertaron num de
ejemplos");
}
if( op == 6 ){
d.insertarPal();
System.out.println("Se insertaron palabras de
ejemplos");
}
if( op == 0 ){
System.out.println("Adios\n\n\n");
System.exit(0);
}




}



}


public void limpiar(){
dic. clear();
}

public int cantElementos(){
return dic.size();
}

public boolean isVacio(){
return dic.isEmpty();
}

public void imprimir( Hashtable h ){
Enumeration e = h.keys();
Object obj;
while (e.hasMoreElements()) {
obj = e.nextElement();
System.out.println(" key "+ obj +": "+ h.get(obj));
}
}

public void insertarNums(){
dic.put(1, "UNO");
dic.put(2, "two");
dic.put(3, "tres");
dic.put(4, "four");
dic.put(8, "ocho");

}

public void insertarPal(){
programacionparajava.blogspot.com


84

dic.put("uno" ,"1");
dic.put("tres" ,"3");
dic.put("tress" ,"33");
dic.put("four" ,"4");
dic.put("cuatro","4");
dic.put("cinco" ,"5");

}


}//End Dic
Este seria el resultado:


Referencias bibliograficas:


http://es.scribd.com/doc/41076913/Colas-Dobles-y-Circulares
http://decsai.ugr.es/~jfv/ed1/tedi/cdrom/docs/ldoble.html
http://ingenierasdesiyvane.blogspot.es/
http://cosasparafuturosingenieros.blogspot.mx/2012/11/codigo-fuente-java-
programa-arbol.html
programacionparajava.blogspot.com


85

http://estructura-de-datos-itsav.blogspot.mx/2012/03/525-balanceo-arboles-
binarios.html
http://ertereg.galeon.com/
http://es.wikipedia.org/wiki/%C3%81rbol-B
programacionparajava.blogspot.com

Anda mungkin juga menyukai