domingo, 25 de noviembre de 2012

Solemne 2. Mi versión.


Hola chicos.
Tengo algo botado el blog, la verdad es que el tiempo me anda trayendo justo.

Sin embargo, para los que dan la prueba este martes una ayudita con mi versión de la prueba:
 


1.- Esta era un regalo, era de cosa de mirar los apuntes:

public AVL RL(AVL t)
    {
        AVL p = t.der ;
        AVL h = p.izq;
        t.der = h.izq;
        p.izq = h.der ;
        h.izq = t ;
        h.der = p ;
        return h ;
    }
2.-Con el programa que pasó el profe se podía resolver en corto tiempo.
También se podía hacer un montón de dibujitos hasta llegar al árbol definitivo, eso sí había que dominar bien los algoritmos de inserción de los AVL, la respuesta es la siguiente.




3.- Esta era más dificil pero con un poco de ingenio y sin dejar de mirar los tres recorridos se podía deducir la estructura. Admiren mi capacidad de creación gráfica computacional:





4.- Esta era cosa de dibujar un arbol balanceado o de simples matemáticas, yo lo resolví así:
Pero como los niveles se expresan en números enteros y son variables según el balance tomamos como mínimo el 4 y el algo más (0.43) como otro nivel probable. o sea en el 4º ó 5º nivel (nivel 3 ó 4).

Bye.

sábado, 6 de octubre de 2012

Prueba Estructura de Datos - Mi versión de la prueba.

Bien niños, para aquellos que sobrevivieron, los que ya recuperaron la conciencia y los que ya hayan salido de la transfusión de sangre les comparto mi versión de la primera prueba de ED. Lamento tener que decirles que las primeras 3 preguntas eran un regalo, solo la cuarta era un marciano.

1.- Recibir un string con una expresión aritmética y retornar su valor entero.

Estaba resuelta en la entrada anterior. Sólo se necesitaba la primera función de la clase. Recuerden que el profe sólo pide algoritmos (como se resuelve un problema) no programas completamente funcionales.

public static int evaluaEcuacion(String strEcuacion)
{
  if(blnIsNum(strEcuacion))
   return Integer.parseInt(strEcuacion);
   
  strEcuacion = quitaParentesisExteriores(strEcuacion);
   
  String strEcIzq = obtenerPrimerMiembro(strEcuacion);
  char   strOp    = strEcuacion.charAt(strEcIzq.length());
  String strEcDer = strEcuacion.substring(strEcIzq.length()+1);
   
  return opera(strOp, evaluaEcuacion(strEcIzq), evaluaEcuacion(strEcDer));
 }

2.- Convertir un entero a string hexadecimal.

Este problema estaba resuelto en el dummyMath.java que envié a la carpeta del curso en google docs, y también estaba en esta entrada del blog.

public static String hexadecimal(int n)
{
 if (n==0) return "";

 int digHex = n%16; 

 switch (digHex)
 {
  case 10: return hexadecimal(n/16)+"A"; 
  case 11: return hexadecimal(n/16)+"B"; 
  case 12: return hexadecimal(n/16)+"C"; 
  case 13: return hexadecimal(n/16)+"D"; 
  case 14: return hexadecimal(n/16)+"E"; 
  case 15: return hexadecimal(n/16)+"F"; 
  default: return hexadecimal(n/16)+Integer.toString(digHex);
 }
}

3.-Insertar un elemento en forma ordenada en una lista circular.

Este era igual al que el profe nos dió en clases pero con una ligera modificación.

public Lista insertarOrdenado(Lista L, int dato)
{
 if (l==null)
 {//Esta es la que había que modificar
  Lista nueva == new Lista(dato);
  nueva.siguiente = nueva;
  return nueva;
 }

 if (dato < l.dato)
 {
  Lista nueva == new Lista(dato);
  nueva.siguiente = this;
  return nueva;
 }

 l.siguiente = insertarOrdenado(l.siguiente, dato);
 return l;
}

4.- Buscar a un usuario en una lista y retornar cuanto tiempo ha hecho uso del sistema.

Este sí que era un marciano. Vamos a definir varios supuestos para simplificar el algoritmo.
  1. La lista es de objetos que tienen los campos descritos en el encabezado de la pregunta, por lo que podemos acceder a ellos así l.accion, l.usuario, l.horario... bla bla bla.
  2. El campo l.horario es un objeto que posee un método que convierte la hora en número decimal.
  3. La función va a devolver un  double (Es decir puede devolver 3,5 si el usuario estuvo conectado 3 horas y media por ejemplo).
  4. Que existe una función llamda diffHora(double salida, double entrada)  que se encarga de convertir a número, sacar la diferencia, ver si se pasó de día... etc.

public double tiempoDeConex(Strng usuario, Lista L, double hora)
{//Si llegamos al final de la lista retornamos 0.
 if (L==null)
  return (double) 0;

 //Si encontramos al usuario preguntamos cual es la acción
 //Si la acción es "Sale" devolvemos la diferencia entre la hora
 //que hay en el elmento de la lista y la que viene como parámetro
 //(Ojo, la hora del parametro viene de la acción "Entra".
 if (L.usuario == usuario)
 {
  if (L.accion == "Sale")
  {// pido el resultado de la recursión siguiente y lo devuelvo
   // sumado con el resultado de la recursión actual
   double horaAux = tiempoDeConex(usuario, L.siguiente, 0);
   return horaAux + difHora(l.horario.toDouble(), hora);
  }
  //Si la accion es "Entra" envío la hora de entrada
  //a la recursión siguiente 
  return tiempoDeConex(usuario, L.siguiente, l.horario.toDouble());
 }
 //Y si no he encontrado al usuario envío todos los datos
 //que vienen en los parámetros al dato siguiente.
 return tiempoDeConex(usuario, L.siguiente, hora);
}
No sé si está bueno. De hecho parece que tampoco lo contesté así en la prueba pero bue... si alguien le encuentra la falla que lo diga y así vamos mejorando esto.

Un abrazo a todos.

miércoles, 3 de octubre de 2012

Recursividad - Ejercicios resueltos 101

Actualización 10-10-2012:

Todo puede mejorar. Ahora puede resolver cualquier sobrecarga de paréntesis y resolver números signados. Tuve que agregar una función recursiva más (cierreParentesis()), esta vez era necesaria, para que discriminara cual paréntesis cerraba a cada cual y así saber si el primero y el último de la expresión se cerraban entre sí.


Fin actualización.


Qué tal chicos.

Para este viernes el profe nos hizo un regalito para la prueba.

Como el regalo es para todos les comparto mi versión.
Este programa funciona con las siguientes restricciones:
  • No se pueden poner números signados entre las operaciones (ej: -13+-51) solo operaciones entre números naturales. (deprecado)
  • Los paréntesis siempre deben estar equilibrados.
  • Entre los paréntesis sólo puede haber operaciones y no números solos o signados (ej: "(+58)").(deprecado)
  • No sirve para elementos con sobrecarga de parentesis, ej: (((9+8))).(deprecado)
Saquen sus versiones modifíquenlo, mejórenlo y nos vemos en la prueba este viernes.

Que nos vaya bien:

6.- Escriba un programa en Java que reciba un string que contenga una expresión aritmética y que retorne el valor de la evaluación.
Ej: "((5+1)*(7-6))" = 6.

Solución:
public class evaluaEcuacionString
{
 public static int evaluaEcuacion(String strEcuacion)
 {
  strEcuacion = quitaParentesisExteriores(strEcuacion);
  
  if(blnIsNum(strEcuacion))
   return Integer.parseInt(strEcuacion);
    
  String strEcIzq = obtenerPrimerMiembro(strEcuacion);
  char   chrOp    = strEcuacion.charAt(strEcIzq.length());
  String strEcDer = strEcuacion.substring(strEcIzq.length()+1);
  
  return opera(chrOp, evaluaEcuacion(strEcIzq), evaluaEcuacion(strEcDer));
 }
 
 private static int opera(char op, int a, int b)
 {
  switch (op)
  {
  case '+': return a + b;
  case '-': return a - b;
  case '*': return a * b;
  default : return (int) a / b;
  }
 }
 
 private static String quitaParentesisExteriores(String ecu)
 {
  if(ecu.charAt(0) =='(')
   if(ecu.charAt(ecu.length()-1) ==')')
    if(entreParentesis(ecu))
     return quitaParentesisExteriores(ecu.substring(1, ecu.length()-1));
   
        return ecu;         
    }
 
 private static boolean entreParentesis(String ecu)
 {
  return (cierreParentesis(ecu,1) == ecu.length()-1);  
 }
 
 private static int cierreParentesis(String ecu, int pos)
 {
  int i = pos;
  int cerrado=-1;
  
  while (i <= ecu.length()-1)
  {
   //if(i < ecu.length())
    if(ecu.charAt(i)==')')
     return i;
   
   if(ecu.charAt(i)=='(')
   {
    cerrado = cierreParentesis(ecu, i+1);
    i = cerrado;
   }
   
   i++;
   
   
   
  }
  return cerrado;// return i==ecu.length();
 }
 
 
 private static String obtenerPrimerMiembro(String ecu)
 {
  String miembro="";
  
  if(ecu.charAt(0)=='(')
  { 
   int equilibrio = 0;
   int i=0;
   do
   {
    char elem = ecu.charAt(i);
    miembro+= elem;
    if(elem == '(')
     equilibrio++;
    
    if(elem == ')')
     equilibrio--;
    
    i++;
    
   }while (equilibrio != 0);
  }
  else
  {
   miembro+=ecu.charAt(0);
   
   for(int i=1; Character.isDigit(ecu.charAt(i)); i++)
    miembro+=ecu.charAt(i);
  }
  return miembro;
 }
 
 private static boolean blnIsNum(String s)
 {
  //retorna true si el string representa un entero
  //con o sin signo
  
  int primerChar = 0;
  if(s.charAt(0)=='+' || s.charAt(0)=='-')
   primerChar=1;
   
  for(int i=primerChar; i< s.length(); i++)
   if(!Character.isDigit(s.charAt(i)))
    return false;
  
  return true;
 }
 
 
 public static void main(String[] args)
 {
  //Modifiquen el string para probarlo
  // ;-)
  
  System.out.println(evaluaEcuacion("(((5*3)/(2-1)))+(((5/3)+8)-60)"));
 }

}

sábado, 8 de septiembre de 2012

Recursividad - Ejercicios resueltos 100

Si fuéramos menos impacientes no tendríamos problema con el backtracking.

Aquellos que son usuarios (y sólo usuarios), están tan acostumbrados a que sus amados computadores les resuelvan todo que no están ni cerca de experimentar un trabajo repetitivo de ensayo y error.

El problema de las ocho reinas es un clásico del ingenio y cual más cual menos, debe utilizar el backtracking para solucionarlo.

El algoritmo general del problema de las ocho reinas se resuelve así:


  1. Se coloca una reina en alguna de las filas.
  2. Se siguen intentando colocar la siguiente reina en la siguiente fila preguntando en cada posición si está amenazada por otra reina existente.
  3. Si no quedan más posiciones, se vuelve a la pieza anterior y se sigue intentando por las siguientes columnas de su fila
¿Nada más?

Nada más. Eso es el algoritmo general. Cuanto más general mayores posibilidades de hacerlo recursivo.


5.- Confeccione una función recursiva que llene un tablero de ajedrez con 8 reinas sin que estas se amenacen entre sí:


La implementación en Java es la siguiente:

public void reinas(int i, int j, int dama)
{
 
 //  Mientras no haya recorrido todo el tablero...
 if ( estaDentro(i,j) )
 {
 
  //  ...y si la posición en la que voy a poner la 
  //  reina no está amenazada...                   
  if (noAmenazada(i,j))
  {
   //Ponemos la reina
   T[i][j]=dama;

   //BORDE: Si logramos colocar la última reina
   //Imprimimos el tablero con la solución
   if (dama == N) imprimir();

   //Y si no es la última recurrimos por la
   //siguiente fila
   reinas(i+1, 0, dama + 1);

   //Si lo anterior falla sacamos la reina
   T[i][j]=0;
  }
  // Si la posición está amenazada recurrimos por la
  // siguiente columna.
  reinas(i, j+1, dama);
  //Si lo anterior falló, quitamos la reina
  T[i][j]=0;
 }
}

miércoles, 5 de septiembre de 2012

Recursividad - Ejercicios resueltos 11

No existe una única forma de implementar una función recursiva. Cuando una solución es de tipo procedural puede que la primera acción no sea el "borde", si no una acción concreta, para luego a través de la validación hacer el llamado recursivo.

4.- Confeccione una función recursiva que llene un tablero n-goro. Un tablero n-goro es una matriz de n x n+1 que se llena consecutivamente en diagonal y cada vez que se desborda la continuidad se sigue por la fila o columna desocupada contigua según corresponda:

1
17
13
9
5
6
2
18
14
10
11
7
3
19
15
16
12
8
4
20

Empezamos inmediatamente a llenar la matriz empezando por la primera posición y continuamos por la diagonal (posiciones 0,0 1,1 2,2 3,3 ... etc).

Borde: Si i=n y j=n+1, quiere decir que llegamos a la última posición de la matriz y podemos imprimir.

Si no es así, debemos revisar si la i (filas) excedió la última posición y debemos mantener el número que queríamos colocar y la posición de la columna pero cambiar la fila por la 0 (empezar de arriba de nuevo).

También debemos validar que la j no exceda n+1, lo que significará que se habrá pasado de la última columna y en ese caso, mantenemos la fila y el número para cambiar la j por 0 (primera columna).

La implementación en Java es la siguiente:

public void nGoro(int i, int j, int paso){
 /*************************************
  * Si se mantiene dentro del tablero,*
  * llenar la posición con el valor   *
  * en la recursión y continuar por la*
  * posición en diagonal.             *
  *************************************/
 
 if( estaDentro(i,j) ){
  T[i][j] = paso;
  nGoro(i+1, j+1, paso + 1);
 }
 /****************************************
  * BORDE:                               *
  * Si se ha llegado a la última posición*
  * se imprime y no hace nada más        *
  ****************************************/
 else if( (i==N) && (j==N+1))
   imprimir( );
 
 /****************************************
  * Si    se ha pasado de la última fila *
  * conservar número y columna y recurrir*
  * por la primera fila                  *
  ****************************************/
 else if ( i == N )
  nGoro(0, j, paso);
  
 /****************************************
  * Si se excede la última columna se    *
  * conserva el número y la fila y se    *
  * recurre por la primera columna.      *
  ****************************************/
 else if ( j == N+1 )
  nGoro(i, 0, paso);
}

domingo, 2 de septiembre de 2012

Recursividad - Ejercicios resueltos 10

Otro algoritmo interesante es el que descompone un número cualquiera en sus factores primos. Lo más entretenido de este ejercicio es que nos prepara para para  recorrer datos en una estructura de árbol (como en el ejercicio de a elevado a n).

3.- Confeccione una función recursiva que permita determinar o presentar los factores primos de un número n.
Ejemplo: 90 = 9 * 10 = (3 * 3) * (2 * 5).

Encontrar los factores "medios" de un número (por así decirlo) pasa por encontrar el factor más cercano a la raíz cuadrada del número. Tomando sólo la parte entera de la raíz cuadrada de n se puede obtener el factor exacto o un número un poco menor. Si es menor lo incrementamos hasta encontrar el factor buscado. El otro factor se obtiene dividiendo n por el factor encontrado. Si los factores no son primos se recurre con estos valores. Por lo tanto la condición de paro (borde) es que n se haya transformado en primo.

La implementación en Java es la siguiente:

public static void factoresPrimos(int n) {

 //Si n es primo se imprime.
 if (esPrimo(n)){
  System.out.print("*"+n+" ");
  return;
 }

 //Si n no es primo calculamos el primer factor... 
 int factor1 = (int) Math.sqrt(n);
 
 while (n % factor1 !=0) factor1++;
 
 //... recurrimos por el primer factor
 factoresPrimos(factor1);

 //... y luego recurrimos por el siguiente factor.
 factoresPrimos(n/factor1);
}

Recursividad - Ejercicios resueltos 1

Anteriormente, habíamos hecho un algoritmo para transformar un número decimal a string binario. Con una pequeña modificación podemos hacer lo mismo pero en base decimal.

2.- Confeccione una función recursiva que reciba un número natural y retorne un string conteniendo su equivalente hexadecimal.

El algoritmo es el mismo del anterior: Se divide consecutivamente el número entero por 16 (la base) y se concatenan los restos de la división. Cabe destacar que como la recolección de los restos debe ser en sentido inverso la recursión debe ser antes de la concatenación con el dígito resultante.


La implementación en Java es la siguiente:

public static String hexadecimal(int n){

 //Si el entero llega a ser cero, quiere decir que terminó la
 //división y como no queda resultado que calcular retornamos
 //un espacio vacío (no en blanco, ojo)
 if (n==0) return "";

 //Pero si aún es mayor que cero debemos calcular el resto de
 //la división por la base y evaluar el caso especial de cada
 //valor. Recordemos que la base 16 o hexadecimal tiene seis
 //dígitos más que representan los números decimales del 10
 //al 15.
 int digHex = n%16; 

 switch (digHex){
  case 10: return hexadecimal(n/16)+"A"; 
  case 11: return hexadecimal(n/16)+"B"; 
  case 12: return hexadecimal(n/16)+"C"; 
  case 13: return hexadecimal(n/16)+"D"; 
  case 14: return hexadecimal(n/16)+"E"; 
  case 15: return hexadecimal(n/16)+"F"; 
  default: return hexadecimal(n/16)+Integer.toString(digHex);
 }
}