]> git.llucax.com Git - z.facultad/75.52/treemulator.git/commitdiff
Toques finales.
authorRicardo Markiewicz <rmarkie@fi.uba.ar>
Tue, 1 Nov 2005 03:44:47 +0000 (03:44 +0000)
committerRicardo Markiewicz <rmarkie@fi.uba.ar>
Tue, 1 Nov 2005 03:44:47 +0000 (03:44 +0000)
Cambio el nombre de los tipos de arboles a los que recomendo Serveto que son
los "correctos".
Tambien modifico el viewer para que compile.

src/btree.cpp
src/btree.h
src/main_var.cpp
viewer/main.cpp
viewer/view_btree.cpp

index ddcb14c49e65f23a19845d77553235da5c9d75d9..3f6fba6e3c2a7f39ca0a33d7d3e1cc3a45e1ea79 100644 (file)
@@ -143,7 +143,7 @@ Clave* BTree::AddKeyLeafR (const Clave *k, uint node_num, uint &left_child, uint
 
                while (it != node_keys.end ()) {
                        datait = (*it);
-                       if (tree_type == TYPE_UNIQUE) {
+                       if (tree_type == TYPE_IDENTIFICACION) {
                                /* Verifico que la clave no existea ya en el arbol */
                                if ((*data) == (*datait)) {
                                        throw new AddException ();
@@ -184,7 +184,7 @@ Clave* BTree::AddKeyLeafR (const Clave *k, uint node_num, uint &left_child, uint
                while (it != node_keys.end ()) {
                        BTreeData *datait;
                        datait = (*it);
-                       if (tree_type == TYPE_UNIQUE) {
+                       if (tree_type == TYPE_IDENTIFICACION) {
                                /* Verifico que la clave no existea ya en el arbol */
                                if ((*data) == (*datait)) {
                                        throw new AddException ();
@@ -284,7 +284,7 @@ Clave* BTree::AddKeyOtherR (const Clave *k, uint node_num, uint &left_child, uin
        posterior = it;
 
        while (it != node_keys.end ()) {
-               if (tree_type == TYPE_UNIQUE) {
+               if (tree_type == TYPE_IDENTIFICACION) {
                        /* Verifico que la clave no existea ya en el arbol */
                        if ((*data) == (*(*it))) {
                                throw new AddException ();
@@ -320,7 +320,7 @@ Clave* BTree::AddKeyOtherR (const Clave *k, uint node_num, uint &left_child, uin
 
                while (it != node_keys.end ()) {
                        datait = (*it);
-                       if (tree_type == TYPE_UNIQUE) {
+                       if (tree_type == TYPE_IDENTIFICACION) {
                                /* Verifico que la clave no existea ya en el arbol */
                                if ((*data) == (*datait)) {
                                        throw new AddException ();
@@ -362,7 +362,7 @@ Clave* BTree::AddKeyOtherR (const Clave *k, uint node_num, uint &left_child, uin
                while (it != node_keys.end ()) {
                        BTreeData *datait;
                        datait = (*it);
-                       if (tree_type == TYPE_UNIQUE) {
+                       if (tree_type == TYPE_IDENTIFICACION) {
                                /* Verifico que la clave no existea ya en el arbol */
                                if ((*data) == (*datait)) {
                                        throw new AddException ();
@@ -1235,3 +1235,8 @@ void BTree::DeleteKeys (std::list<BTreeData *> &keys)
                it++;
        }
 }
+
+int BTree::type () const
+{
+       return key_type;
+}
index ef9f24232358b9150b5c56e56fed967305e30688..2d9ca6a204072cf4eb569b8013a099710773145c 100644 (file)
@@ -4,6 +4,33 @@
 
 /** \page page_btree Árbol B
  * 
+ * \section page_model_class Estructura del árbol en memoria.
+ *
+ * La organización de las clases utilizadas es la siguiente :
+ * 
+ * \image html clases.png
+ * \image latex clases.eps "Diagrama de Clases" width=10cm
+ * 
+ * Para operar con un determinado nodo en memoria, lo que se hace es lo siguiente.
+ * Como primer paso se carga el bloque en memoria llamando a ReadBlock y se lee de él 
+ * su encabezado utilizando una llamada a BTree::ReadNodeHeader, que almacena los datos
+ * en una clase BTreeNodeHeader. A continuación se leen las claves, todavía en formato
+ * RAW, y se genera una lista con instancias de BTreeData. Esta lista es generada
+ * con la llamada a BTree::ReadKeys.
+ *
+ * La operación de búsqueda o inserción se realiza en memoria sobre la lista cargada
+ * anteriormente. Cuando se está listo para guardar todo de nuevo en disco se opera
+ * como se explica a continuación.
+ *
+ * Como primer paso se escriben las claves de la lista nuevamente en el bloque en
+ * memoria en formato RAW, para ello se utilizar WriteKeys, que además de pasar
+ * las claves a formato RAW, también actualiza los datos del header (espacio libre
+ * y cantidad de ítems). Luego se escribe el header en formato RAW con BTree::WriteNodeHeader
+ * y por último se baja a disco el bloque con WriteBlock.
+ *
+ * Para liberar la memoria utilizada solo basta llamar a BTree::DeleteKeys y liberar
+ * el bloque RAW utilizado para el nodo.
+ *
  * \section page_model_estructura Estructura del árbol en disco.
  *
  *  La estructura del archivo donde se almacena el árbol es una secuencia
  * estructura :
  *   <pre>
  *   +--------------+-----------------------------------+
- *   | BloqueHeader | Area de Claves                    |
+ *   | BloqueHeader | Área de Claves                    |
  *   +--------------+-----------------------------------+
  *   </pre>
  *
- * El area de claves depende del tipo de arbol (INDICE o EXAHUSTIVO)
+ * El área de claves depende del tipo de árbol (IDENTIFICACION o CLASIFICACION)
  * y del tipo de Clave (ClaveFija o ClaveVariable).
  *
  * Los nodos que son "hojas" (es decir, aquellos que no tienen hijos) no
- * tienen "punteros", por lo que el area de datos seria algo como :
+ * tienen "punteros", por lo que el área de datos seria algo como :
  *  <pre>
  *  +--------------+--------------+--------------+--------------+
  *  | clave1,dato1 | clave2,dato2 | ............ | claveN,datoN |
  * El par (claveN,datoN) es representado por la clase BTreeLeafData.
  *
  * Ahora, los bloques intermedios tienen punteros a los hijos, y 
- * quedaria algo como :
+ * quedaría algo como :
  *  <pre>
  *  +---------+----------------------+-------+----------------------+
  *  | HijoIzq | clave1,dato1,HijoDer | ..... | claveN,datoN,HijoDer |
  *  +---------+----------------------+-------+----------------------+
  *  </pre>
  *
- * El puntore HijoIzq es representado en memoria por la clase BTreeChildData, y
+ * El puntero HijoIzq es representado en memoria por la clase BTreeChildData, y
  * el resto por BTreeData.
  *
  * El tamaño de la clave es variable, por lo que la cantidad de claves
  *
  * Para saber si hay que romper en dos un nodo, se debe ver si la clave
  * a agregar entra en el espacio libre del nodo encontrado como "lugar
- * de insercion". Ahora, un problema a resolver es cuando se debe
- * juntar nodos, ya que el arbol B este es particular (Preguntar a Cerveto?).
+ * de inserción". Ahora, un problema a resolver es cuando se debe
+ * juntar nodos, ya que el árbol B este es particular <b>(Preguntar a
+ * Cerveto?)</b>.
+ *
+ * \section page_model_op Operaciones Básicas
+ *
+ * En esta sección explicaremos como se realizan las diferentes operaciones
+ * sobre el árbol.
+ *
+ * \subsection page_model_add Agregar una Clave.
+ *
+ * Agregar una clave al árbol es relativamente fácil ya que siempre se agregan
+ * en las hojas.
+ *
+ * El algoritmo comienza a recorrer la raíz buscando la clave inmediatamente
+ * superior (llamada clave de corte) a la que deseamos agregar. Si la raíz es una hoja, la clave es
+ * agregada antes de la clave que corta el algoritmo.
+ *
+ * Si la raíz no es una hoja, se llama recursivamente yendo al nodo hijo de
+ * la clave anterior a la clave de corte, hasta llegar a una hoja y finalmente
+ * agregar la clave.
+ *
+ * En este punto pueden pasar dos cosas. La primera es que la clave entre en el 
+ * lugar libre que le queda al nodo, entonces es agregada y retorna liberando
+ * todo lo que quedó pendiente.
+ *
+ * La segunda situación es que la clave no entre y el nodo deba ser separado
+ * en dos. Cuando esto sucede se crea una lista temporal ordenada con las
+ * claves del nodo a partir y la nueva clave a agregar.
+ * 
+ * La primer mitad se guarda en un nodo, la clave del medio se deja para retornar
+ * al padre y la segunda mitad se pone en un nuevo nodo. Luego de guardar todo
+ * se le retorna al padre una clave. Éste al detectar que un hijo manda una clave
+ * tratará de agregarla siguiendo el mismo procedimiento que el hijo (si no entra
+ * debe realizar un split), hasta llegar a la raíz.
  *
+ * La única diferencia entre el split en una hoja y el resto de los nodos, es que 
+ * estos últimos hace uso de los datos "hijo izquierdo" e "hijo derecho" también
+ * pasados como parámetros luego del split, a fin de ajustar los punteros necesarios.
  *
- * \todo :
- *  * Ver como manejar las claves de manera transparente a las APIs de
- *    agregar y de borrar (EMUFS lo solucionaba bastante bien, se puede
- *    tomar una idea simimar)
+ * \subsection page_model_del Eliminar una Clave.
+ *
+ * El proceso de eliminar una clave es un poco más complejo y cubre más situaciones
+ * particulares.
+ *
+ * El algoritmo se divide básicamente en 2 casos : eliminar de una hoja y eliminar
+ * de un nodo interno.
+ *
+ * Ambos algoritmos comienzan con una búsqueda en profundidad de la clave a borrar.
+ * en el momento de encontrarla se llama a BTree::DelKeyFromLeaf o BTree::DelKeyFromNode
+ * dependiendo del caso.
+ * 
+ * \subsubsection page_model_del_hoja Eliminar de una Hoja.
+ *
+ * Cuando la clave es encontrada en una hoja simplemente se elimina de la hoja.
+ *
+ * Luego debemos verificar que se cumpla la condición de que el nodo tenga al menos
+ * el 50% del espacio ocupado. Si esto no ocurre debemos actuar como se explica a
+ * continuación.
+ *
+ * Como primer intento pedimos prestada una clave a alguno nuestros hermanos. Si 
+ * alguno es capaz de pasar una clave, ésta última se reemplaza en el padre y la
+ * clave del padre para al nodo en cuestión. Esto se hace para mantener el ordenamiento
+ * del árbol intacto.
+ *
+ * Si ningún hermano me puede prestar, lo único que nos queda es unir dos nodos.
+ * La unión se realiza con cualquier nodo disponible, siempre preguntando primero
+ * por el derecho y si este no existe, se une con el izquierdo. Luego de unir se
+ * le notifica al padre y se ajustan los punteros correspondientes.
+ *
+ * \subsubsection page_model_del_nodo Eliminar de un Nodo.
+ *
+ * Cuando la clave a eliminar se encuentra en una hoja se debe tratar de forma
+ * especial. Lo primero que se hace es buscar en todo el árbol la clave
+ * inmediatamente superior. Esto se logra yendo al hijo derecho de la clave a borrar
+ * y luego siempre hacia el hijo izquierdo hasta llegar a una hoja.
+ *
+ * La primer clave de la hoja encontrada es reemplazada por la clave del padre y 
+ * se llama al borrar de una hoja. Como siempre la clave reemplazada en la hoja queda
+ * en primer lugar, no hay problemas que no esté ordenada al momento de llamar
+ * al algoritmo de borrado en una hoja. De acá en más todo sigue como fue descripto
+ * en el borrado en una hoja.
+ *
+ * \subsection page_model_find Búsqueda de una Clave.
+ *
+ * Esta operación se realiza haciendo una búsqueda en profundidad en el árbol.
+ * Si la clave es encontrada se retorna una estructura del tipo BTreeFindResult
+ * con toda la información útil.
+ *
+ * Si no se encuentra retorna NULL.
  */
 
 #include <iostream>
@@ -122,7 +231,7 @@ struct BTreeFindResult {
  */
 class BTree {
        public:
-               BTree (const std::string &filename, unsigned int block_size, int t_t = TYPE_UNIQUE, int k_t = KEY_FIXED, bool create_new_file = false);
+               BTree (const std::string &filename, unsigned int block_size, int t_t = TYPE_IDENTIFICACION, int k_t = KEY_FIXED, bool create_new_file = false);
                ~BTree ();
 
                /** Tipos de clave a usar */
@@ -132,8 +241,8 @@ class BTree {
                };
 
                enum {
-                       TYPE_UNIQUE,
-                       TYPE_SELECTIVE
+                       TYPE_IDENTIFICACION,
+                       TYPE_CLASIFICACION
                };
        
                /** Agrega una nueva clave al árbol. */
@@ -146,6 +255,8 @@ class BTree {
                 */
                BTreeFindResult *FindKey (const Clave &k);
 
+               int type() const;
+
        //protected:
                /* Funciones de Alta */
                Clave* AddKeyR (const Clave *k, uint node_num, uint &left_child, uint &right_child);
index 91359b1f61a1a02a57643e51184af41e85ea9e58..8202096542959e524efcfce48441e7261c5c5e76 100644 (file)
@@ -18,7 +18,7 @@ int main  (int argc, char *argv[])
        int bajas = atoi (argv[3]);
 
        KeyManager<std::string> km;
-       BTree tree ("test.idx", bloque, BTree::TYPE_UNIQUE, BTree::KEY_VARIABLE);
+       BTree tree ("test.idx", bloque, BTree::TYPE_IDENTIFICACION, BTree::KEY_VARIABLE);
        
        std::list<std::string> lst;
        std::list<std::string>::iterator it;
index f7e4d5d0b2458803a6b7fef5b6ef2f3d5c81c397..b4f3c6354666996f5e479066d776651c3451d908 100644 (file)
@@ -129,7 +129,7 @@ void nuevo_arbol ()
                        it = lst.begin ();
                        uint i = 0;
                        while (it != lst.end ()) {
-                               ClaveFija c(*it);
+                               ClaveFija c(*it, 0);
 
                                double l = Random::Double (0.0f, 1.0f);
                                std::cout << l << " >= " << paltas << std::endl;
@@ -150,7 +150,7 @@ void nuevo_arbol ()
                                                otro++;
                                                j++;
                                        }
-                                       ClaveFija c(*otro);
+                                       ClaveFija c(*otro, 0);
 
                                        tree->DelKey (c);
                                        std::string sss = c;
@@ -167,7 +167,7 @@ void nuevo_arbol ()
 
                        it = lst.begin ();
                        while (it != lst.end ()) {
-                               ClaveVariable c(*it);
+                               ClaveVariable c(*it, 0);
 
                                try {
                                        tree->AddKey (c);
@@ -199,12 +199,12 @@ void agregar_clave ()
                Glib::ustring str_key = d.key();
                if (tree->type() == BTree::KEY_FIXED)
                {
-                       ClaveFija c(atoi(str_key.c_str()));
+                       ClaveFija c(atoi(str_key.c_str()), 0);
                        tree->AddKey(c);
                }
                else
                {
-                       ClaveVariable c(str_key);
+                       ClaveVariable c(str_key, 0);
                        tree->AddKey(c);
                }
                delete tree->last_selected;
@@ -228,12 +228,12 @@ void borrar_clave ()
                Glib::ustring str_key = d.key();
                if (tree->type() == BTree::KEY_FIXED)
                {
-                       ClaveFija c(atoi(str_key.c_str()));
+                       ClaveFija c(atoi(str_key.c_str()), 0);
                        tree->DelKey(c);
                }
                else
                {
-                       ClaveVariable c(str_key);
+                       ClaveVariable c(str_key, 0);
                        tree->DelKey(c);
                }
                delete tree->last_selected;
@@ -261,12 +261,12 @@ void buscar_clave ()
                        Glib::ustring str_key = d.key();
                        if (tree->type() == BTree::KEY_FIXED)
                        {
-                               c = new ClaveFija (atoi(str_key.c_str()));
+                               c = new ClaveFija (atoi(str_key.c_str()), 0);
                                result = tree->FindKey(*c);
                        }
                        else
                        {
-                               c = new ClaveVariable (str_key);
+                               c = new ClaveVariable (str_key, 0);
                                result = tree->FindKey(*c);
                        }
                        if (result)
index 43491870f07dea25e295773d1ef5b9f39ce2e814..353fd2bb59361aea736bb178f1d12ee5400d2139 100644 (file)
@@ -8,11 +8,11 @@ double ViewBTree::node_width = 0;
 double ViewBTree::node_height = 0;
 
 ViewBTree::ViewBTree (Canvas::Group *parent, std::string filename, uint block_size, int type):Canvas::Group (*parent, 0, 0),
-       BTree (filename, block_size, BTree::TYPE_UNIQUE, type)
+       BTree (filename, block_size, BTree::TYPE_IDENTIFICACION, type)
 {
        /* Cada bytes lo hago de 5 units de ancho */
-       node_width = 5 * block_size;
-       node_height = node_width/10;
+       node_width = 4 * block_size;
+       node_height = 50;
        byte_to_pixels  = node_width/block_size;
 
        last_selected = NULL;