public ArbolB(int grado)
 {
     this.grado = grado;
     raiz       = null;
     raiz       = new NodoLista <T>(grado);
     nuevito    = null;
 }
        public void recorrer_Hijo(NodoIndividual <T> valor, RecorridoDlg <T> recorrido)
        {
            if (valor.derecho != null)
            {
                for (int j = 0; j <= valor.derecho.valores.Length - 1; j++)
                {
                    NodoIndividual <T> aux = valor.derecho.valores[j];
                    if (aux != null)
                    {
                        recorrido(aux);
                        recorrer_Hijo(aux, recorrido);
                    }
                }
            }

            if (valor.izquierdo != null)
            {
                for (int j = 0; j <= valor.izquierdo.valores.Length - 1; j++)
                {
                    NodoIndividual <T> aux = valor.izquierdo.valores[j];
                    if (aux != null)
                    {
                        recorrido(aux);
                        recorrer_Hijo(aux, recorrido);
                    }
                }
            }
        }
 /// <summary>
 /// Inserta un nodo que ya existe en un nodo lista distinto
 /// </summary>
 /// <param name="aux">Nodo lista en el que inserta</param>
 /// <param name="nodo">Nodo a insertar</param>
 private void insertarExistenteEnArreglo(NodoLista <T> aux, NodoIndividual <T> nodo)
 {
     for (int i = 0; i < aux.valores.Length; i++)
     {
         if (aux.valores[i] == null)
         {
             aux.valores[i] = nodo;
             ordenarNodo(aux.valores);
             break;
         }
     }
 }
 public void recorrer_interno(NodoLista <T> inicio, RecorridoDlg <T> recorrido)
 {
     if (inicio != null)
     {
         for (int j = 0; j <= inicio.valores.Length - 1; j++)
         {
             NodoIndividual <T> aux = inicio.valores[j];
             if (aux != null)
             {
                 recorrido(aux);
                 recorrer_Hijo(aux, recorrido);
             }
         }
     }
 }
 /// <summary>
 /// Ingresa un valor en una lista o arreglo y lo ordena
 /// </summary>
 /// <param name="aux">Arreglo o lista</param>
 /// <param name="dato">Valor</param>
 private void insertarEnArreglo(NodoLista <T> aux, T dato)
 {
     for (int i = 0; i < aux.valores.Length; i++)
     {
         if (aux.valores[i] == null)
         {
             NodoIndividual <T> nuevo = new NodoIndividual <T>();
             nuevo.valor = dato;
             //nuevo.padre = aux.Padre;
             aux.valores[i] = nuevo;
             ordenarNodo(aux.valores);
             break;
         }
     }
 }
        /// <summary>
        /// Insertar general, inserta en la raiz de ser posible sino
        /// busca insertar en el nodo hoja que corresponda
        /// </summary>
        /// <param name="dato">Valor que estara almacenado dentro del nodo</param>
        public void Insertar(T dato)
        {
            nuevito       = new NodoIndividual <T>();
            nuevito.valor = dato;
            if ((this.FuncionCompararLlave == null) || (this.FuncionObtenerLlave == null))
            {
                throw new Exception("No se han inicializado las funciones para operar la estructura");
            }

            if (dato == null)
            {
                throw new ArgumentNullException("El dato ingresado está vacio");
            }

            if (!validarHijos(raiz))
            {
                if (validarEspacio(raiz))
                {
                    insertarEnArreglo(raiz, dato);

                    int ind = buscarEnLista(raiz, dato);
                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(raiz.valores[ind].valor), FuncionObtenerLlavePrincipal(dato)) == 0 &&
                        FuncionCompararLlave(FuncionObtenerLlave(raiz.valores[ind].valor), FuncionObtenerLlave(dato)) == 0)
                    {
                        yaInsertado = true;
                    }
                }
                else //Si ya esta lleno procede a hacer el primer split de todos en la raiz
                {
                    separarNodos(raiz, nuevito);
                }
            }
            else
            {
                insertarInterno(raiz, nuevito);
            }


            if (yaInsertado)
            {
                Insertados.Add(dato);
                asignarPadres3(raiz);
                yaInsertado = false;
                nuevito     = null;
            }
        }
        /// <summary>
        /// Ordena los valores del nodo lista en forma ascendente
        /// </summary>
        /// <param name="aux">Arreglo o lista</param>
        public void ordenarNodo(NodoIndividual <T>[] aux)
        {
            for (int i = 0; i < aux.Length; i++)
            {
                if (i != aux.Length - 1)
                {
                    if (aux[i + 1] != null)
                    {
                        if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux[i].valor), FuncionObtenerLlavePrincipal(aux[i + 1].valor)) == 0)
                        {
                            if (this.FuncionCompararLlave(FuncionObtenerLlave(aux[i].valor), FuncionObtenerLlave(aux[i + 1].valor)) > 0)
                            {
                                NodoIndividual <T> tempo = aux[i];
                                aux[i]     = aux[i + 1];
                                aux[i + 1] = tempo;
                            }

                            if (i != 0 && FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux[i].valor), FuncionObtenerLlavePrincipal(aux[i - 1].valor)) == 0 &&
                                this.FuncionCompararLlave(FuncionObtenerLlave(aux[i].valor), FuncionObtenerLlave(aux[i - 1].valor)) < 0)
                            {
                                ordenarNodo(aux);
                            }
                        }
                        else if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux[i].valor), FuncionObtenerLlavePrincipal(aux[i + 1].valor)) > 0)
                        {
                            NodoIndividual <T> tempo = aux[i];
                            aux[i]     = aux[i + 1];
                            aux[i + 1] = tempo;

                            if (i != 0 && FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux[i].valor), FuncionObtenerLlavePrincipal(aux[i - 1].valor)) < 0)
                            {
                                ordenarNodo(aux);
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Cuando el nodo lista se encuentra lleno se crea un nuevo nodo temporal
        /// con un espacio extra para ordenarse y observar cual es el valor que debe
        /// "subir" al nodo lista Padre hasta que este insertado en una posicion
        /// </summary>
        /// <param name="aux">Arreglo o lista</param>
        /// <param name="valor">Valor a ingresar</param>
        public void separarNodos(NodoLista <T> aux, NodoIndividual <T> valor)
        {
            //Crea la lista temporal y ingresa los datos del nodo lista actual
            NodoLista <T> temp = new NodoLista <T>(grado + 1);

            for (int i = 0; i < temp.valores.Length; i++)
            {
                if (i <= aux.valores.Length - 1)
                {
                    temp.valores[i] = aux.valores[i] as NodoIndividual <T>;
                }
            }

            /*Ya que la lista temporal tiene un espacio adicional al del nodo lista actual
             * (el ultimo espacio) ahi se ingresa el valor que viene y se ordena para
             * escoger que valor "sube" para ser insertado en un espacio real de
             * algun nodo del arbol
             */
            NodoIndividual <T> nodoAux = new NodoIndividual <T>();

            nodoAux = valor;
            temp.valores[temp.valores.Length - 1] = nodoAux;
            ordenarNodo(temp.valores);

            NodoIndividual <T> subir;
            NodoLista <T>      hijoIzq   = new NodoLista <T>(grado);
            NodoLista <T>      hijoDer   = new NodoLista <T>(grado);
            double             indiceaux = ((double)grado / (double)2);
            double             indice    = indiceaux - 1;

            if (grado % 2 == 1)
            {
                indice = indice + 0.5;
            }
            subir = temp.valores[Convert.ToInt32(indice)];
            //Todos los hermanos que tiene a la izquiera seran parte de su hijo izquierdo
            //Y todos los hermanos a la derecha seran parte de su hijo derecho
            for (int i = 0; i < temp.valores.Length; i++)
            {
                if (i < indice)
                {
                    insertarExistenteEnArreglo(hijoIzq, temp.valores[i]);
                }
                else if (i > indice)
                {
                    insertarExistenteEnArreglo(hijoDer, temp.valores[i]);
                }
            }

            subir.izquierdo = hijoIzq;
            subir.derecho   = hijoDer;



            if (aux.Padre != null)
            {
                if (validarEspacio(aux.Padre as NodoLista <T>))
                {
                    insertarExistenteEnArreglo(aux.Padre, subir);
                    hijoDer.Padre = aux.Padre;
                    hijoIzq.Padre = aux.Padre;
                    int ind = buscarEnLista(aux.Padre, subir.valor);
                    if (ind == 0)
                    {
                        if (aux.Padre.valores[0] == subir)
                        {
                            asignarHijos(aux.Padre.valores, ind);
                        }
                    }
                    else
                    {
                        asignarHijos(aux.Padre.valores, ind);
                    }
                    yaInsertado = true;
                }
                else
                {
                    separarNodos((aux.Padre as NodoLista <T>), subir);
                    buscarEnArbol(raiz, subir);
                    encontrado = false;
                }
            }
            else
            {
                NodoLista <T> raizAux = new NodoLista <T>(grado);
                insertarExistenteEnArreglo(raizAux, subir);
                int ind = buscarEnLista(raizAux, subir.valor);
                if (ind == 0)
                {
                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(raizAux.valores[0].valor), FuncionObtenerLlavePrincipal(subir.valor)) == 0 &&
                        FuncionCompararLlave(FuncionObtenerLlave(raizAux.valores[0].valor), FuncionObtenerLlave(subir.valor)) == 0)
                    {
                        raizAux.valores[ind] = subir;
                    }
                }
                raiz          = raizAux;
                raiz.Padre    = null;
                hijoDer.Padre = raiz;
                hijoIzq.Padre = raiz;
                yaInsertado   = true;
            }
        }
        /// <summary>
        /// Metodo para buscar el nuevo nodo lista en el que se encuentra el dato que sube
        /// para asignar los hijos de manera correcta en todo el arbol
        /// </summary>
        /// <param name="aux">Nodo lista donde inicia la busqueda</param>
        /// <param name="dato">Dato que sube</param>
        public void buscarEnArbol(NodoLista <T> aux, NodoIndividual <T> dato)
        {
            K llaveBuscar          = FuncionObtenerLlave(dato.valor);
            J llaveBuscarPrincipal = FuncionObtenerLlavePrincipal(dato.valor);

            for (int i = 0; i < aux.valores.Length; i++)
            {
                if (aux.valores[i] != null)
                {
                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llaveBuscarPrincipal) == 0 &&
                        FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].valor), llaveBuscar) == 0)
                    {
                        int ind = buscarEnLista(aux, dato.valor);
                        if (ind == 0)
                        {
                            if (aux.valores[0] == dato)
                            {
                                asignarHijos(aux.valores, ind);
                                encontrado = true;
                            }
                        }
                        else
                        {
                            asignarHijos(aux.valores, ind);
                            encontrado = true;
                        }
                        break;
                    }
                }
            }

            if (!encontrado)
            {
                for (int i = 0; i < aux.valores.Length; i++)
                {
                    if (aux.valores[i] != null)
                    {
                        //si la funcion principal es igual, pasa al segundo criterio
                        if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llaveBuscarPrincipal) == 0)
                        {
                            //Caso sea menor a la primera posicion
                            if (i == 0 && FuncionCompararLlave(FuncionObtenerLlave(aux.valores[0].valor), llaveBuscar) > 0)
                            {
                                buscarEnArbol(aux.valores[i].izquierdo, dato);
                                break;
                            }
                            //Caso sea mayor a la ultima posicion
                            else if ((i == aux.valores.Length - 1 || aux.valores[i + 1] == null) &&
                                     FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].valor), llaveBuscar) < 0)
                            {
                                buscarEnArbol(aux.valores[i].derecho, dato);
                                break;
                            }
                            //Caso este contenido entre dos valores
                            else if (i < aux.valores.Length - 1 && aux.valores[i + 1] != null &&
                                     (FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].valor), llaveBuscar) < 0 &&
                                      FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i + 1].valor), llaveBuscar) > 0))
                            {
                                buscarEnArbol(aux.valores[i].derecho, dato);
                                break;
                            }
                        }//Caso sea menor a la primera posicion con llave principal
                        else if (i == 0 && FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[0].valor), llaveBuscarPrincipal) > 0)
                        {
                            buscarEnArbol(aux.valores[i].izquierdo, dato);
                            break;
                        }//Caso sea mayor a la ultima posicion llena con llave principal
                        else if ((i == aux.valores.Length - 1 || aux.valores[i + 1] == null) &&
                                 FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llaveBuscarPrincipal) < 0)
                        {
                            buscarEnArbol(aux.valores[i].derecho, dato);
                            break;
                        }//Caso este contenido entre dos valores con llave principal
                        else if (i < aux.valores.Length - 1 && aux.valores[i + 1] != null &&
                                 (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llaveBuscarPrincipal) < 0 &&
                                  FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i + 1].valor), llaveBuscarPrincipal) > 0))
                        {
                            buscarEnArbol(aux.valores[i].derecho, dato);
                            break;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Metodo de insercion recursivo para cuando algun valor del nodo lista
        /// ya tengo hijos
        /// </summary>
        /// <param name="aux">Nodo lista a evaluar o insertar</param>
        /// <param name="dato">Valor a insertar</param>
        private void insertarInterno(NodoLista <T> aux, NodoIndividual <T> dato)
        {
            K llaveInsertar          = FuncionObtenerLlave(dato.valor);
            J llavePrincipalInsertar = FuncionObtenerLlavePrincipal(dato.valor);

            for (int i = 0; i < aux.valores.Length; i++)
            {
                if (aux.valores[i] != null)
                {
                    //si la funcion principal es igual, pasa al segundo criterio
                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llavePrincipalInsertar) == 0)
                    {
                        if (i == 0 && FuncionCompararLlave(FuncionObtenerLlave(aux.valores[0].valor), llaveInsertar) > 0)
                        {
                            if (aux.valores[i].izquierdo != null)
                            {
                                if (!validarHijos(aux.valores[i].izquierdo))
                                {
                                    if (validarEspacio(aux.valores[i].izquierdo))
                                    {
                                        insertarEnArreglo(aux.valores[i].izquierdo, dato.valor);

                                        int ind = buscarEnLista(aux.valores[i].izquierdo, dato.valor);
                                        if (FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].izquierdo.valores[ind].valor), llaveInsertar) == 0)
                                        {
                                            yaInsertado = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        separarNodos(aux.valores[i].izquierdo, dato);
                                        if (yaInsertado)
                                        {
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    insertarInterno(aux.valores[i].izquierdo, dato);
                                }
                            }
                        }//Caso sea mayor a la ultima posicion
                        else if ((i == aux.valores.Length - 1 || aux.valores[i + 1] == null) &&
                                 FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].valor), llaveInsertar) < 0)
                        {
                            if (aux.valores[i].derecho != null)
                            {
                                if (!validarHijos(aux.valores[i].derecho))
                                {
                                    if (validarEspacio(aux.valores[i].derecho))
                                    {
                                        insertarEnArreglo(aux.valores[i].derecho, dato.valor);

                                        int ind = buscarEnLista(aux.valores[i].derecho, dato.valor);
                                        if (FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].derecho.valores[ind].valor), llaveInsertar) == 0)
                                        {
                                            yaInsertado = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        separarNodos(aux.valores[i].derecho, dato);
                                        if (yaInsertado)
                                        {
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    insertarInterno(aux.valores[i].derecho, dato);
                                }
                            }
                        }//Caso este contenido entre dos valores
                        else if (i < aux.valores.Length - 1 && aux.valores[i + 1] != null &&
                                 (FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].valor), llaveInsertar) < 0 &&
                                  FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i + 1].valor), llaveInsertar) > 0))
                        {
                            if (aux.valores[i].derecho != null)
                            {
                                if (!validarHijos(aux.valores[i].derecho))
                                {
                                    if (validarEspacio(aux.valores[i].derecho))
                                    {
                                        insertarEnArreglo(aux.valores[i].derecho, dato.valor);

                                        int ind = buscarEnLista(aux.valores[i].derecho, dato.valor);
                                        if (FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].derecho.valores[ind].valor), llaveInsertar) == 0)
                                        {
                                            yaInsertado = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        separarNodos(aux.valores[i].derecho, dato);
                                        if (yaInsertado)
                                        {
                                            break;
                                        }
                                    }
                                }
                                else
                                {
                                    insertarInterno(aux.valores[i].derecho, dato);
                                }
                            }
                        }
                    }//Caso sea menor a la primera posicion con llave principal
                    else if (i == 0 && FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[0].valor), llavePrincipalInsertar) > 0)
                    {
                        if (aux.valores[i].izquierdo != null)
                        {
                            if (!validarHijos(aux.valores[i].izquierdo))
                            {
                                if (validarEspacio(aux.valores[i].izquierdo))
                                {
                                    insertarEnArreglo(aux.valores[i].izquierdo, dato.valor);

                                    int ind = buscarEnLista(aux.valores[i].izquierdo, dato.valor);
                                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].izquierdo.valores[ind].valor), llavePrincipalInsertar) == 0 &&
                                        FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].izquierdo.valores[ind].valor), llaveInsertar) == 0)
                                    {
                                        yaInsertado = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    separarNodos(aux.valores[i].izquierdo, dato);
                                    if (yaInsertado)
                                    {
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                insertarInterno(aux.valores[i].izquierdo, dato);
                            }
                        }
                    }//Caso sea mayor a la ultima posicion llena con llave principal
                    else if ((i == aux.valores.Length - 1 || aux.valores[i + 1] == null) &&
                             FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llavePrincipalInsertar) < 0)
                    {
                        if (aux.valores[i].derecho != null)
                        {
                            if (!validarHijos(aux.valores[i].derecho))
                            {
                                if (validarEspacio(aux.valores[i].derecho))
                                {
                                    insertarEnArreglo(aux.valores[i].derecho, dato.valor);

                                    int ind = buscarEnLista(aux.valores[i].derecho, dato.valor);
                                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].derecho.valores[ind].valor), llavePrincipalInsertar) == 0 &&
                                        FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].derecho.valores[ind].valor), llaveInsertar) == 0)
                                    {
                                        yaInsertado = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    separarNodos(aux.valores[i].derecho, dato);
                                    if (yaInsertado)
                                    {
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                insertarInterno(aux.valores[i].derecho, dato);
                            }
                        }
                    }//Caso este contenido entre dos valores con llave principal
                    else if (i < aux.valores.Length - 1 && aux.valores[i + 1] != null &&
                             (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].valor), llavePrincipalInsertar) < 0 &&
                              FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i + 1].valor), llavePrincipalInsertar) > 0))
                    {
                        if (aux.valores[i].derecho != null)
                        {
                            if (!validarHijos(aux.valores[i].derecho))
                            {
                                if (validarEspacio(aux.valores[i].derecho))
                                {
                                    insertarEnArreglo(aux.valores[i].derecho, dato.valor);

                                    int ind = buscarEnLista(aux.valores[i].derecho, dato.valor);
                                    if (FuncionCompararLlavePrincipal(FuncionObtenerLlavePrincipal(aux.valores[i].derecho.valores[ind].valor), llavePrincipalInsertar) == 0 &&
                                        FuncionCompararLlave(FuncionObtenerLlave(aux.valores[i].derecho.valores[ind].valor), llaveInsertar) == 0)
                                    {
                                        yaInsertado = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    separarNodos(aux.valores[i].derecho, dato);
                                    if (yaInsertado)
                                    {
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                insertarInterno(aux.valores[i].derecho, dato);
                            }
                        }
                    }
                }
            }
        }