martes, 26 de mayo de 2009

ORDENACION POR METODO HEAPSORT

HEAPSORT

El ordenamiento por heapsort es un algoritmo de ordenación no recursivo, no estable, con complejidad computacional

El Heapsort está basado en el uso de un tipo especial de árbol binario (llamado apilamiento) para estructurar el proceso de ordenamiento. La estructura de ramificación del árbol conserva el número de comparaciones necesarias en O(n log n).

Caracteristicas

¨ Las llaves están acomodadas en los nodos de tal manera que, para cada nodo i,
Ki <= Kj donde el nodo j es el padre del nodo
i. Es decir, al recorrer el camino desde la raíz hacia abajo, las claves se encuentran en orden descendente.

¨ El árbol se llena de izquierda a derecha, lo que implica que si algún(os) nodo(s) no está(n) en el mismo nivel que el resto, éste(os) estará(n) entonces lo más a la izquierda posible del árbol.

Pasos del Heap

1º. Saca el valor máximo del Heap. (El de la posición 1).

2º. Pone el valor sacado en el arreglo ordenado.

3º. Reconstruir el Heap con un elemento menos.

Ejemplo

Ordenamiento : 73 - 50 - 36 - 21 - 46 - 27 - 9 - 18 - 10 - 30

lunes, 25 de mayo de 2009

BUSQUEDA POR EL METODO HASH



Procedimiento
Método consistente en aplicar una función que traduce un conjunto de posibles valores llave en un rango de direcciones relativas
Casos de Colision
soluciones para reducir el número de colisiones
Propagar los registros: Buscar funciones que distribuyan muy aleatoriamente los registros podemos evitar "agrupaciones" de llaves que produzcan las mismas direcciones
Usar memoria extra: En el ejemplo anterior planteamos tener una dirección de entre 1000 posibles, el uso de memoria extra se basa en proponer un espacio de direcciones posibles mucho más grande que el número de registros a usar, de modo que si vamos a insertar 100 registros un espacio de 500 direcciones nos una mejor opción de esparcir mejor.
Colocar más de un registro en una dirección: A diferencia de los casos anteriores donde cada dirección almacena únicamente un registro, este concepto se basa en "buckets" o cubetas de datos en cada dirección, ahí se colocan algunos (casi todos) los registros que colisionan de manera que al hacer una búsqueda debemos recuperar la cubeta entera y ahi buscar por el registro deseado.
9.3.1 Un Algoritmo de Hash
No existe una fórmula "única" para hash, pero el producirla es un algoritmo que básicamente se presenta en 3 pasos: 1) Representar la llave de manera numérica (siempre que no sea de por sí un número) Una buena opción es usar los valores ASCII o bien los Unicode de las letras LOWELL= L O W E L L _ _ _ _ _ _ 76 79 87 69 76 76 32 32 32 32 32 32 2) Plegar y Agregar Combinar algunos de estos números para generar pequeños trozos con los que podamos trabajar 76 79 | 87 69 | 76 76 | 32 32 | 32 32 | 32 32 De manera que podemos hacer algunas operaciones matemáticas con dichos números para finalmente obtener un número del cual obtendremos la dirección 7679 + 8769 + 7676 + 3232 + 3232 = 30 588 Nota: Respecto a la implementación se puede dar el caso de formar números demasiado grandes, tanto que llegue al overflow del tipo de datos que estemos usando. Para solucionar esto podemos usar funciones como el "mod" intermedias para no tener ese problema. 3) Dividir por un número primo y usar el resultado como dirección Los archivos de hash por lo general suelen limitarse a un cierto rango de direcciones posibles para aprovechar mejor el concepto de memoria. de manera que podemos concluir nuestro algoritmo con la fórmula:
o a= s mod n
o donde a es la dirección resultante, s es la suma o resultado de los pasos anteriores y n el número de direcciones posibles en el archivo Existen innumerables operaciones adicionales que pueden aplicarse en las fórmulas, así como las técnicas para limitar el valor final. Entre ellas se encuentran: elevar a alguna potencia, raíz cuadrada, convertir los números de base (hexadecimal, octal), etc...
Ventajas
Se pueden usar los valores naturales de la llave, puesto que se traducen internamente a direcciones fáciles de localizar
Se logra independencia lógica y física, debido a que los valores de las llaves son independientes del espacio de direcciones
No se requiere almacenamiento adicional para los índices.
Desventajas
No pueden usarse registros de longitud variable
El archivo no esta clasificado
No permite llaves repetidas
Solo permite acceso por una sola llave
Costos
o Tiempo de procesamiento requerido para la aplicación de la función hash
o Tiempo de procesamiento y los accesos E/S requeridos para solucionar las colisiones.
Factores de Eficiencia
o La distribución de los valores de llave que realmente se usan
o El numero de valores de llave que realmente están en uso con respecto al tamaño del espacio de direcciones
o El numero de registros que pueden almacenarse en una dirección dad sin causar una colisión
o La técnica usada para resolver el problema de las colisiones
Tipos de Funcion Hash
o Residuo de la división
o Medio del cuadrado
o Pliegue
Hashing por residuo de división
o La idea de este método es la de dividir el valor de la llave entre un numero apropiado, y después utilizar el residuo de la división como dirección relativa para el registro (dirección = llave módulo divisor).
Consideraciones
· Independientemente de que tan bueno sea el divisor, cuando el espacio de direcciones de un archivo esta completamente lleno, la probabilidad de colisión crece dramáticamente. La saturación de archivo de mide mediante su factor de carga, el cual se define como la relación del numero de registros en el archivo contra el numero de registros que el archivo podría contener si estuviese completamente lleno.
Factor de Carga
Todas las funciones hash comienzan a trabajar probablemente cuando el archivo esta casi lleno. Por lo general el máximo factor de carga que puede tolerarse en un archivo para un rendimiento razonable es de entre el 70 % y 80 %.

Hashing por Elevacion al cuadrado
· En esta técnica, la llave es elevada al cuadrado, después algunos dígitos específicos se extraen de la mitad del resultado para constituir la dirección relativa. Si se desea una dirección de n dígitos, entonces los dígitos se truncan en ambos extremos de la llave elevada al cuadrado, tomando n dígitos intermedios. Las mismas posiciones de n dígitos deben extraerse para cada llave.
· Utilizando esta función hashing el tamaño del archivo resultante es de 10n donde n es el numero de dígitos extraídos de los valores de la llave elevada al cuadrado.
Hashing por Pliegue
o En esta técnica el valor de la llave es particionada en varias partes, cada una de las cuales (excepto la ultima) tiene el mismo numero de dígitos que tiene la dirección relativa objetivo. Estas particiones son después plegadas una sobre otra y sumadas. El resultado, es la dirección relativa. Igual que para el método del medio del cuadrado, el tamaño del espacio de direcciones relativas es una potencia de 10.

TEORIA DE GRAFOS

GRAFOS
la teoría de grafos (también llamada teoría de las gráficas) estudia las propiedades de los grafos(también llamadas gráficas). Un grafo es un conjunto, no vacío, de objetos llamados vértices (o nodos) y una selección de pares de vértices, llamados aristas(arcs en inglés) que pueden ser orientados o no. Típicamente, un grafo se representa mediante una serie de puntos (los vértices) conectados por líneas (las aristas).



Existen diferentes formas de almacenar grafos en una computadora. La estructura de datos usada depende de las características del grafo y el algoritmo usado para manipularlo. Entre las estructuras más sencillas y usadas se encuentran las listas y las matrices, aunque frecuentemente se usa una combinación de ambas. Las listas son preferidas en grafos dispersos porque tienen un eficiente uso de la memoria. Por otro lado, las matrices proveen acceso rápido, pero pueden consumir grandes cantidades de memoria.Estructura de listalista de incidencia - Las aristas son representadas con un vector de pares (ordenados, si el grafo es dirigido), donde cada par representa una de las aristas. lista de adyacencia - Cada vértice tiene una lista de vértices los cuales son adyacentes a él. Esto causa redundancia en un grafo no dirigido (ya que A existe en la lista de adyacencia de B y viceversa), pero las búsquedas son más rápidas, al costo de almacenamiento extra. En esta estructura de datos la idea es asociar a cada vertice i del grafo una lista que contenga todos aquellos vértices j que sean adyacentes a él. De esta forma sólo reservará memoria para los arcos adyacentes a i y no para todos los posibles arcos que pudieran tener como origen i. El grafo, por tanto, se representa por medio de un vector de n componentes (si V=n) donde cada componente va a ser una lista de adyacencia correspondiente a cada uno de los vertices del grafo. Cada elemento de la lista consta de un campo indicando el vértice adyacente. En caso de que el grafo sea etiquetado, habrá que añadir un segundo campo para mostrar el valor de la etiqueta.Ejemplo de lista de adyacencia Estructuras matricialesMatriz de incidencia - El grafo está representado por una matriz de A (aristas) por V (vértices), donde [arista, vértice] contiene la información de la arista (1 - conectado, 0 - no conectado) Matriz de adyacencia - El grafo está representado por una matriz cuadrada M de tamaño n2, donde n es el número de vértices. Si hay una arista entre un vértice x y un vértice y, entonces el elemento mx,y es 1, de lo contrario, es 0.
ALGORITMO DE CREACION.
repite
si top=NIL entonces
new(top)
top(la)<--NIL top(ld)<--NIL lee(top(dato)) q<--top en caso contrario new(p) p(ld)<--NIL p(la)<--NIL q(la)<--p lee(p(dato)) q<--p mensaje(otro vertice ?) lee(respuesta) hasta repuesta=no p<--top mientras p<>NIL haz
mensaje(tiene vértices adyacentes p(dato) ?)
lee(respuesta)
si respueta=si entonces
repite
new(q)
lee(q(dato))
q(ld)<--p(ld) p(ld)<--q mensaje(otro vértice ?) lee(respuesta2) hasta respuesta2=no p<--p(la) ALGORITMO DE INSERCION mensaje(valor a insertar ?) lee(valor_a_insertar) si top<>NIL entonces
p<--top mientras p(la)<>NIL haz
p<--p(la) new(q) lee(q(dato)) p(la)<--q q(la)<--NIL mensaje(Hay vértices adyacentes?) lee(respuesta) si respuesta=si entonces mensaje(Cuantos vértices?) lee(número_vértices) desde i=1 hasta número_vértices haz new(p) lee(p(dato)) q(ld)<--p q<--q(ld) en caso contrario mensaje(no existe lista) ALGORITMO DE BUSQUEDA mensaje(vértice a buscar) lee(vértice_a_buscar) p<--top repite si p(dato)=vértice_a_buscar entonces repite p<--p(ld) escribe(p(dato)) hasta p(ld)=NIL en caso contrario p<--(la) hasta p=NIL ALGORITMO DE BORRADO mensaje(vértice a borrar ?) lee(vértice_a_borrar) p&Lt--top r<--p q<--p sw<--falso repite si p(dato)=vértice_a_borrar entonces si p=top entonces top<--top(la) r<--top sw<--verdadero en caso contrario r(la)<--p(la) repite p<--p(ld) dispose(q) q<--p hasta p=NIL si sw=verdadero entonces p<--r q<--p en caso contrario p<--r(la) q<--p en caso contrario r<--p repite q<--p(ld) si q(dato)=vértice_a_borrar entonces p(ld)<--q(ld) dispose(q) q<--p en caso contrario p<--p(ld) hasta p=NIL

miércoles, 29 de abril de 2009


RECORRIDO DE UN ARBOL

public class Test{
public static void main(String args[]){
CArbolBinarioDeBusqueda arbolbb=new CArbolBinarioDeBusqueda();
String nombre;
double nota;
int i=0,cod;
System.out.println("Introducir datos. Finalizar con Ctrl+z.");
System.out.println("nombre: ");
while((nombre=Leer.dato())!=null) {
System.out.print("nota: ");
nota=Leer.datoDouble();
cod=arbolbb.insertar(new CDatos(nombre,nota));
if(cod==CArbolBinarioDeBusqueda.YA_EXISTE) {
CDatos datos=(CDatos)arbolbb.buscar(new CDatos(nombre,nota));
if(nota>=0)
datos.asignarNota(nota);
else {
if(arbolbb.borrar(new CDatos(nombre,nota))==null)
System.out.println("nodo borrado porque no existe");
else System.out.println("nodo borrado");
}
}
System.out.print("nombre: ");
}
System.out.println("\n");
System.out.println("\nArbolInorden: ");
arbolbb.visitarInorden();
System.out.println("\nArbol posorden: ");
arbolbb.visitarPosorden();
System.out.println("\nArbol preorden: ");
arbolbb.visitarPreorden();
}
CREACION DE ARBOLES


MAPA CONCEPTUAL


ARBOLES MULTICAMINOS

ARBOLES BINARIOS

Un árbol binario es un grafo conexo, acíclico y no dirigido tal que el grado de cada vértice no es mayor a 3». De esta forma sólo existe un camino entre un par de nodos.
Un árbol binario con enraizado es como un grafo que tiene uno de sus vértices, llamado raíz, de grado no mayor a 2. Con la raíz escogida, cada vértice tendrá un único padre, y nunca más de dos hijos. Si reusamos el requerimiento de la conectividad, permitiendo múltiples componentes conectados en el grafo, llamaremos a esta última estructura un bosque.


Tipos de árboles binarios
Un árbol binario es un árbol con raíz en el que cada nodo tiene como máximo dos hijos.
Un árbol binario lleno es un árbol en el que cada nodo tiene cero o dos hijos.
Un árbol binario perfecto es un árbol binario lleno en el que todas las hojas (vértices con cero hijos) están a la misma profundidad (distancia desde la raíz, también llamada altura)
A veces un árbol binario perfecto es denominado árbol binario completo. Otros definen un árbol binario completo como un árbol binario lleno en el que todas las hojas están a profundidad n o n-1, para alguna n.
Un árbol binario es un árbol en el que ningún nodo puede tener más de dos subárboles. En un árbol binario cada nodo puede tener cero, uno o dos hijos (subárboles). Se conoce el nodo de la izquierda como hijo izquierdo y el nodo de la derecha como hijo derecho.


ARBOL AVL



Arboles balanceados o equilibrados: · Un árbol binario de búsqueda es k-equilibrado si cada nodo lo es. · Un nodo es k-equilibrado si las alturas de sus subárboles izquierdo y derecho difieren en no más de k. Arboles AVL (Adel’son, Vel’skii, Landis) · Un árbol binario de búsqueda 1-equilibrado se llama árbol AVL. Cabe destacar que un árbol AVL no es un Tipo de dato abstracto sino una estructura de datos.


Árbol-B
B-árbol es un árbol de búsqueda que puede estar vacío o aquel cuyos nodos pueden tener varios hijos, existiendo una relación de orden entre ellos, tal como muestra el dibujo .
Un arbol-B de orden M (el máximo número de hijos que puede tener cada nodo) es un arbol que satisface las siguientes propiedades:
Cada nodo tiene como máximo M hijos.
Cada nodo (excepto raiz y hojas) tiene como mínimo M/2 hijos.
La raiz tiene al menos 2 hijos si no es un nodo hoja.
Todos los nodos hoja aparecen al mismo nivel,y no tienen hijos.
Un nodo no hoja con k hijos contiene k-1 elementos almacenados.
Los hijos que cuelgan de la raíz (r1, · · · rm) tienen que cumplir ciertas condiciones :
El primero tiene valor menor que r1.
El segundo tiene valor mayor que r1 y menor que r2 etc.
El último hijo tiene mayor que rm .
Un arbol B es un tipo de estructura de datos de árboles. Representa una colección de datos ordenados de manera que se permite una inserción y borrado eficientes de elementos. Es un índice, multinivel, dinámico, con un límite máximo y mínimo en el número de claves por nodo.

Crear el arbol B
Conserva las caracteristicas de los arboles binarios, AVL, y ABB.
Se busca la calve a insertar.
Si no esta en el arbol se comienza a insertar.
Si Esta llena la pagina:
Se divide la pagina en dos paginas al mismo nivel extrayendo la clave media
Con esta mediana se sube por el camino de busqueda.
Buscar
Clave = EB
Clave <= EB
Clave >= EB
ARBOL B+
Un árbol-B+ es una variación de un árbol-B. En un árbol-B+, en contraste respecto un árbol-B, toda la información se guarda en las hojas. Los nodos internos sólo contienen claves y punteros. Todas las hojas se encuentran en el mismo, más bajo nivel. Los nodos hoja se encuentran unidos entre sí como una lista enlazada para permitir búsqueda secuencial.
El número máximo de claves en un registro es llamado el orden del árbol-B+.
El mínimo número de claves por registro es la mitad del máximo número de claves. Por ejemplo, si el orden de un árbol-B+ es n, cada nodo (exceptuando la raíz) debe tener entre n/2 y n claves.
El número de claves que pueden ser indexadas usando un árbol-B+ está en función del orden del árbol y su altura.
Para un árbol-B+ de orden n, con una altura h:
Número máximo de claves es: nh
Número mínimo de claves es: 2(n / 2)h − 1

CARACTERISTICAS
  • Nodos internos solo contienen las claves o apuntadores.
  • Todas las hojas se encuentran al mismo nivel.
  • Nodos hojas se encuentran ligados como una lista enlazada para permitir la busqueda mas eficiente.
  • El minimo de claves es 2
    OPERACIONES
  • Buscar
  • Insertar
  • Eliminar

PROGRAMA ARBOLES B+

public class BTree {

private BTree izquierda= null;

private BTree derecha= null;

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(); }}*****************public class BTreeException extends Exception { public BTreeException (String mensaje) {super(mensaje); }}******************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(); }}


COLAS

COLAS

Una cola es una estructura de datos, caracterizada por ser una secuencia de elementos en la que la operación de inserción push se realiza por un extremo y la operación de extracción pop por el otro. También se le llama estructura FIFO(del inglés First In First Out), debido a que el primer elemento en entrar será también el primero en salir.
Las colas se utilizan en sistemas informaticos, transportes y operaciones de investigacion (entre otros), dónde 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.

CODIGO EN JAVA DE COLAS

public void inserta(Elemento x) {
Nodo Nuevo;
Nuevo=new Nodo(x, null);
if (NodoCabeza==null)
NodoCabeza=Nuevo;
else
NodoFinal.Siguiente=Nuevo;
NodoFinal=Nuevo;
}
public Elemento cabeza()throws IllegalArgumentException {
if (NodoCabeza == null) throw new IllegalArgumentException();
else return NodoCabeza.Info;
}
public Cola(){
// Devuelve una Cola vacía
NodoCabeza=null;
NodoFinal=null;
}

Tipos de Colas

Colas circulares (anillos): en las que el último elemento y el primero están unidos. Colas de prioridad: En ellas, los elementos se atienden en el orden indicado por una prioridad asociada a cada uno. Si varios elementos tienen la misma prioridad, se atenderán de modo convencional según la posición que ocupen. Hay 2 formas de implementación:
Añadir un campo a cada nodo con su prioridad. Resulta conveniente mantener la cola ordenada por orden de prioridad.
Crear tantas colas como prioridades haya, y almacenar cada elemento en su cola.
Bicolas: son colas en donde los nodos se pueden añadir y quitar por ambos extremos; se les llama DEQUE (Double Ended QUEue). Para representar las bicolas lo podemos hacer con un array circular con Inicio y Fin que apunten a cada uno de los extremos. Hay variantes: Bicolas de entrada restringida: Son aquellas donde la inserción sólo se hace por el final, aunque podemos eliminar al inicio ó al final.
Bicolas de salida restringida: Son aquellas donde sólo se elimina por el final, aunque se puede insertar al inicio y al final.