martes, 24 de noviembre de 2015

Palíndromo / Capicúa

El ejercicio de detectar si una secuencia de caracteres (o dígitos) es un palíndromo (capicúa)  es uno de los ejercicios más completos, podemos ver: recorrido de vectores, condicionales, uso de variables booleanas y tratamiento de cadenas.

Un ejemplo de palíndromo es la palabra "Radar", si la leemos de izquierda a derecha o viceversa leeremos lo mismo.

¿Cómo saber si es una palíndromo?
Hacemos la lectura en un sentido y otro y comprobamos que decimos lo mismo, esta sería la versión resumida de lo que realmente hace nuestro cerebro. Pero si nos detenemos a pensar en cómo le diríamos al ordenador (procesador) que lo haga ¿cómo lo haríamos?
Si leemos al mismo tiempo en ambas direcciones y comprobamos que cada letra que vamos leyendo es la misma, diríamos que si todas y cada una de las letras que leemos en ambas direcciones son las mismas es un palíndromo. En complemento a este razonamiento podemos decir también que en la comparación letra a letra que hacemos al leer una misma palabra en sentidos opuestos, basta con que algún par difiera para que la palabra NO ses un palíndromo.

Dicho esto, es mucho más claro verlo en código comentado:


//variable que almacena el texto (máximo 10 caracteres)
char palabra[10]; 

//variables para recorrer la palabra
int indicePrimeraLetra = 0; //índice inicio recorrido de izq. a der.
int indiceUltimaLetra; //índice inicio recorrido de der. a izq.

//variable que determina si la palabra es palíndromo
bool esPalindromo = true;

//llenamos el texto con información desde teclado
printf("Ingresa la palabra: ");
scanf ("%s",palabra);
printf("\nLa palabra ingresada es: %s", palabra);

//tratamiento de la cadena
//inicializamos con la última posición para recorrer de der. a izq.
indiceUltimaLetra = strlen(palabra) - 1;
printf("\nNúmero de elementos de la palabra: %d", strlen(palabra));

//realizamos la lectura en ambas direcciones, termina cuando se cruzan los índices o cuando alguna de las letras no coincide
while(esPalindromo && indicePrimeraLetra < indiceUltimaLetra)
{
   //basta que un par de letras no coincida para que NO sea palíndromo
   if (palabra[indicePrimeraLetra] != palabra[indiceUltimaLetra])
      {esPalindromo = false;}
            
   indicePrimeraLetra++;//incrementa índice lectura izq. a der.
   indiceUltimaLetra--;//decrementa índice lectura der. a izq.
}


printf("\n¿Es palindromo? ");
if(esPalindromo) printf("SI");
else printf("NO");


Importante!!
- La inicialización de la variable indiceUltimaLetra se hace después de leer la palabra a evaluar, porque tiene que posicionarse en la última letra y hasta no leer la palabra no sabemos la longitud.
- La dirección del recorrido de las lecturas se determina al incrementar la variable indicePrimeraLetra y al decrementar la variable indiceUltimaLetra
- La condición de salida del while: Si sale por la primera condición es que la palabra NO es un palíndromo, si sale por la segunda condición ha terminado de comprobar y todas coinciden por tanto SI es palindromo.

Finalmente...
¿Sabéis por qué el recorrido termina a la mitad de la palabra (condición indicePrimeraLetra < indiceUltimaLetra) y por que no cuando indicePrimeraLetra llega hasta el final de la palabra (strlen(palabra))?





jueves, 5 de noviembre de 2015

Asignación (=) VS. Comparación (==)

Un error típico es confundir la operación lógica de comparación IGUAL con la de asignación, lo peor de este error es que no se detecta en la compilación ni en la ejecución, sino que genera que el programa realice un flujo diferente al esperado.

La operación de asignación (=) cuando se realiza correctamente devuelve un 1 como resultado indicando que todo ha ido bien, por ejemplo:

int a; //definición de variable a de tipo int
if( a = 3) //si la operación de asignación se realiza correctamente realiza lo que está dentro del if
{
   ...
}

Podría ocurrir que por un error físico o lógico de memoria la operación a=3 se realice mal, en ese caso no se realizaría lo que está dentro del if.

Un ejemplo típico es utilizar variables para determinar el fin de una iteración, como ejemplo tenemos un programa que realiza una operativa siempre que el usuario pulse 1, cuando el usuario marca una tecla distinta termina la ejecución del programa. La estructura del algoritmo sería la siguiente:

int fin_ejecucion = 1; //variable que determina el fin de la ejecución del programa

while (fin_ejecucion == 1)
{
     //aquí realiza la función del programa
     //cuando termina la ejecución pregunta si quiere continuar
     write("Pulse 1 si desea continuar");
     read(fin_ejecucion); //lee del teclado lo que el usuario quiere
}

Si por error, cambiásemos la comparación por la asignación, la consecuencia sería que la operación fin_ejecucion = 1 siempre sería TRUE y por tanto nunca dejará de ejecutar el bucle.

Parece trivial, cuando en resolución de ejercicios (sobretodo los que se hacen en papel), se insiste mucho sobre este tema, pero es muy importante tenerlo en cuenta debido a que el compilador no lo puede detectar (no es un error de sintaxis) y tampoco lanza error en tiempo de ejecución, simplemente el programa hace algo que no le hemos pedido.

En otros lenguajes de programación como el PLSQL es más difícil caer en este error porque la instrucción de asignación se representa con := y la de comparación con =, por esto es importante conocer el set de instrucciones básicas (lógicas y aritméticas) antes de empezar a programar.