Archivo

Entradas Etiquetadas ‘clave’

Almacenando elementos a pares en C++

Viernes, 22 de Julio de 2011 Gaspar Fernández Sin comentarios

En numerosas ocasiones necesitamos almacenar dos datos de diferente o igual tipo bajo la misma variable. Es más, en ocasiones estarán relacionados y no debemos separarlos o no tendría sentido.

La forma más inmediata es almacenar cada dato por su lado y diseñar los algoritmos de modo que siempre vayan los dos datos juntos, aunque tendremos un problema:

  • Será difícil de mantener, tenemos siempre que asegurar que los datos siempre vayan juntos.
  • Tendríamos que crear más documentación, o el que venga detrás de nosotros a hacer el programa lo pasará mal.
  • Debemos crear funciones / métodos para manejar los datos.

De todas formas, C++ , en la biblioteca estándar contienen muchas cosas ya hechas y esta es una de ellas; utilizando la clase pair podemos hacer fácilmente la asignación / comparación / lectura de pares de datos. De la siguiente manera:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

int main()
{
  pair<int,string> p;

  p.first=23;
  p.second="Probandoooo...";

  cout << p.first << endl;
  cout << p.second << endl;

  p = make_pair(10, "Segunda prueba");

  cout << p.first << endl;
  cout << p.second << endl;

  return 0;
}

Fácilmente podremos crear una instancia de pair, especificando los tipos de dato a almacenar y asignarle los datos (para los ejemplos utilizaré los tipos int y string; aunque puede ser cualquier tipo de dato, clases, etc:

  • Desde el mismo constructor: pair p(999, “Dato de ejemplo”);
  • Desde los atributos first y second (como en el ejemplo)
  • Con la función make_pair(), en la que podemos introducir los objetos directamente

De esta forma, tal vez queramos introducir elementos de configuración, o asignar elementos de tipo clave=>valor, asignar un identificador a un elemento, o símplemente pasar dos datos juntos con un mismo elemento.

Pero si lo que en realidad queremos es almacenar un conjunto de datos (claves y valores) podemos utilizar map o multimap. El objetivo es introducir muchos tipos de elementos con su equivalencia (siendo ésta otro tipo de elemento distinto):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <map>

using namespace std;

int main()
{
  map <int, string> m;
  map <int, string>::iterator i;
 
  // Forma 1
  m.insert(pair<int, string>(10, "Elemento numero diez"));
  // Forma 2
  m[20]="Elemento numero veinte";
  // Forma 3
  m.insert(m.begin(), pair<int, string>(30, "Elemento numero treinta"));

  // Insertamos más elementos
  m[40]="Elemento numero cuarenta";
  m[50]="Elemento numero cincuenta";
  m[60]="Elemento numero sesenta";
  m[70]="Elemento numero ochenta";
 
  // Listamos los elementos
  for (i=m.begin(); i!=m.end(); i++)
    {
      cout << "Elemento " << i->first << " = " << i->second << endl;
    }

  cout << endl;
  // Buscamos un elemento
  i=m.find(30);
  cout << "Elemento 30 => "<<i->second<<endl;

  cout << endl;

  // Buscamos un elemento de otra forma
  cout << "Elemento 40 => "<<m[40]<<endl;

  cout << endl;

  // Cuando un elemento no existe...
  i=m.find(35);
  if (i==m.end())
    cout << "Elemento no existe" <<endl;
  else
    cout << "Elemento 35 => " << i->second <<endl;

  // Devuelve un elemento vacío (o recién construido)
  cout << "Elemento 55: "<< m[55] << endl;

  return 0;
}

Para escribir un poco menos a la hora de definir los tipos podemos utilizar typedef:

1
2
3
4
5
6
7
8
9
typedef map <int, string> mis;  // Map Int String
typedef pis <int, string> mis;  // Pair Int String

int main()
{
   mis m;
   mis::iterator m;
   m.insert(pis(10, "Cadena"));
}

O podemos utilizar el #define de toda la vida:

1
2
3
4
5
6
7
8
9
#define is int, string

int main()
{
  map<is> m;
  map<is>::iterator i;
 
  m.insert(pair<is>(10, "Elemento numero diez"));
}

Aunque tendremos que tener cuidado con lo que pongamos con #define ya que los cambios serán globales.

Recopilación de soluciones para los retos de #tuentiContest . Challenge #20

Jueves, 30 de Junio de 2011 Gaspar Fernández Sin comentarios

Últimamente he hablado acerca del I concurso de programación de Tuenti. Un concurso de programación Online que se llevó acabo durante la semana pasada (del 13 al 20 de Junio, muy mala fecha).

Podéis ver los enunciados de todos los problemas, con ejemplos sobre la entrada y salida (aunque a veces no hay que hacerles mucho caso) en la web oficial del concurso, pero en Vidas Concurrentes lo encontramos todo en español.

Challenge #20 : The Clumsy Programmer

Tenemos un viejo Debian de 32bits y hemos borrado nuestro home, además hemos perdido las claves para descifrar nuestros datos, ¡tenemos que recuperarla!

Este reto, casi nadie lo completamos, y en principio yo pensaba que era más difícil de lo que era. Romper un RSA de 1024 es algo muy lento, y vi que algunos lo resolvían en menos de 20 minutos. Cuando me enteré me arrepentí de no haber pasado un poco más de tiempo buscando información en lugar de abandonar, la verdad es que llevaba un ritmo de sueño muy raro esa semana, y preferí dormir un poco.

Para resolverlo, teníamos que tener en cuanta la época, no nos decían cuando, pero era un viejo Debian, era de 32bits y estábamos utilizando openssl. Parece ser que allá por 2008 se descubrió un fallo en la versión de OpenSSL que instalaba Debian (y derivados), en la que los números aleatorios necesarios para la clave RSA, en lugar de ser a través de /dev/random eran a través de la PID de OpenSSL, con lo cual tenemos muy pocas posibilidades teniendo en cuenta que muchas veces, las PID no es muy alta (más de 500 y menos de 15000, vamos generalmente), es decir, tenemos un número muy acotado de posibles claves RSA a utilizar, por lo que podemos hacer un script en bash para probarlas todas.

Para más información, podéis visitar:

Soluciones:

Si no estás en la lista y quieres plantear tu solución, deja un comentario con tu link !

Actualización 2011/07/03 01:52 : Añadida solución de @frisco82
Actualización 2011/07/03 13:52 : Añadida solución de @Rosapolis

Intercalar 2 ó más cadenas en PHP

Lunes, 9 de Agosto de 2010 Gaspar Fernández Sin comentarios

A la hora de crear un hash para una contraseña, es conveniente no incluir sólo la contraseña, sino concatenar una cadena o un número más; lo mismo cuando generamos claves para que interaccionen aplicaciones en varios servidores; aunque hay veces en que, dados los pocos datos de que disponemos a la hora de generar la clave, no tenemos mucho donde elegir a la hora de crear el hash.

Por ese motivo se me ocurrió esta función en PHP, lo que hace es intercalar cadenas, es decir, tenemos dos cadenas, y queremos generar una cadena a partir de las dos anteriores, podemos coger un carácter de una, otro de otra, y así sucesivamente (como si estuviéramos barajando) hasta formar una cadena cuya longitud es la suma de las dos. Por ejemplo si tenemos las palabras “poesia” y “binaria“, resultaría la cadena: pboiensairaia .

Aunque, ya que vamos a hacer algo así, ¿ por qué limitarlo ? Hagamos una función que soporte una cantidad indeterminada de cadenas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function intercalar($cadenas)
{
  $n_cadenas = count ($cadenas);

  if ($n_cadenas==1)        /* Si sólo hay una cadena, la devolvemos */
    return $cadenas[0];

  /* Contamos los caracteres de cada cadena y los almacenamos en un array */
  $chars_cadena=array();
  for ($i=0; $i<$n_cadenas; $i++)
    $chars_cadena[$i]=strlen($cadenas[$i]);

  $max_cadena = max ($chars_cadena); /* La cadena más larga determina cuándo paramos */
  $res='';
  /* Recorremos la longitud de cadena más larga */
  for ($j=0; $j<$max_cadena; $j++)
    {
      /* Recorremos todas las cadenas */
      for ($i=0; $i<$n_cadenas; $i++)
    {
      /* Si la cadena no está terminada añadiremos el carácter a la cadena */
      if ($j<$chars_cadena[$i])
        $res.=$cadenas[$i][$j];
    }
    }

  return $res;
}

echo intercalar (array("Poesia", "Binaria", "Blog", "Gaspar", "Programacion", "Software", "Libre"));

La cadena resultante de este ejemplo será: PBBGPSLoilaroienosofbsagpgtrirarweairaaamraecion.

Visita otras webs de la red