Exemple #1
0
        public ArbolB(int orden, string nombreArchivo, IFabricaTextoTamañoFijo <T> fabrica)
        {
            // Se guardan los parámetros recibidos
            _archivoNombre = nombreArchivo;
            _fabrica       = fabrica;

            // Se abre la conexión al archivo

            _archivo = new FileStream(_archivoNombre, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);

            // Se obtienen los valores del encabezado del archivo
            _raiz = Utilidades.LeerEntero(_archivo, 0);
            _ultimaPosicionLibre = Utilidades.LeerEntero(_archivo, 1);
            Tamaño = Utilidades.LeerEntero(_archivo, 2);
            Orden  = Utilidades.LeerEntero(_archivo, 3);
            Altura = Utilidades.LeerEntero(_archivo, 4);

            // Se corrigen los valores del encabezado cuando el archivos no existe previamente
            if (_ultimaPosicionLibre == Utilidades.ApuntadorVacio)
            {
                _ultimaPosicionLibre = 0;
            }

            if (Tamaño == Utilidades.ApuntadorVacio)
            {
                Tamaño = 0;
            }

            if (Orden == Utilidades.ApuntadorVacio)
            {
                Orden = orden;
            }

            if (Altura == Utilidades.ApuntadorVacio)
            {
                Altura = 1;
            }

            if (_raiz == Utilidades.ApuntadorVacio)
            {
                // Se crea la cabeza del árbol vacía
                // para evitar futurs errores
                NodoB <T> nodoCabeza = new NodoB <T>(Orden, _ultimaPosicionLibre, Utilidades.ApuntadorVacio, _fabrica);
                _ultimaPosicionLibre++;
                _raiz = nodoCabeza.Posicion;
                nodoCabeza.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
            }

            // Si el archivo existe solamente se actualizan los encabezados, sino
            // se crea y luego se almacenan los valores iniciales
            GuardarEncabezado();
        }
Exemple #2
0
        public override T Obtener(string llave)
        {
            int       posicion     = -1;
            NodoB <T> nodoObtenido = ObtenerRecursivo(_raiz, llave, out posicion);

            if (nodoObtenido == null)
            {
                throw new InvalidOperationException("La llave indicada no está en el árbol.");
            }
            else
            {
                return(nodoObtenido.Datos[posicion]);
            }
        }
Exemple #3
0
        public override bool Contiene(string llave)
        {
            int       posicion     = -1;
            NodoB <T> nodoObtenido = ObtenerRecursivo(_raiz, llave, out posicion);

            if (nodoObtenido == null)
            {
                return(false);
            }
            else
            {
                return(true);
            }
        }
Exemple #4
0
        private void RecorrerPostOrdenRecursivo(int posicionActual, StringBuilder texto)
        {
            if (posicionActual == Utilidades.ApuntadorVacio)
            {
                return;
            }

            NodoB <T> nodoActual = NodoB <T> .LeerNodoDesdeDisco(_archivo, _tamañoEncabezadoBinario, Orden, posicionActual, _fabrica);

            for (int i = 0; i < nodoActual.Hijos.Count; i++)
            {
                RecorrerPreOrdenRecursivo(nodoActual.Hijos[i], texto);
            }

            EscribirNodo(nodoActual, texto);
        }
Exemple #5
0
 private void EscribirNodo(NodoB <T> nodoActual, StringBuilder texto)
 {
     for (int i = 0; i < nodoActual.Llaves.Count; i++)
     {
         if (nodoActual.Llaves[i] != "")
         {
             texto.AppendLine(nodoActual.Llaves[i].ToString());
             texto.AppendLine(nodoActual.Datos[i].ToString());
             texto.AppendLine("---------------");
         }
         else
         {
             break;
         }
     }
 }
Exemple #6
0
        internal void SepararNodo(string llave, T dato, int hijoDerecho, NodoB <T> nuevoNodo, ref string llavePorSubir, ref T datoPorSubir)
        {
            if (!Lleno)
            {
                throw new Exception("Uno nodo solo puede separarse si está lleno");
            }

            // Incrementar el tamaño de las listas en una posición
            Llaves.Add("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
            Datos.Add(dato);
            Hijos.Add(Utilidades.ApuntadorVacio);

            // Agregar los nuevos elementos en orden
            AgregarDato(llave, dato, hijoDerecho, false);

            // Obtener los valores a subir
            int mitad = (Orden / 2);

            llavePorSubir = Llaves[mitad];
            datoPorSubir  = Datos[mitad];
            Llaves[mitad] = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%";

            // Llenar las llaves y datos que pasan al nuevo nodo
            int j = 0;

            for (int i = mitad + 1; i < Llaves.Count; i++)
            {
                nuevoNodo.Llaves[j] = Llaves[i];
                nuevoNodo.Datos[j]  = Datos[i];
                Llaves[i]           = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%";
                j++;
            }

            // Llenar los hijos que pasan al nuevo nodo
            j = 0;
            for (int i = mitad + 1; i < Hijos.Count; i++)
            {
                nuevoNodo.Hijos[j] = Hijos[i];
                Hijos[i]           = Utilidades.ApuntadorVacio;
                j++;
            }
            Llaves.RemoveAt(Llaves.Count - 1);
            Datos.RemoveAt(Datos.Count - 1);
            Hijos.RemoveAt(Hijos.Count - 1);
        }
Exemple #7
0
        private void RecorrerInOrdenRecursivo(int posicionActual, StringBuilder texto)
        {
            if (posicionActual == Utilidades.ApuntadorVacio)
            {
                return;
            }

            NodoB <T> nodoActual = NodoB <T> .LeerNodoDesdeDisco(_archivo, _tamañoEncabezadoBinario, Orden, posicionActual, _fabrica);

            for (int i = 0; i < nodoActual.Hijos.Count; i++)
            {
                RecorrerInOrdenRecursivo(nodoActual.Hijos[i], texto);

                if ((i < nodoActual.Llaves.Count) && (nodoActual.Llaves[i] != "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"))
                {
                    miListado.Add(nodoActual.Datos[i].ToString());
                    texto.AppendLine(nodoActual.Llaves[i].ToString());
                    texto.AppendLine(nodoActual.Datos[i].ToString());
                    texto.AppendLine("---------------");
                }
            }
        }
Exemple #8
0
        private void AgregarRecursivo(int posicionNodoActual, string llave, T dato)
        {
            NodoB <T> nodoActual = NodoB <T> .LeerNodoDesdeDisco(_archivo, _tamañoEncabezadoBinario, Orden, posicionNodoActual, _fabrica);

            if (nodoActual.PosicionExactaEnNodo(llave) != -1)
            {
                throw new InvalidOperationException("La llave indicada ya está contenida en el árbol.");
            }

            if (nodoActual.EsHoja)
            {
                // Se debe insertar en este nodo, por lo que se hace la llamada
                // al método encargado de insertar y ajustar el árbol si es necesario
                Subir(nodoActual, llave, dato, Utilidades.ApuntadorVacio);
                GuardarEncabezado();
            }
            else
            {
                // Se hace una llamada recursiva, bajando en el subarbol
                // correspondiente según la posición aproximada de la llave
                AgregarRecursivo(nodoActual.Hijos[nodoActual.PosicionAproximadaEnNodo(llave)], llave, dato);
            }
        }
Exemple #9
0
        private NodoB <T> ObtenerRecursivo(int posicionNodoActual, string llave, out int posicion)
        {
            NodoB <T> nodoActual = NodoB <T> .LeerNodoDesdeDisco(_archivo, _tamañoEncabezadoBinario, Orden, posicionNodoActual, _fabrica);

            posicion = nodoActual.PosicionExactaEnNodo(llave);

            if (posicion != -1)
            {
                return(nodoActual);
            }
            else
            {
                if (nodoActual.EsHoja)
                {
                    return(null);
                }
                else
                {
                    int posicionAproximada = nodoActual.PosicionAproximadaEnNodo(llave);
                    return(ObtenerRecursivo(nodoActual.Hijos[posicionAproximada], llave, out posicion));
                }
            }
        }
Exemple #10
0
        internal static NodoB <T> LeerNodoDesdeDisco(FileStream archivo, int tamañoEncabezado, int orden, int posicion, IFabricaTextoTamañoFijo <T> fabrica)
        {
            if (archivo == null)
            {
                throw new ArgumentNullException("archivo");
            }

            if (tamañoEncabezado < 0)
            {
                throw new ArgumentOutOfRangeException("tamañoEncabezado");
            }

            if ((orden < OrdenMinimo) || (orden > OrdenMaximo))
            {
                throw new ArgumentOutOfRangeException("orden");
            }

            if (posicion < 0)
            {
                throw new ArgumentOutOfRangeException("posicion");
            }
            if (fabrica == null)
            {
                throw new ArgumentNullException("fabrica");
            }
            // Se crea un nodo nulo para poder acceder a las
            // propiedades de tamaño calculadas sobre la instancia
            // el dato de la instancia del nodo
            NodoB <T> nuevoNodo = new NodoB <T>(orden, posicion, 0, fabrica);

            // Se crea un buffer donde se almacenarán los bytes leidos
            byte[] datosBinario = new byte[nuevoNodo.TamañoEnBytes];

            // Variables a ser utilizadas luego de que el archivo sea leido
            string datosCadena = ""; string[] datosSeparados = null; int PosicionEnDatosCadena = 1;

            // Se ubica la posición donde deberá estar el nodo y se lee desde el archivo
            archivo.Seek(nuevoNodo.CalcularPosicionEnDisco(tamañoEncabezado), SeekOrigin.Begin);
            archivo.Read(datosBinario, 0, nuevoNodo.TamañoEnBytes);

            // Se convierten los bytes leidos del archivo a una cadena
            datosCadena = Utilidades.ConvertirBinarioYTexto(datosBinario);

            // Se quitan los saltos de línea y se separa en secciones
            datosCadena    = datosCadena.Replace(Utilidades.TextoNuevaLinea, "");
            datosCadena    = datosCadena.Replace("".PadRight(3, Utilidades.TextoSeparador), Utilidades.TextoSeparador.ToString());
            datosSeparados = datosCadena.Split(Utilidades.TextoSeparador);

            // Se se obtiene la posición del Padre
            nuevoNodo.Padre = Convert.ToInt32(datosSeparados[PosicionEnDatosCadena]);
            PosicionEnDatosCadena++;

            // Se asignan al nodo vacío los hijos desde la cadena separada
            for (int i = 0; i < nuevoNodo.Hijos.Count; i++)
            {
                nuevoNodo.Hijos[i] = Convert.ToInt32(datosSeparados[PosicionEnDatosCadena]);
                PosicionEnDatosCadena++;
            }

            // Se asignan al nodo vacío las llaves desde la cadena separada
            for (int i = 0; i < nuevoNodo.Llaves.Count; i++)
            {
                nuevoNodo.Llaves[i] = datosSeparados[PosicionEnDatosCadena];
                PosicionEnDatosCadena++;
            }

            // Se asignan al nodo vacío los datos la cadena separada
            for (int i = 0; i < nuevoNodo.Datos.Count; i++)
            {
                datosSeparados[PosicionEnDatosCadena] = datosSeparados[PosicionEnDatosCadena].Replace(Utilidades.TextoSustitutoSeparador, Utilidades.TextoSeparador);
                nuevoNodo.Datos[i] = fabrica.Fabricar(datosSeparados[PosicionEnDatosCadena]);
                PosicionEnDatosCadena++;
            }

            // Se retorna el nodo luego de agregar toda la información
            return(nuevoNodo);
        }
Exemple #11
0
        private void Subir(NodoB <T> nodoActual, string llave, T dato, int hijoDerecho)
        {
            // Si el nodo no está lleno, se agrega la información
            // al nodo y el método termina
            if (!nodoActual.Lleno)
            {
                nodoActual.AgregarDato(llave, dato, hijoDerecho);
                nodoActual.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
                return;
            }

            // Creo un nuevo nodo hermano
            NodoB <T> nuevoHermano = new NodoB <T>(Orden, _ultimaPosicionLibre, nodoActual.Padre, _fabrica);

            _ultimaPosicionLibre++;

            // Datos a subir al padre luego de la separación
            string llavePorSubir = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%";
            T      datoPorSubir  = _fabrica.FabricarNulo();

            // Se llama al método que hace la separación
            nodoActual.SepararNodo(llave, dato, hijoDerecho, nuevoHermano, ref llavePorSubir, ref datoPorSubir);

            // Actualizar el apuntador en todos los hijos
            NodoB <T> nodoHijo = null;

            for (int i = 0; i < nuevoHermano.Hijos.Count; i++)
            {
                if (nuevoHermano.Hijos[i] != Utilidades.ApuntadorVacio)
                {
                    // Se carga el hijo para modificar su apuntador al padre
                    nodoHijo = NodoB <T> .LeerNodoDesdeDisco(_archivo, _tamañoEncabezadoBinario, Orden, nuevoHermano.Hijos[i], _fabrica);

                    nodoHijo.Padre = nuevoHermano.Posicion;
                    nodoHijo.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
                }
                else
                {
                    break;
                }
            }

            // Evaluo el caso del Padre
            if (nodoActual.Padre == Utilidades.ApuntadorVacio) // Es la raiz
            {
                // Creo un nuevo nodo Raiz
                NodoB <T> nuevaRaiz = new NodoB <T>(Orden, _ultimaPosicionLibre, Utilidades.ApuntadorVacio, _fabrica);
                _ultimaPosicionLibre++;
                Altura++;

                // Agrego la información
                nuevaRaiz.Hijos[0] = nodoActual.Posicion;
                nuevaRaiz.AgregarDato(llavePorSubir, datoPorSubir, nuevoHermano.Posicion);

                // Actualizo los apuntadores al padre
                nodoActual.Padre   = nuevaRaiz.Posicion;
                nuevoHermano.Padre = nuevaRaiz.Posicion;
                _raiz = nuevaRaiz.Posicion;

                // Guardo los cambios
                nuevaRaiz.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
                nodoActual.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
                nuevoHermano.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
            }
            else
            // No es la raiz
            {
                nodoActual.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
                nuevoHermano.GuardarNodoEnDisco(_archivo, _tamañoEncabezadoBinario);
                // Cargar el nodo Padre
                NodoB <T> nodoPadre = NodoB <T> .LeerNodoDesdeDisco(_archivo, _tamañoEncabezadoBinario, Orden, nodoActual.Padre, _fabrica);

                Subir(nodoPadre, llavePorSubir, datoPorSubir, nuevoHermano.Posicion);
            }
        }