1 #LyX 1.3 created this file. For more info see http://www.lyx.org/
11 \paperpackage widemarginsa4
15 \use_numerical_citations 0
16 \paperorientation portrait
19 \paragraph_separation indent
21 \quotes_language english
25 \paperpagestyle default
29 Organización de Datos (75.06)
34 \begin_inset Formula $\mu$
50 Leandro Lucarella (77891)
52 Ricardo Markiewicz (78226)
55 Segunda Entrega, 31 de Mayo de 2004
59 \begin_inset LatexCommand \tableofcontents{}
69 En esta entrega el trabajo estuvo concentrado en el manejo de índices para
70 los tipos de archivos implementados en la primer entrega.
71 Los índices se implementaron con:
83 Además de esto, se pide 3 funciones distintas para estos índices:
95 Con la autorización de los ayudantes de la cátedra decidimos que el árbol
96 B+ sólo pueda ser utilizado para índices principal ya que de otra manera
97 no tiene sentido el set secuencial (ver página
98 \begin_inset LatexCommand \pageref{sub:justificacion}
102 para una justificación más detallada).
105 Finalmente, para obtener listados basados en campos de los cuales no se
106 tiene un índice, se implementó un ordenamiento externo.
109 A continuación se presenta una descripción un poco más detallada sobre todas
110 herramientas utilizadas para resolver el trabajo práctico.
113 Documentación de la API
116 Para obtener una documentación de la API más completa, se incluye en formato
117 HTML en el CD-ROM la documentación generado con Doxygen.
118 Esta documentación se encuentra en el directorio
120 doc/api/html/index.html
131 Se detallan a continuación los tipos de datos definidos y utilizados en
132 las distintas implementaciones que conforman nuestro sistema, siendo el
133 más importante de ellos en esta entrega, la estructura
137 que actúa como interfaz común para el manejo de cualquier tipo de índice
138 (no importa que tipo de organización física ni de que forma esté implementado,
139 esta estructura proveerá una interfaz abstracta para su manejo).
145 Se agregaron varios tipos comunes nuevos en esta entrega, en su mayoría
146 relacionados a los índices.
147 Estos tipos son brevemente descriptos a continuación y pueden ser hallados
159 : usado para representar el conjunto de un ID más su dato.
166 : indica el tipo de índice (B, B* o B+).
173 : indica la función que cumple el índice (principal, selectivo o exhaustivo).
180 : indica el tipo de dato que se usa como clave.
187 : representa una clave de un índice.
200 es la estructura principal que encapsula todas las funciones para el manejo
202 Posee punteros a funciones que permite utilizar la misma interfaz para
203 distintas implementaciones de árboles.
207 Su declaración puede ser observada en el archivo
214 y cuenta con la siguiente información:
220 Tipo de dato que maneja.
226 Información sobre el desplazamiento para ubicar el dato dentro de la estructura
227 a indexar (para poder tener una implementación genérica que sirva para
228 cualquier estructura).
231 Información sobre archivos auxiliares para almacenar cadenas de texto y
232 otras estructuras que eventualmente requiera un índice.
235 Punteros a funciones para:
245 Verificar la existencia de una entrada.
251 Obtener clave menor o mayor del índice.
254 Obtener siguiente clave (para recorrido secuencial).
258 Esta estructura define los valores de sus punteros según el tipo de implementaci
259 ón que se desee manejar y esto se realiza a través de la API
268 Esta API posee funciones para crear y destruir índices, agregarlos y quitarlos
273 , comparar claves y otras, necesarias para la correcta y completa utilización
274 de los índices a través de la interfaz de
278 descripta en la entrega anterior.
279 \layout Subsubsection
288 Para integrar la utilización de índices a
292 fueron necesarios los siguientes cambios:
295 Nuevos tipos de archivo.
298 Se incluyen dos tipos de archivo nuevos T4 y T5, que representan, respectivament
299 e, un archivo T1 (registros variables, bloques fijos) y un archivo T3 (registros
300 y bloques fijos), ambos organizados como un set secuencial indexado.
301 De esta manera se conserva la interfaz de
305 (los punteros a funciones) incluso cuando se debe insertar de forma ordenada,
306 ya que al saber que es T4 o T5 siempre se inserta de forma ordenada.
309 Puntero a un arreglo de índices.
312 Se agrega a la estructura
316 un puntero a un arreglo de
320 , donde el primero es siempre el índice principal.
323 Especificaciones de índices
335 Una de las pocas decisiones que tuvimos que tomar fue la forma de manejar
337 Hay dos formas comunes de hacerlo:
340 Permitir que el nodo raíz pueda almacenar 2N+1 claves (siendo N el número
341 máximo de claves permitido por nodo).
344 Hacer que se comporte como un árbol B.
347 La primera forma garantiza un mejor aprovechamiento del espacio, ya que
348 se sigue haciendo una partición en 3 nodos hijo con 2/3 de los espacios
350 El problema que encontramos para hacerlo de esa forma fue que usamos un
351 tamaño de nodo fijo de 512 para poder leer un sector completo del disco
352 y ganar algo de velocidad, por lo que para poder mantener este esquema
353 hubiéramos necesitado de 3 bloques de 512 para poder guardar los 2N+1 claves,
354 desperdiciando 512-tamaño_de_clave espacio en el bloque final y haciendo
355 que cualquier ahorro de espacio en los hijos del nodo raíz difícilmente
359 Además de esto, el utilizar la segunda forma trae como ventaja la reutilización
360 de código del árbol B, lo que facilita la implementación y el mantenimiento
364 Estas son las dos razones principales por las cuales elegimos tratar el
365 nodo raíz como lo hace el árbol B.
368 Indice B+ Organizacion Secuencial Indexada
374 Para la implementación de la organización secuencial indexada de archivos,
375 se ha utilizado un árbol B+, conocido por ser utilizado en términos generales
376 para implementaciones de esta índole.
379 Como particularidad el arbol B+, poseerá en sus hojas todas las claves que
380 se hayan insertado en el árbol.
381 No obstante, las mismas no serán todas las claves que se encuentren en
382 el archivo de datos, sino la primer clave de cada bloque de datos, también
383 denominadas 'anclas de bloque'.
386 En torno a esta distinción respecto de los demás arboles, el árbol B+ nos
387 indicará a la hora de grabar registros en nuestro archivo de datos con
388 bloques (Organización del TP1, Tipo1 o 3), en que bloque de datos debemos
389 realizar la mencionada inserción.
390 La operativa se detalla más adelante, pero básicamente realizaremos una
391 búsqueda del ancla menor inmediata a la clave del registro que se desea
392 insertar, y esto nos indicará el bloque apropiado (el bloque donde esta
396 Como resultado concreto de este comportamiento (teniendo en cuenta también
397 el borrado y partición de bloques del .dat), obtendremos un archivo secuencial
398 indexado, en donde los registros se encuentran ordenados a nivel de bloques,
399 esto es, dentro de un bloque dado del archivo de datos, los registros estan
400 ordenados por clave primaria.
401 No obstante, los bloques no estarán necesariamente ordenados, pero igualmente
402 la cantidad de accesos para recorrer el archivo en forma secuencial, se
403 ve minimizada respecto de otras organizaciones, gracias al encadenamiento
404 de las hojas y la posesión de las anclas de bloque, cuya lista resultante
405 del encadenamiento es denominada
408 \layout Subsubsection
411 \begin_inset LatexCommand \label{sub:justificacion}
415 Razones por las cuales el B+ es útil sólo para clave principal.
418 El mejor aprovechamiento del Arbol B+ se da en su utilizacion en implementacion
419 ISAM (Indexed Sequential Access Method), en donde se realiza una indexacion
420 parcial de claves, sólo ingresando en el árbol las claves anclas de cada
421 bloque en el archivo de datos.
425 Esta aplicación del árbol B+ a ISAM, además de indicarnos donde grabar y
426 donde buscar los registros por identificación primaria, nos asegura el
427 ordenamiento de los registros parcialmente a nivel de bloque (esto es,
428 los registros en un bloque dado, estarán ordenados, pero los bloques no
430 Así pués, recorriendo el Sequence Set del Arbol B+, minimizaremos los saltos
431 de lectura en disco, pues dentro de un bloque indicado por un ancla dada
432 en el Sequence Set, podremos recorrer los registros secuencialmente.
435 Visto y considerando que la aplicación más importante a nuestro criterio
436 del Arbol B+, era para la indexacion parcial de claves primarias, y que
437 en caso de utilizarlo para otros índices, el B+ se convertiría simplemente
438 en un B con encadenamiento a nivel de hojas, luego de consultar con los
439 ayudantes, decidimos utilizarlo unicamente para el índice primario, y utilizar
440 el B y B* para los restantes índices y/o el primario.
447 Para comprender mejor la implementación particular que hemos dado al árbol
448 B+, damos una breve reseña de la estructura de un nodo del arbol, la cual
464 Esta estructura se encuentra en el archivo
469 Esta organización permite, con la ayuda del árbol, mantener el archivo de
470 datos ordenado por la clave principal.
473 Para lograr esto, como fue expuesto anteriormente, el árbol nos indicará
474 donde (en qué bloque) debe insertarse un registro.
475 (ver 3.3.1 Inserción)
478 En el caso de una hoja, dado que cada nodo posee un hijo mas que la cantidad
479 de claves, el hijo que sobra será utilizado como referencia al nodo
480 \begin_inset Quotes eld
484 \begin_inset Quotes erd
487 , lo cual constituye el
488 \begin_inset Quotes eld
492 \begin_inset Quotes erd
496 Para un nodo que no sea hoja el hijo será el número de nodo correspondiente
497 según la clave, es decir, para la clave
509 contiene claves menores y el hijo
515 contiene las claves mayores.
516 En el caso particular del nivel 1 (index set) el hijo
522 (sequence set) contiene las claves mayores o iguales ya que el
523 \begin_inset Quotes eld
527 \begin_inset Quotes erd
530 debe contener todas las claves insertadas, esto produce que exista una
531 repetición de las claves entre el nivel 1 y el 0.
534 En nuestro caso hemos implementado un Secuencial Indexado tipo ISAM (Indexed
535 Sequential Access Method) el cual posee en sus hojas las anclas de cada
536 bloque en el archivo de datos, es decir, solo se guardan en los nodos del
537 árbol la menor de las claves de un bloque del archivo de datos, acompañada
538 cada clave por el numero de bloque al cual pertenece.
541 Hemos adoptado que la cantidad de claves máxima en un nodo del árbol sea
542 una cantidad impar, ya que esto facilita la elección de la clave que será
543 promovida hacia su nodo padre en caso de que se produzca un overflow en
550 Para realizar una inserción en el archivo de datos se debe realizar una
551 consulta en el árbol, la cual nos indicará el número de bloque donde debemos
552 insertar el nuevo registro.
555 Las consultas se realizan a través de una estructura INDEX_DAT que posee:
564 Esta estructura se encuentra en el archivo
569 El modo de uso es el siguiente:
572 En primer lugar se carga la clave a insertar en el campo Clave, y en el
573 campo Número de Bloque se almacena un número de bloque válido, mas adelante
574 se explica el por qué.
577 Luego se invoca a la función
579 int emufs_b_plus_get_bloque(INDICE, INDEX_DAT)
581 la cual recibe como parámetro una estructura de índice y un INDEX_DAT para
582 realizar la consulta.
585 Esta función recorre recursivamente el árbol y busca una clave mayor inmediata
586 a la enviada, siempre culminando la búsqueda en una hoja.
587 Al encontrar la clave mayor inmediata, el resultado de la búsqueda será
588 la clave anterior en el nodo, pues cada clave en el nodo es un ancla de
589 bloque de datos, de esta manera la clave anterior será menor a la clave
590 enviada, pues las claves en las hojas están ordenadas.
594 En este paso pueden suceder dos cosas:
597 Que exista una clave menor a la enviada.
600 Que la clave enviada sea menor a todas las claves del árbol.
603 En el primer caso, se ha encontrado la clave y se carga la estructura con
604 el hijo de esa clave, que será el número de bloque donde debe insertarse
605 el nuevo registro (por el cual se realizó la consulta), sobreescribiendo
606 el valor que almacenaba al ingresar, y la función retornará código 0 que
607 indica que se ha encontrado un bloque donde insertar.
610 En el segundo caso, puede darse que la clave enviada sea menor a todas las
611 claves del árbol, por lo cual no es posible encontrar un ancla de bloque
613 Aquí la función retornará código -1 lo cual indica que no se ha encontrado
614 un bloque donde insertar el registro nuevo, y es por esto que la estructura
615 debe inicializarse con un número de bloque válido antes de realizarse la
616 consulta.De esta manera el árbol indica donde debe insertarse un nuevo registro
617 en el archivo de datos.
620 Otro detalle de la inserción es que cuando el árbol indica donde debe insertarse
621 un registro pueden pasar dos cosas nuevamente:
624 Que el registro quepa en el bloque.
627 Que el registro no quepa en el bloque.
630 El primer caso es trivial y el registro se insertará sin problemas en el
634 En el caso que el registro no quepa en el bloque, se deberán separar los
635 registros del bloque en 2 bloques, en original y uno nuevo, cada uno con
636 la mitad (aproximadamente) de los registros.
640 Al partir el bloque el ancla del bloque original no se modificará, pero
641 en el bloque nuevo se crea una nueva anlca de bloque, pues una de las claves
642 pertenecientes a los registros que contiene, será la menor.
645 Antes de actualizar el árbol con el ancla nueva, habrá que discriminar en
646 qué bloque se debe insertar el registro nuevo.
647 Para ello se compara la menor de las claves del nuevo bloque con la clave
648 del registro, si la clave del registro es menor que el ancla del nuevo
649 bloque, este debe ir en el bloque original, y se inserta ordenado en él
650 y se le informa al árbol que actualice (inserte) una nueva clave correspondient
651 e al bloque nuevo, sino se inserta en el bloque nuevo de forma ordenada
652 y en este caso cabe la posibilidad de que el nuevo registro posea la clave
653 mas pequeña de todas en el bloque, por ello se lo inserta ordenadamente
654 con ayuda de la función
656 CLAVE grabar_ordenado_en_bloque(EMUFS *emu, void *ptr, EMUFS_REG_SIZE size,
657 void *bloque, int num_bloque, EMUFS_FREE fs, int *err)
659 la cual inserta el registro ordenado por CLAVE y devuelve la menor de las
660 claves del bloque, que se usará para informarle al árbol que inserte una
661 clave nueva junto con el número de bloque, para indexar este bloque.
667 El proceso de eliminación es bastante similar al de inserción en el sentido
668 que también hay que realizar una consulta en el árbol para obtener el número
669 de bloque al que pertenece una clave.
670 Una vez conocido este número se levanta el bloque correspondiente y se
671 busca secuencialmente el registro que se debe eliminar.
674 Si el registro a eliminar fuera el primero del bloque, habrá que modificar
675 el ancla de bloque en el árbol con el ancla que corresponda a la clave
676 del nuevo menor registro, y si el que se elimina fuera el único registro
677 en el bloque habrá que eliminar la clave del árbol.
680 En cualquier otro caso, solo se eliminará el registro correspondiente y
681 se justificarán los registros a izquierda.
687 El proceso de búsqueda de un registro por su clave de identificación primaria
688 en la Organización Secuencial Indexada, es bastante directa en su entendimiento.
689 Para buscar un registro, acudiremos al árbol B+ con la clave anteriormente
690 mencionada, y obtendremos del mismo, el número de bloque donde se debe
691 encontrar el registro.
694 Para obtener dicho número de bloque, el árbol internamente busca el ancla
695 menor inmediata a la clave buscada y luego devuelve el número de bloque
696 de datos donde está dicha ancla (el nro bloque será el dato asociado a
697 la clave ancla, en el árbol), el cual será el bloque potencial donde se
698 encuentre el registro buscado.
701 Una desventaja de esta implementación con indexación parcial, es que no
702 sabremos si el registro se encuentra efectivamente en el bloque indicado,
703 hasta no buscarlo dentro del mismo en formal secuencial.
704 Si lo hallamos, daremos por finalizada la búsqueda del registro.
707 Recorrida secuencial de registros
710 Una consecuencia importante de la organización secuencial indexada, en este
711 caso implementada a través de un árbol B+ con indexación parcial, es que
712 como mencionamos anteriormente, los registros dentro de un bloque se encuetran
713 ordenados, y si bien los bloques en si pueden no estar ordenados en el
714 archivo de datos, algunos lo estarán, y minimizarán en base a estas característ
715 icas, los tiempos de acceso para una recorrida secuencial de registros.
718 Suponiendo que nos encontramos con varios registros cargados en esta organizació
719 n de archivo, y con el correspondiente árbol de indexación primaria B+ en
720 el disco, si se nos pidiera por ejemplo, recorrer los registros de articulos
721 desde el ID_Articulo 40, hasta el ID_Articulo 1406, la operativa será la
725 Acudimos al árbol y obtenemos el numero de bloque para el ID_Articulo 40,
726 buscando el ancla menor inmediata y obteniendo el nro de bloque de datos
727 donde se encuentra, siendo este el nro de bloque donde debería estar el
728 artículo de clave ID_Articulo 40.
731 Levantamos el bloque de datos y lo recorremos secuencialmente, pues como
732 dijimos anteriormente, sus registros se encuentran ordenados por la clave
733 de identificación primaria, en este caso ID_Articulo.
736 Cuando ya hayamos procesado todo el bloque, debemos obtener la siguiente
737 ancla a través del árbol y repetir el proceso.
740 NOTA: Cabe desatacar, que todas las anclas estan en las hojas del B+, y
741 por ello las recorremos a nivel hojas a traves del Sequence Set, que gracias
742 a su encadenamiento, nos permite obtener en forma muy directa y efectiva,
743 las anclas de bloque ordenadas en secuencia, y por consiguiente, recorrer
744 el archivo en forma secuencial minimizando accesos.
750 Descripción del algoritmo
753 Luego de buscar varias alternativas sobre algoritmos de ordenamiento externo,
754 se optó por el siguiente (que resultó una mezcla de las alternativas analizadas
758 Tomar uno a uno los registros del archivo a ordenar e
762 en un buffer ordenado hasta llenar el buffer.
765 Quitar el menor de los valores (
769 uno nuevo desde el archivo a ordenar) e insertarlo en un archivo temporal.
772 Quitar del buffer el mínimo valor mayor al último insertado en el archivo
777 nuevamente un registro obtenido del archivo a ordenar) y se lo inserta
778 en el archivo temporal.
779 De esta forma quedan ordenados los registros en el archivo temporal.
782 Repetir el paso 3 hasta que se vacíe el buffer o hasta que no haya ningún
783 valor mayor al último insertado en el archivo temporal.
784 Cuando esto suceda se crea un nuevo archivo temporal volviendo al paso
788 En este punto ya tenemos el buffer vacío y todos los valores del archivo
789 a ordenar repartidos en 1 o más archivos temporales ordenados, sólo queda
790 unir los archivos para volver a un sólo archivo completo y ordenado.
791 El procedimiento es simple:
794 Obtener el mínimo valor de los archivos temporales e insertarlo en el archivo
798 Repetir 1 hasta agotar los registros de todos los archivos temporales.
801 Debe quedar claro que los archivos temporales se comportan como una cola.
802 Es decir que al obtener un registro de un archivo temporal se obtiene el
803 primer registro que se haya insertado (el mínimo por la forma en la que
810 A continuación se presenta un ejemplo para una más fácil comprensión del
814 Supongamos que queremos ordenar un archivo con registros de números enteros
815 (el archivo se lee de izquierda a derecha): 9 6 34 2 8 3 12 43 23 4 19
819 Supongamos que disponemos de un buffer capaz de almacenar 3 registros.
822 Se llena el buffer ordenado
825 Se lee 9 del archivo original y se lo inserta en el buffer ordenado.
829 Se lee 6 del archivo original y se lo inserta en el buffer ordenado.
833 Se lee 34 del archivo original y se lo inserta en el buffer ordenado.
837 Se crea el archivo temporal ordenado 1
840 Se lee el mínimo valor del buffer (6), se lo inserta en el archivo temporal
841 y se carga un nuevo valor del archivo original al buffer (2).
846 Se lee el mínimo valor del buffer mayor al insertado anteriormente (9),
847 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
848 original al buffer (8).
853 Se lee el mínimo valor del buffer mayor al insertado anteriormente (34),
854 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
855 original al buffer (3).
860 No hay más valores en el buffer mayores al último insertado (34), fin del
864 Se crea el archivo temporal ordenado 2
867 Se lee el mínimo valor del buffer (2), se lo inserta en el archivo temporal
868 y se carga un nuevo valor del archivo original al buffer (12).
873 Se lee el mínimo valor del buffer mayor al insertado anteriormente (3),
874 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
875 original al buffer (43).
880 Se lee el mínimo valor del buffer mayor al insertado anteriormente (8),
881 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
882 original al buffer (23).
887 Se lee el mínimo valor del buffer mayor al insertado anteriormente (12),
888 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
889 original al buffer (4).
894 Se lee el mínimo valor del buffer mayor al insertado anteriormente (23),
895 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
896 original al buffer (19).
898 Archivo2: 2 3 8 12 23
901 Se lee el mínimo valor del buffer mayor al insertado anteriormente (43),
902 se lo inserta en el archivo temporal y se carga un nuevo valor del archivo
903 original al buffer (21).
905 Archivo2: 2 3 8 12 23 43
908 No hay más valores en el buffer mayores al último insertado (43), fin del
912 Se crea el archivo temporal ordenado 3
915 Se repite el proceso anterior.
920 Se crea el archivo temporal ordenado 4
923 Se repite el proceso anterior.
925 Archivo4: 1 16 36 42 65
928 Se mezclan los archivos temporales ordenados obteniendo un archivo completo
932 Se obtiene el menor valor de los archivos temporales ordenados (sólo tenemos
933 que elegir entre el primer valor de cada uno).
937 Archivo2: 2 3 8 12 23 43.
938 Archivo3: 4 19 21 87.
939 Archivo4: 1 16 36 42 65
942 Sólo debo comparar y obtener el menor entre 6, 2, 4, y 1.
943 Obtengo el 1, lo saco del archivo temporal y lo agrego al de salida:
947 Archivo2: 2 3 8 12 23 43.
948 Archivo3: 4 19 21 87.
949 Archivo4: 16 36 42 65 Salida: 1
952 Repito hasta que no hayan más valores en los archivos temporales:
956 Archivo2: 3 8 12 23 43.
957 Archivo3: 4 19 21 87.
958 Archivo4: 16 36 42 65.
963 Archivo2: 8 12 23 43.
964 Archivo3: 4 19 21 87.
965 Archivo4: 16 36 42 65.
970 Archivo2: 8 12 23 43.
972 Archivo4: 16 36 42 65.
977 Archivo2: 8 12 23 43.
979 Archivo4: 16 36 42 65.
984 Archivo2: 8 12 23 43.
986 Archivo4: 16 36 42 65.
993 Archivo4: 16 36 42 65.
1000 Archivo4: 16 36 42 65.
1001 Salida: 1 2 3 4 6 8 9
1007 Archivo4: 16 36 42 65.
1008 Salida: 1 2 3 4 6 8 9 12
1015 Salida: 1 2 3 4 6 8 9 12 16
1022 Salida: 1 2 3 4 6 8 9 12 16 19
1029 Salida: 1 2 3 4 6 8 9 12 16 19 21
1036 Salida: 1 2 3 4 6 8 9 12 16 19 21 23
1043 Salida: 1 2 3 4 6 8 9 12 16 19 21 23 34
1050 Salida: 1 2 3 4 6 8 9 12 16 19 21 23 34 36
1057 Salida: 1 2 3 4 6 8 9 12 16 19 21 23 34 36 42
1064 Salida: 1 2 3 4 6 8 9 12 16 19 21 23 34 36 42 43
1071 Salida: 1 2 3 4 6 8 9 12 16 19 21 23 34 36 42 43 65
1078 Salida: 1 2 3 4 6 8 9 12 16 19 21 23 34 36 42 43 65 87
1084 Finalmente, tengo en el archivo de salida el archivo original ordenado.
1090 El algoritmo de ordenamiento es completamente genérico, ya que recibe un
1091 puntero void como registro, su tamaño (para poder manipularlo sin conocer
1092 su tipo) y una función de comparación, para poder comparar dos registros
1093 (sin saber su tipo) a través de una relación de orden (descripta por dicha
1097 Decisiones de diseño.
1100 El algoritmo se eligió en base a una serie de razones y cuenta con una serie
1101 de ventajas y desventajas.
1104 El algoritmo es simple, tanto teóricamente como para implementar.
1107 Tiene la desventaja de que puede llegar a usar muchos archivos temporales
1108 y todos abiertos al mismo tiempo, pero considerando que el sistema operativo
1109 en el que se utiliza suele manejar bien grandes cantidades de archivos
1110 no es una desventaja importante.
1113 Al usar un buffer intermedio, se puede controlar muy bien la cantidad de
1114 memoria que utiliza y experimentar con distintos valores para analizar
1118 El buffer ordenado se implementó con un árbol binario debido a que tiene
1119 una buena relación entre velocidad de búsqueda y facilidad de implementación.
1120 Al ser el principal determinante de la velocidad los accesos a disco no
1121 se creyó necesario buscar una alternativa más rápida para mantener el buffer
1122 ordenado en memoria, ya que no cambiaría de forma notable el tiempo total
1124 Otras posibilidades hubieran sido cargar todo el buffer en memoria y ordenarlo
1125 posteriormente (dependiendo del algoritmo de ordenamiento a utilizar puede
1126 ser más o menos rápido que el árbol y más o menos complicado de implementar)
1127 o hacer una búsqueda secuencial sobre un buffer desordenado (es más fácil
1128 de implementar pero claramente más lento).
1129 Una posible ventaja notable de leer el buffer primero y luego ordenarlo
1130 en memoria es que se necesita un sólo acceso al disco para llenar el buffer,
1131 mientras que al obtener uno a uno los valores puede generar muchos accesos
1133 Esto no debería ser muy notable ya que las funciones de acceso a archivos
1134 de la biblioteca estándar de C poseen un buffer interno, por lo que los
1135 accesos a disco probablemente sea muy poco aún cuando se obtienen uno a