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(); }
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]); } }
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); } }
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); }
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; } } }
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); }
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("---------------"); } } }
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); } }
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)); } } }
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); }
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); } }